/*
* RHQ Management Platform
* Copyright (C) 2005-2014 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.modules.plugins.wildfly10.itest.standalone;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.rhq.core.domain.util.ResourceTypeUtility.getMeasurementDefinitions;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.rhq.core.clientapi.agent.inventory.CreateResourceRequest;
import org.rhq.core.clientapi.agent.inventory.CreateResourceResponse;
import org.rhq.core.clientapi.agent.inventory.DeleteResourceRequest;
import org.rhq.core.clientapi.server.content.ContentDiscoveryReport;
import org.rhq.core.clientapi.server.content.ContentServiceResponse;
import org.rhq.core.clientapi.server.content.DeployPackagesRequest;
import org.rhq.core.clientapi.server.content.RetrievePackageBitsRequest;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.configuration.PropertySimple;
import org.rhq.core.domain.content.PackageDetailsKey;
import org.rhq.core.domain.content.transfer.ContentResponseResult;
import org.rhq.core.domain.content.transfer.DeployPackagesResponse;
import org.rhq.core.domain.content.transfer.ResourcePackageDetails;
import org.rhq.core.domain.measurement.DataType;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDataTrait;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.MeasurementReport;
import org.rhq.core.domain.measurement.MeasurementScheduleRequest;
import org.rhq.core.domain.resource.CreateResourceStatus;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceCategory;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.MeasurementDefinitionFilter;
import org.rhq.core.pc.inventory.ResourceContainer;
import org.rhq.core.pc.util.FacetLockType;
import org.rhq.core.pluginapi.measurement.MeasurementFacet;
import org.rhq.core.util.MessageDigestGenerator;
import org.rhq.modules.plugins.wildfly10.itest.AbstractJBossAS7PluginTest;
import org.rhq.modules.plugins.wildfly10.test.util.Constants;
import org.rhq.test.arquillian.DiscoveredResources;
import org.rhq.test.arquillian.MockingServerServices;
import org.rhq.test.arquillian.RunDiscovery;
/**
*
*
* @author Lukas Krejci
*/
@Test(groups = { "integration", "pc", "standalone" }, singleThreaded = true)
public class DeploymentTest extends AbstractJBossAS7PluginTest {
private Resource platform;
private Resource serverResource;
@DiscoveredResources(plugin = Constants.PLUGIN_NAME, resourceType = "Deployment")
private Set<Resource> deploymentResources;
@DiscoveredResources(plugin = Constants.PLUGIN_NAME, resourceType = "Web Runtime")
private Set<Resource> webRuntimeResources;
private static TestDeployments DEPLOYMENT_TO_SERVE = TestDeployments.DEPLOYMENT_1;
@Override
protected void injectMocks(MockingServerServices serverServices) {
Mockito.when(
serverServices.getContentServerService().downloadPackageBitsForChildResource(Mockito.anyInt(),
Mockito.anyString(), Mockito.any(PackageDetailsKey.class), Mockito.any(OutputStream.class))).then(
new Answer<Long>() {
@Override
public Long answer(InvocationOnMock invocation) throws Throwable {
OutputStream out = (OutputStream) invocation.getArguments()[invocation.getArguments().length - 1];
return copyStreamAndReturnCount(out);
}
});
Mockito.when(
serverServices.getContentServerService().downloadPackageBitsGivenResource(Mockito.anyInt(),
Mockito.any(PackageDetailsKey.class), Mockito.any(OutputStream.class))).then(new Answer<Long>() {
@Override
public Long answer(InvocationOnMock invocation) throws Throwable {
OutputStream out = (OutputStream) invocation.getArguments()[invocation.getArguments().length - 1];
return copyStreamAndReturnCount(out);
}
});
}
@Test(priority = 10)
@RunDiscovery
public void initialDiscoveryTest() throws Exception {
platform = validatePlatform();
serverResource = waitForResourceByTypeAndKey(platform, platform, Constants.STANDALONE_RESOURCE_TYPE,
Constants.STANDALONE_RESOURCE_KEY);
}
@Test(priority = 11)
public void testDeploy() throws Exception {
ResourcePackageDetails packageDetails = getTestDeploymentPackageDetails(TestDeployments.DEPLOYMENT_1);
Configuration deploymentConfig = new Configuration();
deploymentConfig.put(new PropertySimple("runtimeName", packageDetails.getName()));
CreateResourceRequest request = new CreateResourceRequest();
request.setPackageDetails(packageDetails);
request.setParentResourceId(serverResource.getId());
request.setPluginConfiguration(null);
request.setPluginName(Constants.PLUGIN_NAME);
request.setResourceConfiguration(deploymentConfig);
request.setResourceName(TestDeployments.DEPLOYMENT_1.getResourceKey());
request.setResourceTypeName("Deployment");
CreateResourceResponse response = pluginContainer.getResourceFactoryManager().executeCreateResourceImmediately(
request);
assert response.getStatus() == CreateResourceStatus.SUCCESS : "The deployment failed with an error mesasge: "
+ response.getErrorMessage();
Resource deployment = waitForResourceByTypeAndKey(platform, serverResource, new ResourceType("Deployment",
Constants.PLUGIN_NAME, ResourceCategory.SERVICE, null), "deployment=" + TestDeployments.DEPLOYMENT_1.getResourceKey());
// these tests may depend on the deployment children to be in inventory, make sure they are
waitForAsyncDiscoveryToStabilize(deployment, 5000L, 10);
}
@Test(priority = 12)
public void testPackageDetectedForArchivedDeployment() throws Exception {
assert deploymentResources != null && deploymentResources.size() == 1 : "The new deployment should have been discovered";
Resource deployment = deploymentResources.iterator().next();
// the resource key and resource name are the same, and should be the filename stripped of version.
assert TestDeployments.DEPLOYMENT_1.getResourceKey().equals(deployment.getName()) : "The deployment doesn't seem to have the expected name";
ContentDiscoveryReport report = pluginContainer.getContentManager().executeResourcePackageDiscoveryImmediately(
deployment.getId(), "file");
Set<ResourcePackageDetails> details = report.getDeployedPackages();
assert details != null && details.size() == 1 : "The archived deployment should be backed by exactly 1 package.";
ResourcePackageDetails actualDetails = details.iterator().next();
ResourcePackageDetails expectedDetails = getTestDeploymentPackageDetails(TestDeployments.DEPLOYMENT_1);
//we don't expect the resource details to be equal, because the version field
//will be different - the test code simplistically just assigns "1.0"
//but the actual code assigns a sha256, because the test war doesn't contain
//explicit version information.
//We therefore just compare the name and type...
String actualName = actualDetails.getName();
String actualType = actualDetails.getPackageTypeName();
String expectedName = expectedDetails.getName();
String expectedType = expectedDetails.getPackageTypeName();
Assert.assertEquals(actualName, expectedName,
"The deployment's package details are called differently than expected.");
Assert.assertEquals(actualType, expectedType,
"The deployment's package details have different type than expected.");
}
@Test(priority = 13)
public void testDeploymentContentRetrieval() throws Exception {
testContentRetrieval(TestDeployments.DEPLOYMENT_1);
}
@Test(priority = 14)
public void testRedeploy() throws Exception {
Resource deployment = deploymentResources.iterator().next();
//we are updating the deployment 1. So provide a key to the first deployment but later on actually
//deliver bits of the deployment 2, so that we get the update we "wanted".
ResourcePackageDetails packageDetails = getTestDeploymentPackageDetails(TestDeployments.DEPLOYMENT_1);
//this is what our mocked serverside is going to serve the package bits for
TestDeployments origServedDeployemnt = DEPLOYMENT_TO_SERVE;
DEPLOYMENT_TO_SERVE = TestDeployments.DEPLOYMENT_2;
try {
DeployPackagesRequest request = new DeployPackagesRequest(1, deployment.getId(),
Collections.singleton(packageDetails));
DeployPackagesResponse response = pluginContainer.getContentManager().deployPackagesImmediately(request);
assertEquals(response.getOverallRequestResult(), ContentResponseResult.SUCCESS);
testContentRetrieval(TestDeployments.DEPLOYMENT_2);
} finally {
//switch the served deployment back, so that other tests aren't affected
DEPLOYMENT_TO_SERVE = origServedDeployemnt;
}
}
@Test(priority = 15)
public void testWebRuntimeMetricsHaveNonNullValues() throws Exception {
assertTrue(webRuntimeResources != null && !webRuntimeResources.isEmpty(),
"Web Runtime resource should have been discovered");
assertEquals(webRuntimeResources.size(), 1, "Found more than one Web Runtime resource: " + webRuntimeResources);
Resource webRuntimeResource = webRuntimeResources.iterator().next();
ResourceContainer webRuntimeResourceContainer = pluginContainer.getInventoryManager().getResourceContainer(
webRuntimeResource);
MeasurementFacet measurementFacet = webRuntimeResourceContainer.createResourceComponentProxy(
MeasurementFacet.class, FacetLockType.READ, SECONDS.toMillis(5), false, false, false);
MeasurementReport report = new MeasurementReport();
Set<MeasurementScheduleRequest> measurementScheduleRequests = getMeasurementScheduleRequests(webRuntimeResource);
measurementFacet.getValues(report, measurementScheduleRequests);
assertEquals(report.getCallTimeData().size(), 0, "No calltime data was requested");
assertTrue(
report.getNumericData().size() + report.getTraitData().size() == measurementScheduleRequests.size(),
"Some requested measurements are missing: "
+ getMissingMeasurements(measurementScheduleRequests, report.getNumericData(), report.getTraitData()));
}
@Test(priority = 16)
public void testUndeploy() throws Exception {
Resource deployment = deploymentResources.iterator().next();
DeleteResourceRequest request = new DeleteResourceRequest(0, deployment.getId());
getServerInventory().removeResource(deployment);
pluginContainer.getResourceFactoryManager().deleteResource(request);
}
private void testContentRetrieval(final TestDeployments deployment) throws Exception {
final boolean[] lockAndTestResult = new boolean[2];
//perform the test in the mocked server-side.
Mockito
.doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
InputStream data = (InputStream) invocation.getArguments()[1];
byte[] md5 = computeHash(data);
synchronized (lockAndTestResult) {
lockAndTestResult[0] = true;
//transfer the test result to the test thread so that
//the assert is captured.
lockAndTestResult[1] = Arrays.equals(deployment.getHash(), md5);
lockAndTestResult.notifyAll();
}
return null;
}
private byte[] computeHash(InputStream data) {
try {
return MessageDigestGenerator.getDigest(data);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
})
.when(serverServices.getContentServerService())
.completeRetrievePackageBitsRequest(Mockito.any(ContentServiceResponse.class),
Mockito.any(InputStream.class));
//setup the content retrieval request and execute it
Resource deploymentResource = deploymentResources.iterator().next();
RetrievePackageBitsRequest request = new RetrievePackageBitsRequest(0, deploymentResource.getId(),
getTestDeploymentPackageDetails(deployment));
pluginContainer.getContentManager().retrievePackageBits(request);
//the content retrieval is async so wait in the test method until the mocked server-side
//completed the test (unless it has already done so).
synchronized (lockAndTestResult) {
if (!lockAndTestResult[0]) {
lockAndTestResult.wait();
}
assert lockAndTestResult[1] : "The data obtained from the deployment are different to what should have been deployed.";
}
}
private long copyStreamAndReturnCount(OutputStream out) throws IOException {
if (null == out) {
System.out.println("**** Unexepected null output stream in mock code!!");
return 0L;
}
String path = DEPLOYMENT_TO_SERVE.getResourcePath();
InputStream in = getClass().getClassLoader().getResourceAsStream(path);
long cnt = 0;
try {
int data;
while ((data = in.read()) != -1) {
if (out != null) {
out.write(data);
}
cnt++;
}
} finally {
in.close();
out.flush();
}
return cnt;
}
static ResourcePackageDetails getTestDeploymentPackageDetails(TestDeployments deployment) {
ResourcePackageDetails details = new ResourcePackageDetails(new PackageDetailsKey(
deployment.getDeploymentName(), "1.0", "file", "noarch"));
details.setFileName(deployment.getDeploymentName());
details.setDeploymentTimeConfiguration(new Configuration());
return details;
}
static Set<String> getMissingMeasurements(Set<MeasurementScheduleRequest> measurementScheduleRequests,
Set<MeasurementDataNumeric> numericData, Set<MeasurementDataTrait> traitData) {
Set<String> missingMeasurements = new HashSet<String>();
for (MeasurementScheduleRequest measurementScheduleRequest : measurementScheduleRequests) {
missingMeasurements.add(measurementScheduleRequest.getName());
}
for (MeasurementDataNumeric measurementDataNumeric : numericData) {
missingMeasurements.remove(measurementDataNumeric.getName());
}
for (MeasurementDataTrait measurementDataTrait : traitData) {
missingMeasurements.remove(measurementDataTrait.getName());
}
return missingMeasurements;
}
static Set<MeasurementScheduleRequest> getMeasurementScheduleRequests(Resource webRuntimeResource) {
Set<MeasurementDefinition> measurementDefinitions = getMeasurementDefinitions(
webRuntimeResource.getResourceType(), new MeasurementDefinitionFilter() {
private final Set<DataType> acceptableDataTypes = EnumSet.of(DataType.MEASUREMENT, DataType.TRAIT);
@Override
public boolean accept(MeasurementDefinition measurementDefinition) {
return acceptableDataTypes.contains(measurementDefinition.getDataType());
}
});
Set<MeasurementScheduleRequest> measurementScheduleRequests = new HashSet<MeasurementScheduleRequest>();
for (MeasurementDefinition measurementDefinition : measurementDefinitions) {
measurementScheduleRequests.add(new MeasurementScheduleRequest(-1, measurementDefinition.getName(), -1,
true, measurementDefinition.getDataType(), measurementDefinition.getRawNumericType()));
}
return measurementScheduleRequests;
}
}