/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.server.upgrade.impl.callback; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; 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.BlockConsistencyGroup; import com.emc.storageos.db.client.model.BlockSnapshot; import com.emc.storageos.db.client.model.BlockSnapshotSession; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.DiscoveredDataObject; import com.emc.storageos.db.client.model.NamedURI; import com.emc.storageos.db.client.model.Project; import com.emc.storageos.db.client.model.StorageSystem; import com.emc.storageos.db.client.model.StringSet; import com.emc.storageos.db.client.model.Volume; import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback; import com.emc.storageos.db.client.upgrade.callbacks.BlockSnapshotSessionMigration; import com.emc.storageos.db.client.util.NullColumnValueGetter; import com.emc.storageos.db.server.upgrade.DbSimpleMigrationTestBase; /** * Test class for the BlockSnashotSessionMigration upgrade callback class. */ public class BlockSnapshotSessionMigrationTest extends DbSimpleMigrationTestBase { // Test constants. private static final String PROJECT_NAME = "Project"; private static final String PARENT_NAME = "Parent"; private static final String GRP_PARENT_NAME = "GrpParent"; private static final String BASE_SNAPSHOT_NAME = "Snapshot"; private static final String BASE_SNAPVX_SNAPSHOT_NAME = "SnapVx_Snapshot"; private static final String BASE_GRP_SNAPVX_SNAPSHOT_NAME = "Grp_SnapVx_Snapshot"; // Settings Instance example: SYMMETRIX-+-<SYMM_ID>-+-<sourceElementId>-+-<elementName>-+-0 private static final String BASE_SETTINGS_INSTANCE = "SYMMETRIX-+-SYMM_ID-+-sourceElementId-+-elementName-+-0"; private static final String BASE_GRP_SETTINGS_INSTANCE = "SYMMETRIX-+-SYMM_ID-+-sourceGroupName-+-elementName-+-0"; private static final String VMAX3_SYSTEM_FW_VERSION = "5977.xxx.xxx"; private static final int SNAPSHOT_COUNT = 5; private static final int SNAPVX_SNAPSHOT_COUNT = 5; private static final int GRP_SETTINGS_INSTANCE_COUNT = 2; // A map of the snapshots whose system supports snapshot sessions keyed by the snapshot id. private static Map<String, BlockSnapshot> _linkedTargetsMap = new HashMap<String, BlockSnapshot>(); // A reference to a logger. private static final Logger s_logger = LoggerFactory.getLogger(BlockSnapshotSessionMigrationTest.class); /** * Setup method executed before test is executed. * * @throws IOException */ @BeforeClass public static void setup() throws IOException { customMigrationCallbacks.put("2.4", new ArrayList<BaseCustomMigrationCallback>() { private static final long serialVersionUID = 1L; { // Add your implementation of migration callback below. add(new BlockSnapshotSessionMigration()); } }); // Adding this, which is typically executed in the base class // call, as it is needed to clear the DB file between runs. _dataDir = new File(dataDir); if (_dataDir.exists() && _dataDir.isDirectory()) { cleanDirectory(_dataDir); } _dataDir.mkdir(); // Commenting this out as it prevents the migration callback // from being executed when the test is executed. // DbsvcTestBase.setup(); } /** * {@inheritDoc} */ @Override protected String getSourceVersion() { return "2.4"; } /** * {@inheritDoc} */ @Override protected String getTargetVersion() { return "3.0"; } /** * {@inheritDoc} */ @Override protected void prepareData() throws Exception { s_logger.info("Preparing data for BlockSnapshotSession migration test."); prepareSingleSnapshotData(); prepareGroupSnapshotData(); } /** * Prepares single volume test data. */ private void prepareSingleSnapshotData() { // A list of database object instances to be created. ArrayList<DataObject> newObjectsToBeCreated = new ArrayList<DataObject>(); // Create some snapshots on a storage system that does not support // snapshot sessions. Snapshots on VNX do not currently support // snapshot sessions. StorageSystem system = new StorageSystem(); URI systemURI = URIUtil.createId(StorageSystem.class); system.setId(systemURI); system.setSystemType(DiscoveredDataObject.Type.vnxblock.name()); newObjectsToBeCreated.add(system); for (int i = 0; i < SNAPSHOT_COUNT; i++) { BlockSnapshot snapshot = new BlockSnapshot(); URI snapshotURI = URIUtil.createId(BlockSnapshot.class); snapshot.setId(snapshotURI); snapshot.setLabel(BASE_SNAPSHOT_NAME + i); snapshot.setSnapsetLabel(snapshot.getLabel()); URI projectURI = URIUtil.createId(Project.class); snapshot.setProject(new NamedURI(projectURI, PROJECT_NAME)); URI parentURI = URIUtil.createId(Volume.class); snapshot.setParent(new NamedURI(parentURI, PARENT_NAME + i)); snapshot.setSettingsInstance(BASE_SETTINGS_INSTANCE + i); snapshot.setStorageController(systemURI); newObjectsToBeCreated.add(snapshot); } // Now create some BlockSnapshot instances on a storage system // that does support snapshot sessions. VMAX3 is the only storage // system for which we currently support snapshot sessions. We // set up the system so that the method on StorageSystem // "checkIfVmax3" returns true. system = new StorageSystem(); systemURI = URIUtil.createId(StorageSystem.class); system.setId(systemURI); system.setSystemType(DiscoveredDataObject.Type.vmax.name()); system.setFirmwareVersion(VMAX3_SYSTEM_FW_VERSION); newObjectsToBeCreated.add(system); for (int i = 0; i < SNAPVX_SNAPSHOT_COUNT; i++) { BlockSnapshot snapshot = new BlockSnapshot(); URI snapshotURI = URIUtil.createId(BlockSnapshot.class); snapshot.setId(snapshotURI); snapshot.setLabel(BASE_SNAPVX_SNAPSHOT_NAME + i); snapshot.setSnapsetLabel(snapshot.getLabel()); URI projectURI = URIUtil.createId(Project.class); snapshot.setProject(new NamedURI(projectURI, PROJECT_NAME)); URI parentURI = URIUtil.createId(Volume.class); snapshot.setParent(new NamedURI(parentURI, PARENT_NAME + i)); snapshot.setSettingsInstance(BASE_SETTINGS_INSTANCE + i); snapshot.setStorageController(systemURI); newObjectsToBeCreated.add(snapshot); _linkedTargetsMap.put(snapshotURI.toString(), snapshot); } // Create the database objects. _dbClient.createObject(newObjectsToBeCreated); } /** * Prepares group snapshot test data. */ private void prepareGroupSnapshotData() { // A list of database object instances to be created. ArrayList<DataObject> newObjectsToBeCreated = new ArrayList<DataObject>(); // Create some group BlockSnapshot instances on a storage system // that supports snapshot sessions. VMAX3 is the only storage // system for which we currently support snapshot sessions. We // set up the system so that the method on StorageSystem // "checkIfVmax3" returns true. StorageSystem system = new StorageSystem(); URI systemURI = URIUtil.createId(StorageSystem.class); system.setId(systemURI); system.setSystemType(DiscoveredDataObject.Type.vmax.name()); system.setFirmwareVersion(VMAX3_SYSTEM_FW_VERSION); newObjectsToBeCreated.add(system); BlockConsistencyGroup cg = new BlockConsistencyGroup(); URI cgURI = URIUtil.createId(BlockConsistencyGroup.class); cg.setId(cgURI); newObjectsToBeCreated.add(cg); URI projectURI = URIUtil.createId(Project.class); for (int i = 0; i < GRP_SETTINGS_INSTANCE_COUNT; i++) { for (int j = 0; j < SNAPVX_SNAPSHOT_COUNT; j++) { BlockSnapshot snapshot = new BlockSnapshot(); URI snapshotURI = URIUtil.createId(BlockSnapshot.class); snapshot.setId(snapshotURI); snapshot.setLabel(BASE_GRP_SNAPVX_SNAPSHOT_NAME + i + j); snapshot.setSnapsetLabel(BASE_GRP_SNAPVX_SNAPSHOT_NAME + i); snapshot.setProject(new NamedURI(projectURI, PROJECT_NAME)); URI parentURI = URIUtil.createId(Volume.class); snapshot.setParent(new NamedURI(parentURI, GRP_PARENT_NAME + i + j)); snapshot.setConsistencyGroup(cgURI); snapshot.setSettingsInstance(BASE_GRP_SETTINGS_INSTANCE + i); snapshot.setStorageController(systemURI); newObjectsToBeCreated.add(snapshot); } } // Create the database objects. _dbClient.createObject(newObjectsToBeCreated); } /** * {@inheritDoc} */ @Override protected void verifyResults() throws Exception { s_logger.info("Verifying results for BlockSnapshotSession migration test."); verifySingleSnapshotResults(); verifyGroupSnapshotResults(); } /** * Verifies the migration results for single volume snapshots. */ private void verifySingleSnapshotResults() { List<URI> snapSessionURIs = _dbClient.queryByType(BlockSnapshotSession.class, true); Iterator<BlockSnapshotSession> snapSessionsIter = _dbClient .queryIterativeObjects(BlockSnapshotSession.class, snapSessionURIs, true); Assert.assertTrue("Did not find any snapshot sessions after migration", snapSessionsIter.hasNext()); int sessionCount = 0; while (snapSessionsIter.hasNext()) { BlockSnapshotSession snapSession = snapSessionsIter.next(); // Process single volume snapshot sessions. if (NullColumnValueGetter.isNullURI(snapSession.getConsistencyGroup())) { sessionCount++; Assert.assertNotNull("Snapshot session is null", snapSession); StringSet linkedTargets = snapSession.getLinkedTargets(); Assert.assertNotNull("Snapshot session linked targets list is null", snapSession); Assert.assertFalse("Snapshot session linked targets list is empty", linkedTargets.isEmpty()); Assert.assertEquals("Snapshot session does not have a singled linked target", linkedTargets.size(), 1); String linkedTargetId = linkedTargets.iterator().next(); Assert.assertTrue("Snapshot session linked target not in linked targets map", _linkedTargetsMap.containsKey(linkedTargetId)); BlockSnapshot linkedTarget = _linkedTargetsMap.remove(linkedTargetId); Assert.assertEquals("Label is not correct", linkedTarget.getLabel(), snapSession.getLabel()); Assert.assertEquals("Session label is not correct", "elementName", snapSession.getSessionLabel()); Assert.assertEquals("Session instance is not correct", linkedTarget.getSettingsInstance(), snapSession.getSessionInstance()); Assert.assertEquals("Project is not correct", linkedTarget.getProject(), snapSession.getProject()); Assert.assertEquals("Parent is not correct", linkedTarget.getParent(), snapSession.getParent()); } } // Get the single volume snapshots in the database. // Note: Don't use List#size() as it is not supported by the derived // List class returned by the DB client. int svSnapshotCount = 0; List<URI> snapshotURIs = _dbClient.queryByType(BlockSnapshot.class, true); Iterator<BlockSnapshot> snapshotsIter = _dbClient.queryIterativeObjects(BlockSnapshot.class, snapshotURIs); while (snapshotsIter.hasNext()) { BlockSnapshot snapshot = snapshotsIter.next(); if (NullColumnValueGetter.isNullURI(snapshot.getConsistencyGroup())) { svSnapshotCount++; } } Assert.assertEquals("Snapshot count is not correct", svSnapshotCount, SNAPVX_SNAPSHOT_COUNT + SNAPSHOT_COUNT); Assert.assertEquals("Snapshot session count is not correct", sessionCount, SNAPVX_SNAPSHOT_COUNT); } /** * Verifies group snapshot migration results. */ private void verifyGroupSnapshotResults() { List<URI> snapSessionURIs = _dbClient.queryByType(BlockSnapshotSession.class, true); Iterator<BlockSnapshotSession> snapSessionsIter = _dbClient .queryIterativeObjects(BlockSnapshotSession.class, snapSessionURIs, true); Assert.assertTrue("Did not find any snapshot sessions after migration", snapSessionsIter.hasNext()); int sessionCount = 0; while (snapSessionsIter.hasNext()) { BlockSnapshotSession snapSession = snapSessionsIter.next(); // Process group snapshot sessions. if (!NullColumnValueGetter.isNullURI(snapSession.getConsistencyGroup())) { sessionCount++; Assert.assertNotNull("Snapshot session is null", snapSession); Assert.assertNull("Parent is not null", snapSession.getParent()); StringSet linkedTargets = snapSession.getLinkedTargets(); Assert.assertNotNull("Snapshot session linked targets list is null", snapSession); Assert.assertFalse("Snapshot session linked targets list is empty", linkedTargets.isEmpty()); Assert.assertEquals("Snapshot session does not have the correct number fo linked targets", linkedTargets.size(), SNAPVX_SNAPSHOT_COUNT); String linkedTargetId = linkedTargets.iterator().next(); BlockSnapshot linkedTarget = _dbClient.queryObject(BlockSnapshot.class, URI.create(linkedTargetId)); Assert.assertNotNull("Linked target is null", linkedTarget); Assert.assertEquals("Label is not correct", linkedTarget.getSnapsetLabel(), snapSession.getLabel()); Assert.assertEquals("Session label is not correct", "elementName", snapSession.getSessionLabel()); Assert.assertEquals("Session instance is not correct", linkedTarget.getSettingsInstance(), snapSession.getSessionInstance()); Assert.assertEquals("Project is not correct", linkedTarget.getProject().getURI(), snapSession.getProject().getURI()); } } // Get the groups snapshots in the database. // Note: Don't use List#size() as it is not supported by the derived // List class returned by the DB client. int grpSnapshotCount = 0; List<URI> snapshotURIs = _dbClient.queryByType(BlockSnapshot.class, true); Iterator<BlockSnapshot> snapshotsIter = _dbClient.queryIterativeObjects(BlockSnapshot.class, snapshotURIs); while (snapshotsIter.hasNext()) { BlockSnapshot snapshot = snapshotsIter.next(); if (!NullColumnValueGetter.isNullURI(snapshot.getConsistencyGroup())) { grpSnapshotCount++; } } Assert.assertEquals("Snapshot count is not correct", grpSnapshotCount, GRP_SETTINGS_INSTANCE_COUNT * SNAPVX_SNAPSHOT_COUNT); Assert.assertEquals("Snapshot session count is not correct", sessionCount, GRP_SETTINGS_INSTANCE_COUNT); } }