/*
* Copyright (c) 2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.server.upgrade.impl.callback;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.model.BlockConsistencyGroup;
import com.emc.storageos.db.client.model.BlockMirror;
import com.emc.storageos.db.client.model.BlockObject;
import com.emc.storageos.db.client.model.BlockSnapshot;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.upgrade.BaseCustomMigrationCallback;
import com.emc.storageos.db.client.upgrade.callbacks.BlockObjectConsistencyGroupMigration;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.server.DbsvcTestBase;
import com.emc.storageos.db.server.upgrade.DbSimpleMigrationTestBase;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.junit.Assert;
/**
* 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:
* - BlockObjectConsistencyGroupMigration
*/
public class BlockObjectConsistencyGroupMigrationTest extends DbSimpleMigrationTestBase {
private static final Logger log = LoggerFactory.getLogger(BlockObjectConsistencyGroupMigrationTest.class);
// Used for migrations tests related to BlockSnapshots.
private static List<URI> testBlockSnapshotURIs = new ArrayList<URI>();
// Used for migrations tests related to RP ProtectionSets.
private static List<URI> testBlockMirrorURIs = new ArrayList<URI>();
// Used for migrations tests related to Volumes.
private static List<URI> testVolumeURIs = new ArrayList<URI>();
@BeforeClass
public static void setup() throws IOException {
customMigrationCallbacks.put("1.1", new ArrayList<BaseCustomMigrationCallback>() {
{
add(new BlockObjectConsistencyGroupMigration());
}
});
DbsvcTestBase.setup();
}
@Override
protected String getSourceVersion() {
return "1.1";
}
@Override
protected String getTargetVersion() {
return "2.0";
}
@Override
protected void prepareData() throws Exception {
createVolumeData("migrationVolume", 10);
createBlockSnapshotData("migrationBlockSnapshot", 10);
createBlockMirrorData("migrationBlockMirror", 10);
}
@Override
protected void verifyResults() throws Exception {
verifyBlockObjectResults();
}
/**
* Creates the consistency group used by the BlockObjects.
*
* @param name
* @return
*/
private URI createBlockConsistencyGroup(String name) {
BlockConsistencyGroup cg = new BlockConsistencyGroup();
URI cgURI = URIUtil.createId(BlockConsistencyGroup.class);
cg.setId(cgURI);
cg.setLabel(name);
_dbClient.createObject(cg);
return cg.getId();
}
/**
* Creates the BlockObject Volume data.
*
* @param volumeName
* @param numTargets
*/
private List<Volume> createVolumeData(String name, int numVolumes) {
List<Volume> volumes = new ArrayList<Volume>();
URI cgUri = createBlockConsistencyGroup(name + "-cg");
for (int i = 1; i <= numVolumes; i++) {
Volume volume = new Volume();
URI volumeURI = URIUtil.createId(Volume.class);
testVolumeURIs.add(volumeURI);
volume.setId(volumeURI);
volume.setLabel(name + i);
volume.setConsistencyGroup(cgUri);
_dbClient.createObject(volume);
}
return volumes;
}
/**
* Creates the BlockObject BlockSnapshot data.
*
* @param name
* @param numSnapshots
* @throws Exception
*/
private void createBlockSnapshotData(String name, int numSnapshots) throws Exception {
// Create the volume for the snapshots
Volume volume = new Volume();
URI volumeURI = URIUtil.createId(Volume.class);
testVolumeURIs.add(volumeURI);
volume.setId(volumeURI);
String volName = "snapVolume";
volume.setLabel(volName);
URI cgUri = createBlockConsistencyGroup(volName + "-cg");
volume.setConsistencyGroup(cgUri);
_dbClient.createObject(volume);
for (int i = 1; i <= numSnapshots; i++) {
BlockSnapshot blockSnapshot = new BlockSnapshot();
URI blockSnapshotURI = URIUtil.createId(BlockSnapshot.class);
testBlockSnapshotURIs.add(blockSnapshotURI);
blockSnapshot.setId(blockSnapshotURI);
blockSnapshot.setLabel(name + i);
blockSnapshot.setSnapsetLabel(name + i);
blockSnapshot.setParent(new NamedURI(volume.getId(), name + i));
blockSnapshot.setConsistencyGroup(cgUri);
_dbClient.createObject(blockSnapshot);
BlockSnapshot querySnap = _dbClient.queryObject(BlockSnapshot.class, blockSnapshotURI);
}
}
/**
* Creates the BlockObject BlockMirror data.
*
* @param name
* @param numSnapshots
* @throws Exception
*/
private void createBlockMirrorData(String name, int numBlockMirrors) throws Exception {
// Create the volume for the snapshots
Volume volume = new Volume();
URI volumeURI = URIUtil.createId(Volume.class);
testVolumeURIs.add(volumeURI);
volume.setId(volumeURI);
volume.setLabel("blockMirrorVolume");
URI cgUri = createBlockConsistencyGroup("blockMirrorVolume-cg");
volume.setConsistencyGroup(cgUri);
_dbClient.createObject(volume);
for (int i = 1; i <= numBlockMirrors; i++) {
BlockMirror blockMirror = new BlockMirror();
URI blockMirrorURI = URIUtil.createId(BlockMirror.class);
testBlockMirrorURIs.add(blockMirrorURI);
blockMirror.setId(blockMirrorURI);
blockMirror.setLabel(name + i);
blockMirror.setConsistencyGroup(cgUri);
_dbClient.createObject(blockMirror);
}
}
/**
* Verifies that the migration has worked properly. Checks all of the Volume, BlockSnapshot,
* and BlockMirror objects to ensure:
* 1) The old consistencyGroup field is null
* 2) The new consistencyGroups field is not null
* 3) The new consistencyGruops field is not empty
*
* @throws Exception
*/
private void verifyBlockObjectResults() throws Exception {
log.info("Verifying migration of BlockObject.consistencyGroup to BlockObject.consistencyGroups.");
List<BlockObject> blockObjects = new ArrayList<BlockObject>();
// get the volumes
Iterator<Volume> volumeItr =
_dbClient.queryIterativeObjects(Volume.class, testVolumeURIs);
// Get the block snapshots
Iterator<BlockSnapshot> blockSnapshotItr =
_dbClient.queryIterativeObjects(BlockSnapshot.class, testBlockSnapshotURIs);
// Get the block snapshots
Iterator<BlockMirror> blockMirrorItr =
_dbClient.queryIterativeObjects(BlockMirror.class, testBlockMirrorURIs);
while (volumeItr.hasNext()) {
blockObjects.add(volumeItr.next());
}
while (blockSnapshotItr.hasNext()) {
blockObjects.add(blockSnapshotItr.next());
}
while (blockMirrorItr.hasNext()) {
blockObjects.add(blockMirrorItr.next());
}
for (BlockObject blockObject : blockObjects) {
Assert.assertTrue("Volume.consistencyGroup field should be null.",
blockObject.getConsistencyGroup().equals(NullColumnValueGetter.getNullURI()));
Assert.assertNotNull("Volume.consistencyGroups field should contain at least 1 consistency group.",
blockObject.getConsistencyGroups());
Assert.assertTrue("Volume.consistencyGroups field should contain at least 1 consistency group.",
!blockObject.getConsistencyGroups().isEmpty());
}
}
}