org.rhq.enterprise.server.discovery.DiscoveryBossBeanTest.java Source code

Java tutorial

Introduction

Here is the source code for org.rhq.enterprise.server.discovery.DiscoveryBossBeanTest.java

Source

/*
 * RHQ Management Platform
 * Copyright (C) 2005-2013 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.enterprise.server.discovery;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.when;
import static org.rhq.core.domain.resource.CreateResourceStatus.SUCCESS;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

import javax.ejb.EJBException;
import javax.persistence.Query;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.dbunit.dataset.xml.FlatXmlProducer;
import org.dbunit.ext.oracle.Oracle10DataTypeFactory;
import org.dbunit.ext.oracle.OracleDataTypeFactory;
import org.dbunit.ext.postgresql.PostgresqlDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.testng.annotations.Test;
import org.xml.sax.InputSource;

import org.rhq.core.clientapi.agent.discovery.DiscoveryAgentService;
import org.rhq.core.clientapi.server.discovery.InventoryReport;
import org.rhq.core.domain.cloud.StorageNode;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.criteria.ResourceCriteria;
import org.rhq.core.domain.discovery.MergeInventoryReportResults;
import org.rhq.core.domain.discovery.MergeInventoryReportResults.ResourceTypeFlyweight;
import org.rhq.core.domain.discovery.MergeResourceResponse;
import org.rhq.core.domain.discovery.PlatformSyncInfo;
import org.rhq.core.domain.discovery.ResourceSyncInfo;
import org.rhq.core.domain.resource.Agent;
import org.rhq.core.domain.resource.CreateResourceHistory;
import org.rhq.core.domain.resource.InventoryStatus;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.core.domain.util.collection.ArrayUtils;
import org.rhq.enterprise.server.auth.SubjectManagerLocal;
import org.rhq.enterprise.server.resource.ResourceManagerLocal;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.test.AbstractEJB3Test;
import org.rhq.enterprise.server.test.TestServerCommunicationsService;
import org.rhq.enterprise.server.test.TransactionCallback;
import org.rhq.enterprise.server.util.LookupUtil;
import org.rhq.enterprise.server.util.ResourceTreeHelper;

/**
 * A unit test for {@link DiscoveryBossBean}.
 */
public class DiscoveryBossBeanTest extends AbstractEJB3Test {
    private static final Log LOG = LogFactory.getLog(DiscoveryBossBeanTest.class);

    private DiscoveryBossLocal discoveryBoss;

    private SubjectManagerLocal subjectManager;

    private ResourceManagerLocal resourceManager;

    private ResourceTypeManagerLocal resourceTypeManager;

    private ResourceType platformType;

    private ResourceType serverType;

    private ResourceType serviceType1;

    private ResourceType serviceType2;

    private ResourceType storagePlatformType;

    private ResourceType storageServerType;

    private Agent agent;

    private TestServerCommunicationsService agentServiceContainer;

    @Override
    protected void beforeMethod() throws Exception {
        discoveryBoss = LookupUtil.getDiscoveryBoss();
        subjectManager = LookupUtil.getSubjectManager();
        resourceManager = LookupUtil.getResourceManager();
        resourceTypeManager = LookupUtil.getResourceTypeManager();

        initDB();

        platformType = getEntityManager().find(ResourceType.class, 15641);
        serverType = getEntityManager().find(ResourceType.class, 15642);
        serviceType1 = getEntityManager().find(ResourceType.class, 15643);
        serviceType2 = getEntityManager().find(ResourceType.class, 15644);
        agent = getEntityManager().find(Agent.class, 15641);

        storagePlatformType = getEntityManager().find(ResourceType.class, 15651);
        storageServerType = getEntityManager().find(ResourceType.class, 15652);

        agentServiceContainer = prepareForTestAgents();
        agentServiceContainer.discoveryService = Mockito.mock(DiscoveryAgentService.class);
        when(agentServiceContainer.discoveryService.manuallyAddResource(any(ResourceType.class), anyInt(),
                any(Configuration.class), anyInt())).thenAnswer(new Answer<MergeResourceResponse>() {
                    public MergeResourceResponse answer(InvocationOnMock invocation) throws Throwable {
                        Resource resource = new Resource(1000000);
                        resource.setUuid(UUID.randomUUID().toString());
                        ResourceType resourceType = (ResourceType) invocation.getArguments()[0];
                        resource.setResourceType(resourceType);
                        long randomLong = UUID.randomUUID().getLeastSignificantBits();
                        resource.setResourceKey(prefix("key-" + randomLong));
                        resource.setName(prefix("name-" + randomLong));
                        int parentResourceId = (Integer) invocation.getArguments()[1];
                        Resource parentResource = resourceManager.getResource(subjectManager.getOverlord(),
                                parentResourceId);
                        resource.setParentResource(parentResource);
                        Integer ownerSubjectId = (Integer) invocation.getArguments()[3];
                        MergeResourceResponse response = discoveryBoss.addResource(resource, ownerSubjectId);
                        return response;
                    }
                });

        prepareScheduler();
    }

    @Override
    protected void afterMethod() throws Exception {
        try {
            cleanDB();
        } finally {
            unprepareForTestAgents();
            unprepareScheduler();
        }
    }

    @Test(groups = "integration.ejb3")
    public void testBasicInventoryReport() throws Exception {
        InventoryReport inventoryReport = new InventoryReport(agent);

        Resource platform = new Resource(prefix("alpha"), prefix("platform"), platformType);
        Resource server = new Resource(prefix("bravo"), prefix("server"), serverType);
        platform.addChildResource(server);
        Resource service1 = new Resource(prefix("charlie"), prefix("service 1"), serviceType1);
        Resource service2 = new Resource(prefix("delta"), prefix("service 2"), serviceType2);
        server.addChildResource(service1);
        server.addChildResource(service2);

        platform.setUuid(String.valueOf(new Random().nextInt()));
        server.setUuid(String.valueOf(new Random().nextInt()));
        service1.setUuid(String.valueOf(new Random().nextInt()));
        service2.setUuid(String.valueOf(new Random().nextInt()));

        inventoryReport.addAddedRoot(platform);

        MergeInventoryReportResults results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert results != null;
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test";
        assertNotNull(results.getPlatformSyncInfo());
    }

    @Test(groups = "integration.ejb3")
    public void testUpdateInventoryReport() throws Exception {
        // First just submit the platform
        InventoryReport inventoryReport = new InventoryReport(agent);
        Resource platform = new Resource(prefix("alpha"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        inventoryReport.addAddedRoot(platform);
        MergeInventoryReportResults results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert results != null;
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test";
        assertNotNull(results.getPlatformSyncInfo());
        Collection<ResourceSyncInfo> syncInfos = discoveryBoss
                .getResourceSyncInfo(results.getPlatformSyncInfo().getPlatform().getId());
        assert syncInfos != null;
        assert !syncInfos.isEmpty();

        platform.setId(results.getPlatformSyncInfo().getPlatform().getId());

        // Now submit the server and its children as an update report
        inventoryReport = new InventoryReport(agent);
        Resource server = new Resource(prefix("bravo"), prefix("server"), serverType);
        platform.addChildResource(server);
        Resource service1 = new Resource(prefix("charlie"), prefix("service 1"), serviceType1);
        Resource service2 = new Resource(prefix("delta"), prefix("service 2"), serviceType2);
        server.addChildResource(service1);
        server.addChildResource(service2);

        server.setUuid(String.valueOf(new Random().nextInt()));
        service1.setUuid(String.valueOf(new Random().nextInt()));
        service2.setUuid(String.valueOf(new Random().nextInt()));

        inventoryReport.addAddedRoot(server);

        results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert results != null;
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test";
        assertNotNull(results.getPlatformSyncInfo());
    }

    // given test interaction there could be ignored types, make sure they are not relevant to these tests
    private boolean checkIgnoredTypes(MergeInventoryReportResults results) {
        return checkIgnoredTypes(results, 0);
    }

    // given test interaction there could be ignored types, make sure they are not relevant to these tests
    private boolean checkIgnoredTypes(MergeInventoryReportResults results, int expectedNumberOfIgnoredTypes) {
        int numberOfRelevantIgnoredTypes = 0;
        Collection<ResourceTypeFlyweight> ignoredTypes = results.getIgnoredResourceTypes();

        if (null != ignoredTypes) {
            if (ignoredTypes.contains(new ResourceTypeFlyweight(serverType))) {
                ++numberOfRelevantIgnoredTypes;
            }
            if (ignoredTypes.contains(new ResourceTypeFlyweight(serviceType1))) {
                ++numberOfRelevantIgnoredTypes;
            }
            if (ignoredTypes.contains(new ResourceTypeFlyweight(serviceType2))) {
                ++numberOfRelevantIgnoredTypes;
            }
        }

        return expectedNumberOfIgnoredTypes == numberOfRelevantIgnoredTypes;
    }

    @Test(groups = "integration.ejb3")
    public void testManuallyAddResource() throws Exception {
        InventoryReport inventoryReport = new InventoryReport(agent);

        Resource platform = new Resource(prefix("alpha"), prefix("platform"), platformType);
        Resource server = new Resource(prefix("bravo"), prefix("server"), serverType);
        platform.addChildResource(server);
        Resource service2 = new Resource(prefix("delta"), prefix("service 2"), serviceType2);
        server.addChildResource(service2);

        platform.setUuid(String.valueOf(new Random().nextInt()));
        server.setUuid(String.valueOf(new Random().nextInt()));
        service2.setUuid(String.valueOf(new Random().nextInt()));

        inventoryReport.addAddedRoot(platform);

        MergeInventoryReportResults results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert results != null;
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test";
        assertNotNull(results.getPlatformSyncInfo());
        assertNotNull(results.getPlatformSyncInfo().getTopLevelServerIds());
        assertTrue(!results.getPlatformSyncInfo().getTopLevelServerIds().isEmpty());
        Integer resourceId = results.getPlatformSyncInfo().getTopLevelServerIds().iterator().next();
        Collection<ResourceSyncInfo> syncInfos = discoveryBoss.getResourceSyncInfo(resourceId);
        assert syncInfos != null;
        assert !syncInfos.isEmpty();

        Resource resource1 = discoveryBoss.manuallyAddResource(subjectManager.getOverlord(), serviceType2.getId(),
                resourceId, new Configuration());

        try {
            Resource resource2 = discoveryBoss.manuallyAddResource(subjectManager.getOverlord(),
                    serviceType2.getId(), resourceId, new Configuration());
            fail("Manually adding a singleton that already existed succeeded: " + resource2);
        } catch (EJBException e) {
            assertEquals(String.valueOf(e.getCause()), RuntimeException.class, e.getCause().getClass());
            assertTrue(String.valueOf(e.getCause()), e.getCause().getMessage().contains("singleton"));
        }
    }

    @Test(groups = "integration.ejb3")
    public void testIgnoreUnignoreAndImportResources() throws Exception {

        // First create an inventory report for a new platform with servers

        InventoryReport inventoryReport = new InventoryReport(agent);

        Resource platform = new Resource(prefix("platform"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        for (int i = 0; i < 17; i++) {
            String serverString = prefix("server " + String.valueOf(i));
            Resource server = new Resource(serverString, serverString, serverType);
            server.setUuid(String.valueOf(new Random().nextInt()));
            platform.addChildResource(server);
        }

        inventoryReport.addAddedRoot(platform);

        // Merge this inventory report
        MergeInventoryReportResults mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        assert checkIgnoredTypes(mergeResults) : "nothing should have been ignored: "
                + mergeResults.getIgnoredResourceTypes();
        PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;

        // Check merge result
        assertEquals(InventoryStatus.NEW, platformSyncInfo.getPlatform().getInventoryStatus());
        assertEquals(platform.getChildResources().size(), platformSyncInfo.getTopLevelServerIds().size());

        // Collect the resource ids generated for the platform and the servers

        int platformId = platformSyncInfo.getPlatform().getId();
        List<Integer> serverIds = new LinkedList<Integer>();
        for (Integer serverId : platformSyncInfo.getTopLevelServerIds()) {
            serverIds.add(serverId);
        }
        int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);

        // Now test ignore, unignore and import behavior
        discoveryBoss.importResources(subjectManager.getOverlord(), new int[] { platformId });
        discoveryBoss.ignoreResources(subjectManager.getOverlord(), arrayOfServerIds);

        try {
            discoveryBoss.importResources(subjectManager.getOverlord(), arrayOfServerIds);
            fail("Import resources should fail for ignored resources");
        } catch (EJBException e) {
            assertEquals(String.valueOf(e.getCause()), IllegalArgumentException.class, e.getCause().getClass());
            assertTrue(String.valueOf(e.getCause()),
                    e.getCause().getMessage().startsWith("Can only set inventory status to"));
        }

        discoveryBoss.unignoreAndImportResources(subjectManager.getOverlord(), arrayOfServerIds);

        // excursus: take this time to do a side test of the resource criteria filtering on parent inv status
        List<InventoryStatus> committedStatus = new ArrayList<InventoryStatus>(1);
        List<InventoryStatus> ignoredStatus = new ArrayList<InventoryStatus>(1);
        committedStatus.add(InventoryStatus.COMMITTED);
        ignoredStatus.add(InventoryStatus.IGNORED);
        ResourceCriteria criteria = new ResourceCriteria();
        criteria.addFilterParentInventoryStatuses(committedStatus);
        criteria.addFilterId(serverIds.get(0));

        // excursus: look for the server with the given ID but only if the parent is committed (this should return the resource)
        List<Resource> lookup = resourceManager.findResourcesByCriteria(subjectManager.getOverlord(), criteria);
        assert 1 == lookup.size() : lookup;
        assert lookup.get(0).getId() == serverIds.get(0) : lookup;

        // excursus: look for the server with the given ID but only if the parent is ignored (this should return nothing)
        criteria.addFilterParentInventoryStatuses(ignoredStatus);
        lookup = resourceManager.findResourcesByCriteria(subjectManager.getOverlord(), criteria);
        assert lookup.isEmpty() : lookup;
    }

    @Test(groups = "integration.ejb3")
    public void testIgnoreResourceType() throws Exception {

        // ignore the server type immediately
        resourceTypeManager.setResourceTypeIgnoreFlagAndUninventoryResources(subjectManager.getOverlord(),
                serverType.getId(), true);

        // create an inventory report with a platform and a server - the server will be of the ignored type
        InventoryReport inventoryReport = new InventoryReport(agent);
        Resource platform = new Resource(prefix("platform"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        Resource server = new Resource(prefix("server0"), prefix("server0"), serverType);
        server.setUuid(String.valueOf(new Random().nextInt()));
        platform.addChildResource(server);
        inventoryReport.addAddedRoot(platform);

        // Merge this inventory report
        MergeInventoryReportResults mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;
        assertNotNull(mergeResults.getIgnoredResourceTypes());
        assert checkIgnoredTypes(mergeResults, 1) : "expected one ignored type";
        assert mergeResults.getIgnoredResourceTypes().contains(new ResourceTypeFlyweight(serverType));

        // Check merge result - make sure we should not see any children under the platform (it should have been ignored)
        assertEquals(InventoryStatus.NEW, platformSyncInfo.getPlatform().getInventoryStatus());
        assertEquals(platformSyncInfo.getTopLevelServerIds().size(), 0);
    }

    @Test(groups = "integration.ejb3")
    public void testReturnAllIgnoredResourceTypes() throws Exception {

        // ignore the service types immediately
        resourceTypeManager.setResourceTypeIgnoreFlagAndUninventoryResources(subjectManager.getOverlord(),
                serviceType1.getId(), true);
        resourceTypeManager.setResourceTypeIgnoreFlagAndUninventoryResources(subjectManager.getOverlord(),
                serviceType2.getId(), true);

        // create an inventory report with just a platform and a server
        InventoryReport inventoryReport = new InventoryReport(agent);
        Resource platform = new Resource(prefix("platform"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        Resource server = new Resource(prefix("server0"), prefix("server0"), serverType);
        server.setUuid(String.valueOf(new Random().nextInt()));
        platform.addChildResource(server);
        inventoryReport.addAddedRoot(platform);

        // Merge this inventory report
        MergeInventoryReportResults mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;

        // now see that we were told about the service types being ignored (even though we had no resources of that type in the report)
        Collection<ResourceTypeFlyweight> ignoredResourceTypes = mergeResults.getIgnoredResourceTypes();
        assertNotNull(ignoredResourceTypes);
        assert checkIgnoredTypes(mergeResults, 2) : "expected two ignored types";
        assert ignoredResourceTypes.contains(new ResourceTypeFlyweight(serviceType1));
        assert ignoredResourceTypes.contains(new ResourceTypeFlyweight(serviceType2));
    }

    @Test(groups = "integration.ejb3")
    public void testIgnoreResourceTypeAndUninventoryResources() throws Exception {

        // First create an inventory report for a new platform with servers - nothing is ignored yet
        InventoryReport inventoryReport = new InventoryReport(agent);
        Resource platform = new Resource(prefix("platform"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        for (int i = 0; i < 17; i++) {
            String serverString = prefix("server " + String.valueOf(i));
            Resource server = new Resource(serverString, serverString, serverType);
            server.setUuid(String.valueOf(new Random().nextInt()));
            platform.addChildResource(server);
        }
        inventoryReport.addAddedRoot(platform);

        // Merge this inventory report to get platform and servers in NEW state
        MergeInventoryReportResults mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        assert checkIgnoredTypes(mergeResults) : "nothing should have been ignored: "
                + mergeResults.getIgnoredResourceTypes();
        PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;

        // Collect the resource ids generated for the platform and the servers
        int platformId = platformSyncInfo.getPlatform().getId();
        List<Integer> serverIds = new LinkedList<Integer>();
        for (Integer serverId : platformSyncInfo.getTopLevelServerIds()) {
            serverIds.add(serverId);
        }
        int[] arrayOfServerIds = ArrayUtils.unwrapCollection(serverIds);

        // Now import platform and servers into inventory
        discoveryBoss.importResources(subjectManager.getOverlord(), new int[] { platformId });
        discoveryBoss.importResources(subjectManager.getOverlord(), arrayOfServerIds);

        // make sure servers are committed into inventory now
        List<Integer> serverTypeIdInList = new ArrayList<Integer>(1);
        serverTypeIdInList.add(serverType.getId());
        PageList<Resource> allServers = resourceManager.findResourceByIds(subjectManager.getOverlord(),
                arrayOfServerIds, false, PageControl.getUnlimitedInstance());
        for (Resource aServer : allServers) {
            assert aServer.getInventoryStatus() == InventoryStatus.COMMITTED : "should be committed: " + aServer;
        }
        assert allServers
                .getTotalSize() == arrayOfServerIds.length : "all servers were not committed into inventory";

        // now ignore the server type - this should uninventory all servers
        resourceTypeManager.setResourceTypeIgnoreFlagAndUninventoryResources(subjectManager.getOverlord(),
                serverType.getId(), true);

        // make sure all servers were uninventoried
        allServers = resourceManager.findResourceByIds(subjectManager.getOverlord(), arrayOfServerIds, false,
                PageControl.getUnlimitedInstance());
        for (Resource aServer : allServers) {
            assert aServer.getInventoryStatus() != InventoryStatus.COMMITTED : "should not be committed: "
                    + aServer;
        }

        // Merge the inventory report again to simulate another discovery - the servers should be ignored now
        mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;
        assertNotNull(mergeResults.getIgnoredResourceTypes());
        assert checkIgnoredTypes(mergeResults, 1) : "expected one ignored type";
        assert mergeResults.getIgnoredResourceTypes().contains(new ResourceTypeFlyweight(serverType));

        assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getPlatform().getInventoryStatus()); // notice platform is committed now
        assertEquals(platformSyncInfo.getTopLevelServerIds().size(), 0); // notice there are no server children now
    }

    @Test(groups = "integration.ejb3")
    public void testAutoImportStorageNode() throws Exception {

        // create an inventory report for a storage node
        InventoryReport inventoryReport = new InventoryReport(agent);

        Resource storagePlatform = new Resource(prefix("storagePlatform"), prefix("storagePlatform"),
                storagePlatformType);
        storagePlatform.setUuid(String.valueOf(new Random().nextInt()));

        Resource storageNode = new Resource(prefix("storageNode"), prefix("storageNode"), storageServerType);
        storageNode.setUuid(String.valueOf(new Random().nextInt()));
        storagePlatform.addChildResource(storageNode);

        storageNode.setPluginConfiguration(Configuration.builder().addSimple("nativeTransportPort", 9142)
                .addSimple("storagePort", 7100).addSimple("host", "localhost").build());

        inventoryReport.addAddedRoot(storagePlatform);

        // Merge this inventory report
        MergeInventoryReportResults mergeResults = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assert mergeResults != null;
        assert checkIgnoredTypes(mergeResults) : "nothing should have been ignored: "
                + mergeResults.getIgnoredResourceTypes();
        PlatformSyncInfo platformSyncInfo = mergeResults.getPlatformSyncInfo();
        assert platformSyncInfo != null;

        // Check merge result
        assertEquals(InventoryStatus.COMMITTED, platformSyncInfo.getPlatform().getInventoryStatus());
        assertEquals(storagePlatform.getChildResources().size(), platformSyncInfo.getTopLevelServerIds().size());

        storageNode = resourceManager.getResourceById(subjectManager.getOverlord(),
                platformSyncInfo.getTopLevelServerIds().iterator().next());
        assertNotNull(storageNode);
        assertEquals(InventoryStatus.COMMITTED, storageNode.getInventoryStatus());
    }

    @Test(groups = "integration.ejb3")
    public void testPersistUserSuppliedResourceNameOnCreatedResource() throws Exception {

        // First inventory the platform and the server
        InventoryReport inventoryReport = new InventoryReport(agent);

        Resource platform = new Resource(prefix("userPlatform"), prefix("platform"), platformType);
        platform.setUuid(String.valueOf(new Random().nextInt()));
        Resource server = new Resource(prefix("userServer"), prefix("server"), serverType);
        server.setUuid(String.valueOf(new Random().nextInt()));
        platform.addChildResource(server);

        inventoryReport.addAddedRoot(platform);

        MergeInventoryReportResults results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assertNotNull(results);
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test "
                + results.getIgnoredResourceTypes();
        final PlatformSyncInfo firstDiscoverySyncInfo = results.getPlatformSyncInfo();
        assertNotNull(firstDiscoverySyncInfo);

        // Then simulate a create resource request
        final String userSuppliedResourceName = prefix("User Supplied Resource Name");
        final String newResourceKey = prefix("Created Resource Key");
        final int serverResourceId = firstDiscoverySyncInfo.getTopLevelServerIds().iterator().next();

        executeInTransaction(false, new TransactionCallback() {
            @Override
            public void execute() throws Exception {
                Resource serverResource = getEntityManager().find(Resource.class, serverResourceId);
                CreateResourceHistory createResourceHistory = new CreateResourceHistory(serverResource,
                        serviceType1, subjectManager.getOverlord().getName(), new Configuration());
                createResourceHistory.setCreatedResourceName(userSuppliedResourceName);
                createResourceHistory.setNewResourceKey(newResourceKey);
                createResourceHistory.setStatus(SUCCESS);
                getEntityManager().persist(createResourceHistory);
                serverResource.addCreateChildResourceHistory(createResourceHistory);
                getEntityManager().flush();
            }
        });

        // Eventually inventory the newly discovered service

        inventoryReport = new InventoryReport(agent);
        Resource service1 = new Resource(newResourceKey, prefix("Plugin Computed Resource Name"), serviceType1);
        service1.setUuid(String.valueOf(new Random().nextInt()));
        server.setId(serverResourceId);
        server.addChildResource(service1);
        inventoryReport.addAddedRoot(server);

        results = discoveryBoss.mergeInventoryReport(serialize(inventoryReport));
        assertNotNull(results);
        assert checkIgnoredTypes(results) : "nothing should have been ignored in this test "
                + results.getIgnoredResourceTypes();
        PlatformSyncInfo secondDiscoverySyncInfo = results.getPlatformSyncInfo();
        assertNotNull(secondDiscoverySyncInfo);

        // Check that the resource ends with the user supplied name in inventory

        Integer toplevelServerId = secondDiscoverySyncInfo.getTopLevelServerIds().iterator().next();
        Collection<ResourceSyncInfo> topLevelServerSyncInfo = discoveryBoss.getResourceSyncInfo(toplevelServerId);
        assert topLevelServerSyncInfo.size() == 2;
        Iterator<ResourceSyncInfo> iter = topLevelServerSyncInfo.iterator();
        Integer childId = iter.next().getId();
        childId = childId.equals(toplevelServerId) ? iter.next().getId() : childId;
        Resource service1Resource = getEntityManager().find(Resource.class, childId);
        assertEquals(userSuppliedResourceName, service1Resource.getName());
    }

    /**
     * Use this to fake like your remoting objects. Can be used to keep your own copy of objects locally transient.
     *
     * @param object
     * @return
     */
    @SuppressWarnings("unchecked")
    private static <T> T serialize(T object) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream(10000);
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            if (LOG.isDebugEnabled()) {
                LOG.debug("****** Size of serialized object: " + baos.size());
            }

            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
            Object transfered = ois.readObject();

            return (T) transfered;
        } catch (Exception e) {
            throw new RuntimeException("Failed serializing and deserializing object: " + object);
        }
    }

    public void initDB() throws Exception {
        Connection connection = null;

        try {
            connection = getConnection();
            IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
            setDbType(dbUnitConnection);
            DatabaseOperation.REFRESH.execute(dbUnitConnection, getDataSet());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    public void cleanDB() throws Exception {
        Connection connection = null;

        try {
            getTransactionManager().begin();

            Query q;
            List<?> doomed;
            q = em.createQuery("" //
                    + "SELECT r FROM Resource r" //
                    + "    WHERE r.resourceType.name LIKE '" + getPrefix() + "%'" //
                    + "       OR r.resourceType.name = 'RHQ Storage Node'" //
                    + " ORDER BY r.id DESC");
            doomed = q.getResultList();
            for (Object removeMe : doomed) {
                Resource res = em.getReference(Resource.class, ((Resource) removeMe).getId());
                StorageNode storageNode = findStorageNode(res);
                if (storageNode != null) {
                    storageNode.setResource(null);
                }
                for (Iterator<CreateResourceHistory> historyIterator = res.getCreateChildResourceRequests()
                        .iterator(); historyIterator.hasNext();) {
                    CreateResourceHistory history = historyIterator.next();
                    historyIterator.remove();
                    em.remove(history);
                }
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Deleting resource " + res);
                }
                ResourceTreeHelper.deleteResource(em, res);
            }
            em.flush();
            getTransactionManager().commit();
        } catch (Exception e) {
            try {
                LOG.error("CANNOT CLEAN UP TEST: Cause: " + e);
                getTransactionManager().rollback();
            } catch (Exception ignore) {
            }
        }

        try {
            connection = getConnection();

            IDatabaseConnection dbUnitConnection = new DatabaseConnection(connection);
            setDbType(dbUnitConnection);
            DatabaseOperation.DELETE.execute(dbUnitConnection, getDataSet());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    private StorageNode findStorageNode(Resource resource) {
        List<StorageNode> storageNodes = em
                .createQuery("SELECT s FROM StorageNode s where s.resource = :resource", StorageNode.class)
                .setParameter("resource", resource).getResultList();
        if (storageNodes.isEmpty()) {
            return null;
        }
        return storageNodes.get(0);
    }

    void setDbType(IDatabaseConnection connection) throws Exception {
        DatabaseConfig dbConfig = connection.getConfig();
        String name = connection.getConnection().getMetaData().getDatabaseProductName().toLowerCase();
        int major = connection.getConnection().getMetaData().getDatabaseMajorVersion();
        IDataTypeFactory type = null;

        if (name.contains("postgres")) {
            type = new PostgresqlDataTypeFactory();
        } else if (name.contains("oracle")) {
            if (major >= 10) {
                type = new Oracle10DataTypeFactory();
            } else {
                type = new OracleDataTypeFactory();
            }
        }

        if (type != null) {
            dbConfig.setProperty("http://www.dbunit.org/properties/datatypeFactory", type);
        }
    }

    IDataSet getDataSet() throws Exception {
        FlatXmlProducer xmlProducer = new FlatXmlProducer(
                new InputSource(getClass().getResourceAsStream(getDataSetFile())));
        xmlProducer.setColumnSensing(true);
        return new FlatXmlDataSet(xmlProducer);
    }

    String getDataSetFile() {
        return getPrefix() + ".xml";
    }

    String prefix(String suffix) {
        return getPrefix() + "-" + suffix;
    }

    String getPrefix() {
        return getClass().getSimpleName();
    }
}