/* * 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.test; import java.util.Collections; import java.util.List; import java.util.Random; import java.util.UUID; import javax.transaction.NotSupportedException; import javax.transaction.SystemException; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.testng.annotations.Test; import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService; import org.rhq.core.domain.alert.Alert; import org.rhq.core.domain.alert.AlertCondition; import org.rhq.core.domain.alert.AlertConditionCategory; import org.rhq.core.domain.alert.AlertConditionOperator; import org.rhq.core.domain.alert.AlertDampening; import org.rhq.core.domain.alert.AlertDefinition; import org.rhq.core.domain.alert.AlertPriority; import org.rhq.core.domain.alert.BooleanExpression; import org.rhq.core.domain.criteria.AlertCriteria; import org.rhq.core.domain.criteria.ResourceCriteria; import org.rhq.core.domain.criteria.ResourceGroupCriteria; import org.rhq.core.domain.discovery.AvailabilityReport; import org.rhq.core.domain.measurement.AvailabilityType; import org.rhq.core.domain.resource.Agent; import org.rhq.core.domain.resource.InventoryStatus; import org.rhq.core.domain.resource.Resource; import org.rhq.core.domain.resource.ResourceCategory; import org.rhq.core.domain.resource.ResourceError; import org.rhq.core.domain.resource.ResourceErrorType; import org.rhq.core.domain.resource.ResourceType; import org.rhq.core.domain.resource.group.GroupCategory; import org.rhq.core.domain.resource.group.ResourceGroup; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.server.alert.AlertDefinitionManagerLocal; import org.rhq.enterprise.server.auth.SessionManager; import org.rhq.enterprise.server.auth.SessionNotFoundException; import org.rhq.enterprise.server.discovery.DiscoveryServerServiceImpl; import org.rhq.enterprise.server.operation.OperationDefinitionNotFoundException; import org.rhq.enterprise.server.resource.ResourceNotFoundException; import org.rhq.enterprise.server.resource.ResourceTypeNotFoundException; import org.rhq.enterprise.server.resource.group.ResourceGroupManagerLocal; import org.rhq.enterprise.server.resource.group.ResourceGroupNotFoundException; import org.rhq.enterprise.server.resource.group.definition.exception.GroupDefinitionNotFoundException; import org.rhq.enterprise.server.resource.metadata.test.UpdatePluginMetadataTestBase; import org.rhq.enterprise.server.util.LookupUtil; /** * Test for {@link ResourceManagerLocal} SLSB. */ @Test public class ResourceManagerBeanTest extends UpdatePluginMetadataTestBase { private Resource newResource; private ResourceGroup newGroup; private ResourceGroupManagerLocal groupManager; @Override protected void beforeMethod() throws Exception { super.beforeMethod(); newResource = createNewResourceWithNewType(); groupManager = LookupUtil.getResourceGroupManager(); newGroup = createNewGroup(); } public void testResourceErrors() { ResourceError error; List<ResourceError> errors; DiscoveryServerServiceImpl serverService = new DiscoveryServerServiceImpl(); errors = resourceManager.findResourceErrors(getOverlord(), newResource.getId(), ResourceErrorType.INVALID_PLUGIN_CONFIGURATION); assert errors.size() == 0; error = new ResourceError(newResource, ResourceErrorType.INVALID_PLUGIN_CONFIGURATION, "test summary", "test detail", 12345); // simulate the agent notifying the server about an error // this will exercise the addResourceError in the SLSB serverService.setResourceError(error); errors = resourceManager.findResourceErrors(getOverlord(), newResource.getId(), ResourceErrorType.INVALID_PLUGIN_CONFIGURATION); assert errors.size() == 1; error = errors.get(0); assert error.getId() > 0; assert error.getSummary().equals("test summary"); assert error.getDetail().equals("test detail"); assert error.getErrorType() == ResourceErrorType.INVALID_PLUGIN_CONFIGURATION; assert error.getTimeOccurred() == 12345; // simulate the agent notifying the server about another error. // there will only be a single invalid plugin config allowed; the prior one will be deleted // this will exercise the addResourceError and deleteResourceError in the SLSB error.setId(0); error.setTimeOccurred(567890); error.setSummary("another summary"); error.setDetail("another detail"); serverService.setResourceError(error); errors = resourceManager.findResourceErrors(getOverlord(), newResource.getId(), ResourceErrorType.INVALID_PLUGIN_CONFIGURATION); assert errors.size() == 1; error = errors.get(0); assert error.getId() > 0; assert error.getSummary().equals("another summary"); assert error.getDetail().equals("another detail"); assert error.getErrorType() == ResourceErrorType.INVALID_PLUGIN_CONFIGURATION; assert error.getTimeOccurred() == 567890; resourceManager.deleteResourceError(getOverlord(), error.getId()); errors = resourceManager.findResourceErrors(getOverlord(), newResource.getId(), ResourceErrorType.INVALID_PLUGIN_CONFIGURATION); assert errors.size() == 0; } @Override protected void afterMethod() throws Exception { if (newGroup != null) { groupManager.deleteResourceGroup(getOverlord(), newGroup.getId()); } deleteNewResourceAgentResourceType(newResource); super.afterMethod(); } public void testResourceLineage() throws Exception { // given a resource id for the leaf resource in a resource hierarchy int leafResourceId = givenASampleResourceHierarchy(); // when List<Resource> resourceLineage = resourceManager.getResourceLineage(leafResourceId); assertEquals(resourceLineage.size(), 4); // then StringBuilder stringBuilder = new StringBuilder(); for (Resource resource : resourceLineage) { stringBuilder.append(resource.getName()); if (resourceLineage.indexOf(resource) != resourceLineage.size() - 1) { stringBuilder.append("::"); } } System.err.println(stringBuilder.toString()); // cleanup the DB for (int i = resourceLineage.size() - 1; i >= 0; i--) { deleteNewResourceAgentResourceType(resourceLineage.get(i)); } } // Make sure our application exceptions are not wrapped public void bz886850Test() { try { resourceManager.getResourceById(getOverlord(), 2637426); fail("Should have thrown a ResourceNotFoundException"); } catch (Throwable t) { if (!(t instanceof ResourceNotFoundException)) { fail("Should have thrown a ResourceNotFoundException but got: " + t); } } try { LookupUtil.getGroupDefinitionManager().getById(3456347); fail("Should have thrown a GroupDefinitionNotFoundException"); } catch (Throwable t) { if (!(t instanceof GroupDefinitionNotFoundException)) { fail("Should have thrown a GroupDefinitionNotFoundException but got: " + t); } } try { LookupUtil.getOperationManager().getOperationDefinition(getOverlord(), 3456347); fail("Should have thrown a OperationDefinitionNotFoundException"); } catch (Throwable t) { if (!(t instanceof OperationDefinitionNotFoundException)) { fail("Should have thrown a OperationDefinitionNotFoundException but got: " + t); } } try { LookupUtil.getResourceTypeManager().getResourceTypeById(getOverlord(), 3456347); fail("Should have thrown a ResourceTypeNotFoundException"); } catch (Throwable t) { if (!(t instanceof ResourceTypeNotFoundException)) { fail("Should have thrown a ResourceTypeNotFoundException but got: " + t); } } try { LookupUtil.getResourceGroupManager().getResourceGroup(getOverlord(), 3456347); fail("Should have thrown a ResourceGroupNotFoundException"); } catch (Throwable t) { if (!(t instanceof ResourceGroupNotFoundException)) { fail("Should have thrown a ResourceGroupNotFoundException but got: " + t); } } try { SessionManager.getInstance().getSubject(3456347); fail("Should have thrown a SessionNotFoundException"); } catch (Throwable t) { if (!(t instanceof SessionNotFoundException)) { fail("Should have thrown a SessionNotFoundException but got: " + t); } } } public void testAddResorceToGroup() { ResourceGroupCriteria criteria = new ResourceGroupCriteria(); criteria.addFilterId(newGroup.getId()); criteria.fetchExplicitResources(true); PageList<ResourceGroup> persistedGroups = groupManager.findResourceGroupsByCriteria(getOverlord(), criteria); assertEquals("There should be just one group with id " + newGroup.getId(), 1, persistedGroups.size()); // equals is based on the name of a group assertEquals("Persisted group should be the same as the group created in before method.", newGroup, persistedGroups.get(0)); assertEquals("There should be no explicit members in the newly created group.", 0, persistedGroups.get(0) .getExplicitResources().size()); // add resource to group groupManager.addResourcesToGroup(getOverlord(), newGroup.getId(), new int[] { newResource.getId() }); persistedGroups = groupManager.findResourceGroupsByCriteria(getOverlord(), criteria); assertEquals("There should be one member in the newly created group.", 1, persistedGroups.get(0).getExplicitResources() .size()); } public void testResourceUninventorization() { // partly a regression test for BZ 878117 ResourceGroupCriteria criteria = new ResourceGroupCriteria(); criteria.addFilterId(newGroup.getId()); criteria.fetchExplicitResources(true); PageList<ResourceGroup> persistedGroups = groupManager.findResourceGroupsByCriteria(getOverlord(), criteria); assertEquals("There should be just one group with id " + newGroup.getId(), 1, persistedGroups.size()); assertEquals("An empty group is considered as MIXED.", GroupCategory.MIXED, persistedGroups.get(0) .getGroupCategory()); // add resource to group groupManager.addResourcesToGroup(getOverlord(), persistedGroups.get(0).getId(), new int[] { newResource.getId() }); persistedGroups = groupManager.findResourceGroupsByCriteria(getOverlord(), criteria); assertEquals("A group with just one explicit member is considered as COMPATIBLE.", GroupCategory.COMPATIBLE, persistedGroups.get(0).getGroupCategory()); // now uninventorize the only resource resourceManager.uninventoryResource(getOverlord(), newResource.getId()); persistedGroups = groupManager.findResourceGroupsByCriteria(getOverlord(), criteria); assertEquals("An empty group is considered as MIXED.", GroupCategory.MIXED, persistedGroups.get(0) .getGroupCategory()); } public void testResourceRemovalFromGroup() { ResourceGroup persistedGroup = groupManager.getResourceGroup(getOverlord(), newGroup.getId()); assertEquals("An empty group is considered as MIXED.", GroupCategory.MIXED, persistedGroup.getGroupCategory()); // add resource to group groupManager.addResourcesToGroup(getOverlord(), persistedGroup.getId(), new int[] { newResource.getId() }); persistedGroup = groupManager.getResourceGroup(getOverlord(), newGroup.getId()); assertEquals("A group with just one explicit member is considered as COMPATIBLE.", GroupCategory.COMPATIBLE, persistedGroup.getGroupCategory()); // now remove the only resource from the group groupManager.removeResourcesFromGroup(getOverlord(), persistedGroup.getId(), new int[] { newResource.getId() }); persistedGroup = groupManager.getResourceGroup(getOverlord(), newGroup.getId()); assertEquals("An empty group is considered as MIXED.", GroupCategory.MIXED, persistedGroup.getGroupCategory()); } public void testLiveAvailability() throws Exception { agentServiceContainer.discoveryService = Mockito.mock(DiscoveryAgentService.class); Mockito.when(agentServiceContainer.discoveryService.getCurrentAvailability(Mockito.any(Resource.class), Mockito.anyBoolean())).then( new Answer<AvailabilityReport>() { int count = 0; @Override public AvailabilityReport answer(InvocationOnMock invocation) throws Throwable { Resource res = (Resource) invocation.getArguments()[0]; AvailabilityType avail = count++ == 0 ? AvailabilityType.DOWN : AvailabilityType.UP; AvailabilityReport ret = new AvailabilityReport(AGENT_NAME); ret.addAvailability(new AvailabilityReport.Datum(res.getId(), avail, System.currentTimeMillis())); return ret; } }); AlertDefinition alertDef = new AlertDefinition(); AlertCondition cond = new AlertCondition(alertDef, AlertConditionCategory.AVAILABILITY); cond.setName(AlertConditionOperator.AVAIL_GOES_UP.name()); alertDef.setName("liveAvailabilityTestAlert"); alertDef.setResource(newResource); alertDef.setPriority(AlertPriority.MEDIUM); alertDef.setRecoveryId(0); alertDef.setAlertDampening(new AlertDampening(AlertDampening.Category.NONE)); alertDef.setConditions(Collections.singleton(cond)); alertDef.setEnabled(true); alertDef.setConditionExpression(BooleanExpression.ALL); AlertDefinitionManagerLocal alertDefinitionManager = LookupUtil.getAlertDefinitionManager(); alertDefinitionManager.createAlertDefinitionInNewTransaction(getOverlord(), alertDef, newResource.getId(), true); //obvious, right? This needs to be done for the alert subsystem to become aware of the new def LookupUtil.getAlertConditionCacheManager().reloadAllCaches(); ResourceCriteria crit = new ResourceCriteria(); crit.addFilterId(newResource.getId()); crit.fetchCurrentAvailability(true); Resource fromDb = resourceManager.findResourcesByCriteria(getOverlord(), crit).get(0); assertEquals(AvailabilityType.UNKNOWN, fromDb.getCurrentAvailability().getAvailabilityType()); //ask for the live avail - the mock agent response will return "DOWN" the first time resourceManager.getLiveResourceAvailability(getOverlord(), newResource.getId()); //check that the resource changed its avail in the db fromDb = resourceManager.getResource(getOverlord(), newResource.getId()); assertEquals(AvailabilityType.DOWN, fromDb.getCurrentAvailability().getAvailabilityType()); //ask for the live avail - the mock agent response will return "UP" the second time resourceManager.getLiveResourceAvailability(getOverlord(), newResource.getId()); // wait for our JMS messages to process and see if we get any alerts Thread.sleep(3000); //check that the resource changed its avail in the db fromDb = resourceManager.getResource(getOverlord(), newResource.getId()); assertEquals(AvailabilityType.UP, fromDb.getCurrentAvailability().getAvailabilityType()); // wait for our JMS messages to process and see if we get any alerts Thread.sleep(3000); //check that the alert fired when going from DOWN to UP AlertCriteria aCrit = new AlertCriteria(); aCrit.addFilterResourceIds(newResource.getId()); List<Alert> alerts = LookupUtil.getAlertManager().findAlertsByCriteria(getOverlord(), aCrit); assertEquals("Unexpected number of alerts on the resource.", 1, alerts.size()); } // we can add a lot more here, but this mainly exists to test some criteria stuff not obviously tested elsewhere public void testFindByResourceCriteria() { ResourceCriteria c = new ResourceCriteria(); List<Resource> result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertNotNull(result); assertEquals(1, result.size()); c.addFilterPluginName("TES"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(1, result.size()); c.setStrict(true); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.setStrict(false); c.setCaseSensitive(true); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.setCaseSensitive(false); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(1, result.size()); c.setStrictFilters("foo"); c.setCaseSensitiveFilters("foo"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(1, result.size()); c.setStrictFilters("pluginName", "foo"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.setStrictFilters(null); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(1, result.size()); c.setCaseSensitiveFilters("pluginName", "foo"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.setCaseSensitiveFilters("pluginName", "foo"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.setStrictFilters("pluginName", "foo"); c.setCaseSensitiveFilters("pluginName", "foo"); c.addFilterPluginName("test"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(1, result.size()); c.addFilterPluginName("TEST"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); c.addFilterPluginName("testy"); result = resourceManager.findResourcesByCriteria(getOverlord(), c); assertEquals(0, result.size()); } private int givenASampleResourceHierarchy() throws NotSupportedException, SystemException { getTransactionManager().begin(); int leafResourceId = 0; try { ResourceType platformType = createResourceType("platform" + System.currentTimeMillis(), "test", null, ResourceCategory.PLATFORM); ResourceType appserverType = createResourceType("jboss AS 5" + System.currentTimeMillis(), "jbossas5", platformType, ResourceCategory.SERVER); ResourceType jvmType = createResourceType("JVM" + System.currentTimeMillis(), "jbossas5", appserverType, ResourceCategory.SERVICE); ResourceType memType = createResourceType("Memory Subsystem" + System.currentTimeMillis(), "jbossas5", jvmType, ResourceCategory.SERVICE); Agent agent = new Agent("agent" + System.currentTimeMillis(), "host" + System.currentTimeMillis(), 1, "", "token" + System.currentTimeMillis()); em.persist(agent); em.flush(); Resource platform = createResource(platformType, agent, "platformKey" + System.currentTimeMillis(), "host.dev.corp", null); Resource appserver = createResource(appserverType, agent, "JEAP" + System.currentTimeMillis(), "JBOSS EAP 5.1.1", platform); Resource jvm = createResource(jvmType, agent, "jvm" + System.currentTimeMillis(), "JBoss AS JVM", appserver); Resource memSubystem = createResource(memType, agent, "mem" + System.currentTimeMillis(), "Memory Subsystem", jvm); leafResourceId = memSubystem.getId(); getTransactionManager().commit(); } catch (Exception e) { try { System.out.println("CANNOT Prepare TEST: Cause: " + e); getTransactionManager().rollback(); } catch (Exception ignore) { } } return leafResourceId; } private Resource createResource(ResourceType platformType, Agent agent, String resourceKey, String resourceName, Resource parent) { Resource resource = new Resource(resourceKey, resourceName, platformType); resource.setUuid(UUID.randomUUID().toString()); resource.setAgent(agent); resource.setParentResource(parent); em.persist(resource); return resource; } private ResourceType createResourceType(String name, String pluginName, ResourceType parentResourceType, ResourceCategory resourceCategory) { ResourceType platformType = new ResourceType(name, pluginName, resourceCategory, parentResourceType); ResourceType resourceType = platformType; em.persist(resourceType); return resourceType; } private Resource createNewResourceWithNewType() throws Exception { getTransactionManager().begin(); Resource resource; try { ResourceType resourceType = new ResourceType("plat" + System.currentTimeMillis(), "test", ResourceCategory.PLATFORM, null); em.persist(resourceType); resource = new Resource("reskey" + System.currentTimeMillis(), "resname", resourceType); setUpAgent(resource); resource.setUuid("" + new Random().nextInt()); resource.setInventoryStatus(InventoryStatus.COMMITTED); em.persist(resource); createServerIdentity(); } catch (Exception e) { System.out.println("CANNOT PREPARE TEST: " + e); getTransactionManager().rollback(); throw e; } getTransactionManager().commit(); return resource; } private ResourceGroup createNewGroup() { ResourceGroup group = new ResourceGroup("testGroup"); groupManager.createResourceGroup(getOverlord(), group); return group; } private void deleteNewResourceAgentResourceType(Resource resource) throws Exception { if (resource != null) { getTransactionManager().begin(); try { Resource res = em.find(Resource.class, resource.getId()); System.out.println("Removing " + res + "..."); List<Integer> deletedIds = resourceManager.uninventoryResource(getOverlord(), res.getId()); for (Integer deletedResourceId : deletedIds) { resourceManager.uninventoryResourceAsyncWork(getOverlord(), deletedResourceId); } em.flush(); ResourceType type = em.find(ResourceType.class, resource.getResourceType().getId()); System.out.println("Removing " + type + "..."); em.remove(type); em.flush(); // NOTE: No need to remove the Agent entity, since uninventorying the platform will do that automatically. getTransactionManager().commit(); } catch (Exception e) { try { System.out.println("CANNOT CLEAN UP TEST: Cause: " + e); getTransactionManager().rollback(); } catch (Exception ignore) { } } } } }