/* * Copyright (C) 2016 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 library 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 library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301 USA */ package org.wildfly.core.test.standalone.mgmt.api.core; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD_CONTENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ARCHIVE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.BYTES; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.COMPOSITE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOY; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.DEPLOYMENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.EXPLODE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INPUT_STREAM_INDEX; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.MANAGED; 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.OVERWRITE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATH; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.PATHS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_ATTRIBUTE_OPERATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_CONTENT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.READ_RESOURCE_OPERATION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE_CONTENT; 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.TARGET_PATH; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.URL; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.VALUE; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.WRITE_ATTRIBUTE_OPERATION; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.inject.Inject; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.client.Operation; import org.jboss.as.controller.client.OperationBuilder; import org.jboss.as.controller.client.helpers.Operations; import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentManager; import org.jboss.as.test.deployment.trivial.ServiceActivatorDeploymentUtil; import org.jboss.as.test.shared.TimeoutUtil; import org.jboss.dmr.ModelNode; import org.jboss.shrinkwrap.api.exporter.ExplodedExporter; import org.jboss.shrinkwrap.api.exporter.ZipExporter; import org.jboss.shrinkwrap.api.spec.JavaArchive; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.wildfly.core.testrunner.ManagementClient; import org.wildfly.core.testrunner.WildflyTestRunner; /** * Tests to check hard requirements and extreme cases for deployment operations. * @author <a href="mailto:mjurc@redhat.com">Michal Jurc</a> (c) 2016 Red Hat, Inc. */ @RunWith(WildflyTestRunner.class) public class DeploymentOperationsTestCase { @Inject private ManagementClient managementClient; private static final int TIMEOUT = TimeoutUtil.adjust(20000); private static final String TEST_DEPLOYMENT_NAME = "test-deployment.jar"; @Before public void cleanEnv() { cleanUp(); } @After public void cleanDeployments() { cleanUp(); } @Test public void testManagedAttributeValue() throws Exception { deployManagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertTrue(getManagedAttribute(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployManagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertTrue(getManagedAttribute(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(getManagedAttribute(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertFalse(getManagedAttribute(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testManagedAttributeReadOnly() throws Exception { deployManagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(writeManagedAttributeAndGetOutcome(TEST_DEPLOYMENT_NAME, false)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployManagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertFalse(writeManagedAttributeAndGetOutcome(TEST_DEPLOYMENT_NAME, false)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(writeManagedAttributeAndGetOutcome(TEST_DEPLOYMENT_NAME, true)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertFalse(writeManagedAttributeAndGetOutcome(TEST_DEPLOYMENT_NAME, true)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testManagedExplodedOperationsFailWithUnmanagedArchiveDeployment() throws Exception { deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(explodeDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertTrue(addContentByByteArrayAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByInputStreamAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByUrlAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertFalse(removeContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertFalse(readContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testManagedExplodedOperationsFailWithUnmanagedExplodedDeployment() throws Exception { deployUnmanagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertFalse(explodeDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertTrue(addContentByByteArrayAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByInputStreamAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByUrlAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertFalse(removeContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertFalse(readContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testManagedExplodedOperationsFailWithManagedArchiveDeployment() throws Exception { deployManagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(explodeDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertTrue(addContentByByteArrayAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByInputStreamAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertTrue(addContentByUrlAndGetOutcome(TEST_DEPLOYMENT_NAME, true).get(ROLLED_BACK).asBoolean()); Assert.assertFalse(removeContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); Assert.assertFalse(readContentFromDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testExplodeFailsWithDeployedManagedArchiveDeployment() throws Exception { deployManagedDeployment(TEST_DEPLOYMENT_NAME, true); Assert.assertFalse(explodeDeploymentAndGetOutcome(TEST_DEPLOYMENT_NAME)); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } @Test public void testAddContentFailsWithoutOverwriteManagedExplodedDeployment() throws Exception { deployManagedDeployment(TEST_DEPLOYMENT_NAME, false); Assert.assertFalse("Operation add-content over existing content in deployment with byte array content and overwrite=false succeeded, should fail", Operations.isSuccessfulOutcome(addContentByByteArrayAndGetOutcome(TEST_DEPLOYMENT_NAME, false))); Assert.assertFalse("Operation add-content over existing content in deployment with input stream index content and overwrite=false succeeded, should fail", Operations.isSuccessfulOutcome(addContentByInputStreamAndGetOutcome(TEST_DEPLOYMENT_NAME, false))); Assert.assertFalse("Operation add-content over existing content in deployment with url content and overwrite=false succeeded, should fail", Operations.isSuccessfulOutcome(addContentByUrlAndGetOutcome(TEST_DEPLOYMENT_NAME, false))); undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } private boolean getManagedAttribute(String deploymentName) { ModelNode op = new ModelNode(); op.get(OP).set(READ_ATTRIBUTE_OPERATION); op.get(OP_ADDR).add(DEPLOYMENT, deploymentName); op.get(NAME).set(MANAGED); Future<ModelNode> future = managementClient.getControllerClient().executeAsync(OperationBuilder.create(op, false).build(), null); try { ModelNode response = future.get(TIMEOUT, TimeUnit.MILLISECONDS); return Operations.readResult(response).asBoolean(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } } private boolean writeManagedAttributeAndGetOutcome(String deploymentName, boolean newValue) { ModelNode op = new ModelNode(); op.get(OP).set(WRITE_ATTRIBUTE_OPERATION); op.get(OP_ADDR).add(DEPLOYMENT, deploymentName); op.get(NAME).set(MANAGED); op.get(VALUE).set(newValue); return Operations.isSuccessfulOutcome(awaitOperationExecutionAndReturnOutcome(op)); } private boolean explodeDeploymentAndGetOutcome(String deploymentName) { ModelNode op = new ModelNode(); op.get(OP).set(EXPLODE); op.get(OP_ADDR).add(DEPLOYMENT, deploymentName); return Operations.isSuccessfulOutcome(awaitOperationExecutionAndReturnOutcome(op)); } private ModelNode addContentByByteArrayAndGetOutcome(String deploymentName, boolean overwrite) throws Exception { final Properties addedContentProperties = new Properties(); addedContentProperties.put(deploymentName + "Service", "isReplaced"); ModelNode addedContentNode = new ModelNode(); addedContentNode.get(TARGET_PATH).set("SimpleTest.properties"); String addedContentString; try (StringWriter writer = new StringWriter()) { addedContentProperties.store(writer, "Added with add-content op"); addedContentString = writer.toString(); addedContentNode.get(BYTES).set(addedContentString.getBytes(StandardCharsets.UTF_8)); } ModelNode addContentOp = new ModelNode(); addContentOp.get(OP).set(ADD_CONTENT); addContentOp.get(OP_ADDR).set(DEPLOYMENT, deploymentName); addContentOp.get(CONTENT).setEmptyList(); addContentOp.get(CONTENT).add(addedContentNode); addContentOp.get(OVERWRITE).add(overwrite); return awaitOperationExecutionAndReturnOutcome(addContentOp); } private ModelNode addContentByInputStreamAndGetOutcome(String deploymentName, boolean overwrite) throws Exception { final Properties addedContentProperties = new Properties(); final ModelControllerClient client = managementClient.getControllerClient(); addedContentProperties.put(deploymentName + "Service", "isReplaced"); List<InputStream> attachments = new ArrayList<>(); String content; try (StringWriter writer = new StringWriter()) { addedContentProperties.store(writer, "New Content"); content = writer.toString(); } try (InputStream is = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) { ModelNode addedContentNode = new ModelNode(); addedContentNode.get(TARGET_PATH).set("SimpleTest.properties"); addedContentNode.get(INPUT_STREAM_INDEX).set(0); attachments.add(is); ModelNode addContentOp = new ModelNode(); addContentOp.get(OP).set(ADD_CONTENT); addContentOp.get(OP_ADDR).set(DEPLOYMENT, deploymentName); addContentOp.get(CONTENT).setEmptyList(); addContentOp.get(CONTENT).add(addedContentNode); addContentOp.get(OVERWRITE).add(overwrite); Future<ModelNode> future = client.executeAsync(Operation.Factory.create(addContentOp, attachments), null); ModelNode response; try { response = future.get(TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } Assert.assertNotNull(response); return response; } } private ModelNode addContentByUrlAndGetOutcome(String deploymentName, boolean overwrite) throws Exception { final Properties addedContentProperties = new Properties(); addedContentProperties.put(deploymentName + "Service", "isReplaced"); ModelNode addedContentNode = new ModelNode(); addedContentNode.get(TARGET_PATH).set("SimpleTest.properties"); File archivesDir = new File("target", "archives"); File addedContentFile = new File(archivesDir, "simpleTest.properties"); if (addedContentFile.exists()) { addedContentFile.delete(); } addedContentFile.getParentFile().mkdirs(); addedContentFile.createNewFile(); try (OutputStream out = new FileOutputStream(addedContentFile, false)) { addedContentProperties.store(out, "Added with add-content op"); addedContentNode.get(URL).set(addedContentFile.toURI().toURL().toString()); } ModelNode addContentOp = new ModelNode(); addContentOp.get(OP).set(ADD_CONTENT); addContentOp.get(OP_ADDR).set(DEPLOYMENT, TEST_DEPLOYMENT_NAME); addContentOp.get(CONTENT).setEmptyList(); addContentOp.get(CONTENT).add(addedContentNode); addContentOp.get(OVERWRITE).add(overwrite); return awaitOperationExecutionAndReturnOutcome(addContentOp); } private boolean removeContentFromDeploymentAndGetOutcome(String deploymentName) throws Exception { ModelNode op = new ModelNode(); op.get(OP).set(REMOVE_CONTENT); op.get(OP_ADDR).add(DEPLOYMENT, deploymentName); op.get(PATHS).setEmptyList(); op.get(PATHS).add("simpleTest.properties"); return Operations.isSuccessfulOutcome(awaitOperationExecutionAndReturnOutcome(op)); } private boolean readContentFromDeploymentAndGetOutcome(String deploymentName) throws Exception { ModelNode op = new ModelNode(); op.get(OP).set(READ_CONTENT); op.get(OP_ADDR).add(DEPLOYMENT, deploymentName); op.get(PATH).set("simpleTest.properties"); return Operations.isSuccessfulOutcome(awaitOperationExecutionAndReturnOutcome(op)); } private void deployManagedDeployment(String deploymentName, boolean archived) throws Exception { final Properties properties = new Properties(); properties.put(deploymentName + "Service", "isNew"); final JavaArchive archive = ServiceActivatorDeploymentUtil.createServiceActivatorDeploymentArchive(deploymentName, properties); final ModelControllerClient client = managementClient.getControllerClient(); final ServerDeploymentManager manager = ServerDeploymentManager.Factory.create(client); try (InputStream is = archive.as(ZipExporter.class).exportAsInputStream()) { if (archived) { Future<?> future = manager.execute(manager.newDeploymentPlan() .add(deploymentName, is) .deploy(deploymentName) .build()); awaitDeploymentExecution(future); } else { Future<?> future = manager.execute(manager.newDeploymentPlan() .add(deploymentName, is) .explodeDeployment(deploymentName) .deploy(deploymentName) .build()); awaitDeploymentExecution(future); } } ServiceActivatorDeploymentUtil.validateProperties(client, properties); } private void deployUnmanagedDeployment(String deploymentName, boolean archived) throws Exception { final Properties properties = new Properties(); properties.put(deploymentName + "Service", "isNew"); final JavaArchive archive = ServiceActivatorDeploymentUtil.createServiceActivatorDeploymentArchive(deploymentName, properties); final ModelControllerClient client = managementClient.getControllerClient(); final File archiveDir = new File("target/archives"); archiveDir.mkdirs(); File deploymentFile; if (archived) { deploymentFile = new File(archiveDir, deploymentName); archive.as(ZipExporter.class).exportTo(deploymentFile, true); } else { archive.as(ExplodedExporter.class).exportExploded(archiveDir); deploymentFile = new File(archiveDir, deploymentName); } ModelNode compositeOp = new ModelNode(); ModelNode content = new ModelNode(); content.get(PATH).set(deploymentFile.getAbsolutePath()); content.get(ARCHIVE).set(archived); ModelNode addOp = new ModelNode(); addOp.get(OP).set(ADD); addOp.get(OP_ADDR).add(DEPLOYMENT, deploymentName); addOp.get(CONTENT).set(content); ModelNode deployOp = new ModelNode(); deployOp.get(OP).set(DEPLOY); deployOp.get(OP_ADDR).add(DEPLOYMENT, deploymentName); compositeOp.get(OP).set(COMPOSITE); compositeOp.get(OP_ADDR).setEmptyList(); compositeOp.get(STEPS).add(addOp); compositeOp.get(STEPS).add(deployOp); awaitOperationExecution(compositeOp); ServiceActivatorDeploymentUtil.validateProperties(client, properties); } private void undeployAndRemoveDeployment(String deploymentName) { final ModelControllerClient client = managementClient.getControllerClient(); final ServerDeploymentManager manager = ServerDeploymentManager.Factory.create(client); Future<?> future = manager.execute(manager.newDeploymentPlan() .undeploy(deploymentName) .remove(deploymentName) .build()); awaitDeploymentExecution(future); File deploymentFile = new File("target/archives/" + deploymentName); if (deploymentFile.exists()) { cleanFile(deploymentFile); } } private void awaitOperationExecution(ModelNode op) { Future<ModelNode> future = managementClient.getControllerClient().executeAsync(OperationBuilder.create(op, false).build(), null); try { ModelNode response = future.get(TIMEOUT, TimeUnit.MILLISECONDS); Assert.assertTrue(Operations.isSuccessfulOutcome(response)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } } private ModelNode awaitOperationExecutionAndReturnOutcome(ModelNode op) { Future<ModelNode> future = managementClient.getControllerClient().executeAsync(OperationBuilder.create(op, false).build(), null); try { return future.get(TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } } private void awaitDeploymentExecution(Future<?> future) { try { future.get(TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e.getCause()); } catch (TimeoutException e) { throw new RuntimeException(e); } } private static void cleanFile(File toClean) { if (toClean.exists()) { if (toClean.isDirectory()) { for (File child : toClean.listFiles()) { cleanFile(child); } } toClean.delete(); } } private void cleanUp() { ModelNode op = new ModelNode(); op.get(OP).set(READ_RESOURCE_OPERATION); op.get(OP_ADDR).set(DEPLOYMENT, TEST_DEPLOYMENT_NAME); ModelNode result = awaitOperationExecutionAndReturnOutcome(op); if (Operations.isSuccessfulOutcome(result)) { undeployAndRemoveDeployment(TEST_DEPLOYMENT_NAME); } String jbossBaseDir = System.getProperty("jboss.home"); Assert.assertNotNull(jbossBaseDir); Path dataDir = new File(jbossBaseDir).toPath().resolve("standalone").resolve("data"); if (Files.exists(dataDir)) { cleanFile(dataDir.resolve("managed-exploded").toFile()); } File archivesDir = new File("target", "archives"); if (Files.exists(archivesDir.toPath())) { cleanFile(archivesDir); } } }