View Javadoc

1   /*
2    * $Id: DeploymentServiceTestCase.java 20792 2010-12-16 16:58:49Z aperepel $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.launcher;
12  
13  import org.mule.api.MuleContext;
14  import org.mule.api.component.JavaComponent;
15  import org.mule.api.config.MuleProperties;
16  import org.mule.api.construct.FlowConstruct;
17  import org.mule.api.registry.MuleRegistry;
18  import org.mule.construct.SimpleService;
19  import org.mule.module.launcher.application.Application;
20  import org.mule.module.launcher.application.ApplicationWrapper;
21  import org.mule.module.launcher.application.PriviledgedMuleApplication;
22  import org.mule.tck.AbstractMuleTestCase;
23  import org.mule.util.CollectionUtils;
24  import org.mule.util.FileUtils;
25  import org.mule.util.StringUtils;
26  import org.mule.util.concurrent.Latch;
27  
28  import java.io.File;
29  import java.io.IOException;
30  import java.net.URL;
31  import java.util.Arrays;
32  import java.util.Collection;
33  import java.util.List;
34  import java.util.Map;
35  
36  import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
37  import org.apache.commons.io.filefilter.DirectoryFileFilter;
38  import org.apache.commons.io.filefilter.SuffixFileFilter;
39  
40  import static org.junit.Assert.assertArrayEquals;
41  
42  /**
43   *
44   */
45  public class DeploymentServiceTestCase extends AbstractMuleTestCase
46  {
47  
48      protected static final int LATCH_TIMEOUT = 10000;
49      protected static final String[] NONE = new String[0];
50  
51      protected File muleHome;
52      protected File appsDir;
53      protected DeploymentService deploymentService;
54      // these latches are re-created during the test, thus need to be declared volatile
55      protected volatile Latch deployLatch;
56      protected volatile Latch installLatch;
57      protected volatile Latch undeployLatch;
58  
59      @Override
60      protected void doSetUp() throws Exception
61      {
62          super.doSetUp();
63          // set up some mule home structure
64          final String tmpDir = System.getProperty("java.io.tmpdir");
65          muleHome = new File(tmpDir, getClass().getSimpleName() + System.currentTimeMillis());
66          appsDir = new File(muleHome, "apps");
67          appsDir.mkdirs();
68          System.setProperty(MuleProperties.MULE_HOME_DIRECTORY_PROPERTY, muleHome.getCanonicalPath());
69  
70          new File(muleHome, "lib/shared/default").mkdirs();
71  
72          deploymentService = new DeploymentService();
73          deploymentService.setDeployer(new TestDeployer());
74          installLatch = new Latch();
75          deployLatch = new Latch();
76          undeployLatch = new Latch();
77      }
78  
79      @Override
80      protected void doTearDown() throws Exception
81      {
82          // comment out the deletion to analyze results after test is done
83          FileUtils.deleteTree(muleHome);
84          if (deploymentService != null)
85          {
86              deploymentService.stop();
87          }
88          super.doTearDown();
89      }
90  
91      public void testPriviledgedApp() throws Exception
92      {
93          final URL url = getClass().getResource("/priviledged-dummy-app.zip");
94          assertNotNull("Test app file not found " + url, url);
95          addAppArchive(url);
96  
97          deploymentService.start();
98  
99          assertTrue("Deployer never invoked", deployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
100 
101         assertAppsDir(NONE, new String[] {"priviledged-dummy-app"}, true);
102 
103         final Application app = findApp("priviledged-dummy-app", 1);
104         // now that we're sure it's the app we wanted, assert the registry has everything
105         // a 'priviledged' app would have had
106         final Object obj = app.getMuleContext().getRegistry().lookupObject(PriviledgedMuleApplication.REGISTRY_KEY_DEPLOYMENT_SERVICE);
107         assertNotNull("Priviledged objects have not been registered", obj);
108         assertTrue(((ApplicationWrapper) app).getDelegate() instanceof PriviledgedMuleApplication);
109     }
110 
111     public void testPriviledgedCrossAppAccess() throws Exception
112     {
113         URL url = getClass().getResource("/priviledged-dummy-app.zip");
114         assertNotNull("Test app file not found " + url, url);
115         addAppArchive(url);
116 
117         url = getClass().getResource("/dummy-app.zip");
118         assertNotNull("Test app file not found " + url, url);
119         addAppArchive(url);
120 
121         deploymentService.start();
122 
123         // a basic latch isn't ideal here, as there are 2 apps to deploy
124         assertTrue("Deployer never invoked", deployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
125 
126         assertAppsDir(NONE, new String[] {"dummy-app", "priviledged-dummy-app"}, true);
127 
128         final Application privApp = findApp("priviledged-dummy-app", 2);
129         final Application dummyApp = findApp("dummy-app", 2);
130         assertTrue(((ApplicationWrapper) privApp).getDelegate() instanceof PriviledgedMuleApplication);
131 
132         final MuleContext muleContext1 = privApp.getMuleContext();
133         System.out.println("muleContext1 = " + muleContext1);
134         assertNotSame(muleContext1, muleContext);
135         assertNotSame(privApp.getDeploymentClassLoader(), dummyApp.getDeploymentClassLoader());
136         final Collection<FlowConstruct> flowConstructs = dummyApp.getMuleContext().getRegistry().lookupObjects(FlowConstruct.class);
137         assertFalse("No FlowConstructs found in the sibling app", flowConstructs.isEmpty());
138         FlowConstruct fc = flowConstructs.iterator().next();
139         assertTrue(fc instanceof SimpleService);
140         SimpleService service = (SimpleService) fc;
141         // note that we don't have this class available to this test directly
142         Class<?> clazz = ((JavaComponent) service.getComponent()).getObjectType();
143         assertEquals("Wrong component implementation class", "org.mule.module.launcher.EchoTest", clazz.getName());
144     }
145 
146     public void testDeployZipOnStartup() throws Exception
147     {
148         final URL url = getClass().getResource("/dummy-app.zip");
149         assertNotNull("Test app file not found " + url, url);
150         addAppArchive(url);
151 
152         deploymentService.start();
153 
154         assertTrue("Deployer never invoked", deployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
155 
156         assertAppsDir(NONE, new String[] {"dummy-app"}, true);
157 
158         // just assert no priviledged entries were put in the registry
159         final Application app = findApp("dummy-app", 1);
160         final MuleRegistry registry = app.getMuleContext().getRegistry();
161         final Object obj = registry.lookupObject(PriviledgedMuleApplication.REGISTRY_KEY_DEPLOYMENT_SERVICE);
162         assertNull(obj);
163         assertFalse(((ApplicationWrapper) app).getDelegate() instanceof PriviledgedMuleApplication);
164 
165         // mule-app.properties from the zip archive must have loaded properly
166         assertEquals("mule-app.properties should have been loaded.", "someValue", registry.get("myCustomProp"));
167     }
168 
169     public void testUpdateAppViaZip() throws Exception
170     {
171         final URL url = getClass().getResource("/dummy-app.zip");
172         assertNotNull("Test app file not found " + url, url);
173         addAppArchive(url);
174 
175         deploymentService.start();
176 
177         assertTrue("Deployer never invoked", deployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
178         assertAppsDir(NONE, new String[] {"dummy-app"}, true);
179         assertEquals("Application has not been properly registered with Mule", 1, deploymentService.getApplications().size());
180 
181         // set up a new deployment latch (can't reuse the old one)
182         deployLatch = new Latch();
183         addAppArchive(url);
184         assertTrue("Undeploy never invoked", undeployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
185         assertTrue("Deployer never invoked", deployLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
186         assertEquals("Application has not been properly registered with Mule", 1, deploymentService.getApplications().size());
187         assertAppsDir(NONE, new String[]{"dummy-app"}, true);
188     }
189 
190     public void testBrokenAppArchive() throws Exception
191     {
192         final URL url = getClass().getResource("/broken-app.zip");
193         assertNotNull("Test app file not found " + url, url);
194         addAppArchive(url);
195 
196         deploymentService.start();
197 
198         assertTrue("Install never invoked", installLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
199 
200         // let the file system's write-behind cache commit the delete operation?
201         Thread.sleep(1000);
202 
203         // zip stays intact, no app dir created
204         assertAppsDir(new String[] {"broken-app.zip"}, NONE, true);
205         // don't assert dir contents, we want to check internal deployer state next
206         assertAppsDir(NONE, new String[] {"dummy-app"}, false);
207         assertEquals("No apps should have been registered with Mule.", 0, deploymentService.getApplications().size());
208         final Map<URL, Long> zombieMap = deploymentService.getZombieMap();
209         assertEquals("Wrong number of zombie apps registered.", 1, zombieMap.size());
210         final Map.Entry<URL, Long> zombie = zombieMap.entrySet().iterator().next();
211         assertEquals("Wrong URL tagged as zombie.", "broken-app.zip", new File(zombie.getKey().getFile()).getName());
212         assertTrue("Invalid lastModified value for file URL.", zombie.getValue() != -1);
213     }
214 
215     public void testBrokenAppName() throws Exception
216     {
217         final URL url = getClass().getResource("/app with spaces.zip");
218         assertNotNull("Test app file not found " + url, url);
219         addAppArchive(url);
220 
221         try
222         {
223             deploymentService.start();
224         }
225         catch (DeploymentInitException e)
226         {
227             assertTrue(e.getMessage().contains("may not contain spaces"));
228         }
229 
230         // zip stays intact, no app dir created
231         // %20 is returned by java file api :/
232         assertAppsDir(new String[] {"app%20with%20spaces.zip"}, NONE, true);
233         final Map<URL, Long> zombieMap = deploymentService.getZombieMap();
234         assertEquals("Wrong number of zombie apps registered.", 1, zombieMap.size());
235         final Map.Entry<URL, Long> zombie = zombieMap.entrySet().iterator().next();
236         assertEquals("Wrong URL tagged as zombie.", "app%20with%20spaces.zip", new File(zombie.getKey().getFile()).getName());
237         assertTrue("Invalid lastModified value for file URL.", zombie.getValue() != -1);
238     }
239 
240     /**
241      * Find a deployed app, performing some basic assertions.
242      */
243     private Application findApp(final String appName, int totalAppsExpected)
244     {
245         // list all apps to validate total count
246         final List<Application> apps = deploymentService.getApplications();
247         assertNotNull(apps);
248         assertEquals(totalAppsExpected, apps.size());
249         final Application app = deploymentService.findApplication(appName);
250         assertNotNull(app);
251         return app;
252     }
253 
254     private void assertAppsDir(String[] expectedZips, String[] expectedApps, boolean performValidation)
255     {
256         final String[] actualZips = appsDir.list(new SuffixFileFilter(".zip"));
257         if (performValidation) {
258             assertArrayEquals("Invalid Mule application archives set", expectedZips, actualZips);
259         }
260         final String[] actualApps = appsDir.list(DirectoryFileFilter.DIRECTORY);
261         if (performValidation) {
262             assertTrue("Invalid Mule exploded applications set",
263                        CollectionUtils.isEqualCollection(Arrays.asList(expectedApps), Arrays.asList(actualApps)));
264         }
265     }
266 
267     /**
268      * Copies a given app archive to the apps folder for deployment.
269      */
270     private void addAppArchive(URL url) throws IOException
271     {
272         // copy is not atomic, copy to a temp file and rename instead (rename is atomic)
273         final String tempFileName = new File(url.getFile() + ".part").getName();
274         final File tempFile = new File(appsDir, tempFileName);
275         FileUtils.copyURLToFile(url, tempFile);
276         tempFile.renameTo(new File(StringUtils.removeEnd(tempFile.getAbsolutePath(), ".part")));
277     }
278 
279 
280     private class TestDeployer implements MuleDeployer
281     {
282         MuleDeployer delegate = new DefaultMuleDeployer(deploymentService);
283 
284         public void deploy(Application app)
285         {
286             System.out.println("DeploymentServiceTestCase$TestDeployer.deploy");
287             delegate.deploy(app);
288             deployLatch.release();
289         }
290 
291         public void undeploy(Application app)
292         {
293             System.out.println("DeploymentServiceTestCase$TestDeployer.undeploy");
294             delegate.undeploy(app);
295             undeployLatch.release();
296         }
297 
298         public Application installFromAppDir(String packedMuleAppFileName) throws IOException
299         {
300             installLatch.release();
301             System.out.println("DeploymentServiceTestCase$TestDeployer.installFromAppDir");
302             return delegate.installFromAppDir(packedMuleAppFileName);
303         }
304 
305         public Application installFrom(URL url) throws IOException
306         {
307             installLatch.release();
308             System.out.println("DeploymentServiceTestCase$TestDeployer.installFrom");
309             return delegate.installFrom(url);
310         }
311 
312     }
313 }