/*
* Copyright (c) 2013-2014 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.Iterator;
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.model.DataObject.Flag;
import com.emc.storageos.db.client.model.FileShare;
import com.emc.storageos.db.client.model.NamedURI;
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.DataObjectInternalFlagsInitializer;
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.
*
*/
public class DbObjInternalFlagsMigrationTest extends DbSimpleMigrationTestBase {
// Used for migrations tests related to VPLEX volumes.
private static List<URI> vplexTestVolumeURIs = new ArrayList<URI>();
// Used for migrations tests related to RP volumes.
private static List<URI> rpTestVolumeURIs = new ArrayList<URI>();
@BeforeClass
public static void setup() throws IOException {
customMigrationCallbacks.put("1.0", new ArrayList<BaseCustomMigrationCallback>() {
{
add(new DataObjectInternalFlagsInitializer());
}
});
DbsvcTestBase.setup();
}
@Override
protected String getSourceVersion() {
return "1.0";
}
@Override
protected String getTargetVersion() {
return "1.1";
}
@Override
protected void prepareData() throws Exception {
prepareFileShareData();
prepareVolumeData();
}
@Override
protected void verifyResults() throws Exception {
verifyFileShareResults();
verifyVolumeResults();
}
private void prepareFileShareData() throws Exception {
String currentLabel = "onePublic";
// create a couple of public FileShares that should be ignored by the migration callback
FileShare fs = new FileShare();
fs.setId(URIUtil.createId(FileShare.class));
fs.setLabel(currentLabel);
fs.setProject(new NamedURI(URI.create("urn:" + currentLabel), currentLabel));
_dbClient.createObject(fs);
currentLabel = "twoPublic";
fs = new FileShare();
fs.setId(URIUtil.createId(FileShare.class));
fs.setLabel(currentLabel);
fs.setProject(new NamedURI(URI.create("urn:" + currentLabel), currentLabel));
_dbClient.createObject(fs);
// create a couple of internal (project==null) FileShares that should be migrated
currentLabel = "oneInternal";
fs = new FileShare();
fs.setId(URIUtil.createId(FileShare.class));
fs.setLabel(currentLabel);
fs.setProject(null);
_dbClient.createObject(fs);
currentLabel = "twoInternal";
fs = new FileShare();
fs.setId(URIUtil.createId(FileShare.class));
fs.setLabel(currentLabel);
fs.setProject(null);
_dbClient.createObject(fs);
// make sure our test data made it into the database as expected
List<URI> fileShareKeys = _dbClient.queryByType(FileShare.class, false);
int count = 0;
for (@SuppressWarnings("unused")
URI ignore : fileShareKeys) {
count++;
}
Assert.assertTrue("expected 4 prepared FileShares, found only " + count, count == 4);
}
private void verifyFileShareResults() throws Exception {
List<URI> fileShareKeys = _dbClient.queryByType(FileShare.class, false);
int count = 0;
Iterator<FileShare> fileShareObjs =
_dbClient.queryIterativeObjects(FileShare.class, fileShareKeys);
while (fileShareObjs.hasNext()) {
FileShare fs = fileShareObjs.next();
count++;
if (fs.getLabel().contains("Internal")) {
Assert.assertNotNull("internal project should not be null after migration", fs.getProject());
Assert.assertEquals("internal project should equal the internal project constant after migration",
fs.getProject().getURI(), FileShare.INTERNAL_OBJECT_PROJECT_URN);
Assert.assertTrue("INTERNAL_OBJECT should be set on internal fs",
fs.checkInternalFlags(Flag.INTERNAL_OBJECT));
Assert.assertTrue("NO_PUBLIC_ACCESS should be set on internal fs",
fs.checkInternalFlags(Flag.NO_PUBLIC_ACCESS));
Assert.assertTrue("NO_METERING should be set on internal fs",
fs.checkInternalFlags(Flag.NO_METERING));
} else if (fs.getLabel().contains("Public")) {
Assert.assertFalse("INTERNAL_OBJECT should not be set on public fs", fs.checkInternalFlags(Flag.INTERNAL_OBJECT));
Assert.assertFalse("NO_PUBLIC_ACCESS should not be set on public fs", fs.checkInternalFlags(Flag.NO_PUBLIC_ACCESS));
Assert.assertFalse("NO_METERING should not be set on public fs", fs.checkInternalFlags(Flag.NO_METERING));
}
}
Assert.assertTrue("we should still have 4 files shares after migration, not " + count, count == 4);
}
/**
* Prepares the data for volume tests.
*
* @throws Exception When an error occurs preparing the volume data.
*/
private void prepareVolumeData() throws Exception {
// Prepare the data for testing VPLEX volumes.
prepareVPlexVolumeData();
// Prepare the data for testing RP volumes.
prepareRPVolumeData();
}
/**
* Verifies the migration results for volumes.
*
* @throws Exception When an error occurs verifying the volume migration
* results.
*/
private void verifyVolumeResults() throws Exception {
// Verify the results for VPLEX volumes
verifyVPlexVolumeResults();
// Verify the results for RP volumes
verifyRPVolumeResults();
}
/**
* Prepares the data for VPLEX volume tests.
*
* @throws Exception When an error occurs preparing the VPLEX volume data.
*/
private void prepareVPlexVolumeData() throws Exception {
// Create two volumes to be used as backend volumes
// for a VPLEX volume.
Volume vplexBackendVolume1 = new Volume();
URI vplexBackendVolume1URI = URIUtil.createId(Volume.class);
vplexTestVolumeURIs.add(vplexBackendVolume1URI);
vplexBackendVolume1.setId(vplexBackendVolume1URI);
vplexBackendVolume1.setLabel("VPlexBackendVolume1");
_dbClient.createObject(vplexBackendVolume1);
Volume vplexBackendVolume2 = new Volume();
URI vplexBackendVolume2URI = URIUtil.createId(Volume.class);
vplexTestVolumeURIs.add(vplexBackendVolume2URI);
vplexBackendVolume2.setId(vplexBackendVolume2URI);
vplexBackendVolume2.setLabel("VPlexBackendVolume2");
_dbClient.createObject(vplexBackendVolume2);
// Get the ids of the VPLEX backend volumes.
StringSet associatedVolumeIds = new StringSet();
associatedVolumeIds.add(vplexBackendVolume1.getId().toString());
associatedVolumeIds.add(vplexBackendVolume2.getId().toString());
// Create the VPLEX volume, settings its associated
// volumes to the ids of the two backend volumes.
Volume vplexVolume = new Volume();
URI vplexVolumeURI = URIUtil.createId(Volume.class);
vplexTestVolumeURIs.add(vplexVolumeURI);
vplexVolume.setId(vplexVolumeURI);
vplexVolume.setLabel("VPlexVolume");
vplexVolume.setAssociatedVolumes(associatedVolumeIds);
_dbClient.createObject(vplexVolume);
// Verify the VPLEX volume data exists in the database.
for (URI volumeURI : vplexTestVolumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
Assert.assertNotNull(String.format("VPLEX test volume %s not found", volumeURI), volume);
}
}
/**
* Verifies the migration results for volumes.
*
* @throws Exception When an error occurs verifying the VPLEX volume
* migration results.
*/
private void verifyVPlexVolumeResults() throws Exception {
for (URI volumeURI : vplexTestVolumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
Assert.assertNotNull(String.format("VPLEX test volume %s not found", volumeURI), volume);
StringSet associatedVolumes = volume.getAssociatedVolumes();
if ((associatedVolumes != null) && (!associatedVolumes.isEmpty())) {
// This is the VPLEX volume.
Assert.assertFalse("INTERNAL_OBJECT should NOT be set for a VPLEX volume",
volume.checkInternalFlags(Flag.INTERNAL_OBJECT));
} else {
// This is one of the backend volumes.
Assert.assertTrue("INTERNAL_OBJECT should be set for a VPLEX backend volume",
volume.checkInternalFlags(Flag.INTERNAL_OBJECT));
}
}
}
/**
* Prepares the data for RP volume tests.
*
* @throws Exception When an error occurs preparing the RP volume data.
*/
private void prepareRPVolumeData() throws Exception {
Volume rpSourceVolume = new Volume();
URI rpSourceVolumeURI = URIUtil.createId(Volume.class);
rpTestVolumeURIs.add(rpSourceVolumeURI);
rpSourceVolume.setId(rpSourceVolumeURI);
rpSourceVolume.setLabel("rpSourceVolume");
rpSourceVolume.setPersonality(Volume.PersonalityTypes.SOURCE.toString());
_dbClient.createObject(rpSourceVolume);
Volume rpTargetVolume = new Volume();
URI rpTargetVolumeURI = URIUtil.createId(Volume.class);
rpTestVolumeURIs.add(rpTargetVolumeURI);
rpTargetVolume.setId(rpTargetVolumeURI);
rpTargetVolume.setLabel("rpTargetVolume");
rpTargetVolume.setPersonality(Volume.PersonalityTypes.TARGET.toString());
_dbClient.createObject(rpTargetVolume);
Volume rpSourceJournalVolume = new Volume();
URI rpSourceJournalVolumeURI = URIUtil.createId(Volume.class);
rpTestVolumeURIs.add(rpSourceJournalVolumeURI);
rpSourceJournalVolume.setId(rpSourceJournalVolumeURI);
rpSourceJournalVolume.setLabel("rpSourceJournalVolume");
rpSourceJournalVolume.setPersonality(Volume.PersonalityTypes.METADATA.toString());
_dbClient.createObject(rpSourceJournalVolume);
Volume rpTargetJournalVolume = new Volume();
URI rpTargetJournalVolumeURI = URIUtil.createId(Volume.class);
rpTestVolumeURIs.add(rpTargetJournalVolumeURI);
rpTargetJournalVolume.setId(rpTargetJournalVolumeURI);
rpTargetJournalVolume.setLabel("rpTargetJournalVolume");
rpTargetJournalVolume.setPersonality(Volume.PersonalityTypes.METADATA.toString());
_dbClient.createObject(rpTargetJournalVolume);
// Verify the rp volume data exists in the database.
for (URI volumeURI : rpTestVolumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
Assert.assertNotNull(String.format("rp test volume %s not found", volumeURI), volume);
}
}
/**
* Verifies the migration results for volumes.
*
* @throws Exception When an error occurs verifying the VPLEX volume
* migration results.
*/
private void verifyRPVolumeResults() throws Exception {
for (URI volumeURI : rpTestVolumeURIs) {
Volume volume = _dbClient.queryObject(Volume.class, volumeURI);
Assert.assertNotNull(String.format("rp test volume %s not found", volumeURI), volume);
if ((volume.getPersonality() != null)
&& !volume.getPersonality().equals(Volume.PersonalityTypes.METADATA.toString())) {
// This is not a RP Journal volume.
Assert.assertFalse("INTERNAL_OBJECT should NOT be set for a RP volume",
volume.checkInternalFlags(Flag.INTERNAL_OBJECT));
Assert.assertFalse("SUPPORTS_FORCE should NOT be set for a RP volume",
volume.checkInternalFlags(Flag.SUPPORTS_FORCE));
}
if ((volume.getPersonality() != null)
&& volume.getPersonality().equals(Volume.PersonalityTypes.METADATA.toString())) {
// This is a RP Journal volume.
Assert.assertTrue("INTERNAL_OBJECT should be set for a RP Journal volume",
volume.checkInternalFlags(Flag.INTERNAL_OBJECT));
Assert.assertTrue("SUPPORTS_FORCE should be set for a RP Journal volume",
volume.checkInternalFlags(Flag.SUPPORTS_FORCE));
}
}
}
}