001/**
002 * Copyright 2005-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kew.plugin;
017
018import static org.junit.Assert.assertEquals;
019import static org.junit.Assert.assertFalse;
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertTrue;
022
023import java.io.File;
024
025import javax.xml.namespace.QName;
026
027import org.apache.commons.io.FileUtils;
028import org.junit.Test;
029import org.kuali.rice.core.api.config.CoreConfigHelper;
030import org.kuali.rice.kew.test.KEWTestCase;
031import org.kuali.rice.kew.test.TestUtilities;
032
033
034/**
035 * Tests the HotDeployer and Reloader which handle hot deployment and hot reloading
036 * of Plugins.
037 *
038 * @author Kuali Rice Team (rice.collab@kuali.org)
039 */
040public class HotDeployTest extends KEWTestCase {
041
042        private File pluginDir;
043        
044        @Override
045        public void setUp() throws Exception {
046        super.setUp();
047                TestUtilities.initializePluginDirectories();
048                this.pluginDir = TestUtilities.getPluginsDirectory(); 
049        }
050                
051        @Override
052        public void tearDown() throws Exception {
053                super.tearDown();
054                TestUtilities.cleanupPluginDirectories();
055        }
056
057        @Test public void testHotDeploy() throws Exception {
058                // Grab the ServerPluginRegistry
059                PluginRegistry theRegistry = PluginUtils.getPluginRegistry();
060                assertNotNull("PluginRegistry should exist.", theRegistry);
061                assertTrue(theRegistry instanceof ServerPluginRegistry);
062                ServerPluginRegistry registry = (ServerPluginRegistry)theRegistry; 
063                
064                // Let's shut down the asynchronous reloader and hot deployer because we want to do this synchronously.
065                HotDeployer hotDeployer = registry.getHotDeployer();
066                Reloader reloader = registry.getReloader();
067                registry.stopHotDeployer();
068                registry.stopReloader();
069                
070                // Assert that there are currently no plugins
071                assertEquals("There should be no plugins.", 0, registry.getPluginEnvironments().size());
072                assertEquals("Resource loader should have no children.", 0, registry.getResourceLoaders().size());
073                
074                // query the hot deployer directly about it's added and removed plugins
075                assertEquals("There should be no plugins added.", 0, hotDeployer.getAddedPlugins().size());
076                assertEquals("There should be no plugins removed.", 0, hotDeployer.getRemovedPlugins().size());
077                hotDeployer.run();
078                assertEquals("There should still be no plugins.", 0, registry.getPluginEnvironments().size());
079                
080                // now let's copy a plugin over and run the hot deployer
081        String pluginZipFileLocation = getBaseDir() + "/src/test/resources/org/kuali/rice/kew/plugin/ziptest.zip";
082                File pluginZipFile = new File(pluginZipFileLocation);
083                assertTrue("Plugin file '" + pluginZipFileLocation + "' should exist", pluginZipFile.exists());
084                assertTrue("Plugin file '" + pluginZipFileLocation + "' should be a file", pluginZipFile.isFile());
085                FileUtils.copyFileToDirectory(pluginZipFile, pluginDir);
086                        
087                assertEquals("There should be one plugin added.", 1, hotDeployer.getAddedPlugins().size());
088                assertEquals("There should be no plugins removed.", 0, hotDeployer.getRemovedPlugins().size());
089                        
090                hotDeployer.run();
091                        
092                // the plugin should have been hot deployed
093                assertEquals("Plugin should have been hot deployed.", 1, registry.getPluginEnvironments().size());
094                
095                // check added plugins again, it should now indicate no new added plugins
096                assertEquals("There should be no plugins added.", 0, hotDeployer.getAddedPlugins().size());
097                assertEquals("There should be no plugins removed.", 0, hotDeployer.getRemovedPlugins().size());
098                
099                // verify that the resource loading and the registry are sane and properly set up with the new plugin
100                assertEquals("Resource loader should have 1 plugin child.", 1, registry.getResourceLoaders().size());
101                Plugin plugin = (Plugin)registry.getResourceLoaders().get(0);
102                assertEquals("Plugin has wrong name.", new QName(CoreConfigHelper.getApplicationId(), "ziptest"), plugin.getName());
103                assertTrue("Plugin should be started.", plugin.isStarted());
104                assertEquals("Plugin in resource loader and environment should be the same.", plugin, registry.getPluginEnvironment(plugin.getName().getLocalPart()).getPlugin());
105                
106                // The reloader should have a reference to the environment
107                assertEquals("Reloader should have a reference to environment.", 1, reloader.getReloadables().size());
108                
109                // now remove the plugin and ensure that it goes away
110                FileUtils.forceDelete(new File(pluginDir, "ziptest.zip"));
111                assertEquals("There should be no plugins added.", 0, hotDeployer.getAddedPlugins().size());
112                assertEquals("There should be one plugin removed.", 1, hotDeployer.getRemovedPlugins().size());
113                hotDeployer.run();
114                
115                // verify that the resource loading and the registry no longer contain the plugin
116                assertEquals("No plugins should be deployed.", 0, registry.getPluginEnvironments().size());
117                assertEquals("Resource loader should have 0 plugin children.", 0, registry.getResourceLoaders().size());
118                
119                // also assert that the reloader no longer has a reference to the environment
120                assertEquals("Reloader should no longer have reference to environment.", 0, reloader.getReloadables().size());
121                                
122        }
123        
124        @Test public void testReloader() throws Exception {
125                // Grab the ServerPluginRegistry
126                PluginRegistry theRegistry = PluginUtils.getPluginRegistry();
127                assertNotNull("PluginRegistry should exist.", theRegistry);
128                assertTrue(theRegistry instanceof ServerPluginRegistry);
129                ServerPluginRegistry registry = (ServerPluginRegistry)theRegistry; 
130                
131                // Let's shut down the asynchronous reloader and hot deployer because we want to do this synchronously.
132                HotDeployer hotDeployer = registry.getHotDeployer();
133                Reloader reloader = registry.getReloader();
134                registry.stopHotDeployer();
135                registry.stopReloader();
136                
137                // Assert that there are currently no plugins
138                assertEquals("There should be no plugins.", 0, registry.getPluginEnvironments().size());
139                assertEquals("Resource loader should have no children.", 0, registry.getResourceLoaders().size());
140                                
141        // now let's copy a plugin over and run the hot deployer
142        String pluginZipFileLocation = getBaseDir() + "/src/test/resources/org/kuali/rice/kew/plugin/ziptest.zip";
143        File pluginZipFile = new File(pluginZipFileLocation);
144        assertTrue("Plugin file '" + pluginZipFileLocation + "' should exist", pluginZipFile.exists());
145        assertTrue("Plugin file '" + pluginZipFileLocation + "' should be a file", pluginZipFile.isFile());
146        FileUtils.copyFileToDirectory(pluginZipFile, pluginDir);
147                
148                // update pluginZipFile to point to the copy
149                pluginZipFile = new File(pluginDir, pluginZipFile.getName());
150                assertTrue(pluginZipFile.exists());
151                
152                // execute a hot deploy
153                hotDeployer.run();
154                        
155                // the plugin should have been hot deployed
156                assertEquals("Plugin should have been hot deployed.", 1, registry.getPluginEnvironments().size());
157                assertEquals("Resource loader should have 1 plugin child.", 1, registry.getResourceLoaders().size());
158                PluginEnvironment environment = registry.getPluginEnvironments().get(0);
159                Plugin plugin = environment.getPlugin();
160                assertTrue(environment.isReloadable());
161                assertFalse(environment.isReloadNeeded());
162                
163                // let's attempt to execute a Reload
164                reloader.run();
165                
166                // a reload should not have occurred here since nothing was updated
167                assertTrue("Original plugin should still be running.", plugin.isStarted());
168                assertEquals("Plugin should not have changed.", plugin, registry.getPluginEnvironments().get(0).getPlugin());
169                
170                // touch the plugin file and then reload
171                FileUtils.touch(pluginZipFile);
172                assertTrue("A reload should be needed now.", environment.isReloadNeeded());
173                reloader.run();
174                
175                // the original plugin should now be stopped
176                assertTrue("original plugin should be stopped.", !plugin.isStarted());
177                assertEquals("There should only be one Plugin.", 1, registry.getResourceLoaders().size());
178                
179                PluginEnvironment newPluginEnvironment = registry.getPluginEnvironments().get(0);
180                Plugin newPlugin = newPluginEnvironment.getPlugin();
181                assertEquals("There should still only be one environment.", 1, registry.getPluginEnvironments().size());
182                assertEquals("The plugin environments should still be the same.", environment, registry.getPluginEnvironments().get(0));
183                
184                assertFalse("The old and new plugins should be different.", newPlugin.equals(plugin));
185                
186                // verify that the resource loader was updated
187                assertEquals("The resource loaders should have been updated with the new plugin.", newPlugin, registry.getResourceLoaders().get(0));
188                
189        }
190
191        
192}