From 0fcf12c25246cc2773082c44775107daaec2512e Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Fri, 27 Mar 2026 14:41:30 -0400 Subject: [PATCH] add tests --- .../volume/VolumeServiceImplClvmTest.java | 195 ++++++- .../kvm/storage/KVMStorageProcessor.java | 2 +- .../kvm/storage/KVMStorageProcessorTest.java | 548 ++++++++++++++++++ 3 files changed, 742 insertions(+), 3 deletions(-) diff --git a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java index 5725bd91ffb..c99193c7387 100644 --- a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java +++ b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/volume/VolumeServiceImplClvmTest.java @@ -17,11 +17,21 @@ package org.apache.cloudstack.storage.volume; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.when; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.storage.ClvmLockManager; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.dao.VMInstanceDao; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,6 +58,18 @@ public class VolumeServiceImplClvmTest { @Mock private VolumeDao volumeDao; + @Mock + private PrimaryDataStoreDao storagePoolDao; + + @Mock + private HostDao _hostDao; + + @Mock + private VMInstanceDao vmDao; + + @Mock + private VolumeDataFactory volFactory; + @Mock private VolumeInfo volumeInfoMock; @@ -55,7 +77,16 @@ public class VolumeServiceImplClvmTest { private VolumeVO volumeVOMock; @Mock - ClvmLockManager clvmLockManager; + private StoragePoolVO storagePoolVOMock; + + @Mock + private HostVO hostVOMock; + + @Mock + private VMInstanceVO vmInstanceVOMock; + + @Mock + private ClvmLockManager clvmLockManager; private static final Long VOLUME_ID = 1L; private static final Long POOL_ID_1 = 100L; @@ -63,12 +94,19 @@ public class VolumeServiceImplClvmTest { private static final Long HOST_ID_1 = 10L; private static final Long HOST_ID_2 = 20L; private static final String POOL_PATH_VG1 = "/vg1"; - private static final String POOL_PATH_VG2 = "/vg2"; @Before public void setup() { when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); when(volumeInfoMock.getUuid()).thenReturn("test-volume-uuid"); + + // Setup volumeService dependencies + volumeService.storagePoolDao = storagePoolDao; + volumeService._hostDao = _hostDao; + volumeService.vmDao = vmDao; + volumeService.volFactory = volFactory; + volumeService._volumeDao = volumeDao; + volumeService.clvmLockManager = clvmLockManager; } @Test @@ -308,4 +346,157 @@ public class VolumeServiceImplClvmTest { StoragePoolType.CLVM, StoragePoolType.CLVM, "/cloudstack-vg-01", "/cloudstack-vg-02")); } + + @Test + public void testTransferVolumeLock_Success() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); + when(volumeInfoMock.getPath()).thenReturn("/dev/vg1/volume-1"); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getName()).thenReturn("test-pool"); + when(clvmLockManager.transferClvmVolumeLock( + "test-volume-uuid", VOLUME_ID, "/dev/vg1/volume-1", storagePoolVOMock, HOST_ID_1, HOST_ID_2)) + .thenReturn(true); + + assertTrue(volumeService.transferVolumeLock(volumeInfoMock, HOST_ID_1, HOST_ID_2)); + } + + @Test + public void testTransferVolumeLock_Failure() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); + when(volumeInfoMock.getPath()).thenReturn("/dev/vg1/volume-1"); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getName()).thenReturn("test-pool"); + when(clvmLockManager.transferClvmVolumeLock( + "test-volume-uuid", VOLUME_ID, "/dev/vg1/volume-1", storagePoolVOMock, HOST_ID_1, HOST_ID_2)) + .thenReturn(false); + + assertFalse(volumeService.transferVolumeLock(volumeInfoMock, HOST_ID_1, HOST_ID_2)); + } + + @Test + public void testTransferVolumeLock_PoolNotFound() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(null); + + assertFalse(volumeService.transferVolumeLock(volumeInfoMock, HOST_ID_1, HOST_ID_2)); + } + + @Test + public void testFindVolumeLockHost_NullVolume() { + Long result = volumeService.findVolumeLockHost(null); + assertNull(result); + } + + @Test + public void testFindVolumeLockHost_ExplicitLockFound() { + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")) + .thenReturn(HOST_ID_1); + + Long result = volumeService.findVolumeLockHost(volumeInfoMock); + assertEquals(HOST_ID_1, result); + } + + @Test + public void testFindVolumeLockHost_FromAttachedVM() { + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")) + .thenReturn(null); + when(volumeInfoMock.getInstanceId()).thenReturn(100L); + when(vmDao.findById(100L)).thenReturn(vmInstanceVOMock); + when(vmInstanceVOMock.getUuid()).thenReturn("vm-uuid"); + when(vmInstanceVOMock.getHostId()).thenReturn(HOST_ID_1); + + Long result = volumeService.findVolumeLockHost(volumeInfoMock); + assertEquals(HOST_ID_1, result); + } + + @Test + public void testFindVolumeLockHost_FallbackToClusterHost() { + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")) + .thenReturn(null); + when(volumeInfoMock.getInstanceId()).thenReturn(null); + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getClusterId()).thenReturn(10L); + when(hostVOMock.getId()).thenReturn(HOST_ID_1); + when(hostVOMock.getStatus()).thenReturn(com.cloud.host.Status.Up); + when(_hostDao.findByClusterId(10L)).thenReturn(java.util.Collections.singletonList(hostVOMock)); + + Long result = volumeService.findVolumeLockHost(volumeInfoMock); + assertEquals(HOST_ID_1, result); + } + + @Test + public void testFindVolumeLockHost_NoHostFound() { + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")) + .thenReturn(null); + when(volumeInfoMock.getInstanceId()).thenReturn(null); + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getClusterId()).thenReturn(10L); + when(_hostDao.findByClusterId(10L)).thenReturn(java.util.Collections.emptyList()); + + Long result = volumeService.findVolumeLockHost(volumeInfoMock); + assertNull(result); + } + + @Test + public void testPerformLockMigration_Success() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); + when(volumeInfoMock.getPath()).thenReturn("/dev/vg1/volume-1"); + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")).thenReturn(HOST_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getName()).thenReturn("test-pool"); + when(clvmLockManager.transferClvmVolumeLock( + "test-volume-uuid", VOLUME_ID, "/dev/vg1/volume-1", storagePoolVOMock, HOST_ID_1, HOST_ID_2)) + .thenReturn(true); + when(volFactory.getVolume(VOLUME_ID)).thenReturn(volumeInfoMock); + + VolumeInfo result = volumeService.performLockMigration(volumeInfoMock, HOST_ID_2); + assertNotNull(result); + } + + @Test + public void testPerformLockMigration_SameHost() { + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")).thenReturn(HOST_ID_1); + + VolumeInfo result = volumeService.performLockMigration(volumeInfoMock, HOST_ID_1); + assertEquals(volumeInfoMock, result); + } + + @Test + public void testPerformLockMigration_SourceHostNull() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")).thenReturn(null); + when(volumeInfoMock.getInstanceId()).thenReturn(null); + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getClusterId()).thenReturn(null); + + VolumeInfo result = volumeService.performLockMigration(volumeInfoMock, HOST_ID_2); + assertNotNull(result); + } + + @Test(expected = com.cloud.utils.exception.CloudRuntimeException.class) + public void testPerformLockMigration_NullVolume() { + volumeService.performLockMigration(null, HOST_ID_2); + } + + @Test(expected = com.cloud.utils.exception.CloudRuntimeException.class) + public void testPerformLockMigration_TransferFails() { + when(volumeInfoMock.getPoolId()).thenReturn(POOL_ID_1); + when(volumeInfoMock.getId()).thenReturn(VOLUME_ID); + when(volumeInfoMock.getPath()).thenReturn("/dev/vg1/volume-1"); + when(clvmLockManager.getClvmLockHostId(VOLUME_ID, "test-volume-uuid")).thenReturn(HOST_ID_1); + when(storagePoolDao.findById(POOL_ID_1)).thenReturn(storagePoolVOMock); + when(storagePoolVOMock.getName()).thenReturn("test-pool"); + when(clvmLockManager.transferClvmVolumeLock( + "test-volume-uuid", VOLUME_ID, "/dev/vg1/volume-1", storagePoolVOMock, HOST_ID_1, HOST_ID_2)) + .thenReturn(false); + + volumeService.performLockMigration(volumeInfoMock, HOST_ID_2); + } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 59e598082a2..fc90c95f420 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -2442,7 +2442,7 @@ public class KVMStorageProcessor implements StorageProcessor { * @return SnapshotObjectTO if fallback to full snapshot occurred, null if validation passed * @throws LibvirtException if libvirt operations fail */ - private SnapshotObjectTO validateClvmNgBitmapAndFallbackIfNeeded(SnapshotObjectTO snapshotObjectTO, + protected SnapshotObjectTO validateClvmNgBitmapAndFallbackIfNeeded(SnapshotObjectTO snapshotObjectTO, KVMStoragePool primaryPool, KVMStoragePool secondaryPool, String secondaryPoolUrl, diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessorTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessorTest.java index cc1e38a908b..899309905e9 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessorTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessorTest.java @@ -22,6 +22,7 @@ import com.cloud.exception.InternalErrorException; import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser; import com.cloud.hypervisor.kvm.resource.LibvirtVMDef; +import com.cloud.storage.Storage; import com.cloud.storage.template.TemplateConstants; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; @@ -53,6 +54,7 @@ import org.mockito.junit.MockitoJUnitRunner; import javax.naming.ConfigurationException; import java.io.File; import java.io.IOException; +import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -499,4 +501,550 @@ public class KVMStorageProcessorTest { Assert.assertEquals("vda", result); } + + @Test + public void testIsBitmapUsable_ValidBitmap() { + String validJsonOutput = "{\n" + + " \"format-specific\": {\n" + + " \"data\": {\n" + + " \"bitmaps\": [\n" + + " {\n" + + " \"name\": \"checkpoint-123\",\n" + + " \"flags\": []\n" + + " }\n" + + " ]\n" + + " }\n" + + " }\n" + + "}"; + + try (MockedStatic