/*
* Copyright 2016 JBoss by Red Hat.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.wildfly.core.test.standalone.mgmt.api;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.CONTENT;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.UUID;
import static org.jboss.as.repository.PathUtil.deleteRecursively;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
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.PathAddress;
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.controller.client.helpers.Operations;
import org.jboss.as.controller.client.helpers.standalone.ServerDeploymentManager;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.test.deployment.trivial.ServiceActivatorDeployment;
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.ZipExporter;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.wildfly.core.testrunner.ManagementClient;
import org.wildfly.core.testrunner.WildflyTestRunner;
/**
*
* @author Emmanuel Hugonnet (c) 2016 Red Hat, inc.
*/
@RunWith(WildflyTestRunner.class)
public class DeploymentOverlayTestCase {
// Max time to wait for some action to complete, in ms
private static final int TIMEOUT = TimeoutUtil.adjust(20000);
private static final PathAddress OVERLAY_ADDR = PathAddress.pathAddress(ModelDescriptionConstants.DEPLOYMENT_OVERLAY, "overlay");
private static final ModelNode OVERLAY_CONTENT_ADDR = OVERLAY_ADDR.append(CONTENT, ServiceActivatorDeployment.PROPERTIES_RESOURCE).toModelNode();
private static final ModelNode OVERLAY_DEPLOYMENT_ADDR = OVERLAY_ADDR.append(ModelDescriptionConstants.DEPLOYMENT, "test-deployment.jar").toModelNode();
private static final ModelNode DEPLOYMENT_ADDR = PathAddress.pathAddress(ModelDescriptionConstants.DEPLOYMENT, "test-deployment.jar").toModelNode();
@Inject
private ManagementClient managementClient;
private static final Properties properties = new Properties();
private static final Properties properties2 = new Properties();
@BeforeClass
public static void clearProperties() throws Exception {
properties.clear();
properties.put("service", "is new");
properties2.clear();
properties2.put("service", "is overwritten");
}
@AfterClass
public static void cleanFiles() throws IOException {
String jbossBaseDir = System.getProperty("jboss.home");
Assert.assertNotNull(jbossBaseDir);
Path dataDir = new File(jbossBaseDir).toPath().resolve("standalone").resolve("data");
Assert.assertTrue(Files.exists(dataDir));
deleteRecursively(dataDir.resolve("managed-exploded"));
}
@Test
public void testDeploymentArchive() throws Exception {
final JavaArchive archive = ServiceActivatorDeploymentUtil.createServiceActivatorDeploymentArchive("test-deployment.jar", properties);
final ModelControllerClient client = managementClient.getControllerClient();
final ServerDeploymentManager manager = ServerDeploymentManager.Factory.create(client);
testDeployments(new OverlayDeploymentExecutor() {
@Override
public void initialDeploy() throws IOException {
try (InputStream is = archive.as(ZipExporter.class).exportAsInputStream()) {
Future<?> future = manager.execute(manager.newDeploymentPlan()
.add("test-deployment.jar", is)
.deploy("test-deployment.jar")
.build());
awaitDeploymentExecution(future);
}
}
@Override
public void undeploy() {
Future<?> future = manager.execute(manager.newDeploymentPlan().undeploy("test-deployment.jar")
.remove("test-deployment.jar").build());
awaitDeploymentExecution(future);
}
@Override
public void redeploy() {
Future<?> future = manager.execute(manager.newDeploymentPlan().undeploy("test-deployment.jar").build());
awaitDeploymentExecution(future);
future = manager.execute(manager.newDeploymentPlan().deploy("test-deployment.jar").build());
awaitDeploymentExecution(future);
}
@Override
public void addOverlay() throws IOException {
ModelNode response = client.execute(Operations.createAddOperation(OVERLAY_ADDR.toModelNode()),
OperationMessageHandler.DISCARD);
Assert.assertTrue(response.toString(), Operations.isSuccessfulOutcome(response));
ModelNode op = Operations.createAddOperation(OVERLAY_CONTENT_ADDR);
op.get(CONTENT).get(ModelDescriptionConstants.INPUT_STREAM_INDEX).set(0);
String content = "";
try (StringWriter writer = new StringWriter()) {
properties2.store(writer, "Overlay Content");
content = writer.toString();
}
try (InputStream is = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) {
Future<?> future = client.executeOperationAsync(Operation.Factory.create(op, Collections.singletonList(is)), OperationMessageHandler.DISCARD);
awaitDeploymentExecution(future);
}
response = client.execute(Operations.createAddOperation(OVERLAY_DEPLOYMENT_ADDR));
Assert.assertTrue(response.toString(), Operations.isSuccessfulOutcome(response));
}
@Override
public void readOverlayContent(String expectedValue) throws IOException {
Future<OperationResponse> future = client.executeOperationAsync(
Operation.Factory.create(
Operations.createReadAttributeOperation(OVERLAY_CONTENT_ADDR, "stream")), OperationMessageHandler.DISCARD);
try {
OperationResponse response = future.get(TIMEOUT, TimeUnit.MILLISECONDS);
Assert.assertTrue(Operations.isSuccessfulOutcome(response.getResponseNode()));
Assert.assertTrue(Operations.readResult(response.getResponseNode()).hasDefined(UUID));
List<OperationResponse.StreamEntry> streams = response.getInputStreams();
Assert.assertThat(streams, is(notNullValue()));
Assert.assertThat(streams.size(), is(1));
try (InputStream in = streams.get(0).getStream()) {
Properties content = new Properties();
content.load(in);
Assert.assertThat(content.getProperty("service"), is(expectedValue));
}
} 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);
}
}
@Override
public void removeOverlay(boolean check) throws IOException {
ModelNode response = client.execute(Operations.createRemoveOperation(OVERLAY_CONTENT_ADDR));
if(check) {
Assert.assertTrue(response.toString(), Operations.isSuccessfulOutcome(response));
}
response = client.execute(Operations.createRemoveOperation(OVERLAY_DEPLOYMENT_ADDR));
if(check) {
Assert.assertTrue(response.toString(), Operations.isSuccessfulOutcome(response));
}
response = client.execute(Operations.createRemoveOperation(OVERLAY_ADDR.toModelNode()));
if(check) {
Assert.assertTrue(response.toString(), Operations.isSuccessfulOutcome(response));
}
}
});
}
private void testDeployments(OverlayDeploymentExecutor deploymentExecutor) throws Exception {
// Initial deploy
Set<String> initialHashes = getAllDeploymentHashesFromContentDir(true);
deploymentExecutor.initialDeploy();
//listener.await();
ServiceActivatorDeploymentUtil.validateProperties(managementClient.getControllerClient(), properties);
try {
// Add overlay
deploymentExecutor.addOverlay();
deploymentExecutor.redeploy();
deploymentExecutor.readOverlayContent("is overwritten");
ServiceActivatorDeploymentUtil.validateProperties(managementClient.getControllerClient(), properties2);
// listener.await();
deploymentExecutor.removeOverlay(true);
deploymentExecutor.redeploy();
ServiceActivatorDeploymentUtil.validateProperties(managementClient.getControllerClient(), properties);
// Undeploy
} finally {
deploymentExecutor.undeploy();
deploymentExecutor.removeOverlay(false);
}
Assert.assertEquals(initialHashes, getAllDeploymentHashesFromContentDir(false));
}
private Set<String> getAllDeploymentHashesFromContentDir(boolean emptyOk) {
String jbossBaseDir = System.getProperty("jboss.home");
Assert.assertNotNull(jbossBaseDir);
File file = new File(jbossBaseDir);
Assert.assertTrue(file.exists());
file = new File(file, "standalone");
Assert.assertTrue(file.exists());
file = new File(file, "data");
if (!file.exists() && emptyOk) {
return new HashSet<>();
}
Assert.assertTrue(file.exists());
file = new File(file, "content");
Assert.assertTrue(file.exists());
Set<String> hashes = new HashSet<>();
for (File top : file.listFiles()) {
if (top.isDirectory() && top.getName().length() == 2) {
for (File content : top.listFiles()) {
hashes.add(top.getName() + content.getName());
}
}
}
return hashes;
}
private void awaitDeploymentExecution(Future<?> future) {
Object t = null;
try {
t = 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 interface OverlayDeploymentExecutor {
void initialDeploy() throws IOException;
void addOverlay() throws IOException;
void readOverlayContent(String expectedValue) throws IOException;
void removeOverlay(boolean check) throws IOException;
void undeploy();
void redeploy();
}
}