/* * RHQ Management Platform * Copyright (C) 2011 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 java.util.Arrays.asList; import static org.rhq.core.domain.drift.DriftCategory.FILE_ADDED; import static org.rhq.core.domain.drift.DriftChangeSetCategory.COVERAGE; import static org.rhq.core.domain.drift.DriftChangeSetCategory.DRIFT; import static org.rhq.core.domain.drift.DriftConfigurationDefinition.BaseDirValueContext.fileSystem; import static org.rhq.core.domain.drift.DriftConfigurationDefinition.DriftHandlingMode.normal; import static org.rhq.enterprise.server.util.LookupUtil.getDriftManager; import static org.rhq.enterprise.server.util.LookupUtil.getDriftTemplateManager; import static org.rhq.test.AssertUtils.assertPropertiesMatch; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import javax.ejb.EJBException; import javax.persistence.EntityManager; import org.testng.annotations.Test; import org.rhq.core.domain.configuration.Configuration; import org.rhq.core.domain.criteria.GenericDriftChangeSetCriteria; import org.rhq.core.domain.drift.Drift; import org.rhq.core.domain.drift.DriftChangeSet; import org.rhq.core.domain.drift.DriftDefinition; import org.rhq.core.domain.drift.DriftDefinitionTemplate; import org.rhq.core.domain.drift.DriftSnapshot; import org.rhq.core.domain.drift.JPADrift; import org.rhq.core.domain.drift.JPADriftChangeSet; import org.rhq.core.domain.drift.JPADriftFile; import org.rhq.core.domain.drift.JPADriftSet; import org.rhq.core.domain.server.EntitySerializer; import org.rhq.core.domain.util.PageList; import org.rhq.enterprise.server.test.TransactionCallback; import org.rhq.test.AssertUtils; public class ManageSnapshotsTest extends AbstractDriftServerTest { private DriftManagerLocal driftMgr; private DriftTemplateManagerLocal templateMgr; @Override protected void beforeMethod(Method testMethod) throws Exception { super.beforeMethod(testMethod); driftMgr = getDriftManager(); templateMgr = getDriftTemplateManager(); } public void pinningSnapshotShouldSetDriftDefAsPinned() { final DriftDefinition driftDef = createAndPersistDriftDef(NAME_PREFIX + "setPinnedFlag"); // create initial change set final JPADriftChangeSet changeSet = new JPADriftChangeSet(resource, 0, COVERAGE, driftDef); final JPADriftFile driftFile1 = new JPADriftFile(NAME_PREFIX + "a1b2c3"); JPADrift drift = new JPADrift(changeSet, "drift.1", FILE_ADDED, null, driftFile1); final JPADriftSet driftSet = new JPADriftSet(); driftSet.addDrift(drift); executeInTransaction(false, new TransactionCallback() { @Override public void execute() throws Exception { EntityManager em = getEntityManager(); em.persist(driftFile1); em.persist(changeSet); em.persist(driftSet); changeSet.setInitialDriftSet(driftSet); em.merge(changeSet); } }); driftMgr.pinSnapshot(getOverlord(), driftDef.getId(), 0); DriftDefinition updatedDriftDef = driftMgr.getDriftDefinition(getOverlord(), driftDef.getId()); assertNotNull("Failed to get " + toString(driftDef), updatedDriftDef); assertTrue("Failed to set pinned flag of " + toString(driftDef), updatedDriftDef.isPinned()); } @SuppressWarnings("unchecked") public void pinningSnapshotShouldMakeSnapshotTheInitialChangeSet() throws Exception { final DriftDefinition driftDef = createAndPersistDriftDef(NAME_PREFIX + "makeSnapshotVersionZero"); // create initial change set final JPADriftChangeSet changeSet0 = new JPADriftChangeSet(resource, 0, COVERAGE, driftDef); final JPADriftFile driftFile1 = new JPADriftFile(NAME_PREFIX + "a1b2c3"); JPADrift drift1 = new JPADrift(changeSet0, "drift.1", FILE_ADDED, null, driftFile1); final JPADriftSet driftSet = new JPADriftSet(); driftSet.addDrift(drift1); // create change set v1 final JPADriftFile driftFile2 = new JPADriftFile(NAME_PREFIX + "1a2b3c"); final JPADriftChangeSet changeSet1 = new JPADriftChangeSet(resource, 1, DRIFT, driftDef); final JPADrift drift2 = new JPADrift(changeSet1, "drift.2", FILE_ADDED, null, driftFile2); executeInTransaction(false, new TransactionCallback() { @Override public void execute() throws Exception { EntityManager em = getEntityManager(); em.persist(driftFile1); em.persist(driftFile2); em.persist(changeSet0); em.persist(driftSet); changeSet0.setInitialDriftSet(driftSet); em.merge(changeSet0); em.persist(changeSet1); em.persist(drift2); } }); driftMgr.pinSnapshot(getOverlord(), driftDef.getId(), 1); // Verify that there is now only one change set for the drift def GenericDriftChangeSetCriteria criteria = new GenericDriftChangeSetCriteria(); criteria.addFilterDriftDefinitionId(driftDef.getId()); PageList<? extends DriftChangeSet<?>> changeSets = driftMgr.findDriftChangeSetsByCriteria(getOverlord(), criteria); assertEquals("All change sets except the change set representing the pinned snapshot should be removed", 1, changeSets.size()); DriftChangeSet<?> changeSet = changeSets.get(0); assertEquals("The pinned snapshot version should be reset to zero", 0, changeSet.getVersion()); assertEquals("The change set category is wrong", COVERAGE, changeSet.getCategory()); JPADriftChangeSet expectedChangeSet = new JPADriftChangeSet(resource, 1, COVERAGE, driftDef); List<? extends Drift> expectedDrifts = asList(new JPADrift(expectedChangeSet, drift1.getPath(), FILE_ADDED, null, driftFile1), new JPADrift(expectedChangeSet, drift2.getPath(), FILE_ADDED, null, driftFile2)); List<? extends Drift> actualDrifts = new ArrayList(changeSet.getDrifts()); AssertUtils.assertCollectionMatchesNoOrder( "Expected to find drifts from change sets 1 and 2 in the new initial change set", (List<Drift>) expectedDrifts, (List<Drift>) actualDrifts, "id", "ctime", "changeSet", "newDriftFile"); // we need to compare the newDriftFile properties separately because // assertCollectionMatchesNoOrder compares properties via equals() and JPADriftFile // does not implement equals. assertPropertiesMatch(drift1.getNewDriftFile(), findDriftByPath(actualDrifts, "drift.1").getNewDriftFile(), "The newDriftFile property was not set correctly for " + drift1); assertPropertiesMatch(drift2.getNewDriftFile(), findDriftByPath(actualDrifts, "drift.2").getNewDriftFile(), "The newDriftFile property was not set correctly for " + drift1); } public void pinningSnapshotShouldSendRequestToAgent() { final DriftDefinition driftDef = createAndPersistDriftDef(NAME_PREFIX + "setPinnedFlag"); // create initial change set final JPADriftChangeSet changeSet = new JPADriftChangeSet(resource, 0, COVERAGE, driftDef); final JPADriftFile driftFile1 = new JPADriftFile(NAME_PREFIX + "a1b2c3"); JPADrift drift = new JPADrift(changeSet, "drift.1", FILE_ADDED, null, driftFile1); final JPADriftSet driftSet = new JPADriftSet(); driftSet.addDrift(drift); executeInTransaction(false, new TransactionCallback() { @Override public void execute() throws Exception { EntityManager em = getEntityManager(); em.persist(driftFile1); em.persist(changeSet); em.persist(driftSet); changeSet.setInitialDriftSet(driftSet); em.merge(changeSet); } }); final AtomicBoolean agentInvoked = new AtomicBoolean(false); agentServiceContainer.driftService = new TestDefService() { @Override public void pinSnapshot(int resourceId, String configName, DriftSnapshot snapshot) { try { agentInvoked.set(true); // serialize the method arguments here to more closely simulate what // happens during the call. We cannot send hibernate-proxied objects // to the agent. This is an attempt to catch that. ObjectOutputStream stream = new ObjectOutputStream(new ByteArrayOutputStream()); EntitySerializer.writeExternalRemote(resourceId, stream); EntitySerializer.writeExternalRemote(configName, stream); EntitySerializer.writeExternalRemote(snapshot, stream); } catch (IOException e) { throw new RuntimeException(e); } } }; driftMgr.pinSnapshot(getOverlord(), driftDef.getId(), 0); assertTrue("Failed to send request to agent to pin snapshot", agentInvoked.get()); } // @Test(expectedExceptions = IllegalArgumentException.class)//, expectedExceptionsMessageRegExp = "Cannot repin.*definition.*") @Test public void doNotAllowSnapshotToBePinnedWhenDefinitionIsAttachedToPinnedTemplate() { // First create the template final DriftDefinition templateDef = new DriftDefinition(new Configuration()); templateDef.setName(NAME_PREFIX + "Template-Pinned_Test"); templateDef.setEnabled(true); templateDef.setDriftHandlingMode(normal); templateDef.setInterval(2400L); templateDef.setBasedir(new DriftDefinition.BaseDirectory(fileSystem, "/foo/bar/test")); final DriftDefinitionTemplate template = templateMgr.createTemplate(getOverlord(), resourceType.getId(), true, templateDef); // Now we will pin the template. We are going to take a bit of a short cut // here. Pinning a template requires a drift definition with at least one // snapshot. For the purposes of this test we can simply set the // changeSetId field of the template to indicate that it is pinned. template.setChangeSetId("1234"); // Next create a resource-level definition from the template. final DriftDefinition driftDef = template.createDefinition(); driftDef.setResource(resource); executeInTransaction(false, new TransactionCallback() { @Override public void execute() throws Exception { EntityManager em = getEntityManager(); em.merge(template); em.persist(driftDef); } }); // Now try resource-level pinning, i.e., pin a snapshot to the definition try { driftMgr.pinSnapshot(getOverlord(), driftDef.getId(), 0); } catch (IllegalArgumentException e) { System.out.println("Got expected IAE"); } catch (EJBException ee) { if (ee.getCause()!=null && ee.getCause() instanceof IllegalArgumentException) { System.out.println("Got expected EJBException wrapping an IAR"); } else { throw ee; } } } private DriftDefinition createAndPersistDriftDef(String name) { final DriftDefinition driftDef = new DriftDefinition(new Configuration()); driftDef.setName(name); driftDef.setEnabled(true); driftDef.setDriftHandlingMode(normal); driftDef.setInterval(1800L); driftDef.setBasedir(new DriftDefinition.BaseDirectory(fileSystem, "/foo/bar/test")); executeInTransaction(false, new TransactionCallback() { @Override public void execute() throws Exception { driftDef.setResource(resource); getEntityManager().persist(driftDef); } }); return driftDef; } }