/* * RHQ Management Platform * Copyright (C) 2005-2008 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.enterprise.server.resource.group.test; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import javax.persistence.EntityManager; import javax.transaction.Status; import org.testng.annotations.Test; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.authz.Permission; import org.rhq.core.domain.authz.Role; import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.util.PageControl; import org.rhq.core.util.jdbc.JDBCUtil; import org.rhq.enterprise.server.auth.SubjectManagerLocal; import org.rhq.enterprise.server.authz.RoleManagerLocal; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal; import org.rhq.enterprise.server.test.AbstractEJB3Test; import org.rhq.enterprise.server.util.LookupUtil; import org.rhq.enterprise.server.util.ResourceTreeHelper; import org.rhq.enterprise.server.util.SessionTestHelper; public class RecursiveResourceGroupTest extends AbstractEJB3Test { private ResourceGroupManagerLocal resourceGroupManager; private ResourceManagerLocal resourceManager; private RoleManagerLocal roleManager; private SubjectManagerLocal subjectManager; @Override protected void beforeMethod() throws Exception { resourceGroupManager = LookupUtil.getResourceGroupManager(); resourceManager = LookupUtil.getResourceManager(); roleManager = LookupUtil.getRoleManager(); subjectManager = LookupUtil.getSubjectManager(); prepareScheduler(); } @Override protected void afterMethod() throws Exception { unprepareScheduler(); } @Test(groups = "integration.session") public void testImplicitGroupMembershipFromInventoryUpdate() throws Throwable { getTransactionManager().begin(); try { EntityManager em = getEntityManager(); // setup simple test structures Subject subject = SessionTestHelper.createNewSubject(em, "fake subject"); Role role = SessionTestHelper .createNewRoleForSubject(em, subject, "fake role", Permission.MANAGE_INVENTORY); ResourceGroup recursiveGroup = SessionTestHelper.createNewMixedGroupForRole(em, role, "fake group", true); // setup the test tree List<Resource> fullTree = getSimpleTree(em); // test simple implicit resources Resource nodeA = ResourceTreeHelper.findNode(fullTree, "A"); List<Resource> resourcesFromTreeA = ResourceTreeHelper.getSubtree(nodeA); resourceGroupManager.addResourcesToGroup(subject, recursiveGroup.getId(), new int[] { nodeA.getId() }); List<Resource> initialExplicitResources = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); assert initialExplicitResources.size() == 1 : "Failed: initial explicit resources, size was " + initialExplicitResources.size(); assert initialExplicitResources.get(0).getId() == nodeA.getId() : "Failed: initial explicit resources id, found " + initialExplicitResources.get(0).getId() + ", expected " + nodeA.getId(); List<Resource> initialImplicitResources = resourceManager.findImplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); verifyEqualByIds("Failed: initial implicit resources", resourcesFromTreeA, initialImplicitResources); // test update implicit resources Resource newChildOfNodeA = new Resource("new nodeOne child", "new nodeOne child", nodeA.getResourceType()); newChildOfNodeA.setUuid("" + new Random().nextInt()); newChildOfNodeA.setInventoryStatus(InventoryStatus.COMMITTED); resourceManager.createResource(subject, newChildOfNodeA, nodeA.getId()); // sets up implicit relationships List<Resource> updatedImplicitResources = resourceManager.findImplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); resourcesFromTreeA.add(newChildOfNodeA); verifyEqualByIds("Failed: simple implicit resources", resourcesFromTreeA, updatedImplicitResources); } catch (Throwable t) { handleThrowable(t); } finally { getTransactionManager().rollback(); } } @Test(groups = "integration.session") public void testUpdateImplicitGroupMembership() throws Throwable { getTransactionManager().begin(); try { EntityManager em = getEntityManager(); // setup simple test structures Subject subject = SessionTestHelper.createNewSubject(em, "fake subject"); Role role = SessionTestHelper .createNewRoleForSubject(em, subject, "fake role", Permission.MANAGE_INVENTORY); ResourceGroup lineageG1 = SessionTestHelper.createNewMixedGroupForRole(em, role, "gen1", true); ResourceGroup lineageG2 = SessionTestHelper.createNewMixedGroupForRole(em, role, "gen2", true); ResourceGroup lineageG3 = SessionTestHelper.createNewMixedGroupForRole(em, role, "gen3", true); ResourceGroup lineageG4 = SessionTestHelper.createNewMixedGroupForRole(em, role, "gen4", true); // setup the test tree List<Resource> fullTree = ResourceTreeHelper.createTree(em, "A=1; 1=a; a=i;"); // resource chain Resource gen1 = ResourceTreeHelper.findNode(fullTree, "A"); Resource gen2 = ResourceTreeHelper.findNode(fullTree, "1"); Resource gen3 = ResourceTreeHelper.findNode(fullTree, "a"); Resource gen4 = ResourceTreeHelper.findNode(fullTree, "i"); resourceGroupManager.addResourcesToGroup(subject, lineageG1.getId(), new int[] { gen1.getId() }); resourceGroupManager.addResourcesToGroup(subject, lineageG2.getId(), new int[] { gen2.getId() }); resourceGroupManager.addResourcesToGroup(subject, lineageG3.getId(), new int[] { gen3.getId() }); resourceGroupManager.addResourcesToGroup(subject, lineageG4.getId(), new int[] { gen4.getId() }); // test update implicit resources Resource gen5 = new Resource("g5", "g5", gen4.getResourceType()); gen5.setUuid("" + new Random().nextInt()); gen5.setInventoryStatus(InventoryStatus.COMMITTED); resourceManager.createResource(subject, gen5, gen4.getId()); // sets up implicit relationships // confirm results List<Integer> newLineageG1 = resourceManager.findImplicitResourceIdsByResourceGroup(lineageG1.getId()); List<Integer> newLineageG2 = resourceManager.findImplicitResourceIdsByResourceGroup(lineageG2.getId()); List<Integer> newLineageG3 = resourceManager.findImplicitResourceIdsByResourceGroup(lineageG3.getId()); List<Integer> newLineageG4 = resourceManager.findImplicitResourceIdsByResourceGroup(lineageG4.getId()); List<Resource> treeGen1 = ResourceTreeHelper.getSubtree(gen1); List<Resource> treeGen2 = ResourceTreeHelper.getSubtree(gen2); List<Resource> treeGen3 = ResourceTreeHelper.getSubtree(gen3); List<Resource> treeGen4 = ResourceTreeHelper.getSubtree(gen4); // gen5 resource should have been added to all of them treeGen1.add(gen5); treeGen2.add(gen5); treeGen3.add(gen5); treeGen4.add(gen5); verifyEqual("Failed: updateImplicitGroupMembership gen1", getIds(treeGen1), newLineageG1); verifyEqual("Failed: updateImplicitGroupMembership gen2", getIds(treeGen2), newLineageG2); verifyEqual("Failed: updateImplicitGroupMembership gen3", getIds(treeGen3), newLineageG3); verifyEqual("Failed: updateImplicitGroupMembership gen4", getIds(treeGen4), newLineageG4); } catch (Throwable t) { handleThrowable(t); } finally { getTransactionManager().rollback(); } } @Test(groups = "integration.session") public void testImplicitGroupMembershipFromComplexGroupUpdates() throws Throwable { Subject subject = null; Role role = null; ResourceGroup recursiveGroup = null; List<Resource> fullTree = null; Resource nodeBigA = null; Resource nodeOne = null; Resource nodeThree = null; Resource nodeLittleA = null; Resource nodeTripleLittleI = null; List<Resource> resultsExplicit = null; List<Resource> expectedImplicit = null; List<Resource> expectedExplicit = new ArrayList<Resource>(); try { try { getTransactionManager().begin(); EntityManager em = getEntityManager(); // setup simple test structures subject = SessionTestHelper.createNewSubject(em, "fake subject"); role = SessionTestHelper.createNewRoleForSubject(em, subject, "fake role", Permission.MANAGE_INVENTORY); recursiveGroup = SessionTestHelper.createNewMixedGroupForRole(em, role, "fake group", true); // setup the test tree fullTree = getSimpleTree(em); ResourceTreeHelper.printForest(fullTree); // get the resources from the tree we want to explicitly add nodeBigA = ResourceTreeHelper.findNode(fullTree, "A"); nodeOne = ResourceTreeHelper.findNode(fullTree, "1"); nodeThree = ResourceTreeHelper.findNode(fullTree, "3"); nodeLittleA = ResourceTreeHelper.findNode(fullTree, "a"); nodeTripleLittleI = ResourceTreeHelper.findNode(fullTree, "iii"); // adding nodeLittleA should give us the subtree under nodeLittleA expectedImplicit = ResourceTreeHelper.getSubtree(nodeLittleA); implicitGroupMembershipAddHelper(subject, recursiveGroup, nodeLittleA, expectedImplicit); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); expectedExplicit.add(nodeLittleA); verifyEqualByIds("explicit add 1", expectedExplicit, resultsExplicit); // adding nodeThree should give us the union of the subtrees under nodeLittleA and nodeThree expectedImplicit.add(nodeThree); implicitGroupMembershipAddHelper(subject, recursiveGroup, nodeThree, expectedImplicit); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); expectedExplicit.add(nodeThree); verifyEqualByIds("explicit add 2", expectedExplicit, resultsExplicit); // adding nodeBigA should give us the union of the entire A tree with the nodeThree subtree expectedImplicit = ResourceTreeHelper.getSubtree(nodeBigA); expectedImplicit.addAll(ResourceTreeHelper.getSubtree(nodeThree)); implicitGroupMembershipAddHelper(subject, recursiveGroup, nodeBigA, expectedImplicit); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); expectedExplicit.add(nodeBigA); verifyEqualByIds("explicit add 3", expectedExplicit, resultsExplicit); // adding nodeOne, which is a child of nodeBigA, shouldn't effect the expected results implicitGroupMembershipAddHelper(subject, recursiveGroup, nodeOne, expectedImplicit); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); expectedExplicit.add(nodeOne); verifyEqualByIds("explicit add 4", expectedExplicit, resultsExplicit); // adding nodeTripleLittleI shouldn't effect the expected results either implicitGroupMembershipAddHelper(subject, recursiveGroup, nodeTripleLittleI, expectedImplicit); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); expectedExplicit.add(nodeTripleLittleI); verifyEqualByIds("explicit add 5", expectedExplicit, resultsExplicit); } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); // removing the subtree nodeTripleLittleI shouldn't affect the expected set implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeTripleLittleI, expectedImplicit); } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); // removing a descendant of a node that is also in the explicit list should be a no-op implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeOne, expectedImplicit); expectedImplicit.remove(nodeThree); // removing the wandering nodeThree, so that results will be the complete nodeBigA subtree implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeThree, expectedImplicit); // removing a root node should remove all descendants that aren't still in the explicit list implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeBigA, ResourceTreeHelper.getSubtree(nodeLittleA)); } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); // remove a node that wasn't in the group - negative testing try { // passing the "real" expected list for the results; this way, if the exception doesn't happen, the helper returns true implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeBigA, ResourceTreeHelper.getSubtree(nodeLittleA)); assert false : "Failed: removed non-existent successfully: node = " + nodeBigA.getName(); } catch (Throwable t) { // expected } } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); // removing the last resource should leave an empty list implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeLittleA, new ArrayList<Resource>()); } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); // remove a node that wasn't in the group - negative testing try { // passing the "real" expected list for the results; this way, if the exception doesn't happen, the helper returns true Resource nodeBigB = ResourceTreeHelper.findNode(fullTree, "B"); implicitGroupMembershipRemoveHelper(subject, recursiveGroup, nodeBigB, ResourceTreeHelper.getSubtree(nodeBigA)); assert false : "Failed: removed non-existent successfully: node = " + nodeBigB.getName(); } catch (Throwable t) { // expected } } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } try { getTransactionManager().begin(); resultsExplicit = resourceManager.findExplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); verifyEqualByIds("explicit remove 0", new ArrayList<Resource>(), resultsExplicit); } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } } finally { // clean up anything that may have gotten created try { getTransactionManager().begin(); EntityManager em = getEntityManager(); Subject overlord = subjectManager.getOverlord(); if (null != subject) { subjectManager.deleteUsers(overlord, new int[] { subject.getId() }); } if (null != role) { roleManager.deleteRoles(overlord, new int[] { role.getId() }); } if (null != recursiveGroup) { resourceGroupManager.deleteResourceGroup(overlord, recursiveGroup.getId()); } if (null != fullTree) { ResourceTreeHelper.deleteForest(em, fullTree); } } catch (Throwable t) { handleThrowable(t); } finally { handleTransaction(); } } } private void handleTransaction() { try { if (getTransactionManager().getTransaction().getStatus() == Status.STATUS_MARKED_ROLLBACK) { getTransactionManager().rollback(); } else { getTransactionManager().commit(); } } catch (Throwable t) { t.printStackTrace(); } } private void handleThrowable(Throwable t) throws Throwable { if (t instanceof SQLException) { String error = JDBCUtil.convertSQLExceptionToString((SQLException) t); System.err.println(error); } else { t.printStackTrace(); } throw t; } private void printGroup(String prefix, Subject subject, ResourceGroup group) { print(prefix + ": exp", resourceManager.findExplicitResourcesByResourceGroup(subject, group, PageControl.getUnlimitedInstance())); print(prefix + ": imp", resourceManager.findImplicitResourcesByResourceGroup(subject, group, PageControl.getUnlimitedInstance())); } private void print(String prefix, List<Resource> resources) { System.out.print(prefix + ": "); for (Resource res : resources) { System.out.print(res.getName() + " "); } System.out.println(); } private void implicitGroupMembershipAddHelper(Subject subject, ResourceGroup recursiveGroup, Resource node, List<Resource> expectedResults) { printGroup("complex implicit before add: node = " + node.getName() + " [" + node.getId() + "]", subject, recursiveGroup); resourceGroupManager.addResourcesToGroup(subject, recursiveGroup.getId(), new int[] { node.getId() }); printGroup("complex implicit after add: node = " + node.getName() + " [" + node.getId() + "]", subject, recursiveGroup); List<Resource> implicitResources = resourceManager.findImplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); verifyEqualByIds("Failed: complex implicit add: node = " + node.getName() + " [" + node.getId() + "]", expectedResults, implicitResources); } private void implicitGroupMembershipRemoveHelper(Subject subject, ResourceGroup recursiveGroup, Resource node, List<Resource> expectedResults) { printGroup("complex implicit before remove: node = " + node.getName() + " [" + node.getId() + "]", subject, recursiveGroup); resourceGroupManager.removeResourcesFromGroup(subject, recursiveGroup.getId(), new int[] { node.getId() }); printGroup("complex implicit after remove: node = " + node.getName() + " [" + node.getId() + "]", subject, recursiveGroup); List<Resource> implicitResources = resourceManager.findImplicitResourcesByResourceGroup(subject, recursiveGroup, PageControl.getUnlimitedInstance()); verifyEqualByIds("Failed: complex implicit remove: node = " + node.getName() + " [" + node.getId() + "]", expectedResults, implicitResources); } private void verifyEqualByIds(String errorMessage, List<Resource> expected, List<Resource> results) { List<Integer> expectedIds = getIds(expected); List<Integer> resultsIds = getIds(results); verifyEqual(errorMessage, expectedIds, resultsIds); } private void verifyEqual(String errorMessage, List<Integer> expectedIds, List<Integer> resultsIds) { assert (expectedIds.containsAll(resultsIds) && resultsIds.containsAll(expectedIds)) : errorMessage + "\nexpected = " + expectedIds + "\nresults = " + resultsIds; } private List<Integer> getIds(List<Resource> resources) { List<Integer> results = new ArrayList<Integer>(); for (Resource res : resources) { results.add(res.getId()); } Collections.sort(results); return results; } private List<Resource> getSimpleTree(EntityManager em) { return ResourceTreeHelper.createTree(em, "A=1,2; 1=a,b; a=i,ii; b=iii,iv; B=3"); } }