/*
* RHQ Management Platform
* Copyright (C) 2005-2010 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.core.pc.upgrade;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jmock.Expectations;
import org.testng.annotations.Test;
import org.rhq.core.clientapi.agent.PluginContainerException;
import org.rhq.core.clientapi.agent.discovery.InvalidPluginConfigurationClientException;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pc.PluginContainer;
import org.rhq.core.pc.inventory.InventoryManager;
import org.rhq.core.pc.inventory.ResourceContainer;
import org.rhq.core.pc.upgrade.plugins.multi.base.BaseResourceComponentInterface;
import org.rhq.core.pluginapi.upgrade.ResourceUpgradeFacet;
import org.rhq.test.pc.PluginContainerSetup;
/**
* The plugins and their resource types form the following dependency structure:
* <pre>
* Root(root)
* / \
* ParentDependency(parentdep) ParentDepSibling(parentsibling)
* / \
* TestResource(test) TestResourceSibling(sibling)
* </pre>
* The dependencies in the above "chart" are formed using either the <code><runs-inside></code>
* or <code>sourcePlugin/sourceType</code> approaches just to test that both are handled correctly.
* <p>
* The <code>parentdep</code>, <code>parentsibling</code>, <code>test</code> and <code>sibling</code> plugins are present
* in two versions and support the {@link ResourceUpgradeFacet}, while the rest of the plugins is
* present only in single version.
*
* @author Lukas Krejci
*/
@Test(singleThreaded = true, invocationCount = 1)
public class ResourceUpgradeFailureHandlingTest extends AbstractResourceUpgradeHandlingTest {
//test names
private static final String SUCCESS_TEST = "SUCCESS_TEST";
private static final String FAILURE_ON_LEAF_TEST = "FAILURE_ON_LEAF_TEST";
private static final String FAILURE_ON_DEPENDENCIES_TEST = "FAILURE_ON_DEPENDENCIES_TEST";
private static final String RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST = "RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST";
//plugin names
private static final String BASE_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-base-1.0.0.jar";
private static final String PARENT_DEP_V1_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-parentdep-1.0.0.jar";
private static final String PARENT_DEP_V2_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-parentdep-2.0.0.jar";
private static final String PARENT_SIBLING_V1_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-parentsibling-1.0.0.jar";
private static final String PARENT_SIBLING_V2_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-parentsibling-2.0.0.jar";
private static final String ROOT_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-root-1.0.0.jar";
private static final String SIBLING_V1_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-sibling-1.0.0.jar";
private static final String SIBLING_V2_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-sibling-2.0.0.jar";
private static final String TEST_V1_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-test-1.0.0.jar";
private static final String TEST_V2_PLUGIN_NAME = "classpath:///resource-upgrade-test-plugin-multi-test-2.0.0.jar";
private static final ResType TEST_TYPE = new ResType("TestResource", "test");
private static final ResType SIBLING_TYPE = new ResType("TestResourceSibling", "test");
private static final ResType PARENT_TYPE = new ResType("TestResourceParent", "test");
private static final ResType PARENT_DEP_TYPE = new ResType("ParentDependency", "parentdep");
private static final ResType PARENT_DEP_SIBLING_TYPE = new ResType("ParentDepSibling", "parentsibling");
private static final ResType ROOT_TYPE = new ResType("Root", "root");
private static List<ResType> ALL_TYPES = Arrays.asList(TEST_TYPE, SIBLING_TYPE, PARENT_TYPE, PARENT_DEP_TYPE,
PARENT_DEP_SIBLING_TYPE, ROOT_TYPE);
@Test
@PluginContainerSetup(plugins = {TEST_V1_PLUGIN_NAME, PARENT_SIBLING_V1_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V1_PLUGIN_NAME, SIBLING_V1_PLUGIN_NAME},
sharedGroup = SUCCESS_TEST, clearDataDir = true, numberOfInitialDiscoveries = 3)
public void testSuccess_V1() throws Exception {
final FakeServerInventory inv = new FakeServerInventory();
setServerSideFake(SUCCESS_TEST, inv);
context.checking(new Expectations() {
{
defineDefaultExpectations(inv, this);
}
});
//let the discovery run in V1
startConfiguredPluginContainer();
}
@Test(dependsOnMethods = "testSuccess_V1")
@PluginContainerSetup(plugins = {TEST_V2_PLUGIN_NAME, PARENT_SIBLING_V2_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V2_PLUGIN_NAME, SIBLING_V2_PLUGIN_NAME},
sharedGroup = SUCCESS_TEST, clearInventoryDat = false, numberOfInitialDiscoveries = 3)
public void testSuccess_V2() throws Exception {
final FakeServerInventory inventory = (FakeServerInventory) getServerSideFake(SUCCESS_TEST);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
Map<ResType, Set<Resource>> resources = getResourcesFromInventory(inventory, ALL_TYPES);
checkPresenceOfResourceTypes(resources, ALL_TYPES);
checkNumberOfResources(resources, ROOT_TYPE, 1);
checkNumberOfResources(resources, PARENT_DEP_TYPE, 1);
//check that the resources are upgraded
checkResourcesUpgraded(resources.get(PARENT_DEP_SIBLING_TYPE), 1);
checkResourcesUpgraded(resources.get(PARENT_TYPE), 3);
checkResourcesUpgraded(resources.get(SIBLING_TYPE), 45);
checkResourcesUpgraded(resources.get(TEST_TYPE), 45);
}
@Test
@PluginContainerSetup(plugins = {TEST_V1_PLUGIN_NAME, PARENT_SIBLING_V1_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V1_PLUGIN_NAME, SIBLING_V1_PLUGIN_NAME},
sharedGroup = FAILURE_ON_LEAF_TEST, clearDataDir = true, numberOfInitialDiscoveries = 3)
public void testFailureOnLeaf_V1() throws Exception {
final FakeServerInventory inventory = new FakeServerInventory();
setServerSideFake(FAILURE_ON_LEAF_TEST, inventory);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
//in here we set up the failures that are going to happen when
//the v2 plugins are run
Resource parent0 = findResourceWithOrdinal(PARENT_TYPE, 0);
assertNotNull(parent0, "Failed to find the parent to setup the failures for.");
Resource parent1 = findResourceWithOrdinal(PARENT_TYPE, 1);
assertNotNull(parent1, "Failed to find the parent to setup the failures for.");
addChildrenToFail(parent0, TEST_TYPE, 1, 2);
addChildrenToFail(parent1, SIBLING_TYPE, 1);
}
@Test(dependsOnMethods = "testFailureOnLeaf_V1")
@PluginContainerSetup(plugins = {TEST_V2_PLUGIN_NAME, PARENT_SIBLING_V2_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V2_PLUGIN_NAME, SIBLING_V2_PLUGIN_NAME},
sharedGroup = FAILURE_ON_LEAF_TEST, clearInventoryDat = false, numberOfInitialDiscoveries = 3)
public void testFailureOnLeaf_V2() throws Exception {
final FakeServerInventory inventory = (FakeServerInventory) getServerSideFake(FAILURE_ON_LEAF_TEST);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
Map<ResType, Set<Resource>> resources = getResourcesFromInventory(inventory, ALL_TYPES);
checkPresenceOfResourceTypes(resources, ALL_TYPES);
checkNumberOfResources(resources, ROOT_TYPE, 1);
checkNumberOfResources(resources, PARENT_DEP_TYPE, 1);
checkResourcesUpgraded(resources.get(PARENT_TYPE), 3);
checkResourcesUpgraded(resources.get(PARENT_DEP_SIBLING_TYPE), 1);
Resource parent0 = findResourceWithOrdinal(PARENT_TYPE, 0);
Resource parent1 = findResourceWithOrdinal(PARENT_TYPE, 1);
Resource parent2 = findResourceWithOrdinal(PARENT_TYPE, 2);
Set<Resource> testsUnderParent0 = filterResources(parent0.getChildResources(), TEST_TYPE);
Set<Resource> siblingsUnderParent0 = filterResources(parent0.getChildResources(), SIBLING_TYPE);
Set<Resource> testsUnderParent1 = filterResources(parent1.getChildResources(), TEST_TYPE);
Set<Resource> siblingsUnderParent1 = filterResources(parent1.getChildResources(), SIBLING_TYPE);
Set<Resource> testsUnderParent2 = filterResources(parent2.getChildResources(), TEST_TYPE);
Set<Resource> siblingsUnderParent2 = filterResources(parent2.getChildResources(), SIBLING_TYPE);
//first check for the successful upgrades
checkResourcesUpgraded(testsUnderParent2, 15);
checkResourcesUpgraded(siblingsUnderParent2, 15);
checkResourcesUpgraded(siblingsUnderParent0, 15);
checkResourcesUpgraded(testsUnderParent1, 15);
//there should be no newly discovered sibling resources of the failed ones
assertEquals(testsUnderParent0.size(), 10);
assertEquals(siblingsUnderParent1.size(), 10);
//check that the failed resources have the error attached to them
//we find the resource instance from the map provided to this method
//because that map contains the resources as found on the server-side
//(i.e. they include error objects).
Resource failedTest1 = getEqualFrom(resources.get(TEST_TYPE),
findResourceWithOrdinal(testsUnderParent0, 1));
Resource failedTest2 = getEqualFrom(resources.get(TEST_TYPE),
findResourceWithOrdinal(testsUnderParent0, 2));
checkResourceFailedUpgrade(failedTest1);
checkResourceFailedUpgrade(failedTest2);
checkOthersUpgraded(testsUnderParent0, failedTest1, failedTest2);
Resource failedSibling = getEqualFrom(resources.get(SIBLING_TYPE),
findResourceWithOrdinal(siblingsUnderParent1, 1));
checkResourceFailedUpgrade(failedSibling);
checkOthersUpgraded(siblingsUnderParent1, failedSibling);
}
@Test
@PluginContainerSetup(plugins = {TEST_V1_PLUGIN_NAME, PARENT_SIBLING_V1_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V1_PLUGIN_NAME, SIBLING_V1_PLUGIN_NAME},
sharedGroup = FAILURE_ON_DEPENDENCIES_TEST, clearDataDir = true, numberOfInitialDiscoveries = 3)
public void testFailureOnDependencies_V1() throws Exception {
final FakeServerInventory inventory = new FakeServerInventory();
setServerSideFake(FAILURE_ON_DEPENDENCIES_TEST, inventory);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
//in here we set up the failures that are going to happen when
//the v2 plugins are run
Resource parent = findResourceWithOrdinal(PARENT_DEP_TYPE, 0);
assertNotNull(parent, "Failed to find the parent to setup the failures for.");
addChildrenToFail(parent, PARENT_TYPE, 0);
}
@Test(dependsOnMethods = "testFailureOnDependencies_V1")
@PluginContainerSetup(plugins = {TEST_V2_PLUGIN_NAME, PARENT_SIBLING_V2_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V2_PLUGIN_NAME, SIBLING_V2_PLUGIN_NAME},
sharedGroup = FAILURE_ON_DEPENDENCIES_TEST, clearInventoryDat = false, numberOfInitialDiscoveries = 3)
public void testFailureOnDependencies_V2() throws Exception {
final FakeServerInventory inventory = (FakeServerInventory) getServerSideFake(FAILURE_ON_DEPENDENCIES_TEST);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
Map<ResType, Set<Resource>> resources = getResourcesFromInventory(inventory, ALL_TYPES);
checkPresenceOfResourceTypes(resources, ALL_TYPES);
checkNumberOfResources(resources, ROOT_TYPE, 1);
checkNumberOfResources(resources, PARENT_DEP_TYPE, 1);
checkResourcesUpgraded(resources.get(PARENT_DEP_SIBLING_TYPE), 1);
//check that the failed resources have the error attached to them
//we find the resource instance from the map provided to this method
//because that map contains the resources as found on the server-side
//(i.e. they include error objects).
Resource parent0 = getEqualFrom(resources.get(PARENT_TYPE), findResourceWithOrdinal(PARENT_TYPE, 0));
Resource parent1 = getEqualFrom(resources.get(PARENT_TYPE), findResourceWithOrdinal(PARENT_TYPE, 1));
checkResourceFailedUpgrade(parent0);
checkOthersUpgraded(resources.get(PARENT_TYPE), parent0);
//v2 plugin discovers 3 resources but because parent0 failed to upgrade,
//the discovery shouldn't have occurred leaving us with the 2 already existing resources.
checkNumberOfResources(resources, PARENT_TYPE, 2);
//parent1 upgraded ok, so discovering its children should have executed.
//this is v2, so we should find 15 of each.
checkResourcesUpgraded(filterResources(parent1.getChildResources(), TEST_TYPE), 15);
checkResourcesUpgraded(filterResources(parent1.getChildResources(), SIBLING_TYPE), 15);
//these shouldn't have been upgraded. in v1 we had 10 resources of TEST_TYPE
//and 10 resources of SIBLING_TYPE and that's what we should be seeing
//now.
checkResourcesNotUpgraded(filterResources(parent0.getChildResources(), TEST_TYPE), 10);
checkResourcesNotUpgraded(filterResources(parent0.getChildResources(), SIBLING_TYPE), 10);
}
@Test
@PluginContainerSetup(plugins = {TEST_V1_PLUGIN_NAME, PARENT_SIBLING_V1_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V1_PLUGIN_NAME, SIBLING_V1_PLUGIN_NAME},
sharedGroup = RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST, clearDataDir = true, numberOfInitialDiscoveries = 3)
public void testResourcesRevertedToOriginalStateAfterFailedUpgrade_V1() throws Exception {
final FakeServerInventory inventory = new FakeServerInventory();
setServerSideFake(RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST, inventory);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
startConfiguredPluginContainer();
}
@Test(dependsOnMethods = "testResourcesRevertedToOriginalStateAfterFailedUpgrade_V1")
@PluginContainerSetup(plugins = {TEST_V2_PLUGIN_NAME, PARENT_SIBLING_V2_PLUGIN_NAME, BASE_PLUGIN_NAME, ROOT_PLUGIN_NAME, PARENT_DEP_V2_PLUGIN_NAME, SIBLING_V2_PLUGIN_NAME},
sharedGroup = RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST, clearInventoryDat = false, numberOfInitialDiscoveries = 3)
public void testResourcesRevertedToOriginalStateAfterFailedUpgrade_V2() throws Exception {
final FakeServerInventory inventory = (FakeServerInventory) getServerSideFake(RESOURCES_REVERTED_TO_ORIGINAL_STATE_AFTER_FAILED_UPGRAGE_TEST);
context.checking(new Expectations() {
{
defineDefaultExpectations(inventory, this);
}
});
inventory.setFailUpgrade(true);
startConfiguredPluginContainer();
Map<ResType, Set<Resource>> resources = getResourcesFromInventory(inventory, ALL_TYPES);
checkPresenceOfResourceTypes(resources, ALL_TYPES);
checkNumberOfResources(resources, ROOT_TYPE, 1);
checkNumberOfResources(resources, PARENT_DEP_TYPE, 1);
//check that the resources are not upgraded
checkResourcesNotUpgraded(resources.get(PARENT_DEP_SIBLING_TYPE), 1);
checkResourcesNotUpgraded(resources.get(PARENT_TYPE), 2);
checkResourcesNotUpgraded(resources.get(SIBLING_TYPE), 20);
checkResourcesNotUpgraded(resources.get(TEST_TYPE), 20);
}
protected static void checkPresenceOfResourceTypes(Map<ResType, Set<Resource>> resources, Collection<ResType> expectedTypes) {
for (ResType resType : expectedTypes) {
assertNotNull(resources.get(resType), "Expecting some resources of type " + resType);
}
}
protected static void checkNumberOfResources(Map<ResType, Set<Resource>> resources, ResType type, int count) {
assertEquals(resources.get(type).size(), count, "Unexpected number of " + type + " discovered.");
}
protected static void checkOthersUpgraded(Set<Resource> resources, Resource... failedResource) {
Set<Resource> others = new HashSet<Resource>(resources);
others.removeAll(Arrays.asList(failedResource));
checkResourcesUpgraded(others, others.size());
}
protected void addChildrenToFail(Resource parent, ResType childResType, int... childrenOrdinals) {
InventoryManager inventoryManager = PluginContainer.getInstance().getInventoryManager();
ResourceContainer parentContainer = inventoryManager.getResourceContainer(parent);
BaseResourceComponentInterface parentComponent = (BaseResourceComponentInterface) parentContainer
.getResourceComponent();
if (parentComponent==null) {
throw new RuntimeException("Did not get a container for parent " + parent.getName() + ", " + parent.getUuid() + ", " + parent.getId());
}
Map<String, Set<Integer>> childrenToFail = new HashMap<String, Set<Integer>>();
Set<Integer> ordinals = new HashSet<Integer>();
for (int i = 0; i < childrenOrdinals.length; ++i) {
ordinals.add(childrenOrdinals[i]);
}
childrenToFail.put(childResType.getResourceTypeName(), ordinals);
Configuration newPluginConfig = parentComponent.createPluginConfigurationWithMarkedFailures(childrenToFail);
try {
int resourceId = parent.getId();
inventoryManager.updatePluginConfiguration(resourceId, newPluginConfig);
} catch (InvalidPluginConfigurationClientException e) {
fail("Updating plugin configuration failed.", e);
} catch (PluginContainerException e) {
fail("Updating plugin configuration failed.", e);
}
}
protected Set<Resource> filterResources(Set<Resource> resources, ResType resType) {
Set<Resource> ret = new HashSet<Resource>(resources);
Iterator<Resource> it = ret.iterator();
while (it.hasNext()) {
ResourceType resourceType = it.next().getResourceType();
if (!resourceType.getName().equals(resType.getResourceTypeName())
|| !resourceType.getPlugin().equals(resType.getResourceTypePluginName())) {
it.remove();
}
}
return ret;
}
private Map<ResType, Set<Resource>> getResourcesFromInventory(FakeServerInventory inventory, Collection<ResType> types) {
Map<ResType, Set<Resource>> resources = new HashMap<ResType, Set<Resource>>();
for(ResType type : types) {
ResourceType resType = PluginContainer.getInstance().getPluginManager().getMetadataManager()
.getType(type.getResourceTypeName(), type.getResourceTypePluginName());
Set<Resource> rs = inventory.findResourcesByType(resType);
resources.put(type, rs);
}
return resources;
}
private static <T> T getEqualFrom(Collection<? extends T> collection, T object) {
for (T other : collection) {
if (object.equals(other)) {
return other;
}
}
return null;
}
}