/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.server.upgrade.impl.callback; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.List; import org.junit.Assert; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.URIUtil; import com.emc.storageos.db.client.model.NamedURI; import com.emc.storageos.db.client.model.Project; import com.emc.storageos.db.client.model.TenantOrg; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.db.client.upgrade.callbacks.VolumeAccessStateLinkStatusMigration; import com.emc.storageos.db.server.DbsvcTestBase; import com.emc.storageos.db.server.upgrade.DbSimpleMigrationTestBase; /** * Test proper population of the new DataObject.internalFlags field * * Here's the basic execution flow for the test case: * - setup() runs, bringing up a "pre-migration" version * of the database, using the DbSchemaScannerInterceptor * you supply to hide your new field or column family * when generating the "before" schema. * - Your implementation of prepareData() is called, allowing * you to use the internal _dbClient reference to create any * needed pre-migration test data. * - The database is then shutdown and restarted (without using * the interceptor this time), so the full "after" schema * is available. * - The dbsvc detects the diffs in the schema and executes the * migration callbacks as part of the startup process. * - Your implementation of verifyResults() is called to * allow you to confirm that the migration of your prepared * data went as expected. * * This class tests the following migration callback classes: * - BlockSnapshotConsistencyGroupMigration * - ProtectionSetToBlockConsistencyGroupMigration * - VolumeRpJournalMigration */ public class VolumeAccessStateLinkStatusMigrationTest extends DbSimpleMigrationTestBase { private static final Logger log = LoggerFactory.getLogger(VolumeAccessStateLinkStatusMigrationTest.class); // Used for migrations tests related to access state and link status private static volatile List<URI> volumeAccessStateLinkStatusURIs = new ArrayList<URI>(); @BeforeClass public static void setup() throws IOException { customMigrationCallbacks.put("1.1", new ArrayList<BaseCustomMigrationCallback>() { { add(new VolumeAccessStateLinkStatusMigration()); } }); DbsvcTestBase.setup(); } @Override protected String getSourceVersion() { return "1.1"; } @Override protected String getTargetVersion() { return "2.0"; } @Override protected void prepareData() throws Exception { prepareVolumeData(); } @Override protected void verifyResults() throws Exception { verifyVolumeResults(); } /** * Prepares the data for RP volume tests. * * @throws Exception When an error occurs preparing the RP volume data. */ private void prepareVolumeData() throws Exception { log.info("Preparing Volumes for VolumeAccessStateLinkStatusMigration"); TenantOrg tenantOrg = new TenantOrg(); URI tenantOrgURI = URIUtil.createId(TenantOrg.class); tenantOrg.setId(tenantOrgURI); _dbClient.createObject(tenantOrg); volumeAccessStateLinkStatusURIs = new ArrayList<URI>(); Project proj = new Project(); URI projectURI = URIUtil.createId(Project.class); String projectLabel = "project"; proj.setId(projectURI); proj.setLabel(projectLabel); proj.setTenantOrg(new NamedURI(tenantOrgURI, projectLabel)); _dbClient.createObject(proj); // Create RP source volume Volume sourceVolume = new Volume(); URI sourceVolumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(sourceVolumeURI); sourceVolume.setId(sourceVolumeURI); sourceVolume.setLabel("SOURCE"); sourceVolume.setPersonality(Volume.PersonalityTypes.SOURCE.toString()); sourceVolume.setRpCopyName("COPY"); _dbClient.createObject(sourceVolume); // Create RP target volume Volume targetVolume = new Volume(); URI targetVolumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(targetVolumeURI); targetVolume.setId(targetVolumeURI); targetVolume.setLabel("TARGET"); targetVolume.setPersonality(Volume.PersonalityTypes.TARGET.toString()); targetVolume.setRpCopyName("COPY"); _dbClient.createObject(targetVolume); // Create RP journal volume Volume journalVolume = new Volume(); URI journalVolumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(journalVolumeURI); journalVolume.setId(journalVolumeURI); journalVolume.setLabel("METADATA"); journalVolume.setPersonality(Volume.PersonalityTypes.METADATA.toString()); journalVolume.setRpCopyName("COPY"); _dbClient.createObject(journalVolume); // Create SRDF source volume Volume srdfSourceVolume = new Volume(); URI srdfSourceVolumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(srdfSourceVolumeURI); srdfSourceVolume.setId(srdfSourceVolumeURI); srdfSourceVolume.setLabel("SOURCE"); srdfSourceVolume.setPersonality(Volume.PersonalityTypes.SOURCE.toString()); srdfSourceVolume.setSrdfParent(new NamedURI(sourceVolume.getId(), "source-srdf")); _dbClient.createObject(srdfSourceVolume); // Create SRDF target volume Volume srdfTargetVolume = new Volume(); URI srdfTargetVolumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(srdfTargetVolumeURI); srdfTargetVolume.setId(srdfTargetVolumeURI); srdfTargetVolume.setLabel("TARGET"); srdfTargetVolume.setPersonality(Volume.PersonalityTypes.TARGET.toString()); srdfTargetVolume.setSrdfParent(new NamedURI(targetVolume.getId(), "target-srdf")); _dbClient.createObject(srdfTargetVolume); // Create a "normal" volume Volume volume = new Volume(); URI volumeURI = URIUtil.createId(Volume.class); volumeAccessStateLinkStatusURIs.add(volumeURI); volume.setId(volumeURI); volume.setLabel("NORMAL"); _dbClient.createObject(volume); } /** * Verifies the results for migrating volumes * * @throws Exception When an error occurs verifying the Volume * migration results. */ private void verifyVolumeResults() throws Exception { log.info("Verifying updated Volume source/target Volume results for VolumeAccessStateLinkStatusMigration."); for (URI volumeURI : volumeAccessStateLinkStatusURIs) { Volume volume = _dbClient.queryObject(Volume.class, volumeURI); // Ensure that the source and target volumes have been assigned journal volume reference if (volume.getPersonality() != null) { if (volume.getPersonality().equalsIgnoreCase(Volume.PersonalityTypes.SOURCE.toString())) { // All source volumes must have access state of READWRITE Assert.assertTrue("Source volume MUST be READWRITE", volume.getAccessState().equals(Volume.VolumeAccessState.READWRITE.toString())); Assert.assertTrue("Source volume MUST be IN_SYNC", volume.getLinkStatus().equals(Volume.LinkStatus.IN_SYNC.toString())); } else if (volume.getPersonality().equalsIgnoreCase(Volume.PersonalityTypes.TARGET.toString())) { Assert.assertTrue("Target volume MUST be NOT_READY", volume.getAccessState().equals(Volume.VolumeAccessState.NOT_READY.toString())); Assert.assertTrue("Target volume MUST be IN_SYNC", volume.getLinkStatus().equals(Volume.LinkStatus.IN_SYNC.toString())); } else if (volume.getPersonality().equalsIgnoreCase(Volume.PersonalityTypes.METADATA.toString())) { Assert.assertTrue("Metadata volume MUST be NOT_READY", volume.getAccessState().equals(Volume.VolumeAccessState.NOT_READY.toString())); } else { Assert.assertTrue("Volume MUST be READWRITE", volume.getAccessState().equals(Volume.VolumeAccessState.READWRITE.toString())); } } else { Assert.assertTrue("Volume MUST be READWRITE", volume.getAccessState().equals(Volume.VolumeAccessState.READWRITE.toString())); } } } }