blob: 8b13fd4749472903bf2a3cf3f06b8ae96e5f06f7 [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.backup;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.alert.AlertManager;
import com.cloud.capacity.CapacityVO;
import com.cloud.configuration.Resource;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.network.Network;
import com.cloud.network.NetworkService;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.DiskOffering;
import com.cloud.service.ServiceOfferingVO;
import com.cloud.service.dao.ServiceOfferingDao;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.storage.Storage;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeApiService;
import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.DomainManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.DateUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.NoTransitionException;
import com.cloud.vm.VMInstanceDetailVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VmDiskInfo;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.VMInstanceDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.gson.Gson;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
import org.apache.cloudstack.api.command.admin.backup.UpdateBackupOfferingCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.DeleteBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupScheduleCmd;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.dao.BackupDetailsDao;
import org.apache.cloudstack.backup.dao.BackupOfferingDao;
import org.apache.cloudstack.backup.dao.BackupScheduleDao;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.impl.ConfigDepotImpl;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.TimeZone;
import java.util.UUID;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.atLeastOnce;
@RunWith(MockitoJUnitRunner.class)
public class BackupManagerTest {
@Spy
@InjectMocks
BackupManagerImpl backupManager = new BackupManagerImpl();
@Mock
BackupOfferingDao backupOfferingDao;
@Mock
BackupDetailsDao backupDetailsDao;
@Mock
BackupProvider backupProvider;
@Mock
VirtualMachineManager virtualMachineManager;
@Mock
VolumeApiService volumeApiService;
@Mock
VolumeDao volumeDao;
@Mock
VMInstanceDao vmInstanceDao;
@Mock
AccountManager accountManager;
@Mock
DomainManager domainManager;
@Mock
ResourceLimitService resourceLimitMgr;
@Mock
BackupScheduleDao backupScheduleDao;
@Mock
BackupDao backupDao;
@Mock
DataCenterDao dataCenterDao;
@Mock
private AlertManager alertManagerMock;
@Mock
private Domain domainMock;
@Mock
private VMInstanceVO vmInstanceVOMock;
@Mock
private CreateBackupScheduleCmd createBackupScheduleCmdMock;
@Mock
private BackupOfferingVO backupOfferingVOMock;
@Mock
private AsyncJobVO asyncJobVOMock;
@Mock
private BackupScheduleVO backupScheduleVOMock;
@Mock
private AccountVO accountVOMock;
@Mock
private CallContext callContextMock;
@Mock
private DeleteBackupScheduleCmd deleteBackupScheduleCmdMock;
@Mock
DiskOfferingDao diskOfferingDao;
@Mock
ServiceOfferingDao serviceOfferingDao;
@Mock
VMTemplateDao vmTemplateDao;
@Mock
UserVmJoinDao userVmJoinDao;
@Mock
PrimaryDataStoreDao primaryDataStoreDao;
@Mock
HostDao hostDao;
@Mock
private NetworkDao networkDao;
@Mock
private NetworkService networkService;
@Mock
private VMInstanceDetailsDao vmInstanceDetailsDao;
@Mock
AccountDao accountDao;
@Mock
DomainDao domainDao;
@Mock
private GuestOSDao _guestOSDao;
private Gson gson;
private String[] hostPossibleValues = {"127.0.0.1", "hostname"};
private String[] datastoresPossibleValues = {"e9804933-8609-4de3-bccc-6278072a496c", "datastore-name"};
private AutoCloseable closeable;
private ConfigDepotImpl configDepotImpl;
private boolean updatedConfigKeyDepot = false;
@Before
public void setup() throws Exception {
gson = new Gson();
closeable = MockitoAnnotations.openMocks(this);
when(backupOfferingDao.findById(null)).thenReturn(null);
when(backupOfferingDao.findById(123l)).thenReturn(null);
BackupOfferingVO offering = Mockito.spy(BackupOfferingVO.class);
when(offering.getName()).thenCallRealMethod();
when(offering.getDescription()).thenCallRealMethod();
when(offering.isUserDrivenBackupAllowed()).thenCallRealMethod();
BackupOfferingVO offeringUpdate = Mockito.spy(BackupOfferingVO.class);
when(backupOfferingDao.findById(1234l)).thenReturn(offering);
when(backupOfferingDao.createForUpdate(1234l)).thenReturn(offeringUpdate);
when(backupOfferingDao.update(1234l, offeringUpdate)).thenAnswer(answer -> {
offering.setName("New name");
offering.setDescription("New description");
offering.setUserDrivenBackupAllowed(true);
return true;
});
backupProvider = mock(BackupProvider.class);
when(backupProvider.getName()).thenReturn("testbackupprovider");
Map<String, BackupProvider> backupProvidersMap = new HashMap<>();
backupProvidersMap.put(backupProvider.getName().toLowerCase(), backupProvider);
ReflectionTestUtils.setField(backupManager, "backupProvidersMap", backupProvidersMap);
Account account = mock(Account.class);
User user = mock(User.class);
CallContext.register(user, account);
}
@After
public void tearDown() throws Exception {
closeable.close();
if (updatedConfigKeyDepot) {
ReflectionTestUtils.setField(BackupManager.BackupFrameworkEnabled, "s_depot", configDepotImpl);
}
CallContext.unregister();
}
private void overrideBackupFrameworkConfigValue() {
ConfigKey configKey = BackupManager.BackupFrameworkEnabled;
this.configDepotImpl = (ConfigDepotImpl) ReflectionTestUtils.getField(configKey, "s_depot");
ConfigDepotImpl configDepot = Mockito.mock(ConfigDepotImpl.class);
Mockito.when(configDepot.getConfigStringValue(Mockito.eq(BackupManager.BackupFrameworkEnabled.key()),
Mockito.eq(ConfigKey.Scope.Global), Mockito.isNull())).thenReturn("true");
Mockito.when(configDepot.getConfigStringValue(Mockito.eq(BackupManager.BackupFrameworkEnabled.key()),
Mockito.eq(ConfigKey.Scope.Zone), Mockito.anyLong())).thenReturn("true");
Mockito.when(configDepot.getConfigStringValue(Mockito.eq(BackupManager.BackupProviderPlugin.key()),
Mockito.eq(ConfigKey.Scope.Zone), Mockito.anyLong())).thenReturn("testbackupprovider");
ReflectionTestUtils.setField(configKey, "s_depot", configDepot);
updatedConfigKeyDepot = true;
}
@Test
public void testExceptionWhenUpdateWithNullId() {
try {
Long id = null;
UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
when(cmd.getId()).thenReturn(id);
backupManager.updateBackupOffering(cmd);
} catch (InvalidParameterValueException e) {
assertEquals("Unable to find Backup Offering with id: [null].", e.getMessage());
}
}
@Test(expected = InvalidParameterValueException.class)
public void testExceptionWhenUpdateWithNonExistentId() {
Long id = 123l;
UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
when(cmd.getId()).thenReturn(id);
backupManager.updateBackupOffering(cmd);
}
@Test(expected = ServerApiException.class)
public void testExceptionWhenUpdateWithoutChanges() {
UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
when(cmd.getName()).thenReturn(null);
when(cmd.getDescription()).thenReturn(null);
when(cmd.getAllowUserDrivenBackups()).thenReturn(null);
Mockito.doCallRealMethod().when(cmd).execute();
cmd.execute();
}
@Test
public void testUpdateBackupOfferingSuccess() {
Long id = 1234l;
UpdateBackupOfferingCmd cmd = Mockito.spy(UpdateBackupOfferingCmd.class);
when(cmd.getId()).thenReturn(id);
when(cmd.getName()).thenReturn("New name");
when(cmd.getDescription()).thenReturn("New description");
when(cmd.getAllowUserDrivenBackups()).thenReturn(true);
BackupOffering updated = backupManager.updateBackupOffering(cmd);
assertEquals("New name", updated.getName());
assertEquals("New description", updated.getDescription());
assertEquals(true, updated.isUserDrivenBackupAllowed());
}
@Test
public void restoreBackedUpVolumeTestHostIpAndDatastoreUuid() {
BackupVO backupVO = new BackupVO();
VMInstanceVO vm = mock(VMInstanceVO.class);
String volumeUuid = "5f4ed903-ac23-4f8a-b595-69c73c40593f";
String vmName = "i-2-3-VM";
VirtualMachine.State vmState = VirtualMachine.State.Running;
Mockito.when(vm.getName()).thenReturn(vmName);
Mockito.when(vm.getState()).thenReturn(vmState);
Pair<String, VirtualMachine.State> vmNameAndState = new Pair<>(vmName, vmState);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getUuid()).thenReturn(volumeUuid);
doReturn(new Pair<Boolean, String>(Boolean.TRUE, "Success"))
.when(backupProvider).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
Pair<Boolean, String> restoreBackedUpVolume = backupManager.restoreBackedUpVolume(volumeInfo, backupVO, backupProvider, hostPossibleValues, datastoresPossibleValues, vm);
assertEquals(Boolean.TRUE, restoreBackedUpVolume.first());
assertEquals("Success", restoreBackedUpVolume.second());
verify(backupProvider, atLeastOnce()).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
}
@Test
public void restoreBackedUpVolumeTestHostIpAndDatastoreName() {
BackupVO backupVO = new BackupVO();
VMInstanceVO vm = mock(VMInstanceVO.class);
String volumeUuid = "5f4ed903-ac23-4f8a-b595-69c73c40593f";
String vmName = "i-2-3-VM";
VirtualMachine.State vmState = VirtualMachine.State.Running;
Mockito.when(vm.getName()).thenReturn(vmName);
Mockito.when(vm.getState()).thenReturn(vmState);
Pair<String, VirtualMachine.State> vmNameAndState = new Pair<>(vmName, vmState);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getUuid()).thenReturn(volumeUuid);
doReturn(new Pair<Boolean, String>(Boolean.TRUE, "Success2"))
.when(backupProvider).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
Pair<Boolean, String> restoreBackedUpVolume = backupManager.restoreBackedUpVolume(volumeInfo, backupVO, backupProvider, hostPossibleValues, datastoresPossibleValues, vm);
assertEquals(Boolean.TRUE, restoreBackedUpVolume.first());
assertEquals("Success2", restoreBackedUpVolume.second());
verify(backupProvider, atLeastOnce()).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
}
@Test
public void restoreBackedUpVolumeTestHostNameAndDatastoreUuid() {
BackupVO backupVO = new BackupVO();
VMInstanceVO vm = mock(VMInstanceVO.class);
String volumeUuid = "5f4ed903-ac23-4f8a-b595-69c73c40593f";
String vmName = "i-2-3-VM";
VirtualMachine.State vmState = VirtualMachine.State.Running;
Mockito.when(vm.getName()).thenReturn(vmName);
Mockito.when(vm.getState()).thenReturn(vmState);
Pair<String, VirtualMachine.State> vmNameAndState = new Pair<>(vmName, vmState);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getUuid()).thenReturn(volumeUuid);
doReturn(new Pair<Boolean, String>(Boolean.TRUE, "Success3"))
.when(backupProvider).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
Pair<Boolean, String> restoreBackedUpVolume = backupManager.restoreBackedUpVolume(volumeInfo, backupVO, backupProvider, hostPossibleValues, datastoresPossibleValues, vm);
assertEquals(Boolean.TRUE, restoreBackedUpVolume.first());
assertEquals("Success3", restoreBackedUpVolume.second());
verify(backupProvider, atLeastOnce()).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
}
@Test
public void restoreBackedUpVolumeTestHostAndDatastoreName() {
BackupVO backupVO = new BackupVO();
VMInstanceVO vm = mock(VMInstanceVO.class);
String volumeUuid = "5f4ed903-ac23-4f8a-b595-69c73c40593f";
String vmName = "i-2-3-VM";
VirtualMachine.State vmState = VirtualMachine.State.Running;
Mockito.when(vm.getName()).thenReturn(vmName);
Mockito.when(vm.getState()).thenReturn(vmState);
Pair<String, VirtualMachine.State> vmNameAndState = new Pair<>(vmName, vmState);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getUuid()).thenReturn(volumeUuid);
doReturn(new Pair<Boolean, String>(Boolean.TRUE, "Success4"))
.when(backupProvider).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
Pair<Boolean, String> restoreBackedUpVolume = backupManager.restoreBackedUpVolume(volumeInfo, backupVO, backupProvider, hostPossibleValues, datastoresPossibleValues, vm);
assertEquals(Boolean.TRUE, restoreBackedUpVolume.first());
assertEquals("Success4", restoreBackedUpVolume.second());
verify(backupProvider, atLeastOnce()).restoreBackedUpVolume(any(Backup.class), any(Backup.VolumeInfo.class),
any(String.class), any(String.class), any(Pair.class));
}
@Test
public void tryRestoreVMTestRestoreSucceeded() throws NoTransitionException {
BackupOffering offering = mock(BackupOffering.class);
VolumeVO volumeVO = mock(VolumeVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
BackupVO backup = mock(BackupVO.class);
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onStartedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(),
Mockito.eq(true), Mockito.eq(0))).thenReturn(1L);
Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(),
Mockito.anyString(), Mockito.eq(0))).thenReturn(2L);
Mockito.when(volumeDao.findIncludingRemovedByInstanceAndType(1L, null)).thenReturn(Collections.singletonList(volumeVO));
Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringRequested), Mockito.any())).thenReturn(true);
Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreRequested))).thenReturn(true);
Mockito.when(vm.getId()).thenReturn(1L);
Mockito.when(offering.getProvider()).thenReturn("veeam");
Mockito.doReturn(backupProvider).when(backupManager).getBackupProvider("veeam");
Mockito.when(backupProvider.restoreVMFromBackup(vm, backup)).thenReturn(true);
backupManager.tryRestoreVM(backup, vm, offering, "Nothing to write here.");
}
}
@Test
public void tryRestoreVMTestRestoreFails() throws NoTransitionException {
BackupOffering offering = mock(BackupOffering.class);
VolumeVO volumeVO = mock(VolumeVO.class);
VMInstanceVO vm = mock(VMInstanceVO.class);
BackupVO backup = mock(BackupVO.class);
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onStartedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(),
Mockito.eq(true), Mockito.eq(0))).thenReturn(1L);
Mockito.when(ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(),
Mockito.anyString(), Mockito.eq(0))).thenReturn(2L);
Mockito.when(volumeDao.findIncludingRemovedByInstanceAndType(1L, null)).thenReturn(Collections.singletonList(volumeVO));
Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringRequested), Mockito.any())).thenReturn(true);
Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreRequested))).thenReturn(true);
Mockito.when(virtualMachineManager.stateTransitTo(Mockito.eq(vm), Mockito.eq(VirtualMachine.Event.RestoringFailed), Mockito.any())).thenReturn(true);
Mockito.when(volumeApiService.stateTransitTo(Mockito.eq(volumeVO), Mockito.eq(Volume.Event.RestoreFailed))).thenReturn(true);
Mockito.when(vm.getId()).thenReturn(1L);
Mockito.when(offering.getProvider()).thenReturn("veeam");
Mockito.doReturn(backupProvider).when(backupManager).getBackupProvider("veeam");
Mockito.when(backupProvider.restoreVMFromBackup(vm, backup)).thenReturn(false);
try {
backupManager.tryRestoreVM(backup, vm, offering, "Checking message error.");
fail("An exception is needed.");
} catch (CloudRuntimeException e) {
assertEquals("Error restoring VM from backup [Checking message error.].", e.getMessage());
}
}
}
@Test
public void testConfigureBackupSchedule() {
Long vmId = 1L;
Long zoneId = 2L;
Long accountId = 3L;
Long domainId = 4L;
Long backupOfferingId = 5L;
CreateBackupScheduleCmd cmd = Mockito.mock(CreateBackupScheduleCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
when(cmd.getTimezone()).thenReturn("GMT");
when(cmd.getIntervalType()).thenReturn(DateUtil.IntervalType.DAILY);
when(cmd.getMaxBackups()).thenReturn(8);
when(cmd.getSchedule()).thenReturn("00:00:00");
when(cmd.getQuiesceVM()).thenReturn(null);
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
when(vmInstanceDao.findById(vmId)).thenReturn(vm);
when(vm.getDataCenterId()).thenReturn(zoneId);
when(vm.getAccountId()).thenReturn(accountId);
when(vm.getBackupOfferingId()).thenReturn(backupOfferingId);
overrideBackupFrameworkConfigValue();
Account account = Mockito.mock(Account.class);
when(accountManager.getAccount(accountId)).thenReturn(account);
when(account.getDomainId()).thenReturn(domainId);
Domain domain = Mockito.mock(Domain.class);
when(domainManager.getDomain(domainId)).thenReturn(domain);
when(resourceLimitMgr.findCorrectResourceLimitForAccount(account, Resource.ResourceType.backup, null)).thenReturn(8L);
when(resourceLimitMgr.findCorrectResourceLimitForDomain(domain, Resource.ResourceType.backup, null)).thenReturn(8L);
BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(offering);
when(offering.isUserDrivenBackupAllowed()).thenReturn(true);
when(offering.getProvider()).thenReturn("test");
BackupScheduleVO schedule = mock(BackupScheduleVO.class);
when(backupScheduleDao.findByVMAndIntervalType(vmId, DateUtil.IntervalType.DAILY)).thenReturn(schedule);
backupManager.configureBackupSchedule(cmd);
verify(schedule, times(1)).setScheduleType((short) DateUtil.IntervalType.DAILY.ordinal());
verify(schedule, times(1)).setSchedule("00:00:00");
verify(schedule, times(1)).setTimezone(TimeZone.getTimeZone("GMT").getID());
verify(schedule, times(1)).setMaxBackups(8);
}
@Test
public void configureBackupScheduleTestEnsureLimitCheckIsPerformed() {
long vmId = 1L;
long zoneId = 2L;
long accountId = 3L;
long domainId = 4L;
long backupOfferingId = 5L;
when(createBackupScheduleCmdMock.getVmId()).thenReturn(vmId);
when(createBackupScheduleCmdMock.getTimezone()).thenReturn("GMT");
when(createBackupScheduleCmdMock.getIntervalType()).thenReturn(DateUtil.IntervalType.DAILY);
when(createBackupScheduleCmdMock.getMaxBackups()).thenReturn(8);
when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
when(vmInstanceVOMock.getDataCenterId()).thenReturn(zoneId);
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
when(vmInstanceVOMock.getBackupOfferingId()).thenReturn(backupOfferingId);
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(backupOfferingVOMock);
when(backupOfferingVOMock.isUserDrivenBackupAllowed()).thenReturn(true);
overrideBackupFrameworkConfigValue();
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(accountVOMock.getDomainId()).thenReturn(domainId);
when(domainManager.getDomain(domainId)).thenReturn(domainMock);
when(resourceLimitMgr.findCorrectResourceLimitForAccount(accountVOMock, Resource.ResourceType.backup, null)).thenReturn(10L);
when(resourceLimitMgr.findCorrectResourceLimitForDomain(domainMock, Resource.ResourceType.backup, null)).thenReturn(1L);
InvalidParameterValueException exception = Assert.assertThrows(InvalidParameterValueException.class,
() -> backupManager.configureBackupSchedule(createBackupScheduleCmdMock));
Assert.assertEquals("'maxbackups' should not exceed the domain/account backup limit.", exception.getMessage());
}
@Test
public void createBackupTestCreateScheduledBackup() throws ResourceAllocationException {
Long vmId = 1L;
Long zoneId = 2L;
Long scheduleId = 3L;
Long backupOfferingId = 4L;
Long accountId = 5L;
Long backupId = 6L;
Long oldestBackupId = 7L;
Long newBackupSize = 1000000000L;
Long oldBackupSize = 400000000L;
when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
when(vmInstanceVOMock.getDataCenterId()).thenReturn(zoneId);
when(vmInstanceVOMock.getBackupOfferingId()).thenReturn(backupOfferingId);
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
overrideBackupFrameworkConfigValue();
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(backupOfferingVOMock);
when(backupOfferingVOMock.isUserDrivenBackupAllowed()).thenReturn(true);
when(backupOfferingVOMock.getProvider()).thenReturn("testbackupprovider");
Mockito.doReturn(scheduleId).when(backupManager).getBackupScheduleId(asyncJobVOMock);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
BackupScheduleVO schedule = mock(BackupScheduleVO.class);
when(backupScheduleDao.findById(scheduleId)).thenReturn(schedule);
when(schedule.getMaxBackups()).thenReturn(2);
VolumeVO volume = mock(VolumeVO.class);
when(volumeDao.findByInstance(vmId)).thenReturn(List.of(volume));
when(volume.getState()).thenReturn(Volume.State.Ready);
when(volumeApiService.getVolumePhysicalSize(null, null, null)).thenReturn(newBackupSize);
BackupProvider backupProvider = mock(BackupProvider.class);
Backup backup = mock(Backup.class);
when(backup.getId()).thenReturn(backupId);
when(backup.getSize()).thenReturn(newBackupSize);
when(backupProvider.getName()).thenReturn("testbackupprovider");
when(backupProvider.takeBackup(vmInstanceVOMock, null)).thenReturn(new Pair<>(true, backup));
Map<String, BackupProvider> backupProvidersMap = new HashMap<>();
backupProvidersMap.put(backupProvider.getName().toLowerCase(), backupProvider);
ReflectionTestUtils.setField(backupManager, "backupProvidersMap", backupProvidersMap);
BackupVO backupVO = mock(BackupVO.class);
when(backupVO.getId()).thenReturn(backupId);
BackupVO oldestBackupVO = mock(BackupVO.class);
when(backupDao.findById(backupId)).thenReturn(backupVO);
List<BackupVO> backups = new ArrayList<>(List.of(oldestBackupVO));
when(backupDao.listBySchedule(scheduleId)).thenReturn(backups);
CreateBackupCmd cmd = Mockito.mock(CreateBackupCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
when(cmd.getName()).thenReturn("new-backup1");
when(cmd.getQuiesceVM()).thenReturn(null);
try (MockedStatic<ActionEventUtils> ignored = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(),
Mockito.anyLong(), Mockito.anyString())).thenReturn(1L);
assertTrue(backupManager.createBackup(cmd, asyncJobVOMock));
Mockito.verify(resourceLimitMgr, times(1)).checkResourceLimit(accountVOMock, Resource.ResourceType.backup);
Mockito.verify(resourceLimitMgr, times(1)).checkResourceLimit(accountVOMock, Resource.ResourceType.backup_storage, newBackupSize);
Mockito.verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup);
Mockito.verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup_storage, newBackupSize);
Mockito.verify(backupDao, times(1)).update(backupVO.getId(), backupVO);
Mockito.verify(backupManager, times(1)).deleteOldestBackupFromScheduleIfRequired(vmId, scheduleId);
}
}
@Test(expected = ResourceAllocationException.class)
public void createBackupTestResourceLimitReached() throws ResourceAllocationException {
Long vmId = 1L;
Long zoneId = 2L;
Long scheduleId = 3L;
Long backupOfferingId = 4L;
Long accountId = 5L;
when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
when(vmInstanceVOMock.getDataCenterId()).thenReturn(zoneId);
when(vmInstanceVOMock.getBackupOfferingId()).thenReturn(backupOfferingId);
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
overrideBackupFrameworkConfigValue();
BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(offering);
when(offering.isUserDrivenBackupAllowed()).thenReturn(true);
when(offering.getProvider()).thenReturn("testbackupprovider");
Account account = Mockito.mock(Account.class);
when(accountManager.getAccount(accountId)).thenReturn(account);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup)).when(resourceLimitMgr).checkResourceLimit(account, Resource.ResourceType.backup);
CreateBackupCmd cmd = Mockito.mock(CreateBackupCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
when(cmd.getQuiesceVM()).thenReturn(null);
String jobParams = "{}";
when(asyncJobVOMock.getCmdInfo()).thenReturn(jobParams);
when(asyncJobVOMock.getId()).thenReturn(1L);
backupManager.createBackup(cmd, asyncJobVOMock);
String msg = "Backup storage space resource limit exceeded for account id : " + accountId + ". Failed to create backup";
Mockito.verify(alertManagerMock, times(1)).sendAlert(AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg, "Backup resource limit exceeded for account id : " + accountId
+ ". Failed to create backups; please use updateResourceLimit to increase the limit");
}
@Test (expected = ResourceAllocationException.class)
public void testCreateBackupStorageLimitReached() throws ResourceAllocationException {
Long vmId = 1L;
Long zoneId = 2L;
Long scheduleId = 3L;
Long backupOfferingId = 4L;
Long accountId = 5L;
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
when(vmInstanceDao.findById(vmId)).thenReturn(vm);
when(vm.getDataCenterId()).thenReturn(zoneId);
when(vm.getBackupOfferingId()).thenReturn(backupOfferingId);
when(vm.getAccountId()).thenReturn(accountId);
overrideBackupFrameworkConfigValue();
BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
when(backupOfferingDao.findById(backupOfferingId)).thenReturn(offering);
when(offering.isUserDrivenBackupAllowed()).thenReturn(true);
when(offering.getProvider()).thenReturn("testbackupprovider");
Mockito.doReturn(scheduleId).when(backupManager).getBackupScheduleId(asyncJobVOMock);
Account account = Mockito.mock(Account.class);
when(accountManager.getAccount(accountId)).thenReturn(account);
Mockito.doThrow(new ResourceAllocationException("", Resource.ResourceType.backup_storage)).when(resourceLimitMgr).checkResourceLimit(account, Resource.ResourceType.backup_storage, 0L);
CreateBackupCmd cmd = Mockito.mock(CreateBackupCmd.class);
when(cmd.getVmId()).thenReturn(vmId);
when(cmd.getQuiesceVM()).thenReturn(null);
backupManager.createBackup(cmd, asyncJobVOMock);
String msg = "Backup storage space resource limit exceeded for account id : " + accountId + ". Failed to create backup";
Mockito.verify(alertManagerMock, times(1)).sendAlert(AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT, 0L, 0L, msg, "Backup storage space resource limit exceeded for account id : " + accountId
+ ". Failed to create backups; please use updateResourceLimit to increase the limit");
}
@Test
public void testBackupSyncTask() {
Long dataCenterId = 1L;
Long vmId = 2L;
Long accountId = 3L;
Long backup2Id = 4L;
String restorePoint1ExternalId = "1234";
Long backup1Size = 1 * Resource.ResourceType.bytesToGiB;
Long backup2Size = 2 * Resource.ResourceType.bytesToGiB;
Long newBackupSize = 3 * Resource.ResourceType.bytesToGiB;
Long restorePointSize = 4 * Resource.ResourceType.bytesToGiB;
overrideBackupFrameworkConfigValue();
DataCenterVO dataCenter = mock(DataCenterVO.class);
when(dataCenter.getId()).thenReturn(dataCenterId);
when(dataCenterDao.listAllZones()).thenReturn(List.of(dataCenter));
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.getName()).thenReturn("testbackupprovider");
backupManager.setBackupProviders(List.of(backupProvider));
backupManager.start();
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getAccountId()).thenReturn(accountId);
List<Long> vmIds = List.of(vmId);
when(backupDao.listVmIdsWithBackupsInZone(dataCenterId)).thenReturn(vmIds);
when(vmInstanceDao.listByZoneAndBackupOffering(dataCenterId, null)).thenReturn(List.of(vm));
Backup.RestorePoint restorePoint1 = new Backup.RestorePoint(restorePoint1ExternalId, DateUtil.now(), "Full", restorePointSize, 0L);
Backup.RestorePoint restorePoint2 = new Backup.RestorePoint("12345", DateUtil.now(), "Full", restorePointSize, 0L);
List<Backup.RestorePoint> restorePoints = new ArrayList<>(List.of(restorePoint1, restorePoint2));
when(backupProvider.listRestorePoints(vm)).thenReturn(restorePoints);
BackupVO backupInDb1 = new BackupVO();
backupInDb1.setSize(backup1Size);
backupInDb1.setAccountId(accountId);
backupInDb1.setExternalId(restorePoint1ExternalId);
BackupVO backupInDb2 = new BackupVO();
backupInDb2.setSize(backup2Size);
backupInDb2.setAccountId(accountId);
backupInDb2.setExternalId(null);
ReflectionTestUtils.setField(backupInDb2, "id", backup2Id);
when(backupDao.findById(backup2Id)).thenReturn(backupInDb2);
when(backupDao.listByVmId(null, vmId)).thenReturn(List.of(backupInDb1, backupInDb2));
BackupVO newBackupEntry = new BackupVO();
newBackupEntry.setSize(newBackupSize);
when(backupProvider.createNewBackupEntryForRestorePoint(restorePoint2, vm)).thenReturn(newBackupEntry);
try (MockedStatic<ActionEventUtils> ignored = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(),
Mockito.anyLong(), Mockito.anyString())).thenReturn(1L);
try (MockedStatic<UsageEventUtils> ignored2 = Mockito.mockStatic(UsageEventUtils.class)) {
BackupManagerImpl.BackupSyncTask backupSyncTask = backupManager.new BackupSyncTask(backupManager);
backupSyncTask.runInContext();
verify(resourceLimitMgr, times(1)).decrementResourceCount(accountId, Resource.ResourceType.backup_storage, backup1Size);
verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup_storage, restorePointSize);
Assert.assertEquals(backupInDb1.getSize(), restorePointSize);
verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup);
verify(resourceLimitMgr, times(1)).incrementResourceCount(accountId, Resource.ResourceType.backup_storage, newBackupSize);
verify(resourceLimitMgr, times(1)).decrementResourceCount(accountId, Resource.ResourceType.backup);
verify(resourceLimitMgr, times(1)).decrementResourceCount(accountId, Resource.ResourceType.backup_storage, backup2Size);
}
}
}
@Test
public void checkCallerAccessToBackupScheduleVmTestExecuteAccessCheckMethods() {
long vmId = 1L;
long dataCenterId = 2L;
try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) {
Mockito.when(vmInstanceDao.findById(vmId)).thenReturn(vmInstanceVOMock);
Mockito.when(vmInstanceVOMock.getDataCenterId()).thenReturn(dataCenterId);
Mockito.when(backupManager.isDisabled(dataCenterId)).thenReturn(false);
mockedCallContext.when(CallContext::current).thenReturn(callContextMock);
Mockito.when(callContextMock.getCallingAccount()).thenReturn(accountVOMock);
Mockito.doNothing().when(accountManager).checkAccess(accountVOMock, null, true, vmInstanceVOMock);
backupManager.checkCallerAccessToBackupScheduleVm(vmId);
verify(accountManager, times(1)).checkAccess(accountVOMock, null, true, vmInstanceVOMock);
}
}
@Test
public void deleteAllVmBackupSchedulesTestReturnSuccessWhenAllSchedulesAreDeleted() {
long vmId = 1L;
List<BackupScheduleVO> backupSchedules = List.of(Mockito.mock(BackupScheduleVO.class), Mockito.mock(BackupScheduleVO.class));
Mockito.when(backupScheduleDao.listByVM(vmId)).thenReturn(backupSchedules);
Mockito.when(backupSchedules.get(0).getId()).thenReturn(2L);
Mockito.when(backupSchedules.get(1).getId()).thenReturn(3L);
Mockito.when(backupScheduleDao.remove(Mockito.anyLong())).thenReturn(true);
boolean success = backupManager.deleteAllVmBackupSchedules(vmId);
assertTrue(success);
Mockito.verify(backupScheduleDao, times(2)).remove(Mockito.anyLong());
}
@Test
public void deleteAllVmBackupSchedulesTestReturnFalseWhenAnyDeletionFails() {
long vmId = 1L;
List<BackupScheduleVO> backupSchedules = List.of(Mockito.mock(BackupScheduleVO.class), Mockito.mock(BackupScheduleVO.class));
Mockito.when(backupScheduleDao.listByVM(vmId)).thenReturn(backupSchedules);
Mockito.when(backupSchedules.get(0).getId()).thenReturn(2L);
Mockito.when(backupSchedules.get(1).getId()).thenReturn(3L);
Mockito.when(backupScheduleDao.remove(2L)).thenReturn(true);
Mockito.when(backupScheduleDao.remove(3L)).thenReturn(false);
boolean success = backupManager.deleteAllVmBackupSchedules(vmId);
assertFalse(success);
Mockito.verify(backupScheduleDao, times(2)).remove(Mockito.anyLong());
}
@Test(expected = InvalidParameterValueException.class)
public void deleteBackupScheduleTestThrowExceptionWhenVmIdAndScheduleIdAreNull() {
when(deleteBackupScheduleCmdMock.getVmId()).thenReturn(null);
when(deleteBackupScheduleCmdMock.getId()).thenReturn(null);
backupManager.deleteBackupSchedule(deleteBackupScheduleCmdMock);
}
@Test
public void deleteBackupScheduleTestDeleteVmSchedulesWhenVmIdIsSpecified() {
long vmId = 1L;
when(deleteBackupScheduleCmdMock.getId()).thenReturn(null);
when(deleteBackupScheduleCmdMock.getVmId()).thenReturn(vmId);
Mockito.doNothing().when(backupManager).checkCallerAccessToBackupScheduleVm(vmId);
Mockito.doReturn(true).when(backupManager).deleteAllVmBackupSchedules(vmId);
boolean success = backupManager.deleteBackupSchedule(deleteBackupScheduleCmdMock);
assertTrue(success);
}
@Test(expected = InvalidParameterValueException.class)
public void deleteBackupScheduleTestThrowExceptionWhenSpecificScheduleIsNotFound() {
long id = 1L;
when(deleteBackupScheduleCmdMock.getId()).thenReturn(id);
backupManager.deleteBackupSchedule(deleteBackupScheduleCmdMock);
}
@Test
public void deleteBackupScheduleTestDeleteSpecificScheduleWhenItsIdIsSpecified() {
long id = 1L;
long vmId = 2L;
when(deleteBackupScheduleCmdMock.getId()).thenReturn(id);
when(deleteBackupScheduleCmdMock.getVmId()).thenReturn(null);
when(backupScheduleDao.findById(id)).thenReturn(backupScheduleVOMock);
when(backupScheduleVOMock.getVmId()).thenReturn(vmId);
Mockito.doNothing().when(backupManager).checkCallerAccessToBackupScheduleVm(vmId);
when(backupScheduleVOMock.getId()).thenReturn(id);
when(backupScheduleDao.remove(id)).thenReturn(true);
boolean success = backupManager.deleteBackupSchedule(deleteBackupScheduleCmdMock);
assertTrue(success);
}
@Test
public void testGetBackupDetailsFromVM() {
Long vmId = 1L;
VirtualMachine vm = mock(VirtualMachine.class);
when(vm.getServiceOfferingId()).thenReturn(1L);
when(vm.getTemplateId()).thenReturn(2L);
when(vm.getId()).thenReturn(vmId);
ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class);
when(serviceOffering.getUuid()).thenReturn("service-offering-uuid");
when(serviceOfferingDao.findById(1L)).thenReturn(serviceOffering);
VMTemplateVO template = mock(VMTemplateVO.class);
when(template.getUuid()).thenReturn("template-uuid");
when(vmTemplateDao.findById(2L)).thenReturn(template);
VMInstanceDetailVO vmInstanceDetail = mock(VMInstanceDetailVO.class);
when(vmInstanceDetail.getName()).thenReturn("mocked-detail-name");
when(vmInstanceDetail.getValue()).thenReturn("mocked-detail-value");
List<VMInstanceDetailVO> vmDetails = Collections.singletonList(vmInstanceDetail);
when(vmInstanceDetailsDao.listDetails(vmId)).thenReturn(vmDetails);
UserVmJoinVO userVmJoinVO = mock(UserVmJoinVO.class);
when(userVmJoinVO.getNetworkUuid()).thenReturn("mocked-network-uuid");
List<UserVmJoinVO> userVmJoinVOs = Collections.singletonList(userVmJoinVO);
when(userVmJoinDao.searchByIds(vmId)).thenReturn(userVmJoinVOs);
Map<String, String> details = backupManager.getBackupDetailsFromVM(vm);
assertEquals("service-offering-uuid", details.get(ApiConstants.SERVICE_OFFERING_ID));
assertEquals("[{\"networkid\":\"mocked-network-uuid\"}]", details.get(ApiConstants.NICS));
assertEquals("{\"mocked-detail-name\":\"mocked-detail-value\"}", details.get(ApiConstants.VM_SETTINGS));
}
@Test
public void getDataDiskInfoListFromBackup() {
Long size1 = 5L * 1024 * 1024 * 1024;
Long size2 = 10L * 1024 * 1024 * 1024;
Backup backup = mock(Backup.class);
Backup.VolumeInfo volumeInfo0 = mock(Backup.VolumeInfo.class);
when(volumeInfo0.getType()).thenReturn(Volume.Type.ROOT);
Backup.VolumeInfo volumeInfo1 = mock(Backup.VolumeInfo.class);
when(volumeInfo1.getDiskOfferingId()).thenReturn("disk-offering-uuid-1");
when(volumeInfo1.getSize()).thenReturn(size1);
when(volumeInfo1.getMinIops()).thenReturn(100L);
when(volumeInfo1.getMaxIops()).thenReturn(300L);
when(volumeInfo1.getType()).thenReturn(Volume.Type.DATADISK);
when(volumeInfo1.getDeviceId()).thenReturn(1L);
Backup.VolumeInfo volumeInfo2 = mock(Backup.VolumeInfo.class);
when(volumeInfo2.getDiskOfferingId()).thenReturn("disk-offering-uuid-2");
when(volumeInfo2.getSize()).thenReturn(size2);
when(volumeInfo2.getMinIops()).thenReturn(200L);
when(volumeInfo2.getMaxIops()).thenReturn(400L);
when(volumeInfo2.getType()).thenReturn(Volume.Type.DATADISK);
when(volumeInfo2.getDeviceId()).thenReturn(2L);
when(backup.getBackedUpVolumes()).thenReturn(List.of(volumeInfo0, volumeInfo1, volumeInfo2));
DiskOfferingVO diskOffering1 = mock(DiskOfferingVO.class);
when(diskOffering1.getUuid()).thenReturn("disk-offering-uuid-1");
when(diskOffering1.getState()).thenReturn(DiskOffering.State.Active);
DiskOfferingVO diskOffering2 = mock(DiskOfferingVO.class);
when(diskOffering2.getUuid()).thenReturn("disk-offering-uuid-2");
when(diskOffering2.getState()).thenReturn(DiskOffering.State.Active);
when(diskOfferingDao.findByUuid("disk-offering-uuid-1")).thenReturn(diskOffering1);
when(diskOfferingDao.findByUuid("disk-offering-uuid-2")).thenReturn(diskOffering2);
List<VmDiskInfo> vmDiskInfoList = backupManager.getDataDiskInfoListFromBackup(backup);
assertEquals(2, vmDiskInfoList.size());
assertEquals("disk-offering-uuid-1", vmDiskInfoList.get(0).getDiskOffering().getUuid());
assertEquals(Long.valueOf(5), vmDiskInfoList.get(0).getSize());
assertEquals(Long.valueOf(1), vmDiskInfoList.get(0).getDeviceId());
assertEquals(Long.valueOf(100), vmDiskInfoList.get(0).getMinIops());
assertEquals(Long.valueOf(300), vmDiskInfoList.get(0).getMaxIops());
assertEquals("disk-offering-uuid-2", vmDiskInfoList.get(1).getDiskOffering().getUuid());
assertEquals(Long.valueOf(10), vmDiskInfoList.get(1).getSize());
assertEquals(Long.valueOf(2), vmDiskInfoList.get(1).getDeviceId());
assertEquals(Long.valueOf(200), vmDiskInfoList.get(1).getMinIops());
assertEquals(Long.valueOf(400), vmDiskInfoList.get(1).getMaxIops());
}
@Test
public void getDataDiskInfoListFromBackupNullIops() {
Long size = 5L * 1024 * 1024 * 1024;
Backup backup = mock(Backup.class);
Backup.VolumeInfo volumeInfo1 = mock(Backup.VolumeInfo.class);
when(volumeInfo1.getDiskOfferingId()).thenReturn("disk-offering-uuid-1");
when(volumeInfo1.getSize()).thenReturn(size);
when(volumeInfo1.getMinIops()).thenReturn(null);
when(volumeInfo1.getMaxIops()).thenReturn(null);
when(volumeInfo1.getType()).thenReturn(Volume.Type.DATADISK);
when(volumeInfo1.getDeviceId()).thenReturn(1L);
when(backup.getBackedUpVolumes()).thenReturn(List.of(volumeInfo1));
DiskOfferingVO diskOffering = mock(DiskOfferingVO.class);
when(diskOffering.getUuid()).thenReturn("disk-offering-uuid-1");
when(diskOffering.getState()).thenReturn(DiskOffering.State.Active);
when(diskOfferingDao.findByUuid("disk-offering-uuid-1")).thenReturn(diskOffering);
List<VmDiskInfo> vmDiskInfoList = backupManager.getDataDiskInfoListFromBackup(backup);
assertEquals(1, vmDiskInfoList.size());
assertEquals("disk-offering-uuid-1", vmDiskInfoList.get(0).getDiskOffering().getUuid());
assertEquals(Long.valueOf(5), vmDiskInfoList.get(0).getSize());
assertEquals(Long.valueOf(1), vmDiskInfoList.get(0).getDeviceId());
assertNull(vmDiskInfoList.get(0).getMinIops());
assertNull(vmDiskInfoList.get(0).getMaxIops());
}
@Test (expected = InvalidParameterValueException.class)
public void testCheckVmDisksSizeAgainstBackup() {
Long sizeInBackup = 5L * 1024 * 1024 * 1024;
Long sizeInCmd = 2L;
Backup backup = mock(Backup.class);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getDiskOfferingId()).thenReturn("disk-offering-uuid-1");
when(volumeInfo.getSize()).thenReturn(sizeInBackup);
when(volumeInfo.getType()).thenReturn(Volume.Type.DATADISK);
when(backup.getBackedUpVolumes()).thenReturn(List.of(volumeInfo));
DiskOfferingVO diskOffering = mock(DiskOfferingVO.class);
when(diskOffering.getState()).thenReturn(DiskOffering.State.Active);
when(diskOfferingDao.findByUuid("disk-offering-uuid-1")).thenReturn(diskOffering);
List<VmDiskInfo> vmDiskInfoList = List.of(new VmDiskInfo(diskOffering, sizeInCmd, 1L, null, null));
backupManager.checkVmDisksSizeAgainstBackup(vmDiskInfoList, backup);
}
@Test
public void testGetRootDiskInfoFromBackup() {
Long size = 5L * 1024 * 1024 * 1024;
Backup backup = mock(Backup.class);
Backup.VolumeInfo volumeInfo = mock(Backup.VolumeInfo.class);
when(volumeInfo.getDiskOfferingId()).thenReturn("root-disk-offering-uuid");
when(volumeInfo.getSize()).thenReturn(size);
when(volumeInfo.getType()).thenReturn(Volume.Type.ROOT);
when(backup.getBackedUpVolumes()).thenReturn(List.of(volumeInfo));
DiskOfferingVO diskOffering = mock(DiskOfferingVO.class);
when(diskOffering.getUuid()).thenReturn("root-disk-offering-uuid");
when(diskOfferingDao.findByUuid("root-disk-offering-uuid")).thenReturn(diskOffering);
VmDiskInfo VmDiskInfo = backupManager.getRootDiskInfoFromBackup(backup);
assertEquals("root-disk-offering-uuid", VmDiskInfo.getDiskOffering().getUuid());
assertEquals(Long.valueOf(5), VmDiskInfo.getSize());
assertEquals(null, VmDiskInfo.getDeviceId());
}
@Test
public void testImportBackupOffering() {
ImportBackupOfferingCmd cmd = Mockito.mock(ImportBackupOfferingCmd.class);
when(cmd.getZoneId()).thenReturn(1L);
when(cmd.getExternalId()).thenReturn("external-id");
when(cmd.getName()).thenReturn("Test Offering");
when(cmd.getDescription()).thenReturn("Test Description");
when(cmd.getUserDrivenBackups()).thenReturn(true);
overrideBackupFrameworkConfigValue();
when(backupOfferingDao.findByExternalId("external-id", 1L)).thenReturn(null);
when(backupOfferingDao.findByName("Test Offering", 1L)).thenReturn(null);
BackupOfferingVO offering = new BackupOfferingVO(1L, "external-id", "testbackupprovider", "Test Offering", "Test Description", true);
when(backupOfferingDao.persist(any(BackupOfferingVO.class))).thenReturn(offering);
when(backupProvider.isValidProviderOffering(cmd.getZoneId(), cmd.getExternalId())).thenReturn(true);
BackupOffering result = backupManager.importBackupOffering(cmd);
assertEquals("Test Offering", result.getName());
assertEquals("Test Description", result.getDescription());
assertEquals(true, result.isUserDrivenBackupAllowed());
assertEquals("external-id", result.getExternalId());
assertEquals("testbackupprovider", result.getProvider());
}
@Test
public void testCreateVolumeInfoFromVolumes() {
Long diskOfferingId = 5L;
DiskOfferingVO diskOffering = Mockito.mock(DiskOfferingVO.class);
Mockito.when(diskOffering.getUuid()).thenReturn("disk-offering-uuid");
Mockito.when(diskOfferingDao.findById(diskOfferingId)).thenReturn(diskOffering);
List<VolumeVO> volumes = new ArrayList<>();
VolumeVO volume1 = new VolumeVO(Volume.Type.ROOT, "vol1", 1L, 2L, 3L,
diskOfferingId, null, 1024L, null, null, null);
volume1.setUuid("uuid1");
volume1.setPath("path1");
volume1.setDeviceId(0L);
volume1.setVolumeType(Volume.Type.ROOT);
volumes.add(volume1);
VolumeVO volume2 = new VolumeVO(Volume.Type.ROOT, "vol2", 1L, 2L, 3L,
diskOfferingId, null, 2048L, 1000L, 2000L, null);
volume2.setUuid("uuid2");
volume2.setPath("path2");
volume2.setDeviceId(1L);
volume2.setVolumeType(Volume.Type.DATADISK);
volumes.add(volume2);
String expectedJson = "[{\"uuid\":\"uuid1\",\"type\":\"ROOT\",\"size\":1024,\"path\":\"path1\",\"deviceId\":0,\"diskOfferingId\":\"disk-offering-uuid\"},{\"uuid\":\"uuid2\",\"type\":\"DATADISK\",\"size\":2048,\"path\":\"path2\",\"deviceId\":1,\"diskOfferingId\":\"disk-offering-uuid\",\"minIops\":1000,\"maxIops\":2000}]";
String actualJson = backupManager.createVolumeInfoFromVolumes(new ArrayList<>(volumes));
assertEquals(expectedJson, actualJson);
}
@Test
public void testAssignVMToBackupOffering() {
Long vmId = 1L;
Long offeringId = 2L;
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
overrideBackupFrameworkConfigValue();
when(vmInstanceDao.findById(vmId)).thenReturn(vm);
when(backupOfferingDao.findById(offeringId)).thenReturn(offering);
when(vm.getState()).thenReturn(VirtualMachine.State.Running);
when(vm.getDataCenterId()).thenReturn(1L);
when(vm.getBackupOfferingId()).thenReturn(null);
when(offering.getProvider()).thenReturn("testbackupprovider");
when(backupProvider.assignVMToBackupOffering(vm, offering)).thenReturn(true);
when(vmInstanceDao.update(1L, vm)).thenReturn(true);
try (MockedStatic<UsageEventUtils> ignored2 = Mockito.mockStatic(UsageEventUtils.class)) {
boolean result = backupManager.assignVMToBackupOffering(vmId, offeringId);
assertTrue(result);
verify(vmInstanceDao, times(1)).findById(vmId);
verify(backupOfferingDao, times(1)).findById(offeringId);
verify(backupManager, times(1)).getBackupProvider("testbackupprovider");
}
}
@Test
public void testRemoveVMFromBackupOffering() {
Long vmId = 1L;
Long accountId = 2L;
Long zoneId = 3L;
Long offeringId = 4L;
Long backupScheduleId = 5L;
String vmHostName = "vm1";
String vmUuid = "uuid1";
String resourceName = "Backup-" + vmHostName + "-" + vmUuid;
boolean forced = true;
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getDataCenterId()).thenReturn(1L);
when(vm.getBackupOfferingId()).thenReturn(offeringId);
when(vm.getAccountId()).thenReturn(accountId);
when(vm.getDataCenterId()).thenReturn(zoneId);
when(vm.getHostName()).thenReturn(vmHostName);
when(vm.getUuid()).thenReturn(vmUuid);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(vmInstanceDao.update(vmId, vm)).thenReturn(true);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
when(backupOfferingDao.findById(vm.getBackupOfferingId())).thenReturn(offering);
when(offering.getProvider()).thenReturn("testbackupprovider");
when(backupProvider.removeVMFromBackupOffering(vm)).thenReturn(true);
when(backupProvider.willDeleteBackupsOnOfferingRemoval()).thenReturn(true);
when(backupDao.listByVmId(null, vmId)).thenReturn(new ArrayList<>());
BackupScheduleVO backupSchedule = new BackupScheduleVO();
ReflectionTestUtils.setField(backupSchedule, "id", backupScheduleId);
when(backupScheduleDao.listByVM(vmId)).thenReturn(List.of(backupSchedule));
overrideBackupFrameworkConfigValue();
try (MockedStatic<UsageEventUtils> usageEventUtilsMocked = Mockito.mockStatic(UsageEventUtils.class)) {
boolean result = backupManager.removeVMFromBackupOffering(vmId, forced);
assertTrue(result);
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
verify(backupOfferingDao, times(1)).findById(vm.getBackupOfferingId());
verify(backupManager, times(1)).getBackupProvider("testbackupprovider");
verify(backupScheduleDao, times(1)).remove(backupScheduleId);
usageEventUtilsMocked.verify(() -> UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_BACKUP_OFFERING_REMOVED_AND_BACKUPS_DELETED, accountId, zoneId, vmId, resourceName,
offeringId, null, null, Backup.class.getSimpleName(), vmUuid));
}
}
@Test
public void testDeleteBackupScheduleByVmId() {
Long vmId = 1L;
Long scheduleId = 2L;
DeleteBackupScheduleCmd cmd = new DeleteBackupScheduleCmd();
ReflectionTestUtils.setField(cmd, "vmId", vmId);
overrideBackupFrameworkConfigValue();
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vmInstanceDao.findById(vmId)).thenReturn(vm);
BackupScheduleVO schedule = mock(BackupScheduleVO.class);
when(schedule.getId()).thenReturn(scheduleId);
when(backupScheduleDao.listByVM(vmId)).thenReturn(List.of(schedule));
when(backupScheduleDao.remove(scheduleId)).thenReturn(true);
boolean result = backupManager.deleteBackupSchedule(cmd);
assertTrue(result);
}
@Test
public void testRestoreBackupToVM() throws NoTransitionException {
Long backupId = 1L;
Long vmId = 2L;
Long hostId = 3L;
Long offeringId = 4L;
Long poolId = 5L;
BackupVO backup = mock(BackupVO.class);
when(backup.getBackupOfferingId()).thenReturn(offeringId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(vm.getId()).thenReturn(vmId);
when(vm.getState()).thenReturn(VirtualMachine.State.Stopped);
when(vm.getHostId()).thenReturn(hostId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.supportsInstanceFromBackup()).thenReturn(true);
overrideBackupFrameworkConfigValue();
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(backupOfferingDao.findByIdIncludingRemoved(offeringId)).thenReturn(offering);
when(offering.getProvider()).thenReturn("testbackupprovider");
when(backupManager.getBackupProvider("testbackupprovider")).thenReturn(backupProvider);
when(virtualMachineManager.stateTransitTo(vm, VirtualMachine.Event.RestoringRequested, hostId)).thenReturn(true);
when(virtualMachineManager.stateTransitTo(vm, VirtualMachine.Event.RestoringSuccess, hostId)).thenReturn(true);
VolumeVO rootVolume = mock(VolumeVO.class);
when(rootVolume.getPoolId()).thenReturn(poolId);
HostVO host = mock(HostVO.class);
when(hostDao.findById(hostId)).thenReturn(host);
StoragePoolVO pool = mock(StoragePoolVO.class);
when(volumeDao.findIncludingRemovedByInstanceAndType(vmId, Volume.Type.ROOT)).thenReturn(List.of(rootVolume));
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
when(rootVolume.getPoolId()).thenReturn(poolId);
when(volumeDao.findIncludingRemovedByInstanceAndType(vmId, Volume.Type.ROOT)).thenReturn(List.of(rootVolume));
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
when(backupProvider.restoreBackupToVM(vm, backup, null, null)).thenReturn(new Pair<>(true, null));
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
boolean result = backupManager.restoreBackupToVM(backupId, vmId);
assertTrue(result);
verify(backupProvider, times(1)).restoreBackupToVM(vm, backup, null, null);
verify(virtualMachineManager, times(1)).stateTransitTo(vm, VirtualMachine.Event.RestoringRequested, hostId);
verify(virtualMachineManager, times(1)).stateTransitTo(vm, VirtualMachine.Event.RestoringSuccess, hostId);
} catch (CloudRuntimeException e) {
fail("Test failed due to exception" + e);
}
}
@Test
public void testRestoreBackupToVMException() throws NoTransitionException {
Long backupId = 1L;
Long vmId = 2L;
Long hostId = 3L;
Long offeringId = 4L;
Long poolId = 5L;
BackupVO backup = mock(BackupVO.class);
when(backup.getBackupOfferingId()).thenReturn(offeringId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(vm.getId()).thenReturn(vmId);
when(vm.getState()).thenReturn(VirtualMachine.State.Stopped);
when(vm.getHostId()).thenReturn(hostId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.supportsInstanceFromBackup()).thenReturn(true);
overrideBackupFrameworkConfigValue();
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(backupOfferingDao.findByIdIncludingRemoved(offeringId)).thenReturn(offering);
when(offering.getProvider()).thenReturn("testbackupprovider");
when(backupManager.getBackupProvider("testbackupprovider")).thenReturn(backupProvider);
when(virtualMachineManager.stateTransitTo(vm, VirtualMachine.Event.RestoringRequested, hostId)).thenReturn(true);
when(virtualMachineManager.stateTransitTo(vm, VirtualMachine.Event.RestoringFailed, hostId)).thenReturn(true);
VolumeVO rootVolume = mock(VolumeVO.class);
when(rootVolume.getPoolId()).thenReturn(poolId);
HostVO host = mock(HostVO.class);
when(hostDao.findById(hostId)).thenReturn(host);
StoragePoolVO pool = mock(StoragePoolVO.class);
when(volumeDao.findIncludingRemovedByInstanceAndType(vmId, Volume.Type.ROOT)).thenReturn(List.of(rootVolume));
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
when(rootVolume.getPoolId()).thenReturn(poolId);
when(volumeDao.findIncludingRemovedByInstanceAndType(vmId, Volume.Type.ROOT)).thenReturn(List.of(rootVolume));
when(primaryDataStoreDao.findById(poolId)).thenReturn(pool);
when(backupProvider.restoreBackupToVM(vm, backup, null, null)).thenReturn(new Pair<>(false, null));
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackupToVM(backupId, vmId));
verify(backupProvider, times(1)).restoreBackupToVM(vm, backup, null, null);
verify(virtualMachineManager, times(1)).stateTransitTo(vm, VirtualMachine.Event.RestoringRequested, hostId);
verify(virtualMachineManager, times(1)).stateTransitTo(vm, VirtualMachine.Event.RestoringFailed, hostId);
}
}
@Test
public void testGetBackupStorageUsedStats() {
Long zoneId = 1L;
overrideBackupFrameworkConfigValue();
when(backupManager.getBackupProvider(zoneId)).thenReturn(backupProvider);
when(backupProvider.getBackupStorageStats(zoneId)).thenReturn(new Pair<>(100L, 200L));
CapacityVO capacity = backupManager.getBackupStorageUsedStats(zoneId);
Assert.assertNotNull(capacity);
Assert.assertEquals(Optional.ofNullable(Long.valueOf(100)), Optional.ofNullable(capacity.getUsedCapacity()));
Assert.assertEquals(Optional.ofNullable(Long.valueOf(200)), Optional.ofNullable(capacity.getTotalCapacity()));
Assert.assertEquals(CapacityVO.CAPACITY_TYPE_BACKUP_STORAGE, capacity.getCapacityType());
}
@Test
public void testCheckAndRemoveBackupOfferingBeforeExpunge() {
Long vmId = 1L;
Long zoneId = 2L;
Long offeringId = 3L;
String vmUuid = "uuid1";
String instanceName = "i-2-1-VM";
String backupExternalId = "backup-external-id";
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getUuid()).thenReturn(vmUuid);
when(vm.getBackupOfferingId()).thenReturn(offeringId);
when(vm.getInstanceName()).thenReturn(instanceName);
when(vm.getBackupExternalId()).thenReturn(backupExternalId);
when(vm.getDataCenterId()).thenReturn(zoneId);
Backup backup = mock(Backup.class);
when(backupDao.listByVmIdAndOffering(zoneId, vmId, offeringId)).thenReturn(List.of(backup));
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.checkAndRemoveBackupOfferingBeforeExpunge(vm));
Assert.assertEquals("This Instance [uuid: uuid1, name: i-2-1-VM] has a "
+ "Backup Offering [id: 3, external id: backup-external-id] with 1 backups. Please, remove the backup offering "
+ "before proceeding to VM exclusion!", exception.getMessage());
}
@Test
public void testGetIpToNetworkMapFromBackup() {
Long networkId1 = 1L;
Long networkId2 = 2L;
String networkUuid1 = "network-uuid-1";
String networkUuid2 = "network-uuid-2";
String ip1 = "10.1.1.1";
String ip2 = "10.1.1.2";
String ipv61 = "2001:db8::1";
String ipv62 = "2001:db8::2";
String mac1 = "00:11:22:33:44:55";
String mac2 = "00:11:22:33:44:56";
// Test case 1: Missing network information
Backup backup1 = mock(Backup.class);
List<Long> networkIds1 = new ArrayList<>();
try {
backupManager.getIpToNetworkMapFromBackup(backup1, true, networkIds1);
fail("Expected CloudRuntimeException for missing network information");
} catch (CloudRuntimeException e) {
assertEquals("Backup doesn't contain network information. Please specify at least one valid network while creating instance", e.getMessage());
}
// Test case 2: IP preservation enabled with IP information
Backup backup2 = mock(Backup.class);
String nicsJson = String.format("[{\"networkid\":\"%s\",\"ipaddress\":\"%s\",\"ip6address\":\"%s\",\"macaddress\":\"%s\"}," +
"{\"networkid\":\"%s\",\"ipaddress\":\"%s\",\"ip6address\":\"%s\",\"macaddress\":\"%s\"}]",
networkUuid1, ip1, ipv61, mac1, networkUuid2, ip2, ipv62, mac2);
when(backup2.getDetail(ApiConstants.NICS)).thenReturn(nicsJson);
NetworkVO network1 = mock(NetworkVO.class);
NetworkVO network2 = mock(NetworkVO.class);
when(networkDao.findByUuid(networkUuid1)).thenReturn(network1);
when(networkDao.findByUuid(networkUuid2)).thenReturn(network2);
when(network1.getId()).thenReturn(networkId1);
when(network2.getId()).thenReturn(networkId2);
Network.IpAddresses ipAddresses1 = mock(Network.IpAddresses.class);
Network.IpAddresses ipAddresses2 = mock(Network.IpAddresses.class);
when(networkService.getIpAddressesFromIps(ip1, ipv61, mac1)).thenReturn(ipAddresses1);
when(networkService.getIpAddressesFromIps(ip2, ipv62, mac2)).thenReturn(ipAddresses2);
List<Long> networkIds2 = new ArrayList<>();
Map<Long, Network.IpAddresses> result2 = backupManager.getIpToNetworkMapFromBackup(backup2, true, networkIds2);
assertEquals(2, result2.size());
assertEquals(ipAddresses1, result2.get(networkId1));
assertEquals(ipAddresses2, result2.get(networkId2));
assertEquals(2, networkIds2.size());
assertTrue(networkIds2.contains(networkId1));
assertTrue(networkIds2.contains(networkId2));
// Test case 3: IP preservation enabled but missing IP information
Backup backup3 = mock(Backup.class);
nicsJson = String.format("[{\"networkid\":\"%s\"}]", networkUuid1);
when(backup3.getDetail(ApiConstants.NICS)).thenReturn(nicsJson);
List<Long> networkIds3 = new ArrayList<>();
Map<Long, Network.IpAddresses> result3 = backupManager.getIpToNetworkMapFromBackup(backup3, true, networkIds3);
assertEquals(1, result3.size());
assertNull(result3.get(networkId1));
assertEquals(1, networkIds3.size());
assertTrue(networkIds3.contains(networkId1));
// Test case 4: IP preservation disabled
Backup backup4 = mock(Backup.class);
nicsJson = String.format("[{\"networkid\":\"%s\"}]", networkUuid1);
when(backup4.getDetail(ApiConstants.NICS)).thenReturn(nicsJson);
List<Long> networkIds4 = new ArrayList<>();
Map<Long, Network.IpAddresses> result4 = backupManager.getIpToNetworkMapFromBackup(backup4, false, networkIds4);
assertEquals(1, result4.size());
assertNull(result4.get(networkId1));
assertEquals(1, networkIds4.size());
assertTrue(networkIds4.contains(networkId1));
}
@Test
public void testDeleteBackupVmNotFound() {
Long backupId = 1L;
Long vmId = 2L;
Long zoneId = 3L;
Long accountId = 4L;
Long backupOfferingId = 5L;
String vmHostName = "vm1";
String vmUuid = "uuid1";
String resourceName = "Backup-" + vmHostName + "-" + vmUuid;
BackupVO backup = mock(BackupVO.class);
when(backup.getId()).thenReturn(backupId);
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getAccountId()).thenReturn(accountId);
when(backup.getBackupOfferingId()).thenReturn(backupOfferingId);
when(backup.getSize()).thenReturn(100L);
overrideBackupFrameworkConfigValue();
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getAccountId()).thenReturn(accountId);
when(vm.getBackupOfferingId()).thenReturn(10L);
when(vm.getDataCenterId()).thenReturn(zoneId);
when(vm.getHostName()).thenReturn(vmHostName);
when(vm.getUuid()).thenReturn(vmUuid);
when(backupDao.findByIdIncludingRemoved(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(backupDao.listByVmIdAndOffering(zoneId, vmId, backupOfferingId)).thenReturn(new ArrayList<>());
BackupOfferingVO offering = mock(BackupOfferingVO.class);
when(backupOfferingDao.findByIdIncludingRemoved(backupOfferingId)).thenReturn(offering);
when(backupProvider.deleteBackup(backup, false)).thenReturn(true);
when(backupDao.remove(backupId)).thenReturn(true);
try (MockedStatic<UsageEventUtils> usageEventUtilsMocked = Mockito.mockStatic(UsageEventUtils.class)) {
boolean result = backupManager.deleteBackup(backupId, false);
assertTrue(result);
verify(backupProvider).deleteBackup(backup, false);
verify(resourceLimitMgr).decrementResourceCount(accountId, Resource.ResourceType.backup);
verify(resourceLimitMgr).decrementResourceCount(accountId, Resource.ResourceType.backup_storage, backup.getSize());
verify(backupDao).remove(backupId);
usageEventUtilsMocked.verify(() -> UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_BACKUP_OFFERING_REMOVED_AND_BACKUPS_DELETED, accountId, zoneId, vmId, resourceName,
backupOfferingId, null, null, Backup.class.getSimpleName(), vmUuid));
}
}
@Test
public void testNewBackupResponse() {
Long vmId = 1L;
Long accountId = 2L;
Long domainId = 3L;
Long zoneId = 4L;
Long vmOfferingId = 5L;
Long backupOfferingId = 6L;
Long backupId = 7L;
Long templateId = 8L;
String templateUuid = "template-uuid1";
String serviceOfferingUuid = "service-offering-uuid1";
BackupVO backup = new BackupVO();
ReflectionTestUtils.setField(backup, "id", backupId);
ReflectionTestUtils.setField(backup, "uuid", "backup-uuid");
backup.setVmId(vmId);
backup.setAccountId(accountId);
backup.setDomainId(domainId);
backup.setZoneId(zoneId);
backup.setBackupOfferingId(backupOfferingId);
backup.setType("Full");
backup.setBackupScheduleId(null);
VMInstanceVO vm = new VMInstanceVO(vmId, 0L, "test-vm", "test-vm", VirtualMachine.Type.User,
0L, Hypervisor.HypervisorType.Simulator, 0L, domainId, accountId, 0L, false);
vm.setDataCenterId(zoneId);
vm.setBackupOfferingId(vmOfferingId);
vm.setTemplateId(templateId);
AccountVO account = new AccountVO();
account.setUuid("account-uuid");
account.setAccountName("test-account");
DomainVO domain = new DomainVO();
domain.setUuid("domain-uuid");
domain.setName("test-domain");
DataCenterVO zone = new DataCenterVO(1L, "test-zone", null, null, null, null, null, null, null, null, DataCenter.NetworkType.Advanced, null, null);
zone.setUuid("zone-uuid");
BackupOfferingVO offering = Mockito.mock(BackupOfferingVO.class);
Mockito.when(offering.getUuid()).thenReturn("offering-uuid");
Mockito.when(offering.getName()).thenReturn("test-offering");
Mockito.when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
Mockito.when(accountDao.findByIdIncludingRemoved(accountId)).thenReturn(account);
Mockito.when(domainDao.findByIdIncludingRemoved(domainId)).thenReturn(domain);
Mockito.when(dataCenterDao.findByIdIncludingRemoved(zoneId)).thenReturn(zone);
Mockito.when(backupOfferingDao.findByIdIncludingRemoved(backupOfferingId)).thenReturn(offering);
VMTemplateVO template = mock(VMTemplateVO.class);
when(template.getFormat()).thenReturn(Storage.ImageFormat.QCOW2);
when(template.getName()).thenReturn("template1");
when(vmTemplateDao.findByUuid(templateUuid)).thenReturn(template);
Map<String, String> details = new HashMap<>();
details.put(ApiConstants.TEMPLATE_ID, templateUuid);
ServiceOfferingVO serviceOffering = mock(ServiceOfferingVO.class);
when(serviceOffering.getName()).thenReturn("service-offering1");
when(serviceOfferingDao.findByUuid(serviceOfferingUuid)).thenReturn(serviceOffering);
details.put(ApiConstants.SERVICE_OFFERING_ID, serviceOfferingUuid);
NetworkVO network = mock(NetworkVO.class);
when(network.getName()).thenReturn("network1");
when(networkDao.findByUuid("network-uuid1")).thenReturn(network);
details.put(ApiConstants.NICS, "[{\"networkid\":\"network-uuid1\"}]");
Mockito.when(backupDetailsDao.listDetailsKeyPairs(backup.getId(), true)).thenReturn(details);
BackupResponse response = backupManager.createBackupResponse(backup, true);
Assert.assertEquals("backup-uuid", response.getId());
Assert.assertEquals("test-vm", response.getVmName());
Assert.assertEquals("account-uuid", response.getAccountId());
Assert.assertEquals("test-account", response.getAccount());
Assert.assertEquals("domain-uuid", response.getDomainId());
Assert.assertEquals("test-domain", response.getDomain());
Assert.assertEquals("zone-uuid", response.getZoneId());
Assert.assertEquals("test-zone", response.getZone());
Assert.assertEquals("offering-uuid", response.getBackupOfferingId());
Assert.assertEquals("test-offering", response.getBackupOffering());
Assert.assertEquals("MANUAL", response.getIntervalType());
Assert.assertEquals("{serviceofferingid=service-offering-uuid1, isiso=false, hypervisor=Simulator, " +
"nics=[{\"networkid\":\"network-uuid1\",\"networkname\":\"network1\"}], serviceofferingname=service-offering1, " +
"templatename=template1, templateid=template-uuid1}", response.getVmDetails().toString());
Assert.assertEquals(true, response.getVmOfferingRemoved());
}
@Test
public void validateAndGetDefaultBackupRetentionIfRequiredTestReturnZeroAsDefaultValue() {
int retention = backupManager.validateAndGetDefaultBackupRetentionIfRequired(null, backupOfferingVOMock, null);
assertEquals(0, retention);
}
@Test(expected = InvalidParameterValueException.class)
public void validateAndGetDefaultBackupRetentionIfRequiredTestThrowExceptionWhenBackupOfferingProviderIsVeeam() {
Mockito.when(backupOfferingVOMock.getProvider()).thenReturn("veeam");
backupManager.validateAndGetDefaultBackupRetentionIfRequired(1, backupOfferingVOMock, vmInstanceVOMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateAndGetDefaultBackupRetentionIfRequiredTestThrowExceptionWhenMaxBackupsIsLessThanZero() {
backupManager.validateAndGetDefaultBackupRetentionIfRequired(-1, backupOfferingVOMock, vmInstanceVOMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateAndGetDefaultBackupRetentionIfRequiredTestThrowExceptionWhenMaxBackupsExceedsAccountLimit() {
int maxBackups = 6;
long accountId = 1L;
long accountLimit = 5L;
long domainId = 10L;
long domainLimit = -1L;
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(resourceLimitMgr.findCorrectResourceLimitForAccount(accountVOMock, Resource.ResourceType.backup, null)).thenReturn(accountLimit);
when(accountVOMock.getDomainId()).thenReturn(domainId);
when(domainManager.getDomain(domainId)).thenReturn(domainMock);
when(resourceLimitMgr.findCorrectResourceLimitForDomain(domainMock, Resource.ResourceType.backup, null)).thenReturn(domainLimit);
when(accountVOMock.getId()).thenReturn(accountId);
when(accountManager.isRootAdmin(accountId)).thenReturn(false);
backupManager.validateAndGetDefaultBackupRetentionIfRequired(maxBackups, backupOfferingVOMock, vmInstanceVOMock);
}
@Test(expected = InvalidParameterValueException.class)
public void validateAndGetDefaultBackupRetentionIfRequiredTestThrowExceptionWhenMaxBackupsExceedsDomainLimit() {
int maxBackups = 6;
long accountId = 1L;
long accountLimit = -1L;
long domainId = 10L;
long domainLimit = 5L;
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(resourceLimitMgr.findCorrectResourceLimitForAccount(accountVOMock, Resource.ResourceType.backup, null)).thenReturn(accountLimit);
when(accountVOMock.getDomainId()).thenReturn(domainId);
when(domainManager.getDomain(domainId)).thenReturn(domainMock);
when(resourceLimitMgr.findCorrectResourceLimitForDomain(domainMock, Resource.ResourceType.backup, null)).thenReturn(domainLimit);
when(accountVOMock.getId()).thenReturn(accountId);
when(accountManager.isRootAdmin(accountId)).thenReturn(false);
backupManager.validateAndGetDefaultBackupRetentionIfRequired(maxBackups, backupOfferingVOMock, vmInstanceVOMock);
}
@Test
public void validateAndGetDefaultBackupRetentionIfRequiredTestIgnoreLimitCheckWhenAccountIsRootAdmin() {
int maxBackups = 6;
long accountId = 1L;
long accountLimit = 5L;
long domainId = 10L;
long domainLimit = 5L;
when(vmInstanceVOMock.getAccountId()).thenReturn(accountId);
when(accountManager.getAccount(accountId)).thenReturn(accountVOMock);
when(resourceLimitMgr.findCorrectResourceLimitForAccount(accountVOMock, Resource.ResourceType.backup, null)).thenReturn(accountLimit);
when(accountVOMock.getDomainId()).thenReturn(domainId);
when(domainManager.getDomain(domainId)).thenReturn(domainMock);
when(resourceLimitMgr.findCorrectResourceLimitForDomain(domainMock, Resource.ResourceType.backup, null)).thenReturn(domainLimit);
when(accountVOMock.getId()).thenReturn(accountId);
when(accountManager.isRootAdmin(accountId)).thenReturn(true);
int retention = backupManager.validateAndGetDefaultBackupRetentionIfRequired(maxBackups, backupOfferingVOMock, vmInstanceVOMock);
assertEquals(maxBackups, retention);
}
@Test
public void getBackupScheduleTestReturnNullWhenBackupIsManual() {
String jobParams = "{}";
when(asyncJobVOMock.getCmdInfo()).thenReturn(jobParams);
when(asyncJobVOMock.getId()).thenReturn(1L);
Long backupScheduleId = backupManager.getBackupScheduleId(asyncJobVOMock);
assertNull(backupScheduleId);
}
@Test
public void getBackupScheduleTestReturnBackupScheduleIdWhenBackupIsScheduled() {
Map<String, String> params = Map.of(
ApiConstants.SCHEDULE_ID, "100"
);
String jobParams = gson.toJson(params);
when(asyncJobVOMock.getCmdInfo()).thenReturn(jobParams);
when(asyncJobVOMock.getId()).thenReturn(1L);
Long backupScheduleId = backupManager.getBackupScheduleId(asyncJobVOMock);
assertEquals(Long.valueOf("100"), backupScheduleId);
}
@Test
public void getBackupScheduleTestReturnNullWhenSpecifiedBackupScheduleIdIsNotALongValue() {
Map<String, String> params = Map.of(
ApiConstants.SCHEDULE_ID, "InvalidValue"
);
String jobParams = gson.toJson(params);
when(asyncJobVOMock.getCmdInfo()).thenReturn(jobParams);
when(asyncJobVOMock.getId()).thenReturn(1L);
Long backupScheduleId = backupManager.getBackupScheduleId(asyncJobVOMock);
assertNull(backupScheduleId);
}
@Test
public void deleteOldestBackupFromScheduleIfRequiredTestSkipDeletionWhenBackupScheduleIsNotFound() {
backupManager.deleteOldestBackupFromScheduleIfRequired(1L, 1L);
Mockito.verify(backupManager, Mockito.never()).deleteExcessBackups(Mockito.anyList(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void deleteOldestBackupFromScheduleIfRequiredTestSkipDeletionWhenRetentionIsEqualToZero() {
Mockito.when(backupScheduleDao.findById(1L)).thenReturn(backupScheduleVOMock);
Mockito.when(backupScheduleVOMock.getMaxBackups()).thenReturn(0);
backupManager.deleteOldestBackupFromScheduleIfRequired(1L, 1L);
Mockito.verify(backupManager, Mockito.never()).deleteExcessBackups(Mockito.anyList(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void deleteOldestBackupFromScheduleIfRequiredTestSkipDeletionWhenAmountOfBackupsToBeDeletedIsLessThanOne() {
List<BackupVO> backups = List.of(Mockito.mock(BackupVO.class), Mockito.mock(BackupVO.class));
Mockito.when(backupScheduleDao.findById(1L)).thenReturn(backupScheduleVOMock);
Mockito.when(backupScheduleVOMock.getMaxBackups()).thenReturn(2);
Mockito.when(backupDao.listBySchedule(1L)).thenReturn(backups);
backupManager.deleteOldestBackupFromScheduleIfRequired(1L, 1L);
Mockito.verify(backupManager, Mockito.never()).deleteExcessBackups(Mockito.anyList(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void deleteOldestBackupFromScheduleIfRequiredTestDeleteBackupsWhenRequired() {
List<BackupVO> backups = List.of(Mockito.mock(BackupVO.class), Mockito.mock(BackupVO.class));
Mockito.when(backupScheduleDao.findById(1L)).thenReturn(backupScheduleVOMock);
Mockito.when(backupScheduleVOMock.getMaxBackups()).thenReturn(1);
Mockito.when(backupDao.listBySchedule(1L)).thenReturn(backups);
Mockito.doNothing().when(backupManager).deleteExcessBackups(Mockito.anyList(), Mockito.anyInt(), Mockito.anyLong());
backupManager.deleteOldestBackupFromScheduleIfRequired(1L, 1L);
Mockito.verify(backupManager).deleteExcessBackups(Mockito.anyList(), Mockito.anyInt(), Mockito.anyLong());
}
@Test
public void deleteExcessBackupsTestEnsureBackupsAreDeletedWhenMethodIsCalled() {
try (MockedStatic<ActionEventUtils> actionEventUtils = Mockito.mockStatic(ActionEventUtils.class)) {
List<BackupVO> backups = List.of(Mockito.mock(BackupVO.class),
Mockito.mock(BackupVO.class),
Mockito.mock(BackupVO.class));
Mockito.when(backups.get(0).getId()).thenReturn(1L);
Mockito.when(backups.get(1).getId()).thenReturn(2L);
Mockito.when(backups.get(0).getAccountId()).thenReturn(1L);
Mockito.when(backups.get(1).getAccountId()).thenReturn(2L);
Mockito.doReturn(true).when(backupManager).deleteBackup(Mockito.anyLong(), Mockito.eq(false));
actionEventUtils.when(() -> ActionEventUtils.onStartedActionEvent(
Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(),
Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(),
Mockito.anyBoolean(), Mockito.anyInt())).thenReturn(1L);
actionEventUtils.when(() -> ActionEventUtils.onCompletedActionEvent(
Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyInt())).thenReturn(2L);
backupManager.deleteExcessBackups(backups, 2, 1L);
Mockito.verify(backupManager, times(2)).deleteBackup(Mockito.anyLong(), Mockito.eq(false));
}
}
@Test
public void sendExceededBackupLimitAlertTestSendAlertForBackupResourceType() {
String accountUuid = UUID.randomUUID().toString();
String expectedMessage = "Failed to create backup: backup resource limit exceeded for account with ID: " + accountUuid + ".";
String expectedAlertDetails = expectedMessage + " Please, use the 'updateResourceLimit' API to increase the backup limit.";
backupManager.sendExceededBackupLimitAlert(accountUuid, Resource.ResourceType.backup);
verify(alertManagerMock).sendAlert(
AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT,
0L,
0L,
expectedMessage,
expectedAlertDetails
);
}
@Test
public void sendExceededBackupLimitAlertTestSendAlertForBackupStorageResourceType() {
String accountUuid = UUID.randomUUID().toString();
String expectedMessage = "Failed to create backup: backup storage space resource limit exceeded for account with ID: " + accountUuid + ".";
String expectedAlertDetails = expectedMessage + " Please, use the 'updateResourceLimit' API to increase the backup limit.";
backupManager.sendExceededBackupLimitAlert(accountUuid, Resource.ResourceType.backup_storage);
verify(alertManagerMock).sendAlert(
AlertManager.AlertType.ALERT_TYPE_UPDATE_RESOURCE_COUNT,
0L,
0L,
expectedMessage,
expectedAlertDetails
);
}
@Test
public void testListBackupSchedulesAsRootAdmin() {
long vmId = 1L;
ListBackupScheduleCmd cmd = Mockito.mock(ListBackupScheduleCmd.class);
Mockito.when(cmd.getVmId()).thenReturn(vmId);
Mockito.when(cmd.getId()).thenReturn(1L);
// Mock VM for validation
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
Mockito.when(vmInstanceDao.findById(vmId)).thenReturn(vm);
Mockito.when(vm.getDataCenterId()).thenReturn(1L);
overrideBackupFrameworkConfigValue();
Mockito.doNothing().when(accountManager).checkAccess(Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.any());
BackupScheduleVO schedule1 = Mockito.mock(BackupScheduleVO.class);
BackupScheduleVO schedule2 = Mockito.mock(BackupScheduleVO.class);
List<BackupScheduleVO> schedules = List.of(schedule1, schedule2);
SearchBuilder<BackupScheduleVO> searchBuilder = Mockito.mock(SearchBuilder.class);
SearchCriteria<BackupScheduleVO> searchCriteria = Mockito.mock(SearchCriteria.class);
BackupScheduleVO entity = Mockito.mock(BackupScheduleVO.class);
Mockito.when(backupScheduleDao.createSearchBuilder()).thenReturn(searchBuilder);
Mockito.when(searchBuilder.entity()).thenReturn(entity);
Mockito.when(searchBuilder.and(Mockito.anyString(), (Object) any(), Mockito.any())).thenReturn(searchBuilder);
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
Mockito.when(backupScheduleDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(new Pair<>(schedules, schedules.size()));
List<BackupSchedule> result = backupManager.listBackupSchedules(cmd);
assertEquals(2, result.size());
assertTrue(result.contains(schedule1));
assertTrue(result.contains(schedule2));
}
@Test
public void testListBackupSchedulesAsNonAdmin() {
long vmId = 1L;
ListBackupScheduleCmd cmd = Mockito.mock(ListBackupScheduleCmd.class);
Mockito.when(cmd.getVmId()).thenReturn(vmId);
Mockito.when(cmd.getId()).thenReturn(1L);
// Mock VM for validation
VMInstanceVO vm = Mockito.mock(VMInstanceVO.class);
Mockito.when(vmInstanceDao.findById(vmId)).thenReturn(vm);
Mockito.when(vm.getDataCenterId()).thenReturn(1L);
overrideBackupFrameworkConfigValue();
Mockito.doNothing().when(accountManager).checkAccess(Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.any());
BackupScheduleVO schedule = Mockito.mock(BackupScheduleVO.class);
List<BackupScheduleVO> schedules = List.of(schedule);
SearchBuilder<BackupScheduleVO> searchBuilder = Mockito.mock(SearchBuilder.class);
SearchCriteria<BackupScheduleVO> searchCriteria = Mockito.mock(SearchCriteria.class);
BackupScheduleVO entity = Mockito.mock(BackupScheduleVO.class);
Mockito.when(backupScheduleDao.createSearchBuilder()).thenReturn(searchBuilder);
Mockito.when(searchBuilder.create()).thenReturn(searchCriteria);
Mockito.when(searchBuilder.entity()).thenReturn(entity);
Mockito.when(searchBuilder.and(Mockito.anyString(), (Object) any(), Mockito.any())).thenReturn(searchBuilder);
Mockito.lenient().when(backupScheduleDao.search(Mockito.eq(searchCriteria), Mockito.any())).thenReturn(schedules);
Mockito.doNothing().when(accountManager).buildACLSearchBuilder(Mockito.any(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.anyList(), Mockito.any());
Mockito.doNothing().when(accountManager).buildACLSearchCriteria(Mockito.any(), Mockito.anyLong(), Mockito.anyBoolean(), Mockito.anyList(), Mockito.any());
Mockito.when(backupScheduleDao.searchAndCount(Mockito.any(), Mockito.any())).thenReturn(new Pair<>(schedules, schedules.size()));
List<BackupSchedule> result = backupManager.listBackupSchedules(cmd);
assertEquals(1, result.size());
assertTrue(result.contains(schedule));
}
@Test
public void testCanCreateInstanceFromBackupAcrossZonesSuccess() {
Long backupId = 1L;
Long backupOfferingId = 2L;
String providerName = "testbackupprovider";
BackupVO backup = mock(BackupVO.class);
when(backup.getBackupOfferingId()).thenReturn(backupOfferingId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
when(offering.getProvider()).thenReturn(providerName);
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.crossZoneInstanceCreationEnabled(offering)).thenReturn(true);
when(backupDao.findById(backupId)).thenReturn(backup);
when(backupOfferingDao.findByIdIncludingRemoved(backupOfferingId)).thenReturn(offering);
when(backupManager.getBackupProvider(providerName)).thenReturn(backupProvider);
Boolean result = backupManager.canCreateInstanceFromBackupAcrossZones(backupId);
assertTrue(result);
verify(backupDao, times(1)).findById(backupId);
verify(backupOfferingDao, times(1)).findByIdIncludingRemoved(backupOfferingId);
verify(backupManager, times(1)).getBackupProvider(providerName);
verify(backupProvider, times(1)).crossZoneInstanceCreationEnabled(offering);
}
@Test
public void testCanCreateInstanceFromBackupAcrossZonesFalse() {
Long backupId = 1L;
Long backupOfferingId = 2L;
String providerName = "testbackupprovider";
BackupVO backup = mock(BackupVO.class);
when(backup.getBackupOfferingId()).thenReturn(backupOfferingId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
when(offering.getProvider()).thenReturn(providerName);
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.crossZoneInstanceCreationEnabled(offering)).thenReturn(false);
when(backupDao.findById(backupId)).thenReturn(backup);
when(backupOfferingDao.findByIdIncludingRemoved(backupOfferingId)).thenReturn(offering);
when(backupManager.getBackupProvider(providerName)).thenReturn(backupProvider);
Boolean result = backupManager.canCreateInstanceFromBackupAcrossZones(backupId);
assertFalse(result);
verify(backupDao, times(1)).findById(backupId);
verify(backupOfferingDao, times(1)).findByIdIncludingRemoved(backupOfferingId);
verify(backupManager, times(1)).getBackupProvider(providerName);
verify(backupProvider, times(1)).crossZoneInstanceCreationEnabled(offering);
}
@Test
public void testCanCreateInstanceFromBackupAcrossZonesOfferingNotFound() {
Long backupId = 1L;
Long backupOfferingId = 2L;
BackupVO backup = mock(BackupVO.class);
when(backup.getBackupOfferingId()).thenReturn(backupOfferingId);
when(backupDao.findById(backupId)).thenReturn(backup);
when(backupOfferingDao.findByIdIncludingRemoved(backupOfferingId)).thenReturn(null);
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.canCreateInstanceFromBackupAcrossZones(backupId));
assertEquals("Failed to find backup offering", exception.getMessage());
verify(backupDao, times(1)).findById(backupId);
verify(backupOfferingDao, times(1)).findByIdIncludingRemoved(backupOfferingId);
verify(backupManager, never()).getBackupProvider(any(String.class));
}
@Test
public void testRestoreBackupSuccess() throws NoTransitionException {
Long backupId = 1L;
Long vmId = 2L;
Long zoneId = 3L;
Long accountId = 4L;
Long domainId = 5L;
Long userId = 6L;
Long offeringId = 7L;
String vmInstanceName = "test-vm";
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.KVM;
BackupVO backup = mock(BackupVO.class);
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
when(backup.getBackupOfferingId()).thenReturn(offeringId);
Backup.VolumeInfo volumeInfo = new Backup.VolumeInfo("uuid", "path", Volume.Type.ROOT, 1024L, 0L, "disk-offering-uuid", 1000L, 2000L);
when(backup.getBackedUpVolumes()).thenReturn(List.of(volumeInfo));
when(backup.getUuid()).thenReturn("backup-uuid");
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getDataCenterId()).thenReturn(zoneId);
when(vm.getDomainId()).thenReturn(domainId);
when(vm.getAccountId()).thenReturn(accountId);
when(vm.getUserId()).thenReturn(userId);
when(vm.getInstanceName()).thenReturn(vmInstanceName);
when(vm.getHypervisorType()).thenReturn(hypervisorType);
when(vm.getState()).thenReturn(VirtualMachine.State.Stopped);
when(vm.getRemoved()).thenReturn(null);
when(vm.getBackupOfferingId()).thenReturn(offeringId);
BackupOfferingVO offering = mock(BackupOfferingVO.class);
when(offering.getProvider()).thenReturn("testbackupprovider");
VolumeVO volume = mock(VolumeVO.class);
when(volumeDao.findByInstance(vmId)).thenReturn(Collections.singletonList(volume));
BackupProvider backupProvider = mock(BackupProvider.class);
when(backupProvider.restoreVMFromBackup(vm, backup)).thenReturn(true);
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
when(backupOfferingDao.findByIdIncludingRemoved(offeringId)).thenReturn(offering);
when(backupManager.getBackupProvider("testbackupprovider")).thenReturn(backupProvider);
doReturn(true).when(backupManager).importRestoredVM(zoneId, domainId, accountId, userId, vmInstanceName, hypervisorType, backup);
doNothing().when(backupManager).validateBackupForZone(any());
when(virtualMachineManager.stateTransitTo(any(), any(), any())).thenReturn(true);
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onStartedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(),
Mockito.eq(true), Mockito.eq(0))).thenReturn(1L);
boolean result = backupManager.restoreBackup(backupId);
assertTrue(result);
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
verify(backupOfferingDao, times(2)).findByIdIncludingRemoved(offeringId);
verify(backupProvider, times(1)).restoreVMFromBackup(vm, backup);
verify(backupManager, times(1)).importRestoredVM(zoneId, domainId, accountId, userId, vmInstanceName, hypervisorType, backup);
}
}
@Test
public void testRestoreBackupBackupNotFound() {
Long backupId = 1L;
when(backupDao.findById(backupId)).thenReturn(null);
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackup(backupId));
assertEquals("Backup " + backupId + " does not exist", exception.getMessage());
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, never()).findByIdIncludingRemoved(any());
}
@Test
public void testRestoreBackupBackupNotBackedUp() {
Long backupId = 1L;
BackupVO backup = mock(BackupVO.class);
when(backup.getStatus()).thenReturn(Backup.Status.BackingUp);
when(backupDao.findById(backupId)).thenReturn(backup);
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackup(backupId));
assertEquals("Backup should be in BackedUp state", exception.getMessage());
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, never()).findByIdIncludingRemoved(any());
}
@Test
public void testRestoreBackupVmExpunging() {
Long backupId = 1L;
Long vmId = 2L;
Long zoneId = 3L;
BackupVO backup = mock(BackupVO.class);
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getState()).thenReturn(VirtualMachine.State.Expunging);
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
doNothing().when(backupManager).validateBackupForZone(any());
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackup(backupId));
assertEquals("The Instance from which the backup was taken could not be found.", exception.getMessage());
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
}
@Test
public void testRestoreBackupVmNotStopped() {
Long backupId = 1L;
Long vmId = 2L;
Long zoneId = 3L;
BackupVO backup = mock(BackupVO.class);
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getState()).thenReturn(VirtualMachine.State.Running);
when(vm.getRemoved()).thenReturn(null);
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
doNothing().when(backupManager).validateBackupForZone(any());
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackup(backupId));
assertEquals("Existing VM should be stopped before being restored from backup", exception.getMessage());
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
}
@Test
public void testRestoreBackupVolumeMismatch() {
Long backupId = 1L;
Long vmId = 2L;
Long zoneId = 3L;
BackupVO backup = mock(BackupVO.class);
when(backup.getVmId()).thenReturn(vmId);
when(backup.getZoneId()).thenReturn(zoneId);
when(backup.getStatus()).thenReturn(Backup.Status.BackedUp);
when(backup.getBackedUpVolumes()).thenReturn(Collections.emptyList());
VMInstanceVO vm = mock(VMInstanceVO.class);
when(vm.getId()).thenReturn(vmId);
when(vm.getState()).thenReturn(VirtualMachine.State.Destroyed);
when(vm.getRemoved()).thenReturn(null);
when(vm.getBackupVolumeList()).thenReturn(Collections.emptyList());
VolumeVO volume = mock(VolumeVO.class);
when(volumeDao.findByInstance(vmId)).thenReturn(Collections.singletonList(volume));
when(backupDao.findById(backupId)).thenReturn(backup);
when(vmInstanceDao.findByIdIncludingRemoved(vmId)).thenReturn(vm);
doNothing().when(backupManager).validateBackupForZone(any());
try (MockedStatic<ActionEventUtils> utils = Mockito.mockStatic(ActionEventUtils.class)) {
Mockito.when(ActionEventUtils.onStartedActionEvent(Mockito.anyLong(), Mockito.anyLong(),
Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(),
Mockito.eq(true), Mockito.eq(0))).thenReturn(1L);
CloudRuntimeException exception = Assert.assertThrows(CloudRuntimeException.class,
() -> backupManager.restoreBackup(backupId));
assertEquals("Unable to restore VM with the current backup as the backup has different number of disks as the VM", exception.getMessage());
}
verify(backupDao, times(1)).findById(backupId);
verify(vmInstanceDao, times(1)).findByIdIncludingRemoved(vmId);
verify(volumeDao, times(1)).findByInstance(vmId);
}
}