From cbe491a37d21dc5eb8d53118e1a03580d32bc0fe Mon Sep 17 00:00:00 2001 From: Pierre Charton Date: Fri, 13 Dec 2024 15:57:50 +0100 Subject: [PATCH] Unit Test --- plugins/backup/backroll/pom.xml | 2 +- .../backup/BackrollBackupProvider.java | 15 +- .../backup/backroll/BackrollClient.java | 7 +- .../backup/BackrollBackupProviderTest.java | 489 +++++------------- .../backup/backroll/BackrollClientTest.java | 275 ++++++---- 5 files changed, 313 insertions(+), 475 deletions(-) diff --git a/plugins/backup/backroll/pom.xml b/plugins/backup/backroll/pom.xml index 37b2c1572ed..acf9f6a77fb 100644 --- a/plugins/backup/backroll/pom.xml +++ b/plugins/backup/backroll/pom.xml @@ -25,7 +25,7 @@ cloudstack-plugins org.apache.cloudstack - 4.20.0.0-SNAPSHOT + 4.21.0.0-SNAPSHOT ../../pom.xml diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java index a74bfc5e931..892b594fe3b 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/BackrollBackupProvider.java @@ -31,7 +31,6 @@ import javax.inject.Inject; import org.apache.cloudstack.backup.Backup.Metric; import org.apache.cloudstack.backup.backroll.BackrollClient; -import org.apache.cloudstack.backup.backroll.BackrollService; import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics; import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus; import org.apache.cloudstack.backup.backroll.model.BackrollVmBackup; @@ -44,6 +43,8 @@ import org.apache.cloudstack.framework.config.Configurable; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.ParseException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.joda.time.DateTime; import com.cloud.utils.Pair; @@ -79,6 +80,15 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide @Inject private VMInstanceDao vmInstanceDao; + public BackrollBackupProvider(BackupDao backupDao, VMInstanceDao vmInstanceDao, BackrollClient client, Logger logger){ + this.backupDao = backupDao; + this.vmInstanceDao = vmInstanceDao; + this.backrollClient = client; + this.logger = logger; + } + + public BackrollBackupProvider(){} + @Override public String getName() { return "backroll"; @@ -209,7 +219,7 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide syncBackups(vm, null); return result; } - } catch (KeyManagementException | NoSuchAlgorithmException | ParseException | InterruptedException | IOException e) { + } catch (ParseException | BackrollApiException | IOException e) { throw new CloudRuntimeException("Failed to take backup"); } return false; @@ -254,7 +264,6 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size } - } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { } catch (BackrollApiException | IOException e) { logger.error(e); throw new CloudRuntimeException("Failed to get backup metrics"); diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java index 21e7fca2ac7..cd831295e5e 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/BackrollClient.java @@ -24,8 +24,6 @@ import java.util.ArrayList; import java.util.List; import org.apache.cloudstack.backup.BackupOffering; import org.apache.cloudstack.backup.Backup.Metric; -import org.apache.cloudstack.backup.backroll.BackrollService.NotOkBodyException; -import org.apache.cloudstack.backup.backroll.model.BackrollBackup; import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics; import org.apache.cloudstack.backup.backroll.model.BackrollOffering; import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus; @@ -161,6 +159,11 @@ public class BackrollClient { return isBackupDeleted; } + public void triggerTaskStatus(String urlToRequest) + throws IOException, BackrollApiException{ + httpProvider.waitGetWithoutParseResponse(urlToRequest); + } + public Metric getVirtualMachineMetrics(final String vmId) throws IOException, BackrollApiException { logger.info("Trying to retrieve virtual machine metric from Backroll for vm {}", vmId); diff --git a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java index 1dde11d8479..1143e5b4e4a 100644 --- a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java +++ b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/BackrollBackupProviderTest.java @@ -16,404 +16,153 @@ // under the License. package org.apache.cloudstack.backup; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + import java.io.IOException; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HashMap; +import java.util.Arrays; +import java.util.Date; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; +import java.util.UUID; -import javax.inject.Inject; - -import org.apache.cloudstack.backup.Backup.Metric; -import org.apache.cloudstack.backup.backroll.BackrollClientTest; -import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics; +import org.apache.cloudstack.backup.backroll.BackrollClient; +import org.apache.cloudstack.backup.backroll.utils.BackrollApiException; import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus; import org.apache.cloudstack.backup.backroll.model.BackrollVmBackup; +import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics; +import org.apache.cloudstack.backup.backroll.model.response.TaskState; import org.apache.cloudstack.backup.dao.BackupDao; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.Configurable; - -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.StringUtils; import org.apache.http.ParseException; -import org.joda.time.DateTime; +import org.apache.logging.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; -import com.cloud.utils.Pair; -import com.cloud.utils.component.AdapterBase; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.VMInstanceDao; -public class BackrollBackupProviderTest extends AdapterBase implements BackupProvider, Configurable { +import net.bytebuddy.agent.VirtualMachine; - public static final String BACKUP_IDENTIFIER = "-CSBKP-"; +public class BackrollBackupProviderTest { + @Mock + BackrollClient clientMock; - public ConfigKey BackrollUrlConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.url", - "http://api.backup.demo.ccc:5050/api/v1", - "Url for backroll plugin.", true, ConfigKey.Scope.Zone); + @Spy + @InjectMocks + BackrollBackupProvider backupProvider; - public ConfigKey BackrollAppNameConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.appname", - "backroll-api", - "App Name for backroll plugin.", true, ConfigKey.Scope.Zone); + @Mock + BackrollBackupProvider backupProviderMock; - public ConfigKey BackrollPasswordConfigKey = new ConfigKey<>("Advanced", String.class, - "backup.plugin.backroll.config.password", - "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", - "Password for backroll plugin.", true, ConfigKey.Scope.Zone); + @Mock + VMInstanceDao vmInstanceDao; - private BackrollClientTest backrollClient; + @Mock + BackupDao backupDao; - @Inject - private BackupDao backupDao; - @Inject - private VMInstanceDao vmInstanceDao; + @Before + public void setUp() throws Exception { + vmInstanceDao = mock(VMInstanceDao.class); + clientMock = mock(BackrollClient.class); + backupDao = mock(BackupDao.class); + backupProviderMock = mock(BackrollBackupProvider.class); + backupProvider = new BackrollBackupProvider(backupDao, vmInstanceDao, clientMock, Mockito.mock(Logger.class)); + } + @Test + public void syncBackups_Test() throws BackrollApiException, IOException { + VMInstanceVO vmInstanceVO = new VMInstanceVO(); + vmInstanceVO.setInstanceName("test"); + vmInstanceVO.setDataCenterId(2l); + vmInstanceVO.setBackupOfferingId(2l); + Backup.Metric metric = new Backup.Metric(2L, 3L); - @Override - public String getName() { - return "backroll"; + BackupVO backupBackingUp = new BackupVO(); + backupBackingUp.setVmId(1l); + backupBackingUp.setExternalId("abc,defgh"); + backupBackingUp.setType("Full"); + backupBackingUp.setSize(2L); + backupBackingUp.setZoneId(2l); + backupBackingUp.setStatus(Backup.Status.BackingUp); + + BackupVO backupBackedUp = new BackupVO(); + backupBackedUp.setVmId(6l); + backupBackedUp.setExternalId("abc,defgh"); + backupBackedUp.setType("Full"); + backupBackedUp.setZoneId(2l); + backupBackedUp.setSize(2L); + backupBackedUp.setStatus(Backup.Status.BackedUp); + + BackupVO backupFailed = new BackupVO(); + backupFailed.setVmId(6l); + backupFailed.setExternalId("abc,defgh"); + backupFailed.setType("Full"); + backupFailed.setZoneId(2l); + backupFailed.setSize(2L); + backupFailed.setStatus(Backup.Status.Failed); + + BackrollTaskStatus backupStatus = new BackrollTaskStatus(); + backupStatus.setState(TaskState.SUCCESS); + + BackrollBackupMetrics metrics = new BackrollBackupMetrics(2L, 3L); + + List backupsFromBackroll = Arrays.asList( + new BackrollVmBackup("OK","OK", new Date())); + + List backupsInDb = Arrays.asList(backupBackingUp, backupBackedUp, backupFailed); + Mockito.doReturn(backupsInDb).when(backupDao).listByVmId(Mockito.anyLong(), Mockito.anyLong()); + Mockito.doReturn(backupStatus).when(clientMock).checkBackupTaskStatus(Mockito.anyString()); + Mockito.doReturn(metrics).when(clientMock).getBackupMetrics(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(new BackupVO()).when(backupDao).persist(Mockito.any(BackupVO.class)); + Mockito.doReturn(backupsFromBackroll).when(clientMock).getAllBackupsfromVirtualMachine(Mockito.anyString()); + Mockito.doReturn(true).when(backupDao).remove(Mockito.anyLong()); + + backupProvider.syncBackups(vmInstanceVO, metric); } - @Override - public String getDescription() { - return "Backroll Backup Plugin"; + + @Test + public void getClient_Test() { + BackrollClient client = backupProvider.getClient(2L); + assertEquals(client, clientMock); } - @Override - public List listBackupOfferings(Long zoneId) { - logger.debug("Listing backup policies on backroll B&R Plugin"); - logger.info("Listing backup policies on backroll B&R Plugin"); - BackrollClientTest client = getClient(zoneId); - try{ - String urlToRequest = client.getBackupOfferingUrl(); - logger.info("BackrollProvider: urlToRequest: " + urlToRequest); - if (!StringUtils.isEmpty(urlToRequest)){ - List results = new ArrayList(); - // return client.getBackupOfferings(urlToRequest); - results = client.getBackupOfferings(urlToRequest); - if(results.size()>0) { - logger.info("BackrollProvider: results > 0"); - } else { - logger.info("BackrollProvider: results <= 0"); - } - return results; - } - } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { - logger.info("BackrollProvider: catch erreur!!!!!!!!!!!!!!!!!!!!!!!!"); - throw new CloudRuntimeException("Failed to load backup offerings"); - } - return new ArrayList(); + @Test + public void deleteBackupTestSuccess_Test() throws BackrollApiException, IOException { + VMInstanceVO vmInstanceVO = new VMInstanceVO(); + vmInstanceVO.setInstanceName("test"); + vmInstanceVO.setDataCenterId(2l); + vmInstanceVO.setUuid(UUID.randomUUID().toString()); + BackupVO backup = new BackupVO(); + backup.setVmId(1l); + backup.setExternalId("abc,defgh"); + backup.setType("Full"); + backup.setZoneId(2l); + backup.setStatus(Backup.Status.Removed); + Boolean deleteBackupResponse = true; + Mockito.doReturn(vmInstanceVO).when(vmInstanceDao).findByIdIncludingRemoved(Mockito.anyLong()); + Mockito.doReturn(deleteBackupResponse).when(clientMock).deleteBackup(Mockito.anyString(), Mockito.anyString()); + Mockito.doReturn(new BackupVO()).when(backupDao).persist(Mockito.any(BackupVO.class)); + boolean result = backupProvider.deleteBackup(backup, true); + assertEquals(true, result); } - @Override - public boolean isValidProviderOffering(Long zoneId, String uuid) { - logger.info("Checking if backup offering exists on the Backroll Backup Provider"); - return true; - } - - @Override - public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) { - logger.info("Creating VM backup for VM {} from backup offering {}", vm.getInstanceName(), backupOffering.getName()); - ((VMInstanceVO) vm).setBackupExternalId(backupOffering.getUuid()); - return true; - } - - @Override - public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) { - logger.debug("Restoring vm {} from backup {} on the backroll Backup Provider", vm.getUuid(), backup.getUuid()); - boolean isSuccess; + @Test + public void deleteBackupBackinUp_Test() { + BackupVO backup = new BackupVO(); + backup.setStatus(Backup.Status.BackingUp); try { - isSuccess = getClient(vm.getDataCenterId()).restoreVMFromBackup(vm.getUuid(), getBackupName(backup)); - } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to restore VM from Backrup"); - } - return isSuccess; - } - - @Override - public Map getBackupMetrics(Long zoneId, List vms) { - final Map metrics = new HashMap<>(); - if (CollectionUtils.isEmpty(vms)) { - logger.warn("Unable to get VM Backup Metrics because the list of VMs is empty."); - return metrics; - } - - List vmUuids = vms.stream().filter(Objects::nonNull).map(VirtualMachine::getUuid).collect(Collectors.toList()); - logger.debug("Get Backup Metrics for VMs: {}.", String.join(", ", vmUuids)); - - for (final VirtualMachine vm : vms) { - if (vm == null) { - continue; - } - - Metric metric; - try { - metric = getClient(zoneId).getVirtualMachineMetrics(vm.getUuid()); - } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to retrieve backup metrics"); - } - logger.debug("Metrics for VM [uuid: {}, name: {}] is [backup size: {}, data size: {}].", vm.getUuid(), - vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize()); - metrics.put(vm, metric); - } - return metrics; - } - - @Override - public boolean removeVMFromBackupOffering(VirtualMachine vm) { - return true; - } - - @Override - public boolean willDeleteBackupsOnOfferingRemoval() { - return false; - } - - @Override - public boolean takeBackup(VirtualMachine vm) { - logger.info("Starting backup for VM ID {} on backroll provider", vm.getUuid()); - final BackrollClientTest client = getClient(vm.getDataCenterId()); - - try { - String urlToRequest = client.startBackupJob(vm.getUuid()); - - String backupJob = urlToRequest.replace("/status/", ""); - if (!StringUtils.isEmpty(backupJob)) { - BackupVO backup = new BackupVO(); - backup.setVmId(vm.getId()); - backup.setExternalId(backupJob); - backup.setType("INCREMENTAL"); - backup.setDate(new DateTime().toDate()); - backup.setSize(0L); - backup.setProtectedSize(0L); - backup.setStatus(Backup.Status.BackingUp); - backup.setBackupOfferingId(vm.getBackupOfferingId()); - backup.setAccountId(vm.getAccountId()); - backup.setDomainId(vm.getDomainId()); - backup.setZoneId(vm.getDataCenterId()); - Boolean result = backupDao.persist(backup) != null; - client.triggerTaskStatus(urlToRequest); - syncBackups(vm, null); - return result; - } - } catch (KeyManagementException | NoSuchAlgorithmException | ParseException | InterruptedException | IOException e) { - throw new CloudRuntimeException("Failed to take backup"); - } - return false; - } - - - @Override - public void syncBackups(VirtualMachine vm, Backup.Metric metric) { - logger.info("Starting sync backup for VM ID " + vm.getUuid() + " on backroll provider"); - - final BackrollClientTest client = getClient(vm.getDataCenterId()); - List backupsInDb = backupDao.listByVmId(null, vm.getId()); - - for (Backup backup : backupsInDb) { - if (backup.getStatus().equals(Backup.Status.BackingUp)) { - BackrollTaskStatus response; - try { - response = client.checkBackupTaskStatus(backup.getExternalId()); - } catch (KeyManagementException | ParseException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to sync backups"); - } - - if (response != null) { - logger.debug("backroll backup id: {}", backup.getExternalId()); - logger.debug("backroll backup status: {}", response.getState()); - - BackupVO backupToUpdate = new BackupVO(); - backupToUpdate.setVmId(backup.getVmId()); - backupToUpdate.setExternalId(backup.getExternalId()); - backupToUpdate.setType(backup.getType()); - backupToUpdate.setDate(backup.getDate()); - backupToUpdate.setSize(backup.getSize()); - backupToUpdate.setProtectedSize(backup.getProtectedSize()); - backupToUpdate.setBackupOfferingId(vm.getBackupOfferingId()); - backupToUpdate.setAccountId(backup.getAccountId()); - backupToUpdate.setDomainId(backup.getDomainId()); - backupToUpdate.setZoneId(backup.getZoneId()); - - if (response.getState().equals("PENDING")) { - backupToUpdate.setStatus(Backup.Status.BackingUp); - } else if (response.getState().equals("FAILURE")) { - backupToUpdate.setStatus(Backup.Status.Failed); - } else if (response.getState().equals("SUCCESS")) { - backupToUpdate.setStatus(Backup.Status.BackedUp); - backupToUpdate.setExternalId(backup.getExternalId() + "," + response.getInfo()); - - BackrollBackupMetrics backupMetrics = null; - try { - backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo()); - if (backupMetrics != null) { - backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size - backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size - } - } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to get backup metrics"); - } - } else { - backupToUpdate.setStatus(Backup.Status.BackingUp); - } - - if (backupDao.persist(backupToUpdate) != null) { - logger.info("Backroll mise à jour enregistrée"); - backupDao.remove(backup.getId()); - } - } - } else if (backup.getStatus().equals(Backup.Status.BackedUp) && backup.getSize().equals(0L)) { - String backupId = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); - BackrollBackupMetrics backupMetrics; - try { - backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId); - } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to get backup metrics"); - } - - if (backupMetrics != null) { - BackupVO backupToUpdate = ((BackupVO) backup); - backupToUpdate.setSize(backupMetrics.getDeduplicated()); // real size - backupToUpdate.setProtectedSize(backupMetrics.getSize()); // total size - backupDao.persist(backupToUpdate); - } - } - } - - // Backups synchronisation between Backroll ad CS Db - List backupsFromBackroll = client.getAllBackupsfromVirtualMachine(vm.getUuid()); - backupsInDb = backupDao.listByVmId(null, vm.getId()); - - // insert new backroll backup in CS - for (BackrollVmBackup backupInBackroll : backupsFromBackroll) { - Backup backupToFind = backupsInDb.stream() - .filter(backupInDb -> backupInDb.getExternalId().contains(backupInBackroll.getName())) - .findAny() - .orElse(null); - - if (backupToFind == null) { - BackupVO backupToInsert = new BackupVO(); - backupToInsert.setVmId(vm.getId()); - backupToInsert.setExternalId(backupInBackroll.getId() + "," + backupInBackroll.getName()); - backupToInsert.setType("INCREMENTAL"); - backupToInsert.setDate(backupInBackroll.getDate()); - backupToInsert.setSize(0L); - backupToInsert.setProtectedSize(0L); - backupToInsert.setStatus(Backup.Status.BackedUp); - backupToInsert.setBackupOfferingId(vm.getBackupOfferingId()); - backupToInsert.setAccountId(vm.getAccountId()); - backupToInsert.setDomainId(vm.getDomainId()); - backupToInsert.setZoneId(vm.getDataCenterId()); - backupDao.persist(backupToInsert); - } - if (backupToFind != null && backupToFind.getStatus() == Backup.Status.Removed) { - BackupVO backupToUpdate = ((BackupVO) backupToFind); - backupToUpdate.setStatus(Backup.Status.BackedUp); - if (backupDao.persist(backupToUpdate) != null) { - logger.info("Backroll update saved"); - backupDao.remove(backupToFind.getId()); - } - } - } - - // delete deleted backroll backup in CS - backupsInDb = backupDao.listByVmId(null, vm.getId()); - for (Backup backup : backupsInDb) { - String backupName = backup.getExternalId().contains(",") ? backup.getExternalId().split(",")[1] : backup.getExternalId(); - BackrollVmBackup backupToFind = backupsFromBackroll.stream() - .filter(backupInBackroll -> backupInBackroll.getName().contains(backupName)) - .findAny() - .orElse(null); - - if (backupToFind == null) { - BackupVO backupToUpdate = ((BackupVO) backup); - backupToUpdate.setStatus(Backup.Status.Removed); - if (backupDao.persist(backupToUpdate) != null) { - logger.debug("Backroll delete saved (sync)"); - } - } + backupProvider.deleteBackup(backup, false); + } catch (Exception e) { + assertEquals(CloudRuntimeException.class, e.getClass()); + String expected = String.format("You can't delete a backup while it still BackingUp"); + assertEquals(expected , e.getMessage()); } } - - @Override - public String getConfigComponentName() { - return BackupService.class.getSimpleName(); - } - - @Override - public ConfigKey[] getConfigKeys() { - return new ConfigKey[]{ - BackrollUrlConfigKey, - BackrollAppNameConfigKey, - BackrollPasswordConfigKey - }; - } - - @Override - public boolean deleteBackup(Backup backup, boolean forced) { - logger.info("backroll delete backup id: {}", backup.getExternalId()); - if (backup.getStatus().equals(Backup.Status.BackingUp)) { - throw new CloudRuntimeException("You can't delete a backup while it still BackingUp"); - } else { - logger.debug("backroll - try delete backup"); - VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId()); - - if (backup.getStatus().equals(Backup.Status.Removed) || backup.getStatus().equals(Backup.Status.Failed)){ - return deleteBackupInDb(backup); - } else { - try { - if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { - logger.debug("Backup deletion for backup {} complete on backroll side.", backup.getUuid()); - return deleteBackupInDb(backup); - } - } catch (KeyManagementException | NoSuchAlgorithmException | IOException e) { - throw new CloudRuntimeException("Failed to delete backup"); - } - } - } - return false; - } - - private boolean deleteBackupInDb(Backup backup) { - BackupVO backupToUpdate = ((BackupVO) backup); - backupToUpdate.setStatus(Backup.Status.Removed); - if (backupDao.persist(backupToUpdate) != null) { - logger.debug("Backroll backup {} deleted in database.", backup.getUuid()); - return true; - } - return false; - } - - protected BackrollClientTest getClient(final Long zoneId) { - logger.debug("Backroll Provider GetClient with zone id {}", zoneId); - try { - if (backrollClient == null) { - logger.debug("backroll client null - instanciation of new one "); - backrollClient = new BackrollClientTest(BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600); - } - return backrollClient; - } catch (URISyntaxException e) { - throw new CloudRuntimeException("Failed to parse Backroll API URL: " + e.getMessage()); - } catch (NoSuchAlgorithmException | KeyManagementException e) { - logger.info("Failed to build Backroll API client due to: ", e); - } - throw new CloudRuntimeException("Failed to build Backroll API client"); - } - - private String getBackupName(Backup backup) { - return backup.getExternalId().substring(backup.getExternalId().indexOf(",") + 1); - } - - @Override - public Pair restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid, Pair vmNameAndState) { - logger.debug("Restoring volume {} from backup {} on the Backroll Backup Provider", volumeUuid, backup.getUuid()); - throw new CloudRuntimeException("Backroll plugin does not support this feature"); - } -} +} \ No newline at end of file diff --git a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java index 437277adffe..1ce259749d0 100644 --- a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java +++ b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/BackrollClientTest.java @@ -16,45 +16,49 @@ // under the License. package org.apache.cloudstack.backup.backroll; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; +import java.io.IOException; +import java.util.Arrays; import java.util.List; -import org.apache.cloudstack.backup.BackupService; +import org.apache.cloudstack.backup.Backup.Metric; +import org.apache.cloudstack.backup.BackupOffering; +import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics; +import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus; import org.apache.cloudstack.backup.backroll.model.BackrollVmBackup; - -import org.apache.http.HttpEntity; -import org.apache.http.StatusLine; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.util.EntityUtils; - +import org.apache.cloudstack.backup.backroll.model.response.BackrollTaskRequestResponse; +import org.apache.cloudstack.backup.backroll.model.response.TaskState; +import org.apache.cloudstack.backup.backroll.model.response.archive.BackrollBackupsFromVMResponse; +import org.apache.cloudstack.backup.backroll.model.response.metrics.backup.BackrollBackupMetricsResponse; +import org.apache.cloudstack.backup.backroll.model.response.metrics.backup.BackupMetricsInfo; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.BackrollVmMetricsResponse; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.CacheStats; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.InfosCache; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachine.MetricsInfos; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.VirtualMachineBackupsResponse; +import org.apache.cloudstack.backup.backroll.model.response.policy.BackrollBackupPolicyResponse; +import org.apache.cloudstack.backup.backroll.model.response.policy.BackupPoliciesResponse; +import org.apache.cloudstack.backup.backroll.utils.BackrollApiException; +import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider; import org.apache.logging.log4j.Logger; - -import org.junit.Assert; +import org.json.JSONObject; import org.junit.Before; import org.junit.Rule; import org.junit.Test; + import org.mockito.Mock; import org.mockito.Mockito; - -import com.cloud.utils.exception.CloudRuntimeException; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.tomakehurst.wiremock.junit.WireMockRule; public class BackrollClientTest { private BackrollClient client; @Mock - private BackrollService mockBackrollService; + private BackrollHttpClientProvider backrollHttpClientProviderMock; @Rule @@ -62,101 +66,174 @@ public class BackrollClientTest { @Before public void setUp() throws Exception { - mockBackrollService = mock(BackrollService.class); - mockBackrollService.logger = Mockito.mock(Logger.class); - client = new BackrollClient("http://localhost:5050/api/v1/", "backroll", "password", true, 300, 600, mockBackrollService); + backrollHttpClientProviderMock = mock(BackrollHttpClientProvider.class); + client = new BackrollClient(backrollHttpClientProviderMock); + client.logger = Mockito.mock(Logger.class); } @Test public void getAllBackupsfromVirtualMachine_test() throws Exception { String vmId = "TEST-vm_uuid"; - CloseableHttpResponse mockHttpResponse = mock(CloseableHttpResponse.class); - CloseableHttpResponse mockHttpResponse2 = mock(CloseableHttpResponse.class); - - // Define mock behavior for first HTTP response - String responseContent1 = "{\"Location\":\"/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782\"}"; - - // Define mock behavior for second HTTP response - String responseContent2 = "{ \"state\": \"SUCCESS\", \"info\": { \"archives\": [ { \"archive\": \"ROOT-00000\", \"barchive\": \"ROOT-00000\", \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\", \"name\": \"ROOT-00000\", \"start\": \"2024-11-08T18:24:48.000000\", \"time\": \"2024-11-08T18:24:48.000000\" } ], \"encryption\": { \"mode\": \"none\" }, \"repository\": { \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\", \"last_modified\": \"2024-11-29T09:53:09.000000\", \"location\": \"/mnt/backup/backup1\" } } }"; + String virtualMachineResponseString = "{ \"state\": \"SUCCESS\", \"info\": { \"archives\": [ { \"archive\": \"ROOT-00000\", \"barchive\": \"ROOT-00000\", \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\", \"name\": \"ROOT-00000\", \"start\": \"2024-11-08T18:24:48.000000\", \"time\": \"2024-11-08T18:24:48.000000\" } ], \"encryption\": { \"mode\": \"none\" }, \"repository\": { \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\", \"last_modified\": \"2024-11-29T09:53:09.000000\", \"location\": \"/mnt/backup/backup1\" } } }"; + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + VirtualMachineBackupsResponse virtualMachineBackupsResponseMock = new ObjectMapper().readValue(virtualMachineResponseString, VirtualMachineBackupsResponse.class); // Mocking client responses - doReturn(mockHttpResponse).when(mockBackrollService).get(Mockito.any(URI.class), Mockito.matches(".*/virtualmachines/.*")); - doReturn(responseContent1).when(mockBackrollService).okBody(mockHttpResponse); - doReturn(responseContent2).when(mockBackrollService).waitGet(Mockito.any(URI.class), Mockito.anyString()); - doReturn(mockHttpResponse2).when(mockBackrollService).get(Mockito.any(URI.class), Mockito.matches(".*/status/.*")); - - // Assuming getAllBackupsfromVirtualMachine belongs to a class named BackupService - + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any()); + doReturn(virtualMachineBackupsResponseMock).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any()); // Run the method under test List backupsTestList = client.getAllBackupsfromVirtualMachine(vmId); // Check results assertEquals(1, backupsTestList.size()); // Should be 1 based on provided mock data - - // Optional: Verifications - verify(mockHttpResponse).close(); } - // @Test - // public void getAllBackupsfromVirtualMachine_test2() throws Exception { - // String vmId = "TEST-vm_uuid"; - // CloseableHttpResponse mockHttpResponse = mock(CloseableHttpResponse.class); - // CloseableHttpResponse mockHttpResponse2 = mock(CloseableHttpResponse.class); - // StatusLine mockStatusLine = mock(StatusLine.class); - // HttpEntity mockEntity = mock(HttpEntity.class); - // HttpEntity mockEntity2 = mock(HttpEntity.class); - // //InputStream mockInputStream = new ByteArrayInputStream("{\"Location\":\"/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782\"}".getBytes()); + @Test + public void getBackupMetrics_Test() throws IOException, BackrollApiException { + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + BackrollBackupMetricsResponse mockResponse = new BackrollBackupMetricsResponse(); + mockResponse.info = new BackupMetricsInfo(); + mockResponse.info.originalSize = "1000"; + mockResponse.info.deduplicatedSize = "800"; - // // Define mock behavior - // when(mockHttpResponse.getStatusLine()).thenReturn(mockStatusLine); - // when(mockStatusLine.getStatusCode()).thenReturn(200); - // when(mockHttpResponse.getEntity()).thenReturn(mockEntity); - // when(mockEntity.getContentLength()).thenReturn(400L); + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any()); + doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any()); - // String responseContent = "{\"Location\":\"/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782\"}"; - // InputStream stream = new ByteArrayInputStream(responseContent.getBytes()); - // when(mockEntity.getContent()).thenReturn(stream); + BackrollBackupMetrics metrics = client.getBackupMetrics("dummyVMId", "dummyBackupId"); - // when(mockHttpResponse2.getStatusLine()).thenReturn(mockStatusLine); - // when(mockStatusLine.getStatusCode()).thenReturn(200); - // when(mockHttpResponse2.getEntity()).thenReturn(mockEntity2); - // when(mockEntity2.getContentLength()).thenReturn(400L); + assertEquals(1000L, metrics.getSize()); + assertEquals(800L, metrics.getDeduplicated()); + } - // String responseContent2 = "{\r\n" + // - // " \"state\": \"SUCCESS\",\r\n" + // - // " \"info\": {\r\n" + // - // " \"archives\": [\r\n" + // - // " {\r\n" + // - // " \"archive\": \"ROOT-00000\",\r\n" + // - // " \"barchive\": \"ROOT-00000\",\r\n" + // - // " \"id\": \"25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457\",\r\n" + // - // " \"name\": \"ROOT-00000\",\r\n" + // - // " \"start\": \"2024-11-08T18:24:48.000000\",\r\n" + // - // " \"time\": \"2024-11-08T18:24:48.000000\"\r\n" + // - // " }\r\n" + // - // " ],\r\n" + // - // " \"encryption\": {\r\n" + // - // " \"mode\": \"none\"\r\n" + // - // " },\r\n" + // - // " \"repository\": {\r\n" + // - // " \"id\": \"36a11ebc0775a097c927735cc7015d19be7309be69fc15b896c5b1fd87fcbd79\",\r\n" + // - // " \"last_modified\": \"2024-11-29T09:53:09.000000\",\r\n" + // - // " \"location\": \"/mnt/backup/backup1\"\r\n" + // - // " }\r\n" + // - // " }\r\n" + // - // "}"; - // InputStream stream2 = new ByteArrayInputStream(responseContent2.getBytes()); - // when(mockEntity2.getContent()).thenReturn(stream2); + @Test + public void getVirtualMachineMetrics_Test() throws IOException, BackrollApiException { + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; - // try { - // Mockito.doReturn(mockHttpResponse).when(mockClient).get(Mockito.matches(".*/virtualmachines/.*")); - // Mockito.doReturn(mockHttpResponse2).when(mockClient).get(Mockito.matches(".*/api/v1.*")); - // List backupsTesList = mockClient.getAllBackupsfromVirtualMachine(vmId); - // Assert.assertTrue(backupsTesList.size() > 0); - // fail(); - // } catch (Exception e) { - // Assert.assertEquals(CloudRuntimeException.class, e.getClass()); - // Assert.assertEquals("Failed to get Repository Name from Job [name: TEST-BACKUP].", e.getMessage()); - // } - // } + BackrollVmMetricsResponse mockResponse = new BackrollVmMetricsResponse(); + mockResponse.state = TaskState.SUCCESS; + mockResponse.infos = new MetricsInfos(); + mockResponse.infos.cache = new InfosCache(); + mockResponse.infos.cache.stats = new CacheStats(); + mockResponse.infos.cache.stats.totalSize = "10000"; + + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any()); + doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any()); + + Metric metrics = client.getVirtualMachineMetrics("dummyVMId"); + + assertEquals(10000L, (long)metrics.getBackupSize()); + assertEquals(10000L, (long)metrics.getDataSize()); + } + @Test + public void deleteBackup_Test() throws IOException, BackrollApiException{ + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + + BackrollBackupsFromVMResponse mockResponse = new BackrollBackupsFromVMResponse(); + mockResponse.state = TaskState.SUCCESS; + + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).delete(Mockito.matches(".*/virtualmachines/.*"), Mockito.any()); + doReturn(mockResponse).when(backrollHttpClientProviderMock).waitGet(Mockito.anyString(), Mockito.any()); + + Boolean isBackupDeleted = client.deleteBackup("dummyVMId", "dummyBackUpName"); + + assertTrue(isBackupDeleted); + } + @Test + public void checkBackupTaskStatusSuccess_Test() throws IOException, BackrollApiException { + String backupResponse = "{\"state\":\"SUCCESS\",\"info\":\"test\"}"; + doReturn(backupResponse).when(backrollHttpClientProviderMock).getWithoutParseResponse(Mockito.matches(".*status/.*")); + + BackrollTaskStatus status = client.checkBackupTaskStatus("dummytaskid"); + + assertEquals(TaskState.SUCCESS, status.getState()); + assertEquals("test", status.getInfo()); + } + + @Test + public void checkBackupTaskStatus_Test() throws IOException, BackrollApiException { + String backupResponse = "{\"state\":\"PENDING\",\"current\":0,\"total\":1,\"status\":\"Pending...\"}"; + doReturn(backupResponse).when(backrollHttpClientProviderMock).getWithoutParseResponse(Mockito.matches(".*/status/.*")); + + BackrollTaskStatus status = client.checkBackupTaskStatus("dummytaskid"); + + assertEquals(TaskState.PENDING, status.getState()); + } + @Test + public void restoreVMFromBackup_Test() throws IOException, BackrollApiException { + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + String resultMock = "SUCCESS WOW YOUHOU"; + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).post(Mockito.matches(".*/tasks/restore/.*"), Mockito.any(JSONObject.class),Mockito.any()); + doReturn(resultMock).when(backrollHttpClientProviderMock).waitGetWithoutParseResponse(Mockito.anyString()); + + Boolean isRestoreOk = client.restoreVMFromBackup("dummyVMId", "dummyBackUpName"); + + assertTrue(isRestoreOk); + } + + @Test + public void startBackupJob_Test() throws IOException, BackrollApiException { + + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).post(Mockito.matches(".*/tasks/singlebackup/.*"), Mockito.nullable(JSONObject.class),Mockito.any()); + + String response = client.startBackupJob("dummyJobId"); + + assertEquals("f32092e4-3e8a-461b-8733-ed93e23fa782", response); + } + + @Test + public void getBackupOfferingUrl_Test() throws IOException, BackrollApiException { + BackrollTaskRequestResponse backrollTaskReqResponseMock = new BackrollTaskRequestResponse(); + backrollTaskReqResponseMock.location = "/api/v1/status/f32092e4-3e8a-461b-8733-ed93e23fa782"; + doReturn(backrollTaskReqResponseMock).when(backrollHttpClientProviderMock).get(Mockito.matches(".*/backup_policies.*"), Mockito.any()); + + String response = client.getBackupOfferingUrl(); + + assertEquals("/status/f32092e4-3e8a-461b-8733-ed93e23fa782", response); + } + + @Test + public void getBackupOfferings_Test() throws BackrollApiException, IOException { + + BackrollBackupPolicyResponse policy1 = new BackrollBackupPolicyResponse(); + policy1.name = "User-Policy-1"; + policy1.retentionDay = 6; + policy1.schedule = "0 0 * * 1"; + policy1.retentionMonth = 0; + policy1.storage = "f32092e4-3e8a-461b-8733-ed93e23fa782"; + policy1.enabled = false; + policy1.description = "User's policy 1 description"; + policy1.id = "f32092e4-3e8a-461b-8733-ed93e23fa782"; + policy1.retentionWeek = 0; + policy1.retentionYear = 0; + policy1.externalHook = null; + + BackrollBackupPolicyResponse policy2 = new BackrollBackupPolicyResponse(); + policy1.name = "User-Policy-2"; + policy1.retentionDay = 6; + policy1.schedule = "0 0 * * 1"; + policy1.retentionMonth = 0; + policy1.storage = "f32092e4-3e8a-461b-8733-ed93e23fa782"; + policy1.enabled = false; + policy1.description = "User's policy 2 description"; + policy1.id = "f32092e4-3e8a-461b-8733-ed93e23fa782"; + policy1.retentionWeek = 0; + policy1.retentionYear = 0; + policy1.externalHook = null; + BackupPoliciesResponse backupPoliciesResponseMock = new BackupPoliciesResponse(); + backupPoliciesResponseMock.backupPolicies = Arrays.asList(policy1, policy2); + + doReturn(backupPoliciesResponseMock).when(backrollHttpClientProviderMock).waitGet(Mockito.matches("/status/f32092e4-3e8a-461b-8733-ed93e23fa782"), Mockito.any()); + + List response = client.getBackupOfferings("/status/f32092e4-3e8a-461b-8733-ed93e23fa782"); + + assertEquals(response.size(), 2); + + } } \ No newline at end of file