Added unit tests

This commit is contained in:
Harikrishna Patnala 2024-01-30 13:05:54 +05:30
parent 4898bbe30b
commit 702aa801c9
7 changed files with 343 additions and 4 deletions

View File

@ -201,7 +201,7 @@ public class VolumeServiceImpl implements VolumeService {
@Inject
private VolumeOrchestrationService _volumeMgr;
@Inject
private StorageManager _storageMgr;
protected StorageManager _storageMgr;
@Inject
private AnnotationDao annotationDao;
@Inject

View File

@ -19,14 +19,24 @@
package org.apache.cloudstack.storage.volume;
import com.cloud.agent.api.storage.CheckVolumeAndRepairAnswer;
import com.cloud.agent.api.storage.CheckVolumeAndRepairCommand;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.exception.StorageUnavailableException;
import com.cloud.storage.CheckAndRepairVolumePayload;
import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool;
import com.cloud.storage.Storage;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.storage.snapshot.SnapshotManager;
import com.cloud.utils.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import junit.framework.TestCase;
import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
@ -66,6 +76,9 @@ public class VolumeServiceTest extends TestCase{
@Mock
SnapshotManager snapshotManagerMock;
@Mock
StorageManager storageManagerMock;
@Mock
VolumeVO volumeVoMock;
@ -75,6 +88,7 @@ public class VolumeServiceTest extends TestCase{
volumeServiceImplSpy.volFactory = volumeDataFactoryMock;
volumeServiceImplSpy.volDao = volumeDaoMock;
volumeServiceImplSpy.snapshotMgr = snapshotManagerMock;
volumeServiceImplSpy._storageMgr = storageManagerMock;
}
@Test(expected = InterruptedException.class)
@ -213,4 +227,63 @@ public class VolumeServiceTest extends TestCase{
volumeServiceImplSpy.destroySourceVolumeAfterMigration(ObjectInDataStoreStateMachine.Event.DestroyRequested, null, volumeObject,
volumeObject, true);
}
@Test
public void testCheckAndRepairVolume() throws StorageUnavailableException {
VolumeInfo volume = Mockito.mock(VolumeInfo.class);
Mockito.when(volume.getPoolId()).thenReturn(1L);
StoragePool pool = Mockito.mock(StoragePool.class);
Mockito.when(storageManagerMock.getStoragePool(1L)).thenReturn(pool);
CheckAndRepairVolumePayload payload = new CheckAndRepairVolumePayload(false);
Mockito.when(volume.getpayload()).thenReturn(payload);
Mockito.when(volume.getPath()).thenReturn("cbac516a-0f1f-4559-921c-1a7c6c408ccf");
Mockito.when(volume.getPassphrase()).thenReturn(new byte[] {3, 1, 2, 3});
Mockito.when(volume.getEncryptFormat()).thenReturn("LUKS");
String checkResult = "{\n" +
" \"image-end-offset\": 6442582016,\n" +
" \"total-clusters\": 163840,\n" +
" \"check-errors\": 0,\n" +
" \"leaks\": 124,\n" +
" \"allocated-clusters\": 98154,\n" +
" \"filename\": \"/var/lib/libvirt/images/26be20c7-b9d0-43f6-a76e-16c70737a0e0\",\n" +
" \"format\": \"qcow2\",\n" +
" \"fragmented-clusters\": 96135\n" +
"}";
CheckVolumeAndRepairCommand command = new CheckVolumeAndRepairCommand(volume.getPath(), new StorageFilerTO(pool), payload.isRepair(),
volume.getPassphrase(), volume.getEncryptFormat());
CheckVolumeAndRepairAnswer answer = new CheckVolumeAndRepairAnswer(command, true, checkResult);
answer.setVolumeCheckExecutionResult(checkResult);
Mockito.when(storageManagerMock.sendToPool(pool, null, command)).thenReturn(answer);
Pair<String, String> result = volumeServiceImplSpy.checkAndRepairVolume(volume);
Assert.assertEquals(result.first(), checkResult);
Assert.assertEquals(result.second(), null);
}
@Test
public void testCheckAndRepairVolumeWhenFailure() throws StorageUnavailableException {
VolumeInfo volume = Mockito.mock(VolumeInfo.class);
Mockito.when(volume.getPoolId()).thenReturn(1L);
StoragePool pool = Mockito.mock(StoragePool.class);
Mockito.when(storageManagerMock.getStoragePool(1L)).thenReturn(pool);
CheckAndRepairVolumePayload payload = new CheckAndRepairVolumePayload(false);
Mockito.when(volume.getpayload()).thenReturn(payload);
Mockito.when(volume.getPath()).thenReturn("cbac516a-0f1f-4559-921c-1a7c6c408ccf");
Mockito.when(volume.getPassphrase()).thenReturn(new byte[] {3, 1, 2, 3});
Mockito.when(volume.getEncryptFormat()).thenReturn("LUKS");
CheckVolumeAndRepairCommand command = new CheckVolumeAndRepairCommand(volume.getPath(), new StorageFilerTO(pool), payload.isRepair(),
volume.getPassphrase(), volume.getEncryptFormat());
CheckVolumeAndRepairAnswer answer = new CheckVolumeAndRepairAnswer(command, false, "Unable to execute qemu command");
Mockito.when(storageManagerMock.sendToPool(pool, null, command)).thenReturn(answer);
Pair<String, String> result = volumeServiceImplSpy.checkAndRepairVolume(volume);
Assert.assertEquals(null, result);
}
}

View File

@ -47,7 +47,7 @@ import java.util.Arrays;
import java.util.List;
@ResourceWrapper(handles = CheckVolumeAndRepairCommand.class)
public final class LibvirtCheckVolumeAndRepairCommandWrapper extends CommandWrapper<CheckVolumeAndRepairCommand, Answer, LibvirtComputingResource> {
public class LibvirtCheckVolumeAndRepairCommandWrapper extends CommandWrapper<CheckVolumeAndRepairCommand, Answer, LibvirtComputingResource> {
private static final Logger s_logger = Logger.getLogger(LibvirtCheckVolumeAndRepairCommandWrapper.class);
@ -87,7 +87,7 @@ public final class LibvirtCheckVolumeAndRepairCommandWrapper extends CommandWrap
}
}
private String checkVolumeAndRepair(final KVMPhysicalDisk vol, final boolean repair, final QemuObject.EncryptFormat encryptFormat, byte[] passphrase, final LibvirtComputingResource libvirtComputingResource) throws CloudRuntimeException {
protected String checkVolumeAndRepair(final KVMPhysicalDisk vol, final boolean repair, final QemuObject.EncryptFormat encryptFormat, byte[] passphrase, final LibvirtComputingResource libvirtComputingResource) throws CloudRuntimeException {
List<QemuObject> passphraseObjects = new ArrayList<>();
QemuImageOptions imgOptions = null;
if (ArrayUtils.isEmpty(passphrase)) {

View File

@ -0,0 +1,103 @@
/*
* Licensed 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 com.cloud.hypervisor.kvm.resource.wrapper;
import com.cloud.agent.api.storage.CheckVolumeAndRepairAnswer;
import com.cloud.agent.api.storage.CheckVolumeAndRepairCommand;
import com.cloud.agent.api.to.StorageFilerTO;
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
import com.cloud.storage.Storage;
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
import org.apache.cloudstack.utils.qemu.QemuImg;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@RunWith(PowerMockRunner.class)
public class LibvirtCheckVolumeAndRepairCommandWrapperTest {
@Spy
LibvirtCheckVolumeAndRepairCommandWrapper libvirtCheckVolumeAndRepairCommandWrapperSpy = Mockito.spy(LibvirtCheckVolumeAndRepairCommandWrapper.class);
@Mock
LibvirtComputingResource libvirtComputingResourceMock;
@Mock
CheckVolumeAndRepairCommand checkVolumeAndRepairCommand;
@Mock
QemuImg qemuImgMock;
@Before
public void init() {
Mockito.when(libvirtComputingResourceMock.getCmdsTimeout()).thenReturn(60);
}
@Test
@PrepareForTest(LibvirtCheckVolumeAndRepairCommandWrapper.class)
public void testCheckAndRepairVolume() throws Exception {
CheckVolumeAndRepairCommand cmd = Mockito.mock(CheckVolumeAndRepairCommand.class);
Mockito.when(cmd.getPath()).thenReturn("cbac516a-0f1f-4559-921c-1a7c6c408ccf");
Mockito.when(cmd.needRepair()).thenReturn(false);
StorageFilerTO spool = Mockito.mock(StorageFilerTO.class);
Mockito.when(cmd.getPool()).thenReturn(spool);
KVMStoragePoolManager storagePoolMgr = Mockito.mock(KVMStoragePoolManager.class);
Mockito.when(libvirtComputingResourceMock.getStoragePoolMgr()).thenReturn(storagePoolMgr);
KVMStoragePool pool = Mockito.mock(KVMStoragePool.class);
Mockito.when(spool.getType()).thenReturn(Storage.StoragePoolType.PowerFlex);
Mockito.when(spool.getUuid()).thenReturn("b6be258b-42b8-49a4-ad51-3634ef8ff76a");
Mockito.when(storagePoolMgr.getStoragePool(Storage.StoragePoolType.PowerFlex, "b6be258b-42b8-49a4-ad51-3634ef8ff76a")).thenReturn(pool);
Mockito.when(pool.connectPhysicalDisk("cbac516a-0f1f-4559-921c-1a7c6c408ccf", null)).thenReturn(true);
KVMPhysicalDisk vol = Mockito.mock(KVMPhysicalDisk.class);
Mockito.when(pool.getPhysicalDisk("cbac516a-0f1f-4559-921c-1a7c6c408ccf")).thenReturn(vol);
VolumeInfo volume = Mockito.mock(VolumeInfo.class);
Mockito.when(volume.getPoolId()).thenReturn(1L);
Mockito.when(volume.getPath()).thenReturn("cbac516a-0f1f-4559-921c-1a7c6c408ccf");
String checkResult = "{\n" +
" \"image-end-offset\": 6442582016,\n" +
" \"total-clusters\": 163840,\n" +
" \"check-errors\": 0,\n" +
" \"leaks\": 124,\n" +
" \"allocated-clusters\": 98154,\n" +
" \"filename\": \"/var/lib/libvirt/images/26be20c7-b9d0-43f6-a76e-16c70737a0e0\",\n" +
" \"format\": \"qcow2\",\n" +
" \"fragmented-clusters\": 96135\n" +
"}";
PowerMockito.whenNew(QemuImg.class).withArguments(Mockito.anyInt()).thenReturn(qemuImgMock);
Mockito.when(qemuImgMock.checkAndRepair(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean())).thenReturn(checkResult); // Replace with the desired result
CheckVolumeAndRepairAnswer result = (CheckVolumeAndRepairAnswer) libvirtCheckVolumeAndRepairCommandWrapperSpy.execute(cmd, libvirtComputingResourceMock);
Assert.assertEquals(checkResult, result.getVolumeCheckExecutionResult());
}
}

View File

@ -368,4 +368,21 @@ public class QemuImgTest {
Assert.assertTrue("should support qcow2", QemuImg.helpSupportsImageFormat(partialHelp, PhysicalDiskFormat.QCOW2));
Assert.assertFalse("should not support http", QemuImg.helpSupportsImageFormat(partialHelp, PhysicalDiskFormat.SHEEPDOG));
}
@Test
public void testCheckAndRepair() throws LibvirtException {
String filename = "/tmp/" + UUID.randomUUID() + ".qcow2";
QemuImgFile file = new QemuImgFile(filename);
try {
QemuImg qemu = new QemuImg(0);
qemu.checkAndRepair(file, null, null, false);
} catch (QemuImgException e) {
fail(e.getMessage());
}
File f = new File(filename);
f.delete();
}
}

View File

@ -1887,7 +1887,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
}
}
private void validationsForCheckVolumeOperation(long volumeId) {
protected void validationsForCheckVolumeOperation(long volumeId) {
final VolumeVO volume = _volsDao.findById(volumeId);
Account caller = CallContext.current().getCallingAccount();
_accountMgr.checkAccess(caller, null, true, volume);

View File

@ -25,6 +25,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ -39,6 +40,7 @@ import java.util.concurrent.ExecutionException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.user.volume.CheckVolumeAndRepairCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
@ -1660,4 +1662,148 @@ public class VolumeApiServiceImplTest {
// test passed
}
}
@Test
public void testValidationsForCheckVolumeAPI() {
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(1L);
UserVmVO vm = mock(UserVmVO.class);
when(userVmDaoMock.findById(1L)).thenReturn(vm);
when(vm.getState()).thenReturn(State.Stopped);
when(volume.getState()).thenReturn(Volume.State.Ready);
when(volume.getId()).thenReturn(1L);
when(volumeDaoMock.getHypervisorType(1L)).thenReturn(HypervisorType.KVM);
volumeApiServiceImpl.validationsForCheckVolumeOperation(1L);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidationsForCheckVolumeAPIWithRunningVM() {
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(1L);
UserVmVO vm = mock(UserVmVO.class);
when(userVmDaoMock.findById(1L)).thenReturn(vm);
when(vm.getState()).thenReturn(State.Running);
volumeApiServiceImpl.validationsForCheckVolumeOperation(1L);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidationsForCheckVolumeAPIWithNonexistedVM() {
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(1L);
when(userVmDaoMock.findById(1L)).thenReturn(null);
volumeApiServiceImpl.validationsForCheckVolumeOperation(1L);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidationsForCheckVolumeAPIWithAllocatedVolume() {
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(1L);
UserVmVO vm = mock(UserVmVO.class);
when(userVmDaoMock.findById(1L)).thenReturn(vm);
when(vm.getState()).thenReturn(State.Stopped);
when(volume.getState()).thenReturn(Volume.State.Allocated);
volumeApiServiceImpl.validationsForCheckVolumeOperation(1L);
}
@Test(expected = InvalidParameterValueException.class)
public void testValidationsForCheckVolumeAPIWithNonKVMhypervisor() {
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(1L);
UserVmVO vm = mock(UserVmVO.class);
when(userVmDaoMock.findById(1L)).thenReturn(vm);
when(vm.getState()).thenReturn(State.Stopped);
when(volume.getState()).thenReturn(Volume.State.Ready);
when(volume.getId()).thenReturn(1L);
when(volumeDaoMock.getHypervisorType(1L)).thenReturn(HypervisorType.VMware);
volumeApiServiceImpl.validationsForCheckVolumeOperation(1L);
}
@Test
public void testCheckAndRepairVolume() throws ResourceAllocationException {
CheckVolumeAndRepairCmd cmd = mock(CheckVolumeAndRepairCmd.class);
when(cmd.getId()).thenReturn(1L);
when(cmd.getRepair()).thenReturn(false);
VolumeVO volume = mock(VolumeVO.class);
when(volumeDaoMock.findById(1L)).thenReturn(volume);
AccountVO account = new AccountVO("admin", 1L, "networkDomain", Account.Type.NORMAL, "uuid");
UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN);
CallContext.register(user, account);
lenient().doNothing().when(accountManagerMock).checkAccess(any(Account.class), any(AccessType.class), any(Boolean.class), any(ControlledEntity.class));
when(volume.getInstanceId()).thenReturn(null);
when(volume.getState()).thenReturn(Volume.State.Ready);
when(volume.getId()).thenReturn(1L);
when(volumeDaoMock.getHypervisorType(1L)).thenReturn(HypervisorType.KVM);
VolumeInfo volumeInfo = mock(VolumeInfo.class);
when(volumeDataFactoryMock.getVolume(1L)).thenReturn(volumeInfo);
String checkResult = "{\n" +
" \"image-end-offset\": 6442582016,\n" +
" \"total-clusters\": 163840,\n" +
" \"check-errors\": 0,\n" +
" \"leaks\": 124,\n" +
" \"allocated-clusters\": 98154,\n" +
" \"filename\": \"/var/lib/libvirt/images/26be20c7-b9d0-43f6-a76e-16c70737a0e0\",\n" +
" \"format\": \"qcow2\",\n" +
" \"fragmented-clusters\": 96135\n" +
"}";
String repairResult = null;
Pair<String, String> result = new Pair<>(checkResult, repairResult);
when(volumeServiceMock.checkAndRepairVolume(volumeInfo)).thenReturn(result);
Pair<String, String> finalresult = volumeApiServiceImpl.checkAndRepairVolume(cmd);
Assert.assertEquals(result, finalresult);
}
}