/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, 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.test.integration.domain.suites;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import org.apache.http.impl.client.HttpClients;
import org.jboss.as.test.shared.TestSuiteEnvironment;
import org.junit.Assert;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.jboss.as.cli.Util;
import org.jboss.as.controller.client.Operation;
import org.jboss.as.controller.client.OperationBuilder;
import org.jboss.as.controller.client.helpers.domain.DomainClient;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.test.integration.domain.management.util.DomainTestSupport;
import org.jboss.as.test.shared.FileUtils;
import org.jboss.dmr.ModelNode;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
import org.jboss.shrinkwrap.api.exporter.ZipExporter;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
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.DEPLOYMENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ENABLED;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.HOST;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INCLUDE_RUNTIME;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.INPUT_STREAM_INDEX;
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.READ_RESOURCE_OPERATION;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.REMOVE;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SOCKET_BINDING_GROUP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.STEPS;
import static org.jboss.as.test.integration.domain.management.util.DomainTestSupport.cleanFile;
import static org.jboss.as.test.integration.domain.management.util.DomainTestSupport.validateResponse;
import static org.junit.Assert.assertEquals;
/**
* Test of various management operations involving deployment overlays
*/
public class DeploymentOverlayTestCase {
public static final String TEST_OVERLAY = "test";
public static final String TEST_WILDCARD = "test-server";
private static final String TEST = "test.war";
private static final String REPLACEMENT = "test.war.v2";
private static final ModelNode ROOT_ADDRESS = new ModelNode();
private static final ModelNode ROOT_DEPLOYMENT_ADDRESS = new ModelNode();
private static final ModelNode ROOT_REPLACEMENT_ADDRESS = new ModelNode();
private static final ModelNode MAIN_SERVER_GROUP_ADDRESS = new ModelNode();
private static final ModelNode MAIN_SERVER_GROUP_DEPLOYMENT_ADDRESS = new ModelNode();
private static final ModelNode MAIN_RUNNING_SERVER_ADDRESS = new ModelNode();
private static final ModelNode MAIN_RUNNING_SERVER_DEPLOYMENT_ADDRESS = new ModelNode();
static {
ROOT_ADDRESS.setEmptyList();
ROOT_ADDRESS.protect();
ROOT_DEPLOYMENT_ADDRESS.add(DEPLOYMENT, TEST);
ROOT_DEPLOYMENT_ADDRESS.protect();
ROOT_REPLACEMENT_ADDRESS.add(DEPLOYMENT, REPLACEMENT);
ROOT_REPLACEMENT_ADDRESS.protect();
MAIN_SERVER_GROUP_ADDRESS.add(SERVER_GROUP, "main-server-group");
MAIN_SERVER_GROUP_ADDRESS.protect();
MAIN_SERVER_GROUP_DEPLOYMENT_ADDRESS.add(SERVER_GROUP, "main-server-group");
MAIN_SERVER_GROUP_DEPLOYMENT_ADDRESS.add(DEPLOYMENT, TEST);
MAIN_SERVER_GROUP_DEPLOYMENT_ADDRESS.protect();
MAIN_RUNNING_SERVER_ADDRESS.add(HOST, "master");
MAIN_RUNNING_SERVER_ADDRESS.add(SERVER, "main-one");
MAIN_RUNNING_SERVER_ADDRESS.protect();
MAIN_RUNNING_SERVER_DEPLOYMENT_ADDRESS.add(HOST, "master");
MAIN_RUNNING_SERVER_DEPLOYMENT_ADDRESS.add(SERVER, "main-one");
MAIN_RUNNING_SERVER_DEPLOYMENT_ADDRESS.add(DEPLOYMENT, TEST);
MAIN_RUNNING_SERVER_DEPLOYMENT_ADDRESS.protect();
}
private static DomainTestSupport testSupport;
private static WebArchive webArchive;
private static File tmpDir;
@BeforeClass
public static void setupDomain() throws Exception {
// Create our deployment
webArchive = ShrinkWrap.create(WebArchive.class, TEST);
webArchive.addAsWebInfResource("deploymentoverlay/web.xml", "web.xml");
webArchive.addClass(DeploymentOverlayServlet.class);
// Make versions on the filesystem for URL-based deploy and for unmanaged content testing
tmpDir = new File("target/deployments/" + DeploymentOverlayTestCase.class.getSimpleName());
new File(tmpDir, "archives").mkdirs();
new File(tmpDir, "exploded").mkdirs();
webArchive.as(ZipExporter.class).exportTo(new File(tmpDir, "archives/" + TEST), true);
webArchive.as(ExplodedExporter.class).exportExploded(new File(tmpDir, "exploded"));
// Launch the domain
testSupport = DomainTestSuite.createSupport(DeploymentOverlayTestCase.class.getSimpleName());
}
@AfterClass
public static void tearDownDomain() throws Exception {
try {
testSupport = null;
DomainTestSuite.stopSupport();
} finally {
cleanFile(tmpDir);
}
}
/**
* Validate that there are no deployments; try and clean if there are.
*
* @throws Exception
*/
@Before
@After
public void confirmNoDeployments() throws Exception {
List<ModelNode> deploymentList = getDeploymentList(ROOT_ADDRESS);
if (deploymentList.size() > 0) {
cleanDeployments();
}
deploymentList = getDeploymentList(new ModelNode());
assertEquals("Deployments are removed from the domain", 0, deploymentList.size());
}
/**
* Remove all deployments from the model.
*
* @throws java.io.IOException
*/
private void cleanDeployments() throws IOException {
List<ModelNode> deploymentList = getDeploymentList(MAIN_SERVER_GROUP_ADDRESS);
for (ModelNode deployment : deploymentList) {
removeDeployment(deployment.asString(), MAIN_SERVER_GROUP_ADDRESS);
}
deploymentList = getDeploymentList(ROOT_ADDRESS);
for (ModelNode deployment : deploymentList) {
removeDeployment(deployment.asString(), ROOT_ADDRESS);
}
}
public void setupDeploymentOverride() throws Exception {
ModelNode op = new ModelNode();
op.get(ModelDescriptionConstants.OP_ADDR).set(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_OVERLAY);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
executeOnMaster(op);
//add an override that will not be linked via a wildcard
//add the content
op = new ModelNode();
OperationBuilder builder = new OperationBuilder(op, true);
ModelNode addr = new ModelNode();
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_OVERLAY);
addr.add(ModelDescriptionConstants.CONTENT, "WEB-INF/web.xml");
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
op.get(ModelDescriptionConstants.CONTENT).get(INPUT_STREAM_INDEX).set(0);
builder.addInputStream(getClass().getClassLoader().getResourceAsStream("deploymentoverlay/override.xml"));
executeOnMaster(builder.build());
//add the non-wildcard link to the server group
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.SERVER_GROUP, "main-server-group");
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_OVERLAY);
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
executeOnMaster(op);
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.SERVER_GROUP, "main-server-group");
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_OVERLAY);
addr.add(ModelDescriptionConstants.DEPLOYMENT, "test.war");
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
executeOnMaster(op);
//add the wildard link
final ModelNode composite = new ModelNode();
final OperationBuilder opBuilder = new OperationBuilder(composite, true);
composite.get(Util.OPERATION).set(Util.COMPOSITE);
composite.get(Util.ADDRESS).setEmptyList();
final ModelNode steps = composite.get(Util.STEPS);
op = new ModelNode();
op.get(ModelDescriptionConstants.OP_ADDR).set(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_WILDCARD);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
steps.add(op);
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_WILDCARD);
addr.add(ModelDescriptionConstants.CONTENT, "WEB-INF/web.xml");
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
op.get(ModelDescriptionConstants.CONTENT).get(ModelDescriptionConstants.BYTES).set(FileUtils.readFile(getClass().getClassLoader().getResource("deploymentoverlay/wildcard-override.xml")).getBytes());
steps.add(op);
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_WILDCARD);
addr.add(ModelDescriptionConstants.CONTENT, "WEB-INF/classes/wildcard-new-file");
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
op.get(ModelDescriptionConstants.CONTENT).get(ModelDescriptionConstants.INPUT_STREAM_INDEX).set(0);
opBuilder.addInputStream(new ByteArrayInputStream("new file".getBytes()));
steps.add(op);
//add the non-wildcard link to the server group
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.SERVER_GROUP, "main-server-group");
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_WILDCARD);
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
steps.add(op);
op = new ModelNode();
addr = new ModelNode();
addr.add(ModelDescriptionConstants.SERVER_GROUP, "main-server-group");
addr.add(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, TEST_WILDCARD);
addr.add(ModelDescriptionConstants.DEPLOYMENT, "*.war");
op.get(ModelDescriptionConstants.OP_ADDR).set(addr);
op.get(ModelDescriptionConstants.OP).set(ModelDescriptionConstants.ADD);
steps.add(op);
executeOnMaster(opBuilder.build());
}
/**
* This test creates and links two deployment overlays, does a deployment, and then tests that the overlay has taken effect
* @throws Exception
*/
@Test
public void testDeploymentOverlayInDomainMode() throws Exception {
setupDeploymentOverride();
ModelNode content = new ModelNode();
content.get(INPUT_STREAM_INDEX).set(0);
ModelNode composite = createDeploymentOperation(content, MAIN_SERVER_GROUP_DEPLOYMENT_ADDRESS);
OperationBuilder builder = new OperationBuilder(composite, true);
builder.addInputStream(webArchive.as(ZipExporter.class).exportAsInputStream());
executeOnMaster(builder.build());
DomainClient client = testSupport.getDomainMasterLifecycleUtil().createDomainClient();
Assert.assertEquals("OVERRIDDEN", performHttpCall(client, "master", "main-one", "standard-sockets"));
Assert.assertEquals("OVERRIDDEN", performHttpCall(client, "slave", "main-three", "standard-sockets"));
}
private String performHttpCall(DomainClient client, String host, String server, String socketBindingGroup) throws Exception {
ModelNode op = new ModelNode();
op.get(OP).set(READ_RESOURCE_OPERATION);
op.get(OP_ADDR).add(HOST, host).add(SERVER, server).add(SOCKET_BINDING_GROUP, socketBindingGroup).add(SOCKET_BINDING, "http");
op.get(INCLUDE_RUNTIME).set(true);
ModelNode socketBinding = validateResponse(client.execute(op));
URL url = new URL("http",
TestSuiteEnvironment.formatPossibleIpv6Address(socketBinding.get("bound-address").asString()),
socketBinding.get("bound-port").asInt(),
"/test/");
HttpGet get = new HttpGet(url.toURI());
HttpClient httpClient = HttpClients.createDefault();
HttpResponse response = httpClient.execute(get);
return getContent(response);
}
public static String getContent(HttpResponse response) throws IOException {
InputStreamReader reader = new InputStreamReader(response.getEntity().getContent());
StringBuilder content = new StringBuilder();
int c;
while (-1 != (c = reader.read())) {
content.append((char) c);
}
reader.close();
return content.toString();
}
private static ModelNode executeOnMaster(ModelNode op) throws IOException {
return validateResponse(testSupport.getDomainMasterLifecycleUtil().getDomainClient().execute(op));
}
private static ModelNode executeOnMaster(Operation op) throws IOException {
return validateResponse(testSupport.getDomainMasterLifecycleUtil().getDomainClient().execute(op));
}
private static ModelNode createDeploymentOperation(ModelNode content, ModelNode... serverGroupAddressses) {
ModelNode composite = getEmptyOperation(COMPOSITE, ROOT_ADDRESS);
ModelNode steps = composite.get(STEPS);
ModelNode step1 = steps.add();
step1.set(getEmptyOperation(ADD, ROOT_DEPLOYMENT_ADDRESS));
step1.get(CONTENT).add(content);
for (ModelNode serverGroup : serverGroupAddressses) {
ModelNode sg = steps.add();
sg.set(getEmptyOperation(ADD, serverGroup));
sg.get(ENABLED).set(true);
}
return composite;
}
private static List<ModelNode> getDeploymentList(ModelNode address) throws IOException {
ModelNode op = getEmptyOperation("read-children-names", address);
op.get("child-type").set("deployment");
ModelNode response = testSupport.getDomainMasterLifecycleUtil().getDomainClient().execute(op);
ModelNode result = validateResponse(response);
return result.isDefined() ? result.asList() : Collections.<ModelNode>emptyList();
}
private static void removeDeployment(String deploymentName, ModelNode address) throws IOException {
ModelNode deplAddr = new ModelNode();
deplAddr.set(address);
deplAddr.add("deployment", deploymentName);
ModelNode op = getEmptyOperation(REMOVE, deplAddr);
ModelNode response = testSupport.getDomainMasterLifecycleUtil().getDomainClient().execute(op);
validateResponse(response);
}
private static ModelNode getEmptyOperation(String operationName, ModelNode address) {
ModelNode op = new ModelNode();
op.get(OP).set(operationName);
if (address != null) {
op.get(OP_ADDR).set(address);
}
else {
// Just establish the standard structure; caller can fill in address later
op.get(OP_ADDR);
}
return op;
}
}