blob: ea1a221c8c0f5668cf4c288cebf5c9a1f3edd8db [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cloudstack.storage.motion;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.HashMap;
import java.util.Map;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.StrategyPriority;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.storage.datastore.PrimaryDataStoreImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.image.store.ImageStoreImpl;
import org.apache.cloudstack.storage.volume.VolumeObject;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.verification.VerificationMode;
import com.cloud.agent.api.MigrateCommand;
import com.cloud.host.HostVO;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.ImageStore;
import com.cloud.storage.ScopeType;
import com.cloud.storage.Storage;
import com.cloud.storage.Storage.StoragePoolType;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@RunWith(MockitoJUnitRunner.class)
public class StorageSystemDataMotionStrategyTest {
@Spy
@InjectMocks
private StorageSystemDataMotionStrategy strategy;
@Mock
private VolumeObject volumeObjectSource;
@Mock
private DataObject dataObjectDestination;
@Mock
private PrimaryDataStore sourceStore;
@Mock
private ImageStore destinationStore;
@Mock
private PrimaryDataStoreDao primaryDataStoreDao;
@Mock
StoragePoolVO sourceStoragePoolVoMock, destinationStoragePoolVoMock;
@Mock
Map<String, Storage.StoragePoolType> mapStringStoragePoolTypeMock;
List<ScopeType> scopeTypes = Arrays.asList(ScopeType.CLUSTER, ScopeType.ZONE);
@Before
public void setUp() throws Exception {
sourceStore = mock(PrimaryDataStoreImpl.class);
destinationStore = mock(ImageStoreImpl.class);
volumeObjectSource = mock(VolumeObject.class);
dataObjectDestination = mock(VolumeObject.class);
initMocks(strategy);
}
@Test
public void cantHandleSecondary() {
lenient().doReturn(sourceStore).when(volumeObjectSource).getDataStore();
doReturn(DataStoreRole.Primary).when(sourceStore).getRole();
lenient().doReturn(destinationStore).when(dataObjectDestination).getDataStore();
doReturn(DataStoreRole.Image).when((DataStore)destinationStore).getRole();
doReturn(sourceStore).when(volumeObjectSource).getDataStore();
doReturn(destinationStore).when(dataObjectDestination).getDataStore();
StoragePoolVO storeVO = new StoragePoolVO();
doReturn(storeVO).when(primaryDataStoreDao).findById(0l);
assertTrue(strategy.canHandle(volumeObjectSource, dataObjectDestination) == StrategyPriority.CANT_HANDLE);
}
@Test
public void internalCanHandleTestAllStoragePoolsAreManaged() {
configureAndTestInternalCanHandle(true, true, StrategyPriority.HIGHEST);
}
@Test
public void internalCanHandleTestFirstStoragePoolsIsManaged() {
configureAndTestInternalCanHandle(false, true, StrategyPriority.HIGHEST);
}
@Test
public void internalCanHandleTestSecondStoragePoolsIsManaged() {
configureAndTestInternalCanHandle(true, false, StrategyPriority.HIGHEST);
}
@Test
public void internalCanHandleTestNoStoragePoolsIsManaged() {
configureAndTestInternalCanHandle(false, false, StrategyPriority.CANT_HANDLE);
}
private void configureAndTestInternalCanHandle(boolean sPool0IsManaged, boolean sPool1IsManaged, StrategyPriority expectedStrategyPriority) {
VolumeObject volumeInfo = Mockito.spy(new VolumeObject());
Mockito.doReturn(0l).when(volumeInfo).getPoolId();
DataStore ds = Mockito.spy(new PrimaryDataStoreImpl());
Mockito.doReturn(1l).when(ds).getId();
Map<VolumeInfo, DataStore> volumeMap = new HashMap<>();
volumeMap.put(volumeInfo, ds);
StoragePoolVO storagePool0 = Mockito.spy(new StoragePoolVO());
Mockito.doReturn(sPool0IsManaged).when(storagePool0).isManaged();
StoragePoolVO storagePool1 = Mockito.spy(new StoragePoolVO());
Mockito.doReturn(sPool1IsManaged).when(storagePool1).isManaged();
Mockito.doReturn(storagePool0).when(primaryDataStoreDao).findById(0l);
Mockito.doReturn(storagePool1).when(primaryDataStoreDao).findById(1l);
StrategyPriority strategyPriority = strategy.internalCanHandle(volumeMap, new HostVO("srcHostUuid"), new HostVO("destHostUuid"));
Assert.assertEquals(expectedStrategyPriority, strategyPriority);
}
@Test
public void isStoragePoolTypeOfFileTest() {
StoragePoolVO sourceStoragePool = Mockito.spy(new StoragePoolVO());
StoragePoolType[] storagePoolTypeArray = StoragePoolType.values();
for (int i = 0; i < storagePoolTypeArray.length; i++) {
Mockito.doReturn(storagePoolTypeArray[i]).when(sourceStoragePool).getPoolType();
boolean result = strategy.isStoragePoolTypeOfFile(sourceStoragePool);
if (sourceStoragePool.getPoolType() == StoragePoolType.Filesystem) {
Assert.assertTrue(result);
} else {
Assert.assertFalse(result);
}
}
}
@Test
public void generateDestPathTest() {
VolumeObject destVolumeInfo = Mockito.spy(new VolumeObject());
HostVO destHost = new HostVO("guid");
Mockito.doReturn("iScsiName").when(destVolumeInfo).get_iScsiName();
Mockito.doReturn(0l).when(destVolumeInfo).getPoolId();
Mockito.doReturn("expected").when(strategy).connectHostToVolume(destHost, 0l, "iScsiName");
String expected = strategy.generateDestPath(destHost, Mockito.mock(StoragePoolVO.class), destVolumeInfo);
Assert.assertEquals(expected, "expected");
Mockito.verify(strategy).connectHostToVolume(destHost, 0l, "iScsiName");
}
@Test
public void configureMigrateDiskInfoTest() {
VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
MigrateCommand.MigrateDiskInfo migrateDiskInfo = strategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", null);
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.BLOCK, migrateDiskInfo.getDiskType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.RAW, migrateDiskInfo.getDriverType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.DEV, migrateDiskInfo.getSource());
Assert.assertEquals("destPath", migrateDiskInfo.getSourceText());
Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
}
@Test
public void configureMigrateDiskInfoWithBackingTest() {
VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
MigrateCommand.MigrateDiskInfo migrateDiskInfo = strategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", "backingPath");
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.BLOCK, migrateDiskInfo.getDiskType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.RAW, migrateDiskInfo.getDriverType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.DEV, migrateDiskInfo.getSource());
Assert.assertEquals("destPath", migrateDiskInfo.getSourceText());
Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
Assert.assertEquals("backingPath", migrateDiskInfo.getBackingStoreText());
}
@Test
public void setVolumePathTest() {
VolumeVO volume = new VolumeVO("name", 0l, 0l, 0l, 0l, 0l, "folder", "path", Storage.ProvisioningType.THIN, 0l, Volume.Type.ROOT);
String volumePath = "iScsiName";
volume.set_iScsiName(volumePath);
strategy.setVolumePath(volume);
Assert.assertEquals(volumePath, volume.getPath());
}
@Test
public void shouldMigrateVolumeTest() {
StoragePoolVO sourceStoragePool = Mockito.spy(new StoragePoolVO());
HostVO destHost = new HostVO("guid");
StoragePoolVO destStoragePool = new StoragePoolVO();
StoragePoolType[] storagePoolTypes = StoragePoolType.values();
for (int i = 0; i < storagePoolTypes.length; i++) {
Mockito.lenient().doReturn(storagePoolTypes[i]).when(sourceStoragePool).getPoolType();
boolean result = strategy.shouldMigrateVolume(sourceStoragePool, destHost, destStoragePool);
Assert.assertTrue(result);
}
}
@Test
public void isSourceAndDestinationPoolTypeOfNfsTestNfsNfs() {
configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(StoragePoolType.NetworkFilesystem, StoragePoolType.NetworkFilesystem, true);
}
@Test
public void isSourceAndDestinationPoolTypeOfNfsTestNfsAny() {
StoragePoolType[] storagePoolTypeArray = StoragePoolType.values();
for (int i = 0; i < storagePoolTypeArray.length - 1; i++) {
if (storagePoolTypeArray[i] != StoragePoolType.NetworkFilesystem) {
configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(StoragePoolType.NetworkFilesystem, storagePoolTypeArray[i], false);
}
}
}
@Test
public void isSourceAndDestinationPoolTypeOfNfsTestAnyNfs() {
StoragePoolType[] storagePoolTypeArray = StoragePoolType.values();
for (int i = 0; i < storagePoolTypeArray.length - 1; i++) {
if (storagePoolTypeArray[i] != StoragePoolType.NetworkFilesystem) {
configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(storagePoolTypeArray[i], StoragePoolType.NetworkFilesystem, false);
}
}
}
@Test
public void isSourceAndDestinationPoolTypeOfNfsTestAnyAny() {
StoragePoolType[] storagePoolTypeArray = StoragePoolType.values();
for (int i = 0; i < storagePoolTypeArray.length - 1; i++) {
for (int j = 0; j < storagePoolTypeArray.length - 1; j++) {
if (storagePoolTypeArray[i] != StoragePoolType.NetworkFilesystem || storagePoolTypeArray[j] != StoragePoolType.NetworkFilesystem) {
configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(storagePoolTypeArray[i], storagePoolTypeArray[j], false);
}
}
}
}
private void configureAndVerifyIsSourceAndDestinationPoolTypeOfNfs(StoragePoolType destStoragePoolType, StoragePoolType sourceStoragePoolType, boolean expected) {
VolumeInfo srcVolumeInfo = Mockito.mock(VolumeObject.class);
Mockito.lenient().when(srcVolumeInfo.getId()).thenReturn(0l);
DataStore destDataStore = Mockito.mock(PrimaryDataStoreImpl.class);
Mockito.when(destDataStore.getId()).thenReturn(1l);
StoragePoolVO destStoragePool = Mockito.mock(StoragePoolVO.class);
Mockito.when(destStoragePool.getPoolType()).thenReturn(destStoragePoolType);
StoragePoolVO sourceStoragePool = Mockito.mock(StoragePoolVO.class);
Mockito.when(sourceStoragePool.getPoolType()).thenReturn(sourceStoragePoolType);
Map<VolumeInfo, DataStore> volumeDataStoreMap = new HashMap<>();
volumeDataStoreMap.put(srcVolumeInfo, destDataStore);
Mockito.doReturn(sourceStoragePool).when(primaryDataStoreDao).findById(0l);
Mockito.doReturn(destStoragePool).when(primaryDataStoreDao).findById(1l);
boolean result = strategy.isSourceAndDestinationPoolTypeOfNfs(volumeDataStoreMap);
Assert.assertEquals(expected, result);
}
@Test
public void formatMigrationElementsAsJsonToDisplayOnLogValidateFormat(){
String objectName = "test";
Long object = 1L, from = 2L, to = 3L;
Assert.assertEquals(String.format("{%s: \"%s\", from: \"%s\", to:\"%s\"}", objectName, object, from, to), strategy.formatMigrationElementsAsJsonToDisplayOnLog(objectName,
object, from, to));
}
@Test
public void formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLogValidateFormat(){
Long volume = 1L, from = 2L, to = 3L;
VolumeInfo volumeInfo = Mockito.mock(VolumeInfo.class);
DataStore dataStore = Mockito.mock(DataStore.class);
Mockito.when(volumeInfo.getId()).thenReturn(volume);
Mockito.when(volumeInfo.getPoolId()).thenReturn(from);
Mockito.when(dataStore.getId()).thenReturn(to);
Assert.assertEquals(String.format("{volume: \"%s\", from: \"%s\", to:\"%s\"}", volume, from, to), strategy.formatEntryOfVolumesAndStoragesAsJsonToDisplayOnLog(new AbstractMap.SimpleEntry<>(volumeInfo, dataStore)));
}
@Test
public void validateSupportStoragePoolTypeDefaultValues() {
Set<StoragePoolType> supportedTypes = new HashSet<>();
supportedTypes.add(StoragePoolType.NetworkFilesystem);
supportedTypes.add(StoragePoolType.SharedMountPoint);
for (StoragePoolType poolType : StoragePoolType.values()) {
boolean isSupported = strategy.supportStoragePoolType(poolType);
if (supportedTypes.contains(poolType)) {
assertTrue(isSupported);
} else {
assertFalse(isSupported);
}
}
}
@Test
public void validateSupportStoragePoolTypeExtraValues() {
Set<StoragePoolType> supportedTypes = new HashSet<>();
supportedTypes.add(StoragePoolType.NetworkFilesystem);
supportedTypes.add(StoragePoolType.SharedMountPoint);
supportedTypes.add(StoragePoolType.Iscsi);
supportedTypes.add(StoragePoolType.CLVM);
for (StoragePoolType poolType : StoragePoolType.values()) {
boolean isSupported = strategy.supportStoragePoolType(poolType, StoragePoolType.Iscsi, StoragePoolType.CLVM);
if (supportedTypes.contains(poolType)) {
assertTrue(isSupported);
} else {
assertFalse(isSupported);
}
}
}
@Test
public void validateIsStoragePoolTypeInListReturnsTrue() {
StoragePoolType[] listTypes = new StoragePoolType[3];
listTypes[0] = StoragePoolType.LVM;
listTypes[1] = StoragePoolType.NetworkFilesystem;
listTypes[2] = StoragePoolType.SharedMountPoint;
assertTrue(strategy.isStoragePoolTypeInList(StoragePoolType.SharedMountPoint, listTypes));
}
@Test
public void validateIsStoragePoolTypeInListReturnsFalse() {
StoragePoolType[] listTypes = new StoragePoolType[3];
listTypes[0] = StoragePoolType.LVM;
listTypes[1] = StoragePoolType.NetworkFilesystem;
listTypes[2] = StoragePoolType.RBD;
assertFalse(strategy.isStoragePoolTypeInList(StoragePoolType.SharedMountPoint, listTypes));
}
@Test
public void validateAddSourcePoolToPoolsMapDestinationPoolIsManaged() {
Mockito.doReturn(true).when(destinationStoragePoolVoMock).isManaged();
strategy.addSourcePoolToPoolsMap(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
Mockito.verify(destinationStoragePoolVoMock).isManaged();
Mockito.verifyNoMoreInteractions(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
}
@Test
public void validateAddSourcePoolToPoolsMapDestinationPoolIsNotNFS() {
List<StoragePoolType> storagePoolTypes = new LinkedList<>(Arrays.asList(StoragePoolType.values()));
storagePoolTypes.remove(StoragePoolType.NetworkFilesystem);
Mockito.doReturn(false).when(destinationStoragePoolVoMock).isManaged();
storagePoolTypes.forEach(poolType -> {
Mockito.doReturn(poolType).when(destinationStoragePoolVoMock).getPoolType();
strategy.addSourcePoolToPoolsMap(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
});
VerificationMode times = Mockito.times(storagePoolTypes.size());
Mockito.verify(destinationStoragePoolVoMock, times).isManaged();
Mockito.verify(destinationStoragePoolVoMock, times).getPoolType();
Mockito.verifyNoMoreInteractions(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
}
@Test
public void validateAddSourcePoolToPoolsMapMapContainsKey() {
Mockito.doReturn(false).when(destinationStoragePoolVoMock).isManaged();
Mockito.doReturn(StoragePoolType.NetworkFilesystem).when(destinationStoragePoolVoMock).getPoolType();
Mockito.doReturn("").when(sourceStoragePoolVoMock).getUuid();
Mockito.doReturn(true).when(mapStringStoragePoolTypeMock).containsKey(Mockito.anyString());
strategy.addSourcePoolToPoolsMap(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
Mockito.verify(destinationStoragePoolVoMock, never()).getScope();
Mockito.verify(destinationStoragePoolVoMock).isManaged();
Mockito.verify(destinationStoragePoolVoMock).getPoolType();
Mockito.verify(sourceStoragePoolVoMock).getUuid();
Mockito.verify(mapStringStoragePoolTypeMock).containsKey(Mockito.anyString());
Mockito.verifyNoMoreInteractions(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
}
@Test
public void validateAddSourcePoolToPoolsMapMapDoesNotContainsKey() {
List<StoragePoolType> storagePoolTypes = new LinkedList<>(Arrays.asList(StoragePoolType.values()));
Mockito.doReturn(false).when(destinationStoragePoolVoMock).isManaged();
Mockito.doReturn(StoragePoolType.NetworkFilesystem).when(destinationStoragePoolVoMock).getPoolType();
Mockito.doReturn("").when(sourceStoragePoolVoMock).getUuid();
Mockito.doReturn(false).when(mapStringStoragePoolTypeMock).containsKey(Mockito.anyString());
Mockito.doReturn(null).when(mapStringStoragePoolTypeMock).put(Mockito.anyString(), Mockito.any());
storagePoolTypes.forEach(poolType -> {
Mockito.doReturn(poolType).when(sourceStoragePoolVoMock).getPoolType();
strategy.addSourcePoolToPoolsMap(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
});
VerificationMode times = Mockito.times(storagePoolTypes.size());
Mockito.verify(destinationStoragePoolVoMock, never()).getScope();
Mockito.verify(destinationStoragePoolVoMock, times).isManaged();
Mockito.verify(destinationStoragePoolVoMock, times).getPoolType();
Mockito.verify(sourceStoragePoolVoMock, times).getUuid();
Mockito.verify(mapStringStoragePoolTypeMock, times).containsKey(Mockito.anyString());
Mockito.verify(sourceStoragePoolVoMock, times).getPoolType();
Mockito.verify(mapStringStoragePoolTypeMock, times).put(Mockito.anyString(), Mockito.any());
Mockito.verifyNoMoreInteractions(mapStringStoragePoolTypeMock, sourceStoragePoolVoMock, destinationStoragePoolVoMock);
}
}