/* * 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.drift; import static org.apache.commons.io.FileUtils.deleteDirectory; import static org.rhq.common.drift.FileEntry.addedFileEntry; import static org.rhq.common.drift.FileEntry.changedFileEntry; import static org.rhq.core.domain.drift.DriftChangeSetCategory.COVERAGE; import static org.rhq.core.domain.drift.DriftChangeSetCategory.DRIFT; import java.io.File; import java.util.Iterator; import java.util.List; import java.util.Random; import org.testng.annotations.Test; import org.rhq.common.drift.ChangeSetWriter; import org.rhq.common.drift.ChangeSetWriterImpl; import org.rhq.common.drift.Headers; import org.rhq.core.clientapi.server.drift.DriftServerService; import org.rhq.core.domain.auth.Subject; import org.rhq.core.domain.common.EntityContext; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.criteria.DriftDefinitionCriteria; import org.rhq.core.domain.criteria.JPADriftChangeSetCriteria; import org.rhq.core.domain.drift.Drift; import org.rhq.core.domain.drift.DriftCategory; import org.rhq.core.domain.drift.DriftChangeSet; import org.rhq.core.domain.drift.DriftConfigurationDefinition.BaseDirValueContext; import org.rhq.core.domain.drift.DriftDefinition; import org.rhq.core.domain.drift.DriftDefinition.BaseDirectory; import org.rhq.core.domain.drift.DriftDefinitionTemplate; import org.rhq.core.domain.drift.DriftFile; import org.rhq.core.domain.drift.DriftFileStatus; 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.ResourceType; import org.rhq.core.domain.util.PageOrdering; import org.rhq.core.util.MessageDigestGenerator; import org.rhq.core.util.ZipUtil; import org.rhq.enterprise.server.resource.ResourceManagerLocal; import org.rhq.enterprise.server.test.AbstractEJB3Test; import org.rhq.enterprise.server.test.TestServerCommunicationsService; import org.rhq.enterprise.server.util.LookupUtil; /** * Test for {@link DriftManagerBean} SLSB. * * !!! Actually, this is really testing only the JPA impl, it does not actually go through the * !!! configured drift server plugin. To enhance this to do that then you may need to model this * !!! mode like BundleManagerBeanTest */ public class DriftManagerBeanTest extends AbstractEJB3Test { private JPADriftServerLocal jpaDriftServer; private DriftManagerLocal driftManager; private Subject overlord; private Resource newResource; @SuppressWarnings("unused") private DriftServerService driftServerService; MessageDigestGenerator digestGenerator; @Override protected void beforeMethod() throws Exception { digestGenerator = new MessageDigestGenerator(MessageDigestGenerator.SHA_256); jpaDriftServer = LookupUtil.getJPADriftServer(); driftManager = LookupUtil.getDriftManager(); overlord = LookupUtil.getSubjectManager().getOverlord(); driftServerService = new DriftServerServiceImpl(); TestServerCommunicationsService agentServiceContainer = prepareForTestAgents(); agentServiceContainer.driftService = new TestDefService(); prepareScheduler(); DriftServerPluginService driftServerPluginService = new DriftServerPluginService(getTempDir()); prepareCustomServerPluginService(driftServerPluginService); driftServerPluginService.masterConfig.getPluginDirectory().mkdirs(); driftServerPluginService.startMasterPluginContainer(); deleteDriftFiles(); newResource = createNewResource(); } @Override protected void afterMethod() throws Exception { try { deleteNewResource(newResource); } finally { unprepareServerPluginService(); unprepareForTestAgents(); unprepareScheduler(); } } @Test public void testStoreChangeSet() throws Exception { File rootDir = getTempDir(); File changeSetsDir = new File(rootDir, "changesets"); deleteDirectory(changeSetsDir); changeSetsDir.mkdirs(); Headers headers = new Headers(); headers.setResourceId(newResource.getId()); headers.setDriftDefinitionId(1); headers.setDriftDefinitionName("test-1"); headers.setBasedir(rootDir.getAbsolutePath()); headers.setType(COVERAGE); headers.setVersion(0); String file1Hash = sha256("test-1-file-1"); File changeSet1 = new File(changeSetsDir, "changeset-1.txt"); ChangeSetWriter writer = new ChangeSetWriterImpl(changeSet1, headers); writer.write(addedFileEntry("test/file-1", file1Hash, 56789L, 1024L)); writer.close(); File changeSet1Zip = new File(changeSetsDir, "changeset-1.zip"); ZipUtil.zipFileOrDirectory(changeSet1, changeSet1Zip); assertTrue("Expected to find change set zip file: " + changeSet1Zip.getPath(), changeSet1Zip.exists()); jpaDriftServer.storeChangeSet(overlord, newResource.getId(), changeSet1Zip); JPADriftChangeSetCriteria c = new JPADriftChangeSetCriteria(); c.addFilterResourceId(newResource.getId()); c.fetchDrifts(true); List<? extends DriftChangeSet<?>> changeSets = jpaDriftServer.findDriftChangeSetsByCriteria(overlord, c); assertEquals(1, changeSets.size()); DriftChangeSet<?> changeSet = changeSets.get(0); assertEquals(0, changeSet.getVersion()); assertEquals("Expected to find one entry in change set", 1, changeSet.getDrifts().size()); DriftFile driftFile = jpaDriftServer.getDriftFile(overlord, file1Hash); assertNotNull(driftFile); assertEquals(DriftFileStatus.REQUESTED, driftFile.getStatus()); // the second change set should report drift String modifiedFile1Hash = sha256("test-2-file-1-modified"); headers.setType(DRIFT); headers.setVersion(1); File changeSet2 = new File(changeSetsDir, "changeset-2.txt"); writer = new ChangeSetWriterImpl(changeSet2, headers); writer.write(changedFileEntry("test/file-1", file1Hash, modifiedFile1Hash, 56789L, 1024L)); writer.close(); File changeSet2Zip = new File(changeSetsDir, "changeset-2.zip"); ZipUtil.zipFileOrDirectory(changeSet2, changeSet2Zip); assertTrue("Expected to find change set file: " + changeSet2Zip.getPath(), changeSet2Zip.exists()); jpaDriftServer.storeChangeSet(overlord, newResource.getId(), changeSet2Zip); c.addSortVersion(PageOrdering.ASC); c.addFilterCategory(DRIFT); changeSets = jpaDriftServer.findDriftChangeSetsByCriteria(overlord, c); assertEquals(1, changeSets.size()); changeSet = changeSets.get(0); assertEquals("The change set version is wrong", 1, changeSet.getVersion()); assertEquals("Expected to find one entry in change set", 1, changeSet.getDrifts().size()); changeSet = changeSets.get(0); assertEquals(1, changeSet.getVersion()); assertEquals(1, changeSet.getDrifts().size()); Drift<?, ?> drift = changeSet.getDrifts().iterator().next(); assertEquals("test/file-1", drift.getPath()); assertEquals(file1Hash, drift.getOldDriftFile().getHashId()); assertEquals(modifiedFile1Hash, drift.getNewDriftFile().getHashId()); assertEquals(DriftCategory.FILE_CHANGED, drift.getCategory()); driftFile = jpaDriftServer.getDriftFile(overlord, modifiedFile1Hash); assertNotNull(driftFile); assertEquals(DriftFileStatus.REQUESTED, driftFile.getStatus()); } @Test public void testDriftDef() throws Exception { Configuration config = new Configuration(); DriftDefinition driftDefPojo = new DriftDefinition(config); driftDefPojo.setName("testDriftDef"); driftDefPojo.setInterval(60L); driftDefPojo.setBasedir(new BaseDirectory(BaseDirValueContext.fileSystem, "foo/bar")); driftManager.updateDriftDefinition(overlord, EntityContext.forResource(newResource.getId()), driftDefPojo); DriftDefinitionCriteria c = new DriftDefinitionCriteria(); c.addFilterResourceIds(newResource.getId()); c.fetchConfiguration(true); List<DriftDefinition> driftDefs = driftManager.findDriftDefinitionsByCriteria(overlord, c); assertNotNull(driftDefs); assertEquals(3, driftDefs.size()); DriftDefinition driftDef = null; for (Iterator<DriftDefinition> i = driftDefs.iterator(); i.hasNext();) { driftDef = i.next(); if (driftDefPojo.getName().equals(driftDef.getName())) break; } assertTrue(driftDef.getConfiguration().getId() > 0); // persisted assertEquals(driftDefPojo.getName(), driftDef.getName()); assertEquals(driftDefPojo.getBasedir(), driftDef.getBasedir()); assertEquals(driftDefPojo.getInterval(), driftDef.getInterval()); driftDefPojo.setInterval(120L); driftManager.updateDriftDefinition(overlord, EntityContext.forResource(newResource.getId()), driftDefPojo); driftDefs = driftManager.findDriftDefinitionsByCriteria(overlord, c); assertNotNull(driftDefs); assertEquals(3, driftDefs.size()); driftDef = null; for (Iterator<DriftDefinition> i = driftDefs.iterator(); i.hasNext();) { driftDef = i.next(); if (driftDefPojo.getName().equals(driftDef.getName())) break; } assertEquals(driftDefPojo.getName(), driftDef.getName()); assertTrue(driftDef.getConfiguration().getId() > 0); // persisted assertEquals(driftDefPojo.getBasedir(), driftDef.getBasedir()); assertEquals(120L, driftDef.getInterval()); driftDefPojo = new DriftDefinition(driftDef.getConfiguration().deepCopyWithoutProxies()); driftDefPojo.setName("testDriftDef-2"); driftDefPojo.setInterval(30L); driftDefPojo.setBasedir(new BaseDirectory(BaseDirValueContext.fileSystem, "foo/baz")); driftManager.updateDriftDefinition(overlord, EntityContext.forResource(newResource.getId()), driftDefPojo); driftDefs = driftManager.findDriftDefinitionsByCriteria(overlord, c); assertNotNull(driftDefs); assertEquals(4, driftDefs.size()); for (Iterator<DriftDefinition> i = driftDefs.iterator(); i.hasNext();) { driftDef = i.next(); if ("testDriftDef".equals(driftDef.getName())) { assertTrue(driftDef.getConfiguration().getId() > 0); // persisted assertEquals("foo/bar", driftDef.getBasedir().getValueName()); assertEquals(BaseDirValueContext.fileSystem, driftDef.getBasedir().getValueContext()); assertEquals(120L, driftDef.getInterval()); } else if ("testDriftDef-2".equals(driftDef.getName())) { assertTrue(driftDef.getConfiguration().getId() > 0); // persisted assertEquals(driftDefPojo.getBasedir(), driftDef.getBasedir()); assertEquals(driftDefPojo.getInterval(), driftDef.getInterval()); } else if (!"test-1".equals(driftDef.getName()) && !"test-2".equals(driftDef.getName())) { fail("Unexpected drift def name: " + driftDef.getName()); } } driftManager.deleteDriftDefinition(overlord, EntityContext.forResource(newResource.getId()), "testDriftDef"); driftDefs = driftManager.findDriftDefinitionsByCriteria(overlord, c); assertNotNull(driftDefs); assertEquals(3, driftDefs.size()); for (Iterator<DriftDefinition> i = driftDefs.iterator(); i.hasNext();) { driftDef = i.next(); if (driftDefPojo.getName().equals(driftDef.getName())) break; } assertTrue(driftDef.getConfiguration().getId() > 0); // persisted assertEquals(driftDefPojo.getName(), driftDef.getName()); assertEquals(driftDefPojo.getBasedir(), driftDef.getBasedir()); assertEquals(driftDefPojo.getInterval(), driftDef.getInterval()); } private void deleteDriftFiles() throws Exception { getTransactionManager().begin(); try { try { // wipe out any test DriftFiles (the test files have sha256 0,1,...) for (int i = 0, numDeleted = 1; (numDeleted > 0); ++i) { numDeleted = getEntityManager().createQuery("delete from JPADriftFile where hash_id = '" + i + "'") .executeUpdate(); } } catch (Exception e) { System.out.println("CANNOT PREPARE TEST: " + e); getTransactionManager().rollback(); throw e; } em.flush(); getTransactionManager().commit(); } finally { } } private Resource createNewResource() throws Exception { getTransactionManager().begin(); Resource resource; try { try { ResourceType resourceType = new ResourceType("plat" + System.currentTimeMillis(), "test", ResourceCategory.PLATFORM, null); DriftDefinitionTemplate template = new DriftDefinitionTemplate(); template.setName("test-template"); DriftDefinition templateDef = new DriftDefinition(new Configuration()); templateDef.setName("test-template-def"); template.setTemplateDefinition(templateDef); template.setUserDefined(true); resourceType.addDriftDefinitionTemplate(template); em.persist(resourceType); Agent agent = new Agent("testagent", "testaddress", 1, "", "testtoken"); em.persist(agent); em.flush(); DriftDefinition test1Def = new DriftDefinition(new Configuration()); test1Def.setName("test-1"); DriftDefinition test2Def = new DriftDefinition(new Configuration()); test2Def.setName("test-2"); resource = new Resource("reskey" + System.currentTimeMillis(), "resname", resourceType); resource.setUuid("" + new Random().nextInt()); resource.setAgent(agent); resource.setInventoryStatus(InventoryStatus.COMMITTED); resource.addDriftDefinition(test1Def); resource.addDriftDefinition(test2Def); em.persist(resource); } catch (Exception e) { System.out.println("CANNOT PREPARE TEST: " + e); getTransactionManager().rollback(); throw e; } em.flush(); getTransactionManager().commit(); } finally { } return resource; } private void deleteNewResource(Resource resource) throws Exception { if (null != resource) { try { ResourceManagerLocal resourceManager = LookupUtil.getResourceManager(); // invoke bulk delete on the resource to remove any dependencies not defined in the hibernate entity model // perform in-band and out-of-band work in quick succession List<Integer> deletedIds = resourceManager.uninventoryResource(overlord, resource.getId()); for (Integer deletedResourceId : deletedIds) { resourceManager.uninventoryResourceAsyncWork(overlord, deletedResourceId); } // now dispose of other hibernate entities getTransactionManager().begin(); ResourceType type = em.find(ResourceType.class, resource.getResourceType().getId()); Agent agent = em.find(Agent.class, resource.getAgent().getId()); if (null != agent) { em.remove(agent); } if (null != type) { em.remove(type); } getTransactionManager().commit(); } catch (Exception e) { try { System.out.println("CANNOT CLEAN UP TEST (" + this.getClass().getSimpleName() + ")"); e.printStackTrace(); getTransactionManager().rollback(); } catch (Exception ignore) { } } finally { } } } String sha256(String s) throws Exception { return digestGenerator.calcDigestString(s); } }