Skip to content

Commit 4c1548a

Browse files
committed
add unit tests
Signed-off-by: Abhishek Kumar <[email protected]>
1 parent da6af2f commit 4c1548a

File tree

2 files changed

+262
-12
lines changed

2 files changed

+262
-12
lines changed

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,22 +2407,23 @@ protected VolumeVO getVmExistingVolumeForVolumeAttach(UserVmVO vm, VolumeInfo vo
24072407
}
24082408
}
24092409
}
2410-
if (existingVolumeOfVm != null) {
2410+
if (existingVolumeOfVm == null) {
24112411
if (s_logger.isTraceEnabled()) {
2412-
String msg = "attaching volume %s/%s to a VM (%s/%s) with an existing volume %s/%s on primary storage %s";
2413-
s_logger.trace(String.format(msg,
2414-
volumeToAttach.getName(), volumeToAttach.getUuid(),
2412+
s_logger.trace(String.format("No existing volume found for VM (%s/%s) to attach volume %s/%s",
24152413
vm.getName(), vm.getUuid(),
2416-
existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(),
2417-
existingVolumeOfVm.getPoolId()));
2414+
volumeToAttach.getName(), volumeToAttach.getUuid()));
24182415
}
2416+
return null;
24192417
}
24202418
if (s_logger.isTraceEnabled()) {
2421-
s_logger.trace(String.format("No existing volume found for VM (%s/%s) to attach volume %s/%s",
2419+
String msg = "attaching volume %s/%s to a VM (%s/%s) with an existing volume %s/%s on primary storage %s";
2420+
s_logger.trace(String.format(msg,
2421+
volumeToAttach.getName(), volumeToAttach.getUuid(),
24222422
vm.getName(), vm.getUuid(),
2423-
volumeToAttach.getName(), volumeToAttach.getUuid()));
2423+
existingVolumeOfVm.getName(), existingVolumeOfVm.getUuid(),
2424+
existingVolumeOfVm.getPoolId()));
24242425
}
2425-
return null;
2426+
return existingVolumeOfVm;
24262427
}
24272428

24282429
protected StoragePool getPoolForAllocatedOrUploadedVolumeForAttach(final VolumeInfo volumeToAttach, final UserVmVO vm) {
@@ -2448,7 +2449,7 @@ protected StoragePool getPoolForAllocatedOrUploadedVolumeForAttach(final VolumeI
24482449
return pool;
24492450
}
24502451

2451-
protected VolumeInfo createVolumeOnSecondaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) {
2452+
protected VolumeInfo createVolumeOnPrimaryForAttachIfNeeded(final VolumeInfo volumeToAttach, final UserVmVO vm, VolumeVO existingVolumeOfVm) {
24522453
VolumeInfo newVolumeOnPrimaryStorage = volumeToAttach;
24532454
boolean volumeOnSecondary = volumeToAttach.getState() == Volume.State.Uploaded;
24542455
if (!Arrays.asList(Volume.State.Allocated, Volume.State.Uploaded).contains(volumeToAttach.getState())) {
@@ -2466,7 +2467,7 @@ protected VolumeInfo createVolumeOnSecondaryForAttachIfNeeded(final VolumeInfo v
24662467
destPrimaryStorage = getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
24672468
}
24682469
try {
2469-
if (volumeOnSecondary && destPrimaryStorage.getPoolType() == Storage.StoragePoolType.PowerFlex) {
2470+
if (volumeOnSecondary && Storage.StoragePoolType.PowerFlex.equals(destPrimaryStorage.getPoolType())) {
24702471
throw new InvalidParameterValueException("Cannot attach uploaded volume, this operation is unsupported on storage pool type " + destPrimaryStorage.getPoolType());
24712472
}
24722473
newVolumeOnPrimaryStorage = _volumeMgr.createVolumeOnPrimaryStorage(vm, volumeToAttach,
@@ -2487,7 +2488,7 @@ private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long device
24872488

24882489
UserVmVO vm = _userVmDao.findById(vmId);
24892490
VolumeVO existingVolumeOfVm = getVmExistingVolumeForVolumeAttach(vm, volumeToAttach);
2490-
VolumeInfo newVolumeOnPrimaryStorage = createVolumeOnSecondaryForAttachIfNeeded(volumeToAttach, vm, existingVolumeOfVm);
2491+
VolumeInfo newVolumeOnPrimaryStorage = createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, existingVolumeOfVm);
24912492

24922493
// reload the volume from db
24932494
newVolumeOnPrimaryStorage = volFactory.getVolume(newVolumeOnPrimaryStorage.getId());

server/src/test/java/com/cloud/storage/VolumeApiServiceImplTest.java

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
4646
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
4747
import org.apache.cloudstack.context.CallContext;
48+
import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
4849
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
4950
import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
5051
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStore;
@@ -86,8 +87,12 @@
8687
import com.cloud.api.query.dao.ServiceOfferingJoinDao;
8788
import com.cloud.configuration.Resource;
8889
import com.cloud.configuration.Resource.ResourceType;
90+
import com.cloud.dc.ClusterVO;
8991
import com.cloud.dc.DataCenterVO;
92+
import com.cloud.dc.HostPodVO;
93+
import com.cloud.dc.dao.ClusterDao;
9094
import com.cloud.dc.dao.DataCenterDao;
95+
import com.cloud.dc.dao.HostPodDao;
9196
import com.cloud.event.EventTypes;
9297
import com.cloud.event.UsageEventUtils;
9398
import com.cloud.exception.InvalidParameterValueException;
@@ -122,10 +127,12 @@
122127
import com.cloud.utils.db.TransactionLegacy;
123128
import com.cloud.utils.exception.CloudRuntimeException;
124129
import com.cloud.utils.fsm.NoTransitionException;
130+
import com.cloud.vm.DiskProfile;
125131
import com.cloud.vm.UserVmManager;
126132
import com.cloud.vm.UserVmVO;
127133
import com.cloud.vm.VirtualMachine;
128134
import com.cloud.vm.VirtualMachine.State;
135+
import com.cloud.vm.VirtualMachineManager;
129136
import com.cloud.vm.dao.UserVmDao;
130137
import com.cloud.vm.dao.VMInstanceDao;
131138
import com.cloud.vm.snapshot.VMSnapshotVO;
@@ -199,6 +206,15 @@ public class VolumeApiServiceImplTest {
199206
private DataStoreManager dataStoreMgr;
200207
@Mock
201208
private SnapshotHelper snapshotHelper;
209+
@Mock
210+
VirtualMachineManager virtualMachineManager;
211+
@Mock
212+
HostPodDao podDao;
213+
@Mock
214+
ClusterDao clusterDao;
215+
@Mock
216+
VolumeOrchestrationService volumeOrchestrationService;
217+
202218

203219
private DetachVolumeCmd detachCmd = new DetachVolumeCmd();
204220
private Class<?> _detachCmdClass = detachCmd.getClass();
@@ -1820,4 +1836,237 @@ public void testValidationsForCheckVolumeAPIWithInvalidVolumeFormat() {
18201836

18211837
volumeApiServiceImpl.validationsForCheckVolumeOperation(volume);
18221838
}
1839+
1840+
private UserVmVO getMockedVm() {
1841+
UserVmVO vm = Mockito.mock(UserVmVO.class);
1842+
Mockito.when(vm.getId()).thenReturn(1L);
1843+
Mockito.when(vm.getTemplateId()).thenReturn(10L);
1844+
Mockito.when(vm.getHostName()).thenReturn("test-vm");
1845+
return vm;
1846+
}
1847+
1848+
private VMTemplateVO getMockedTemplate() {
1849+
VMTemplateVO template = Mockito.mock(VMTemplateVO.class);
1850+
Mockito.when(template.isDeployAsIs()).thenReturn(false);
1851+
return template;
1852+
}
1853+
1854+
@Test(expected = CloudRuntimeException.class)
1855+
public void testGetVmExistingVolumeForVolumeAttach_MultipleRootVolumes_ThrowsException() {
1856+
UserVmVO vm = getMockedVm();
1857+
VMTemplateVO template = getMockedTemplate();
1858+
when(templateDao.findById(10L)).thenReturn(template);
1859+
when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT))
1860+
.thenReturn(Arrays.asList(Mockito.mock(VolumeVO.class), Mockito.mock(VolumeVO.class)));
1861+
volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class));
1862+
}
1863+
1864+
@Test
1865+
public void testGetVmExistingVolumeForVolumeAttach_SingleRootVolume() {
1866+
UserVmVO vm = getMockedVm();
1867+
VMTemplateVO template = getMockedTemplate();
1868+
VolumeVO rootVolume = Mockito.mock(VolumeVO.class);
1869+
Mockito.when(rootVolume.getId()).thenReturn(20L);
1870+
Mockito.when(templateDao.findById(10L)).thenReturn(template);
1871+
Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT))
1872+
.thenReturn(Collections.singletonList(rootVolume));
1873+
VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class));
1874+
Assert.assertNotNull(result);
1875+
Assert.assertEquals(20L, result.getId());
1876+
}
1877+
1878+
private VolumeVO getMockedDataVolume() {
1879+
VolumeVO volume = Mockito.mock(VolumeVO.class);
1880+
Mockito.when(volume.getId()).thenReturn(30L);
1881+
Mockito.when(volume.getState()).thenReturn(Volume.State.Ready);
1882+
return volume;
1883+
}
1884+
1885+
@Test
1886+
public void testGetVmExistingVolumeForVolumeAttach_NoRootVolume_DataDiskAvailable() {
1887+
UserVmVO vm = getMockedVm();
1888+
VMTemplateVO template = getMockedTemplate();
1889+
VolumeVO dataDisk = getMockedDataVolume();
1890+
List<VolumeVO> rootVolumes = Collections.emptyList();
1891+
List<VolumeVO> dataVolumes = Collections.singletonList(dataDisk);
1892+
Mockito.when(templateDao.findById(10L)).thenReturn(template);
1893+
Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)).thenReturn(rootVolumes);
1894+
Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.DATADISK)).thenReturn(dataVolumes);
1895+
VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class));
1896+
Assert.assertNotNull(result);
1897+
Assert.assertEquals(30L, result.getId());
1898+
}
1899+
1900+
@Test
1901+
public void testGetVmExistingVolumeForVolumeAttach_NoVolumesAtAll() {
1902+
UserVmVO vm = getMockedVm();
1903+
VMTemplateVO template = getMockedTemplate();
1904+
Mockito.when(templateDao.findById(10L)).thenReturn(template);
1905+
Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.ROOT)).thenReturn(Collections.emptyList());
1906+
Mockito.when(volumeDaoMock.findByInstanceAndType(1L, Volume.Type.DATADISK)).thenReturn(Collections.emptyList());
1907+
VolumeVO result = volumeApiServiceImpl.getVmExistingVolumeForVolumeAttach(vm, Mockito.mock(VolumeInfo.class));
1908+
Assert.assertNull(result);
1909+
}
1910+
1911+
private void mockDiskOffering() {
1912+
DiskOfferingVO offering = Mockito.mock(DiskOfferingVO.class);
1913+
Mockito.when(_diskOfferingDao.findById(1L)).thenReturn(offering);
1914+
Mockito.when(offering.isUseLocalStorage()).thenReturn(true);
1915+
Mockito.when(offering.isRecreatable()).thenReturn(false);
1916+
}
1917+
1918+
private DataCenterVO mockZone() {
1919+
DataCenterVO zone = Mockito.mock(DataCenterVO.class);
1920+
Mockito.when(_dcDao.findById(1L)).thenReturn(zone);
1921+
return zone;
1922+
}
1923+
1924+
@Test
1925+
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_Success() {
1926+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
1927+
UserVmVO vm = Mockito.mock(UserVmVO.class);
1928+
ClusterVO cluster = Mockito.mock(ClusterVO.class);
1929+
HostPodVO pod = Mockito.mock(HostPodVO.class);
1930+
DataCenterVO zone = mockZone();
1931+
mockDiskOffering();
1932+
StoragePool pool = Mockito.mock(StoragePool.class);
1933+
when(vm.getDataCenterId()).thenReturn(1L);
1934+
when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(1L, 2L));
1935+
when(clusterDao.findById(1L)).thenReturn(cluster);
1936+
when(cluster.getPodId()).thenReturn(1L);
1937+
when(podDao.findById(1L)).thenReturn(pod);
1938+
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
1939+
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
1940+
.thenReturn(pool);
1941+
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
1942+
Assert.assertNotNull(result);
1943+
Assert.assertEquals(pool, result);
1944+
}
1945+
1946+
@Test(expected = CloudRuntimeException.class)
1947+
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoPoolFound_ThrowsException() {
1948+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
1949+
UserVmVO vm = Mockito.mock(UserVmVO.class);
1950+
DataCenterVO zone = mockZone();
1951+
Pair<Long, Long> clusterHostId = new Pair<>(1L, 2L);
1952+
ClusterVO cluster = Mockito.mock(ClusterVO.class);
1953+
HostPodVO pod = Mockito.mock(HostPodVO.class);
1954+
mockDiskOffering();
1955+
when(vm.getDataCenterId()).thenReturn(1L);
1956+
when(clusterDao.findById(1L)).thenReturn(cluster);
1957+
when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(clusterHostId);
1958+
when(podDao.findById(anyLong())).thenReturn(pod);
1959+
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
1960+
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(1L), eq(2L), eq(vm), eq(Collections.emptySet())))
1961+
.thenReturn(null);
1962+
volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
1963+
}
1964+
1965+
@Test
1966+
public void testGetPoolForAllocatedOrUploadedVolumeForAttach_NoCluster() {
1967+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
1968+
UserVmVO vm = Mockito.mock(UserVmVO.class);
1969+
DataCenterVO zone = mockZone();
1970+
HostPodVO pod = Mockito.mock(HostPodVO.class);
1971+
mockDiskOffering();
1972+
StoragePool pool = Mockito.mock(StoragePool.class);
1973+
when(vm.getDataCenterId()).thenReturn(1L);
1974+
when(vm.getPodIdToDeployIn()).thenReturn(2L);
1975+
when(virtualMachineManager.findClusterAndHostIdForVm(vm, false)).thenReturn(new Pair<>(null, 2L));
1976+
when(podDao.findById(2L)).thenReturn(pod);
1977+
when(volumeToAttach.getDiskOfferingId()).thenReturn(1L);
1978+
when(volumeOrchestrationService.findStoragePool(any(DiskProfile.class), eq(zone), eq(pod), eq(null), eq(2L), eq(vm), eq(Collections.emptySet())))
1979+
.thenReturn(pool);
1980+
StoragePool result = volumeApiServiceImpl.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
1981+
Assert.assertNotNull(result);
1982+
Assert.assertEquals(pool, result);
1983+
}
1984+
1985+
1986+
@Test
1987+
public void testCreateVolumeOnSecondaryForAttachIfNeeded_VolumeNotAllocatedOrUploaded() {
1988+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
1989+
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Ready);
1990+
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(
1991+
volumeToAttach, Mockito.mock(UserVmVO.class), null);
1992+
Assert.assertSame(volumeToAttach, result);
1993+
Mockito.verifyNoInteractions(primaryDataStoreDaoMock, volumeOrchestrationService);
1994+
}
1995+
1996+
@Test
1997+
public void testCreateVolumeOnSecondaryForAttachIfNeeded_ExistingVolumeDeterminesStoragePool() {
1998+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
1999+
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
2000+
UserVmVO vm = Mockito.mock(UserVmVO.class);
2001+
VolumeVO existingVolume = Mockito.mock(VolumeVO.class);
2002+
Mockito.when(existingVolume.getState()).thenReturn(Volume.State.Ready);
2003+
when(existingVolume.getPoolId()).thenReturn(1L);
2004+
StoragePoolVO destPrimaryStorage = Mockito.mock(StoragePoolVO.class);
2005+
Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
2006+
Mockito.when(primaryDataStoreDaoMock.findById(1L)).thenReturn(destPrimaryStorage);
2007+
VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class);
2008+
try {
2009+
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage))
2010+
.thenReturn(newVolumeOnPrimaryStorage);
2011+
} catch (NoTransitionException nte) {
2012+
Assert.fail(nte.getMessage());
2013+
}
2014+
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, existingVolume);
2015+
Assert.assertSame(newVolumeOnPrimaryStorage, result);
2016+
Mockito.verify(primaryDataStoreDaoMock).findById(1L);
2017+
}
2018+
2019+
@Test
2020+
public void testCreateVolumeOnPrimaryForAttachIfNeeded_UsesGetPoolForAttach() {
2021+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
2022+
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Allocated);
2023+
UserVmVO vm = Mockito.mock(UserVmVO.class);
2024+
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
2025+
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
2026+
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
2027+
VolumeInfo newVolumeOnPrimaryStorage = Mockito.mock(VolumeInfo.class);
2028+
try {
2029+
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(
2030+
vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage))
2031+
.thenReturn(newVolumeOnPrimaryStorage);
2032+
} catch (NoTransitionException nte) {
2033+
Assert.fail(nte.getMessage());
2034+
}
2035+
VolumeInfo result = volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
2036+
Assert.assertSame(newVolumeOnPrimaryStorage, result);
2037+
verify(volumeApiServiceImpl).getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
2038+
}
2039+
2040+
@Test(expected = InvalidParameterValueException.class)
2041+
public void testCreateVolumeOnPrimaryForAttachIfNeeded_UnsupportedPoolType_ThrowsException() {
2042+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
2043+
when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
2044+
UserVmVO vm = Mockito.mock(UserVmVO.class);
2045+
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
2046+
when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.PowerFlex);
2047+
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
2048+
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
2049+
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null);
2050+
}
2051+
2052+
@Test
2053+
public void testCreateVolumeOnSecondaryForAttachIfNeeded_CreateVolumeFails_ThrowsException() {
2054+
VolumeInfo volumeToAttach = Mockito.mock(VolumeInfo.class);
2055+
Mockito.when(volumeToAttach.getState()).thenReturn(Volume.State.Uploaded);
2056+
UserVmVO vm = Mockito.mock(UserVmVO.class);
2057+
StoragePool destPrimaryStorage = Mockito.mock(StoragePool.class);
2058+
Mockito.when(destPrimaryStorage.getPoolType()).thenReturn(Storage.StoragePoolType.NetworkFilesystem);
2059+
Mockito.doReturn(destPrimaryStorage).when(volumeApiServiceImpl)
2060+
.getPoolForAllocatedOrUploadedVolumeForAttach(volumeToAttach, vm);
2061+
try {
2062+
Mockito.when(volumeOrchestrationService.createVolumeOnPrimaryStorage(vm, volumeToAttach, vm.getHypervisorType(), destPrimaryStorage))
2063+
.thenThrow(new NoTransitionException("Mocked exception"));
2064+
} catch (NoTransitionException nte) {
2065+
Assert.fail(nte.getMessage());
2066+
}
2067+
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class, () ->
2068+
volumeApiServiceImpl.createVolumeOnPrimaryForAttachIfNeeded(volumeToAttach, vm, null)
2069+
);
2070+
Assert.assertTrue(exception.getMessage().contains("Failed to create volume on primary storage"));
2071+
}
18232072
}

0 commit comments

Comments
 (0)