/* * JBoss, Home of Professional Open Source. * Copyright 2015, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.as.server.deployment.scanner; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.is; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CANCELLED; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.COMPOSITE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOY; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILED; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FULL_REPLACE_DEPLOYMENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.NAME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OUTCOME; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OWNER; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PERSISTENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_CHILDREN_RESOURCES_OPERATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REDEPLOY; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ROLLED_BACK; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STEPS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUCCESS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UNDEPLOY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Pattern; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.client.Operation; import org.jboss.as.controller.client.OperationMessageHandler; import org.jboss.as.controller.client.OperationResponse; import org.jboss.as.server.deployment.scanner.api.DeploymentOperations; import org.jboss.as.server.deployment.scanner.logging.DeploymentScannerLogger; import org.jboss.byteman.contrib.bmunit.BMRule; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.jboss.dmr.ModelNode; import org.jboss.logging.Logger; import org.jboss.threads.AsyncFuture; import org.junit.After; import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; /** * Unit tests of {@link FileSystemDeploymentService}. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ @RunWith(BMUnitRunner.class) public class FileSystemDeploymentServiceUnitTestCase { private static Logger logger = Logger.getLogger(FileSystemDeploymentServiceUnitTestCase.class); private static long count = System.currentTimeMillis(); private static final Random random = new Random(System.currentTimeMillis()); private static final DiscardTaskExecutor executor = new DiscardTaskExecutor(); private static final PathAddress resourceAddress = PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, DeploymentScannerExtension.SUBSYSTEM_NAME), PathElement.pathElement(DeploymentScannerExtension.SCANNERS_PATH.getKey(), DeploymentScannerExtension.DEFAULT_SCANNER_NAME)); private static AutoDeployTestSupport testSupport; private File tmpDir; @BeforeClass public static void createTestSupport() throws Exception { testSupport = new AutoDeployTestSupport(FileSystemDeploymentServiceUnitTestCase.class.getSimpleName()); } @AfterClass public static void cleanup() throws Exception { if (testSupport != null) { testSupport.cleanupFiles(); } } @Before public void setup() throws Exception { executor.clear(); File root = testSupport.getTempDir(); for (int i = 0; i < 200; i++) { tmpDir = new File(root, String.valueOf(count++)); if (!tmpDir.exists() && tmpDir.mkdirs()) { break; } } if (!tmpDir.exists()) { throw new RuntimeException("cannot create tmpDir"); } } @After public void tearDown() throws Exception { testSupport.cleanupChannels(); } @Test public void testIgnoreNoMarker() throws Exception { File f1 = createFile("foo.war"); TesteeSet ts = createTestee(); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); // ts.controller.addGetDeploymentNamesResponse(); ts.testee.scan(); assertTrue(f1.exists()); assertFalse(deployed.exists()); } @Test public void testBasicDeploy() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } @Test public void testBasicXmlDeploy() throws Exception { File xml = createXmlFile("foo.xml", "<rootElement/>"); File dodeploy = createFile("foo.xml" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.xml" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(xml.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } @Test public void testAutoXmlDeploy() throws Exception { File xml = createXmlFile("foo.xml", "<rootElement/>"); File deployed = new File(tmpDir, "foo.xml" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.setAutoDeployXMLContent(true); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(xml.exists()); assertTrue(deployed.exists()); } /** * Tests that an incomplete XML deployment does not * auto-deploy. */ @Test public void testIncompleteXmlDeployment() throws Exception { File xml = createXmlFile("foo.xml", "<rootElement><incomplete>"); File deployed = new File(tmpDir, "foo.xml" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.setAutoDeployXMLContent(true); ts.testee.scan(); assertTrue(xml.exists()); assertFalse(deployed.exists()); } @Test public void testNestedDeploy() throws Exception { TesteeSet ts = createTestee(); File nestedDir = new File(tmpDir, "nested"); File war = createFile(nestedDir, "foo.war"); File dodeploy = createFile(nestedDir, "foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(nestedDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } @Test public void testTwoFileDeploy() throws Exception { File war1 = createFile("foo.war"); File dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File war2 = createFile("bar.war"); File dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(deployed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); } @Test public void testBasicFailure() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(1, 1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(failed.exists()); } @Test public void testCompositeFailure() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); ts.controller.addCompositeFailureResultResponse(2, 2); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(failed.exists()); } @Test public void testTwoFileFailure() throws Exception { File war1 = createFile("foo.war"); File dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); File war2 = createFile("bar.war"); File dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(2, 2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertFalse(deployed1.exists()); assertTrue(failed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertFalse(deployed2.exists()); assertTrue(failed2.exists()); } @Test // WFLY-364 Test a partial failure, where a runtime failure does not trigger a complete rollback public void testPartialCompositeFailure() throws Exception { File war1 = createFile("foo.war"); File dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File war2 = createFile("bar.war"); File dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); TesteeSet ts = createTestee(); ts.controller.addPartialCompositeFailureResultResponse(2, 2); ts.testee.scan(); String[] list = tmpDir.list(); String deployed = null; String failed = null; for (final String name : list) { if (name.endsWith(FileSystemDeploymentService.DEPLOYED)) { Assert.assertNull(deployed); deployed = name.substring(0, name.length() - FileSystemDeploymentService.DEPLOYED.length()); } else if (name.endsWith(FileSystemDeploymentService.FAILED_DEPLOY)) { Assert.assertNull(failed); failed = name.substring(0, name.length() - FileSystemDeploymentService.FAILED_DEPLOY.length()); } } Assert.assertNotNull(deployed); Assert.assertNotNull(failed); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); File deployed1 = new File(tmpDir, deployed + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, deployed + FileSystemDeploymentService.FAILED_DEPLOY); File deployed2 = new File(tmpDir, failed + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, failed + FileSystemDeploymentService.FAILED_DEPLOY); assertTrue(deployed1.getAbsolutePath(), deployed1.exists()); assertFalse(failed1.getAbsolutePath(), failed1.exists()); assertFalse(deployed2.exists()); assertTrue(failed2.exists()); dodeploy2 = createFile(failed + FileSystemDeploymentService.DO_DEPLOY); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); deployed2 = new File(tmpDir, failed + FileSystemDeploymentService.DEPLOYED); failed2 = new File(tmpDir, failed + FileSystemDeploymentService.FAILED_DEPLOY); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); assertFalse(failed2.exists()); } @Test public void testCancellationDueToFailure() throws Exception { File war1 = createFile("bar.war"); File dodeploy1 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.FAILED_DEPLOY); File war2 = createFile("foo.war"); File dodeploy2 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(2, 1); // Retry fails as well ts.controller.addCompositeFailureResponse(1, 1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertFalse(deployed1.exists()); assertTrue(failed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertFalse(deployed2.exists()); assertTrue(failed2.exists()); } @Test public void testSuccessfulRetry() throws Exception { File war1 = createFile("bar.war"); File dodeploy1 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.FAILED_DEPLOY); File war2 = createFile("foo.war"); File dodeploy2 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(2, 1); // Retry succeeds ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy1.exists()); assertFalse(dodeploy2.exists()); assertFalse(deployed1.exists() && deployed2.exists()); assertTrue(failed1.exists() || failed2.exists()); } @Test public void testCleanSpuriousMarkers() throws Exception { File f1 = createFile("spurious" + FileSystemDeploymentService.DEPLOYED); File f2 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.DEPLOYED); File f3 = createFile("ok" + FileSystemDeploymentService.DEPLOYED); File f4 = createFile(new File(tmpDir, "nested"), "nested-ok" + FileSystemDeploymentService.DEPLOYED); File f5 = createFile("spurious" + FileSystemDeploymentService.FAILED_DEPLOY); File f6 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.FAILED_DEPLOY); File f7 = createFile("spurious" + FileSystemDeploymentService.DEPLOYING); File f8 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.DEPLOYING); File f9 = createFile("spurious" + FileSystemDeploymentService.UNDEPLOYING); File f10 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.UNDEPLOYING); File f11 = createFile("spurious" + FileSystemDeploymentService.PENDING); File f12 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.PENDING); File ok = createFile("ok"); File nestedOK = createFile(new File(tmpDir, "nested"), "nested-ok"); // We expect 2 requests for children names due to subdir "nested" MockServerController sc = new MockServerController("ok", "nested-ok"); // sc.responses.add(sc.responses.get(0)); TesteeSet ts = createTestee(sc); ts.testee.scan(); // These should get cleaned during initial scan Assert.assertFalse(f1.exists()); Assert.assertFalse(f2.exists()); Assert.assertTrue(f3.exists()); Assert.assertTrue(f4.exists()); Assert.assertTrue(ok.exists()); Assert.assertTrue(nestedOK.exists()); // failed deployments should not be cleaned on initial scan - will retry Assert.assertTrue(f5.exists()); Assert.assertTrue(f6.exists()); // The others should get cleaned in a scan Assert.assertFalse(f7.exists()); Assert.assertFalse(f8.exists()); Assert.assertFalse(f9.exists()); Assert.assertFalse(f10.exists()); Assert.assertFalse(f11.exists()); Assert.assertFalse(f12.exists()); Assert.assertTrue(ok.exists()); Assert.assertTrue(nestedOK.exists()); f1 = createFile("spurious" + FileSystemDeploymentService.DEPLOYED); f2 = createFile(new File(tmpDir, "nested"), "nested" + FileSystemDeploymentService.DEPLOYED); ts.testee.scan(); // Failed deployments should be cleaned on subsequent scans. Assert.assertFalse(f5.exists()); Assert.assertFalse(f6.exists()); Assert.assertFalse(f1.exists()); Assert.assertFalse(f2.exists()); Assert.assertTrue(ok.exists()); Assert.assertTrue(nestedOK.exists()); } @Test public void testOverridePreexisting() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee("foo.war"); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } @Test public void testRedeploy() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee("foo.war"); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); // Since AS7-431 the content is no longer managed //assertTrue(Arrays.equals(bytes, ts.repo.content.iterator().next())); dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] newbytes = ts.controller.deployed.get("foo.war"); assertFalse(Arrays.equals(newbytes, bytes)); // Since AS7-431 the content is no longer managed /* boolean installed = false; for (byte[] content : ts.repo.content) { if (Arrays.equals(newbytes, content)) { installed = true; break; } } assertTrue(installed); */ } @Test public void testTwoFileRedeploy() throws Exception { File war1 = createFile("foo.war"); File dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File war2 = createFile("bar.war"); File dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(deployed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(4, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(deployed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); } @Test public void testFailedRedeploy() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee("foo.war"); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(failed.exists()); dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(1, 1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(failed.exists()); } @Test public void testTwoFileFailedRedeploy() throws Exception { File war1 = createFile("bar.war"); File dodeploy1 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.FAILED_DEPLOY); File war2 = createFile("foo.war"); File dodeploy2 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(deployed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(2, 1); // Retry fails as well ts.controller.addCompositeFailureResponse(1, 1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(4, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertFalse(deployed1.exists()); assertTrue(failed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertFalse(deployed2.exists()); assertTrue(failed2.exists()); } @Test public void testFailedRedeployNoMarker() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeFailureResponse(1, 1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(failed.exists()); // New deployment won't work unless content timestamp is newer than failed marker, so... failed.setLastModified(0); testSupport.createZip(war, 0, false, false, true, false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(failed.exists()); } @Test public void testSuccessfulRetryRedeploy() throws Exception { File war1 = createFile("bar.war"); File dodeploy1 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.DEPLOYED); File failed1 = new File(tmpDir, "bar.war" + FileSystemDeploymentService.FAILED_DEPLOY); File war2 = createFile("foo.war"); File dodeploy2 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed2 = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war1.exists()); assertFalse(dodeploy1.exists()); assertTrue(deployed1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy2.exists()); assertTrue(deployed2.exists()); dodeploy1 = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); dodeploy2 = createFile("bar.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeFailureResponse(2, 1); // Retry succeeds ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(4, ts.repo.content.size()); assertTrue(war1.exists()); assertTrue(war2.exists()); assertFalse(dodeploy1.exists()); assertFalse(dodeploy2.exists()); assertFalse(deployed1.exists() && deployed2.exists()); assertTrue(failed1.exists() || failed2.exists()); } @Test public void testUndeployByMarkerDeletion() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(deployed.delete()); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); } @Test public void testUndeployByContentDeletionZipped() throws Exception { undeployByContentDeletionZippedTest(tmpDir); } @Test public void testUndeployContentInSubdirectory() throws Exception { File subdir = createDirectory(tmpDir, "sub"); undeployByContentDeletionZippedTest(subdir); } private void undeployByContentDeletionZippedTest(File baseDir) throws Exception { // First, zipped content File war = createFile(baseDir, "foo.war"); File dodeploy = createFile(baseDir, "foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(baseDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(baseDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(war.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertFalse(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); // Next, zipped content with auto-deploy disabled war = createFile(baseDir, "foo.war"); dodeploy = createFile(baseDir, "foo.war" + FileSystemDeploymentService.DO_DEPLOY); deployed = new File(baseDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); undeployed = new File(baseDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); ts = createTestee(); ts.testee.setAutoDeployZippedContent(false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(war.delete()); ts.testee.scan(); assertFalse(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); } @Test public void testUndeployByContentDeletionExploded() throws Exception { // First, auto-deploy enabled File war = new File(tmpDir, "foo.war"); war.mkdirs(); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(war.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertFalse(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); // Next, with auto-deploy disabled war = new File(tmpDir, "foo.war"); war.mkdirs(); dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); ts = createTestee(); ts.testee.setAutoDeployExplodedContent(false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(war.delete()); ts.testee.scan(); assertFalse(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); // Now, exploded content war = new File(tmpDir, "foo.war"); war.mkdirs(); dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); assertTrue(war.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertFalse(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); } @Test public void testRedeployUndeploy() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); // Since AS7-431 the content is no longer managed //assertTrue(Arrays.equals(bytes, ts.repo.content.iterator().next())); dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] newbytes = ts.controller.deployed.get("foo.war"); assertFalse(Arrays.equals(newbytes, bytes)); assertTrue(deployed.delete()); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(2, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); } @Test public void testRedeployUndeployedNoMarker() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); assertTrue(deployed.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); // new content will be ignored unless it has a timestamp newer than .undeployed // so, rather than sleeping... undeployed.setLastModified(0); testSupport.createZip(war, 0, false, false, false, false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] newbytes = ts.controller.deployed.get("foo.war"); assertFalse(Arrays.equals(newbytes, bytes)); } @Test public void testRedeployUndeployedEnabled() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); assertTrue(deployed.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); assertEquals(0, ts.controller.added.size()); assertEquals(0, ts.controller.deployed.size()); ts.controller.added.put("foo.war", bytes); ts.controller.deployed.put("foo.war", bytes); //as .undeployed timestamp is after the war file timestamp, only the re-enabling of the deployment removes it testSupport.createZip(war, 0, false, false, false, false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); } @Test public void testDirectory() throws Exception { final File war = createDirectory("foo.war", "index.html"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee("foo.war"); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertTrue(deployed.delete()); // ts.controller.addGetDeploymentNamesResponse(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // Since AS7-431 the content is no longer managed //assertEquals(1, ts.repo.content.size()); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); } @Test public void testUndeployDeployExternalDeployment() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); //Undeploy externally assertTrue(undeployed.createNewFile()); undeployed.setLastModified(war.lastModified()); assertTrue(deployed.delete()); ts.controller.deployed.clear(); ts.controller.added.clear(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); //Deploy externally loaded deployment ts.controller.added.put("foo.war", bytes); ts.controller.deployed.put("foo.war", bytes); ts.controller.externallyDeployed.put("foo.war", null); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); } @Test public void testUndeployDeploy() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); byte[] bytes = ts.controller.deployed.get("foo.war"); //Undeploy externally assertTrue(undeployed.createNewFile()); undeployed.setLastModified(war.lastModified()); assertTrue(deployed.delete()); ts.controller.deployed.clear(); ts.controller.added.clear(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertFalse(deployed.exists()); assertTrue(undeployed.exists()); //Deploy externally the current deployment ts.controller.added.put("foo.war", bytes); ts.controller.deployed.put("foo.war", bytes); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertEquals(1, ts.controller.added.size()); assertEquals(1, ts.controller.deployed.size()); } /** * Tests that autodeploy does not happen by default. */ @Test public void testNoDefaultAutoDeploy() throws Exception { File zip = new File(tmpDir, "foo.war"); File zipdeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File zippending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); testSupport.createZip(zip, 0, false, false, true, false); File exploded = new File(tmpDir, "exploded.ear"); exploded.mkdirs(); File explodeddeployed = new File(tmpDir, "exploded.war" + FileSystemDeploymentService.DEPLOYED); File explodedpending = new File(tmpDir, "exploded.war" + FileSystemDeploymentService.PENDING); TesteeSet ts = createTestee(); ts.testee.scan(); assertFalse(zipdeployed.exists()); assertFalse(zippending.exists()); assertFalse(explodeddeployed.exists()); assertFalse(explodedpending.exists()); assertTrue(zip.exists()); assertTrue(exploded.exists()); } /** * Tests that an incomplete zipped deployment does not auto-deploy. */ @Test public void testIncompleteZipped() throws Exception { File incomplete = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); testSupport.createZip(incomplete, 0, false, true, true, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertTrue(pending.exists()); incomplete.delete(); testSupport.createZip(incomplete, 0, false, false, false, false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(deployed.exists()); assertFalse(pending.exists()); } /** * Tests that an exploded deployment with an incomplete child * does not auto-deploy, but does auto-deploy when the child * is complete. */ @Test public void testIncompleteExploded() throws Exception { File deployment = new File(tmpDir, "foo.ear"); deployment.mkdirs(); File deployed = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.PENDING); File incomplete = new File(deployment, "bar.war"); testSupport.createZip(incomplete, 0, false, true, true, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertTrue(pending.exists()); incomplete.delete(); testSupport.createZip(incomplete, 0, false, false, true, false); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(deployed.exists()); assertFalse(pending.exists()); } /** * Test that an incomplete deployment prevents changing other items */ @Test public void testIncompleteBlocksComplete() throws Exception { File incomplete = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); testSupport.createZip(incomplete, 0, false, true, true, false); File complete = new File(tmpDir, "complete.jar"); File completeDeployed = new File(tmpDir, "complete.jar" + FileSystemDeploymentService.DEPLOYED); File completePending = new File(tmpDir, "complete.jar" + FileSystemDeploymentService.PENDING); testSupport.createZip(complete, 0, false, false, true, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertFalse(completeDeployed.exists()); assertTrue(pending.exists()); assertTrue(completePending.exists()); incomplete.delete(); testSupport.createZip(incomplete, 0, false, false, false, false); ts.controller.addCompositeSuccessResponse(2); ts.testee.scan(); assertTrue(deployed.exists()); assertTrue(completeDeployed.exists()); assertFalse(pending.exists()); assertFalse(completePending.exists()); } /** * Tests that an incomplete deployment that makes no progress gets a .failed marker */ @Test public void testMaxNoProgress() throws Exception { File incomplete = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); testSupport.createZip(incomplete, 0, false, true, true, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.testee.setMaxNoProgress(-1); // trigger immediate failure ts.testee.scan(); assertFalse(deployed.exists()); assertTrue(failed.exists()); assertFalse(pending.exists()); } /** * Tests that non-archive/non-marker files are ignored */ @Test public void testIgnoreNonArchive() throws Exception { File txt = createFile("foo.txt"); File deployed = new File(tmpDir, "foo.txt" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.txt" + FileSystemDeploymentService.PENDING); TesteeSet ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); assertTrue(txt.exists()); assertFalse(pending.exists()); assertFalse(deployed.exists()); } /** * Tests that non-archive files nested in an exploded deployment are ignored */ @Test public void testIgnoreNonArchiveInExplodedDeployment() throws Exception { File deployment = new File(tmpDir, "foo.ear"); deployment.mkdirs(); File deployed = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.PENDING); File nonarchive = createFile(deployment, "index.html"); TesteeSet ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(deployed.exists()); assertFalse(pending.exists()); assertTrue(nonarchive.exists()); } /** * Tests that the .skipdeploy marker prevents auto-deploy */ @Test public void testSkipDeploy() throws Exception { File deployment = new File(tmpDir, "foo.ear"); deployment.mkdirs(); File deployed = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.ear" + FileSystemDeploymentService.PENDING); File skip = createFile(tmpDir, "foo.ear" + FileSystemDeploymentService.SKIP_DEPLOY); TesteeSet ts = createTestee(); ts.testee.setAutoDeployExplodedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertFalse(pending.exists()); skip.delete(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(deployed.exists()); assertFalse(pending.exists()); } /** * Tests that an incompletely copied file with a nested jar * *and* extraneous leading bytes fails cleanly. */ @Test public void testNonScannableZipped() throws Exception { File incomplete = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); testSupport.createZip(incomplete, 1, false, true, true, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertTrue(failed.exists()); assertFalse(pending.exists()); } /** * Tests that a ZIP64 format autodeployed file fails cleanly. * If ZIP 64 support is added, this test should be revised. */ @Test public void testZip64Zipped() throws Exception { File zip64 = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File pending = new File(tmpDir, "foo.war" + FileSystemDeploymentService.PENDING); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); testSupport.createZip(zip64, 0, false, false, true, true); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); assertFalse(deployed.exists()); assertTrue(failed.exists()); assertFalse(pending.exists()); } /** * Test for JBAS-9226 -- deleting a .deployed marker does not result in a redeploy * * @throws Exception */ @Test public void testIgnoreUndeployed() throws Exception { File war = new File(tmpDir, "foo.war"); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); testSupport.createZip(war, 0, false, false, false, false); TesteeSet ts = createTestee(); ts.testee.setAutoDeployZippedContent(true); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(deployed.exists()); // Undeploy deployed.delete(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(undeployed.exists()); assertFalse(deployed.exists()); // Confirm it doesn't come back ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(undeployed.exists()); assertFalse(deployed.exists()); } @Test public void testDeploymentTimeout() throws Exception { File deployment = new File(tmpDir, "foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); testSupport.createZip(deployment, 0, false, false, true, true); TesteeSet ts = createTestee(new DiscardTaskExecutor() { @Override public <T> AsyncFuture<T> submit(Callable<T> tCallable) { return new TimeOutFuture<T>(5, tCallable); } }); ts.testee.setDeploymentTimeout(5); ts.testee.scan(); assertFalse(deployed.exists()); assertFalse(dodeploy.exists()); assertTrue(failed.exists()); } @Test public void testArchiveRedeployedAfterReboot() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); // Create a new testee to simulate a reboot ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } @Test public void testExplodedRedeployedAfterReboot() throws Exception { final File war = createDirectory("foo.war", "index.html"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); // Create a new testee to simulate a reboot ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); } /** * Tests that a deployment which had failed earlier, is redeployed (i.e. picked for deployment) when the deployment * file is updated (i.e. timestamp changes). * * @throws Exception */ @Test public void testFailedArchiveRedeployedAfterDeploymentUpdate() throws Exception { final String warName = "helloworld.war"; // create our deployment file File war = new File(tmpDir, warName); testSupport.createZip(war, 0, false, false, false, false); // trigger deployment TesteeSet ts = createTestee(); ts.controller.addCompositeFailureResponse(1, 1); // set the auto-deploy of zipped content on the scanner ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); // make sure the deployment exists after the scan assertTrue(war.getAbsolutePath() + " is missing after deployment", war.exists()); // failed marker file File failed = new File(tmpDir, warName + FileSystemDeploymentService.FAILED_DEPLOY); // make sure the failed marker exists assertTrue(failed.getAbsolutePath() + " marker file not found after deployment", failed.exists()); // Now update the timestamp of the deployment war and retrigger a deployment scan expecting it to process // the deployment war and create a deployed (a.k.a successful) deployment marker. This simulates the case where the // original deployment file is "fixed" and the deployment scanner should pick it up even in the presence of the // (previous) failed marker long newLastModifiedTime = failed.lastModified() + 1000; logger.info("Updating last modified time of war " + war + " from " + war.lastModified() + " to " + newLastModifiedTime + " to simulate changes to the deployment"); war.setLastModified(newLastModifiedTime); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // make sure the deployment exists after the scan assertTrue(war.getAbsolutePath() + " is missing after re-deployment", war.exists()); // make sure the deployed marker exists File deployed = createFile(warName + FileSystemDeploymentService.DEPLOYED); assertTrue(deployed.getAbsolutePath() + " marker file not found after re-deployment", deployed.exists()); // make sure the failed marker *no longer exists* failed = new File(tmpDir, warName + FileSystemDeploymentService.FAILED_DEPLOY); assertFalse(failed.getAbsolutePath() + " marker file (unexpectedly) exists after re-deployment", failed.exists()); } /** * Tests that a deployment which had been undeployed earlier, is redeployed (i.e. picked for deployment) when the deployment * file is updated (i.e. timestamp changes). * * @throws Exception */ @Test public void testUndeployedArchiveRedeployedAfterDeploymentUpdate() throws Exception { final String warName = "helloworld2.war"; // create our deployment file File war = new File(tmpDir, warName); testSupport.createZip(war, 0, false, false, false, false); // trigger deployment TesteeSet ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); // set the auto-deploy of zipped content on the scanner ts.testee.setAutoDeployZippedContent(true); ts.testee.scan(); // make sure the deployment exists after the scan assertTrue(war.getAbsolutePath() + " is missing after deployment", war.exists()); // deployed marker file File deployed = new File(tmpDir, warName + FileSystemDeploymentService.DEPLOYED); // make sure the deployed marker exists assertTrue(deployed.getAbsolutePath() + " marker file not found after deployment", deployed.exists()); // now trigger an undeployment by removing the "deployed" marker file assertTrue("Could not delete " + deployed.getAbsolutePath() + " marker file", deployed.delete()); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // make sure undeployed marker exists File undeployed = new File(tmpDir, warName + FileSystemDeploymentService.UNDEPLOYED); assertTrue(undeployed.getAbsolutePath() + " marker file not found after undeployment", undeployed.exists()); // Now update the timestamp of the deployment war and retrigger a deployment scan expecting it to process // the deployment war and create a deployed (a.k.a successful) deployment marker. This simulates the case where the // original deployment file is redeployed and the deployment scanner should pick it up even in the presence of the // (previous) undeployed marker long newLastModifiedTime = undeployed.lastModified() + 1000; logger.info("Updating last modified time of war " + war + " from " + war.lastModified() + " to " + newLastModifiedTime + " to simulate changes to the deployment"); war.setLastModified(newLastModifiedTime); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); // make sure the deployment exists after the scan assertTrue(war.getAbsolutePath() + " is missing after re-deployment", war.exists()); // make sure the deployed marker exists deployed = createFile(warName + FileSystemDeploymentService.DEPLOYED); assertTrue(deployed.getAbsolutePath() + " marker file not found after re-deployment", deployed.exists()); // make sure the undeployed marker *no longer exists* undeployed = new File(tmpDir, warName + FileSystemDeploymentService.UNDEPLOYED); assertFalse(undeployed.getAbsolutePath() + " marker file (unexpectedly) exists after re-deployment", undeployed.exists()); } /** AS7-784 */ @Test public void testUndeployedExternally() throws Exception { File f1 = createFile("undeployed" + FileSystemDeploymentService.DEPLOYED); File f2 = new File(tmpDir, "undeployed" + FileSystemDeploymentService.UNDEPLOYED); File f3 = createFile(new File(tmpDir, "nested"), "nested-undeployed" + FileSystemDeploymentService.DEPLOYED); File f4 = new File(new File(tmpDir, "nested"), "nested-undeployed" + FileSystemDeploymentService.UNDEPLOYED); File f5 = createFile("removed" + FileSystemDeploymentService.DEPLOYED); File f6 = new File(tmpDir, "removed" + FileSystemDeploymentService.UNDEPLOYED); File f7 = createFile(new File(tmpDir, "nested"), "nested-removed" + FileSystemDeploymentService.DEPLOYED); File f8 = new File(new File(tmpDir, "nested"), "nested-removed" + FileSystemDeploymentService.UNDEPLOYED); File undeployed = createFile("undeployed"); File nestedUndeployed = createFile(new File(tmpDir, "nested"), "nested-undeployed"); File removed = createFile("removed"); File nestedRemoved = createFile(new File(tmpDir, "nested"), "nested-removed"); // We expect 2 requests for children names due to subdir "nested" MockServerController sc = new MockServerController("undeployed", "nested-undeployed", "removed", "nested-removed"); // sc.responses.add(sc.responses.get(0)); TesteeSet ts = createTestee(sc); Assert.assertTrue(f1.exists()); Assert.assertFalse(f2.exists()); Assert.assertTrue(f3.exists()); Assert.assertFalse(f4.exists()); Assert.assertTrue(f5.exists()); Assert.assertFalse(f6.exists()); Assert.assertTrue(undeployed.exists()); Assert.assertTrue(nestedUndeployed.exists()); Assert.assertTrue(removed.exists()); Assert.assertTrue(nestedRemoved.exists()); // WFCORE-1579: before tampering with deployments, at least one scan must proceed so that deployment directory // content is established ts.testee.scan(); // Simulate the CLI or console undeploying 2 deployments and removing 2 sc.deployed.remove("undeployed"); sc.deployed.remove("nested-undeployed"); sc.added.remove("removed"); sc.added.remove("nested-removed"); sc.deployed.remove("removed"); sc.deployed.remove("nested-removed"); ts.testee.scan(); Assert.assertFalse(f1.exists()); Assert.assertTrue(f2.exists()); Assert.assertFalse(f3.exists()); Assert.assertTrue(f4.exists()); Assert.assertFalse(f5.exists()); Assert.assertTrue(f6.exists()); Assert.assertTrue(undeployed.exists()); Assert.assertTrue(nestedUndeployed.exists()); Assert.assertTrue(removed.exists()); Assert.assertTrue(nestedRemoved.exists()); Assert.assertEquals(0, sc.deployed.size()); ts.testee.scan(); Assert.assertFalse(f1.exists()); Assert.assertTrue(f2.exists()); Assert.assertFalse(f3.exists()); Assert.assertTrue(f4.exists()); Assert.assertFalse(f5.exists()); Assert.assertTrue(f6.exists()); Assert.assertTrue(undeployed.exists()); Assert.assertTrue(nestedUndeployed.exists()); Assert.assertTrue(removed.exists()); Assert.assertTrue(nestedRemoved.exists()); Assert.assertEquals(0, sc.deployed.size()); } /** WFCORE-64 */ @Test public void testForcedUndeployment() throws Exception { MockServerController sc = new MockServerController("foo.war", "failure.ear"); TesteeSet ts = createTestee(sc); ts.controller.externallyDeployed.put("foo.war", null); ts.controller.addCompositeSuccessResponse(1); assertThat(ts.controller.deployed.size(), is(2)); //ts.testee.scan(true, new DefaultDeploymentOperations(sc), true); ts.testee.forcedUndeployScan(); assertThat(ts.controller.deployed.size(), is(1)); //Only non persistent deployments should be undeployed. assertThat(ts.controller.deployed.keySet(), hasItems("foo.war")); } @Test public void testUncleanShutdown() throws Exception { File deployment = new File(tmpDir, "foo.war"); final File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); final File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); final File deploying = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYING); final DiscardTaskExecutor myWaitingExecutor = new DiscardTaskExecutor(true) { @Override public <T> AsyncFuture<T> submit(Callable<T> tCallable) { return new WaitingFuture<T>(50000, tCallable); } }; MockServerController sc = new MockServerController(myWaitingExecutor); final BlockingDeploymentOperations ops = new BlockingDeploymentOperations(sc); final DiscardTaskExecutor myExecutor = new DiscardTaskExecutor(true); final TesteeSet ts = createTestee(sc, myExecutor, ops); ts.testee.setAutoDeployZippedContent(true); sc.addCompositeSuccessResponse(1); testSupport.createZip(deployment, 0, false, false, true, true); Future<Boolean> lockDone = Executors.newSingleThreadExecutor().submit(new Callable<Boolean>() { @Override public Boolean call() throws Exception { try { while (!ops.ready) {//Waiting for deployment to start. Thread.sleep(100); } ts.testee.stopScanner(); return true; } catch (InterruptedException ex) { throw new RuntimeException(ex); } } }); ts.testee.setScanInterval(10000); lockDone.get(60000, TimeUnit.MILLISECONDS); } /** * WFCORE-210 */ @BMRule(name = "Test IO failure", targetClass = "FileSystemProvider", targetMethod = "newDirectoryStream", targetLocation = "AT ENTRY", isOverriding = true, action = "throw new java.io.IOException(\"Thanks Byteman\")" ) @Test public void testNoUndeployment() throws Exception { MockServerController sc = new MockServerController("foo.war", "failure.ear"); TesteeSet ts = createTestee(sc); ts.controller.externallyDeployed.put("foo.war", null); ts.controller.addCompositeSuccessResponse(1); assertThat(ts.controller.deployed.size(), is(2)); try { ts.testee.bootTimeScan(new DefaultDeploymentOperations(sc)); fail("RuntimeException expected"); } catch (Exception ex) { assertThat(ex.getClass().isAssignableFrom(RuntimeException.class), is(true)); assertThat(ex.getLocalizedMessage(), is(DeploymentScannerLogger.ROOT_LOGGER.cannotListDirectoryFiles(ex.getCause(), tmpDir).getLocalizedMessage())); } assertThat(ts.controller.deployed.size(), is(2)); //Only non persistent deployments should be undeployed. assertThat(ts.controller.deployed.keySet(), hasItems("foo.war", "failure.ear")); } @Test public void testArchivePatterns() throws Exception { Pattern pattern = FileSystemDeploymentService.ARCHIVE_PATTERN; assertTrue(pattern.matcher("x.war").matches()); assertTrue(pattern.matcher("x.War").matches()); assertTrue(pattern.matcher("x.WAr").matches()); assertTrue(pattern.matcher("x.WAR").matches()); assertTrue(pattern.matcher("x.jar").matches()); assertTrue(pattern.matcher("x.Jar").matches()); assertTrue(pattern.matcher("x.sar").matches()); assertTrue(pattern.matcher("x.Sar").matches()); assertTrue(pattern.matcher("x.ear").matches()); assertTrue(pattern.matcher("x.Ear").matches()); assertTrue(pattern.matcher("x.rar").matches()); assertTrue(pattern.matcher("x.Rar").matches()); assertTrue(pattern.matcher("x.wab").matches()); assertTrue(pattern.matcher("x.WaB").matches()); assertTrue(pattern.matcher("x.esa").matches()); assertTrue(pattern.matcher("x.ESA").matches()); } /** * Test that a scanner does not interfere with a deployment it does not own. Basic case with * a persistent deployment but no owner; i.e. a typical deployment added by the user via CLI or console. */ @Test public void testIgnoreExternalPersistentDeployment() throws Exception { testIgnoreExternalDeployment(null); } /** * Test that a scanner does not interfere with a deployment it does not own. WFCORE-632 case. where external deployment * is not persistent, but is not owned by a scanner. */ @Test public void testIgnoreExternalNonPersistentDeployment() throws Exception { testIgnoreExternalDeployment(new ExternalDeployment(null, false)); } /** * Test that a scanner does not interfere with a deployment it does not own. WFCORE-65 case. where external deployment * is owned by a different scanner. */ @Test public void testIgnoreExternalScannerDeployment() throws Exception { PathAddress externalScanner = PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, DeploymentScannerExtension.SUBSYSTEM_NAME), PathElement.pathElement(DeploymentScannerExtension.SCANNERS_PATH.getKey(), "other")); testIgnoreExternalDeployment(new ExternalDeployment(externalScanner, false)); } /** * Checks that deployments are redeployed after reboot (as in {@link #testArchiveRedeployedAfterReboot()}), * even if deployment dir is not available during scanner start. */ @Test public void testUnreadableDeploymentDirDuringStart() throws Exception { if (!tmpDir.delete()) { Assert.fail("Couldn't delete tmpDir"); } // start scanner with non-readable deployment dir TesteeSet ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); // create deployment dir with archive deployment and .DEPLOYED marker - this deployment should be redeployed createFile("foo.war"); File dodeploy = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = createFile("foo.war" + FileSystemDeploymentService.DEPLOYED); // run scan ts.testee.scan(); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertTrue(ts.controller.deployed.containsKey("foo.war")); } /** * Checks temporary inaccessible deployment dir */ @Test public void testUnreadableDeploymentDirDuringScan() throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); TesteeSet ts = createTestee(); ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertEquals(1, ts.controller.deployed.size()); byte[] deploymentHash = ts.controller.deployed.get("foo.war"); // make the deployment dir temporary inaccessible and run a scan File movedDir = new File(tmpDir.getAbsolutePath() + ".moved"); Files.move(tmpDir.toPath(), movedDir.toPath()); ts.testee.scan(); // scan should not fail assertEquals(1, ts.controller.deployed.size()); assertEquals(deploymentHash, ts.controller.deployed.get("foo.war")); // shouldn't have been redeployed // make the deployment dir accessible again and run a scan Files.move(movedDir.toPath(), tmpDir.toPath()); ts.testee.scan(); assertEquals(1, ts.controller.deployed.size()); assertEquals(deploymentHash, ts.controller.deployed.get("foo.war")); // shouldn't have been redeployed // update marker file timestamp and run a scan if (!deployed.setLastModified(System.currentTimeMillis() + 1000)) { Assert.fail("Couldn't update last modified flag."); } ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertEquals(1, ts.controller.deployed.size()); assertNotEquals(deploymentHash, ts.controller.deployed.get("foo.war")); // should have been redeployed } private void testIgnoreExternalDeployment(ExternalDeployment externalDeployment) throws Exception { File war = createFile("foo.war"); File dodeploy = createFile("foo.war" + FileSystemDeploymentService.DO_DEPLOY); File deployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.DEPLOYED); File undeployed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.UNDEPLOYED); File failed = new File(tmpDir, "foo.war" + FileSystemDeploymentService.FAILED_DEPLOY); TesteeSet ts = createTestee(); //Deploy externally loaded deployment byte[] bytes = randomHash(); ts.controller.added.put("external.war", bytes); ts.controller.deployed.put("external.war", bytes); ts.controller.externallyDeployed.put("external.war", externalDeployment); // Scan ts.controller.addCompositeSuccessResponse(1); ts.testee.scan(); assertTrue(war.exists()); assertFalse(dodeploy.exists()); assertTrue(deployed.exists()); assertFalse(undeployed.exists()); assertFalse(failed.exists()); assertEquals(2, ts.controller.added.size()); assertEquals(2, ts.controller.deployed.size()); assertEquals(bytes, ts.controller.added.get("external.war")); assertEquals(bytes, ts.controller.deployed.get("external.war")); } private TesteeSet createTestee(String... existingContent) throws OperationFailedException { return createTestee(new MockServerController(existingContent)); } private TesteeSet createTestee(final DiscardTaskExecutor executorService, final String... existingContent) throws OperationFailedException { return createTestee(new MockServerController(executorService, existingContent), executorService); } private TesteeSet createTestee(final MockServerController sc) throws OperationFailedException { return createTestee(sc, executor); } private TesteeSet createTestee(final MockServerController sc, final ScheduledExecutorService executor) throws OperationFailedException { return createTestee(sc, executor, new DefaultDeploymentOperations(sc)); } private TesteeSet createTestee(final MockServerController sc, final ScheduledExecutorService executor, DeploymentOperations ops) throws OperationFailedException { final FileSystemDeploymentService testee = new FileSystemDeploymentService(resourceAddress, null, tmpDir, null, sc, executor, null); testee.startScanner(ops); return new TesteeSet(testee, sc); } private File createFile(String fileName) throws IOException { return createFile(tmpDir, fileName); } private File createFile(File dir, String fileName) throws IOException { dir.mkdirs(); File f = new File(dir, fileName); Files.write(f.toPath(), fileName.getBytes(StandardCharsets.UTF_8)); assertTrue(f.exists()); return f; } private File createXmlFile(String fileName, String contents) throws IOException { tmpDir.mkdirs(); File f = new File(tmpDir, fileName); Files.write(f.toPath(), contents.getBytes(StandardCharsets.UTF_8)); assertTrue(f.exists()); return f; } private File createDirectory(String name, String... children) throws IOException { return createDirectory(tmpDir, name, children); } private File createDirectory(File dir, String name, String... children) throws IOException { final File directory = new File(dir, name); directory.mkdirs(); for (final String child : children) { createFile(directory, child); } return directory; } private static class TesteeSet { private final FileSystemDeploymentService testee; private final MockServerController controller; public TesteeSet(FileSystemDeploymentService testee, MockServerController sc) { this.testee = testee; this.controller = sc; } } private static class MockServerController implements ModelControllerClient, DeploymentOperations.Factory { private final DiscardTaskExecutor executorService; private final List<ModelNode> requests = new ArrayList<ModelNode>(1); private final List<Response> responses = new ArrayList<Response>(1); private final Map<String, byte[]> added = new HashMap<String, byte[]>(); private final Map<String, byte[]> deployed = new HashMap<String, byte[]>(); private final Map<String, ExternalDeployment> externallyDeployed = new HashMap<String, ExternalDeployment>(); @Override public ModelNode execute(ModelNode operation) throws IOException { requests.add(operation); return processOp(operation); } @Override public ModelNode execute(Operation operation) throws IOException { return execute(operation.getOperation()); } @Override public ModelNode execute(ModelNode operation, OperationMessageHandler messageHandler) throws IOException { throw new UnsupportedOperationException(); } @Override public ModelNode execute(Operation operation, OperationMessageHandler messageHandler) throws IOException { throw new UnsupportedOperationException(); } @Override public OperationResponse executeOperation(Operation operation, OperationMessageHandler messageHandler) throws IOException { throw new UnsupportedOperationException(); } @Override public AsyncFuture<ModelNode> executeAsync(final ModelNode operation, OperationMessageHandler messageHandler) { return executorService.submit(new Callable<ModelNode>() { @Override public ModelNode call() throws Exception { return execute(operation); } }); } @Override public AsyncFuture<ModelNode> executeAsync(Operation operation, OperationMessageHandler messageHandler) { throw new UnsupportedOperationException(); } @Override public AsyncFuture<OperationResponse> executeOperationAsync(Operation operation, OperationMessageHandler messageHandler) { throw new UnsupportedOperationException(); } @Override public void close() throws IOException { executorService.shutdown(); } @Override public DeploymentOperations create() { return new DefaultDeploymentOperations(this); } private static class Response { private final boolean ok; private final ModelNode rsp; Response(boolean ok, ModelNode rsp) { this.ok = ok; this.rsp = rsp; } } MockServerController(String... existingDeployments) { this(executor, existingDeployments); } MockServerController(DiscardTaskExecutor executorService, String... existingDeployments) { for (String dep : existingDeployments) { added.put(dep, randomHash()); deployed.put(dep, added.get(dep)); } this.executorService = executorService; } public void addCompositeSuccessResponse(int count) { ModelNode rsp = new ModelNode(); rsp.get(OUTCOME).set(SUCCESS); ModelNode result = rsp.get(RESULT); for (int i = 1; i <= count; i++) { result.get("step-" + i, OUTCOME).set(SUCCESS); result.get("step-" + i, RESULT); } responses.add(new Response(true, rsp)); } public void addCompositeFailureResponse(int count, int failureStep) { if (count < failureStep) { throw new IllegalArgumentException("failureStep must be > count"); } ModelNode rsp = new ModelNode(); rsp.get(OUTCOME).set(FAILED); ModelNode result = rsp.get(RESULT); for (int i = 1; i <= count; i++) { String step = "step-" + i; if (i < failureStep) { result.get(step, OUTCOME).set(FAILED); result.get(step, RESULT); result.get(step, ROLLED_BACK).set(true); } else if (i == failureStep) { result.get(step, OUTCOME).set(FAILED); result.get(step, FAILURE_DESCRIPTION).set(new ModelNode().set("badness happened")); result.get(step, ROLLED_BACK).set(true); } else { result.get(step, OUTCOME).set(CANCELLED); } } rsp.get(FAILURE_DESCRIPTION).set(new ModelNode().set("badness happened")); rsp.get(ROLLED_BACK).set(true); responses.add(new Response(true, rsp)); } public void addCompositeFailureResultResponse(int count, int failureStep) { if (count < failureStep) { throw new IllegalArgumentException("failureStep must be > count"); } ModelNode rsp = new ModelNode(); rsp.get(OUTCOME).set(SUCCESS); ModelNode result = rsp.get(RESULT); ModelNode failedStep = result.get("step-" + failureStep); failedStep.get(OUTCOME).set(SUCCESS); ModelNode stepResult = failedStep.get(RESULT); for (int i = 1; i <= count; i++) { String step = "step-" + i; if (i < failureStep) { stepResult.get(step, OUTCOME).set(SUCCESS); stepResult.get(step, RESULT); stepResult.get(step, ROLLED_BACK).set(true); } else if (i == failureStep) { stepResult.get(step, OUTCOME).set(FAILED); stepResult.get(step, FAILURE_DESCRIPTION).set(new ModelNode().set("true failed step")); stepResult.get(step, ROLLED_BACK).set(true); } else { stepResult.get(step, OUTCOME).set(CANCELLED); } } rsp.get(FAILURE_DESCRIPTION).set(new ModelNode().set("badness happened")); rsp.get(ROLLED_BACK).set(true); responses.add(new Response(true, rsp)); } public void addPartialCompositeFailureResultResponse(int count, int failureStep) { if (count < failureStep) { throw new IllegalArgumentException("failureStep must be > count"); } ModelNode rsp = new ModelNode(); rsp.get(OUTCOME).set(SUCCESS); ModelNode result = rsp.get(RESULT); for (int i = 1; i <= count; i++) { String step = "step-" + i; if (i < failureStep) { result.get(step, OUTCOME).set(SUCCESS); result.get(step, RESULT); result.get(step, RESULT, "step-1", OUTCOME).set(SUCCESS); result.get(step, RESULT, "step-1", RESULT); result.get(step, RESULT, "step-2", OUTCOME).set(SUCCESS); result.get(step, RESULT, "step-2", RESULT); } else if (i == failureStep) { result.get(step, OUTCOME).set(SUCCESS); result.get(step, RESULT); result.get(step, RESULT, "step-1", OUTCOME).set(SUCCESS); result.get(step, RESULT, "step-1", RESULT); result.get(step, RESULT, "step-2", OUTCOME).set(FAILED); result.get(step, RESULT, "step-2", FAILURE_DESCRIPTION).set(new ModelNode().set("badness happened")); } else { result.get(step, OUTCOME).set(CANCELLED); } } responses.add(new Response(true, rsp)); } private ModelNode getDeploymentNamesResponse() { ModelNode content = new ModelNode(); content.get(OUTCOME).set(SUCCESS); ModelNode result = content.get(RESULT); result.setEmptyObject(); for (String deployment : added.keySet()) { result.get(deployment, ENABLED).set(deployed.containsKey(deployment)); if (externallyDeployed.containsKey(deployment)) { ExternalDeployment externalDeployment = externallyDeployed.get(deployment); if (externalDeployment != null) { // Report what a different owner (e.g. different scanner) would configure result.get(deployment, PERSISTENT).set(externalDeployment.persistent); ModelNode ownerNode = result.get(deployment, OWNER); if (externalDeployment.ownerAddress != null) { ownerNode.set(externalDeployment.ownerAddress.toModelNode()); } // else leave undefined } else { // Report what a non-scanner deployment would configure result.get(deployment, PERSISTENT).set(true); result.get(deployment, OWNER).set(new ModelNode()); } } else { // Report what our scanner would configure result.get(deployment, PERSISTENT).set(false); result.get(deployment, OWNER).set(resourceAddress.toModelNode()); } } return content; } private ModelNode processOp(ModelNode op) { String opName = op.require(OP).asString(); if (READ_CHILDREN_RESOURCES_OPERATION.equals(opName)) { return getDeploymentNamesResponse(); } else if (COMPOSITE.equals(opName)) { for (ModelNode child : op.require(STEPS).asList()) { opName = child.require(OP).asString(); if (COMPOSITE.equals(opName)) { return processOp(child); } if (responses.isEmpty()) { Assert.fail("unexpected request " + op); return null; // unreachable } if (!responses.get(0).ok) { // don't change state for a failed response continue; } PathAddress address = PathAddress.pathAddress(child.require(OP_ADDR)); if (ADD.equals(opName)) { // Since AS7-431 the content is no longer managed //added.put(address.getLastElement().getValue(), child.require(CONTENT).require(0).require(HASH).asBytes()); added.put(address.getLastElement().getValue(), randomHash()); } else if (REMOVE.equals(opName)) { added.remove(address.getLastElement().getValue()); } else if (DEPLOY.equals(opName)) { String name = address.getLastElement().getValue(); deployed.put(name, added.get(name)); } else if (UNDEPLOY.equals(opName)) { deployed.remove(address.getLastElement().getValue()); } else if (REDEPLOY.equals(opName)) { byte[] newHash = randomHash(); added.put(address.getLastElement().getValue(), newHash); deployed.put(address.getLastElement().getValue(), newHash); } else if (FULL_REPLACE_DEPLOYMENT.equals(opName)) { String name = child.require(NAME).asString(); // Since AS7-431 the content is no longer managed //byte[] hash = child.require(CONTENT).require(0).require(HASH).asBytes(); final byte[] hash = randomHash(); added.put(name, hash); deployed.put(name, hash); } else { throw new IllegalArgumentException("unexpected step " + opName); } } return responses.remove(0).rsp; } else { throw new IllegalArgumentException("unexpected operation " + opName); } } } private static class DiscardTaskExecutor extends ScheduledThreadPoolExecutor { private final List<Runnable> tasks = new ArrayList<Runnable>(); private final boolean allowRejection; private DiscardTaskExecutor() { this(false); } private DiscardTaskExecutor(boolean mayShutdown) { super(0); this.allowRejection = mayShutdown; } @Override public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { tasks.add(command); return null; } @Override public <T> AsyncFuture<T> submit(Callable<T> tCallable) { if (allowRejection && (isShutdown() || isTerminating())) { throw new RejectedExecutionException("DiscardTaskExecutor has shutdown we can't run " + tCallable); } return new CallOnGetFuture<T>(tCallable); } void clear() { tasks.clear(); } } private static class CallOnGetFuture<T> implements AsyncFuture<T> { final Callable<T> callable; private CallOnGetFuture(Callable<T> callable) { this.callable = callable; } @Override public boolean cancel(boolean b) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return false; } @Override public T get() throws InterruptedException, ExecutionException { try { return callable.call(); } catch (Exception e) { throw new RuntimeException(e); } } @Override public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { return get(); } @Override public AsyncFuture.Status await() throws InterruptedException { throw new UnsupportedOperationException(); } @Override public AsyncFuture.Status await(long timeout, TimeUnit unit) throws InterruptedException { throw new UnsupportedOperationException(); } @Override public T getUninterruptibly() throws CancellationException, ExecutionException { throw new UnsupportedOperationException(); } @Override public T getUninterruptibly(long timeout, TimeUnit unit) throws CancellationException, ExecutionException, TimeoutException { throw new UnsupportedOperationException(); } @Override public AsyncFuture.Status awaitUninterruptibly() { throw new UnsupportedOperationException(); } @Override public AsyncFuture.Status awaitUninterruptibly(long timeout, TimeUnit unit) { throw new UnsupportedOperationException(); } @Override public AsyncFuture.Status getStatus() { throw new UnsupportedOperationException(); } @Override public <A> void addListener(AsyncFuture.Listener<? super T, A> listener, A attachment) { throw new UnsupportedOperationException(); } @Override public void asyncCancel(boolean interruptionDesired) { throw new UnsupportedOperationException(); } } private static class TimeOutFuture<T> extends CallOnGetFuture<T> { final long expectedTimeout; private TimeOutFuture(long expectedTimeout, Callable<T> callable) { super(callable); this.expectedTimeout = expectedTimeout; } @Override public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { assertEquals("Should use the configured timeout", expectedTimeout, l); throw new TimeoutException(); } } private static class WaitingFuture<T> extends CallOnGetFuture<T> { private final long duration; private WaitingFuture(long duration, Callable<T> callable) { super(callable); this.duration = duration; } @Override public T get() throws InterruptedException, ExecutionException { Thread.sleep(duration); return super.get(); } } private static class BlockingDeploymentOperations implements DeploymentOperations { private volatile boolean ready = false; private final DefaultDeploymentOperations delegate; BlockingDeploymentOperations(final ModelControllerClient controllerClient) { delegate = new DefaultDeploymentOperations(controllerClient); } @Override public Future<ModelNode> deploy(final ModelNode operation, ExecutorService executorService) { ready = true; return delegate.deploy(operation, null); } @Override public Map<String, Boolean> getDeploymentsStatus() { return delegate.getDeploymentsStatus(); } @Override public void close() throws IOException { delegate.close(); } @Override public Set<String> getUnrelatedDeployments(ModelNode owner) { return delegate.getUnrelatedDeployments(owner); } } private static class ExternalDeployment { private final PathAddress ownerAddress; private final boolean persistent; private ExternalDeployment(PathAddress ownerAddress, boolean persistent) { this.ownerAddress = ownerAddress; this.persistent = persistent; } } private static byte[] randomHash() { final byte[] hash = new byte[20]; random.nextBytes(hash); return hash; } }