Fix unit tests, fix metrics (waiting PR #10140 to finish to fix metrics)

This commit is contained in:
Pierre Charton 2025-04-04 09:54:22 +02:00
parent 86f5066d99
commit f9038713fb
6 changed files with 136 additions and 155 deletions

View File

@ -34,6 +34,7 @@ import org.apache.cloudstack.backup.Backup.Metric;
import org.apache.cloudstack.backup.Backup.RestorePoint;
import org.apache.cloudstack.backup.backroll.BackrollClient;
import org.apache.cloudstack.backup.backroll.model.BackrollBackupMetrics;
import org.apache.cloudstack.backup.backroll.model.BackrollTaskStatus;
import org.apache.cloudstack.backup.backroll.utils.BackrollApiException;
import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider;
import org.apache.cloudstack.backup.dao.BackupDao;
@ -167,16 +168,111 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide
if (vm == null) {
continue;
}
Metric metric;
try {
metric = client.getVirtualMachineMetrics(vm.getUuid());
// get backups from database
List<Backup> backupsInDb = backupDao.listByVmId(zoneId, vm.getId());
// check backing up task
for (Backup backup : backupsInDb) {
if (backup.getStatus().equals(Backup.Status.BackingUp)) {
BackrollTaskStatus response;
try {
response = client.checkBackupTaskStatus(backup.getExternalId());
} catch (ParseException | BackrollApiException | IOException e) {
logger.error(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 = ((BackupVO) backup);
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(response.getInfo());
BackrollBackupMetrics backupMetrics = null;
try {
backupMetrics = client.getBackupMetrics(vm.getUuid() , response.getInfo());
if (backupMetrics != null) {
backupToUpdate.setProtectedSize(backupMetrics.getDeduplicated());
backupToUpdate.setSize(backupMetrics.getSize());
}
} catch (BackrollApiException | IOException e) {
logger.error(e);
throw new CloudRuntimeException("Failed to get backup metrics");
}
} else {
backupToUpdate.setStatus(Backup.Status.BackingUp);
}
if (backupDao.persist(backupToUpdate) != null) {
logger.info("Backroll backup updated");
}
}
} else {
if(backup.getExternalId().contains(",")) {
String backupId = backup.getExternalId().split(",")[1];
BackupVO backupToUpdate = ((BackupVO) backup);
backupToUpdate.setExternalId(backupId);
try {
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , backupId);
if (backupMetrics != null) {
backupToUpdate.setProtectedSize(backupMetrics.getDeduplicated());
backupToUpdate.setSize(backupMetrics.getSize());
}
} catch (BackrollApiException | IOException e) {
logger.error(e);
throw new CloudRuntimeException("Failed to get backup metrics");
}
if (backupDao.persist(backupToUpdate) != null) {
logger.info("Backroll backup updated");
}
}
}
}
// refresh backup in database list
backupsInDb = backupDao.listByVmId(zoneId, vm.getId());
Long usedSize = 0L;
Long dataSize = 0L;
List<RestorePoint> backups = client.listRestorePoints(vm.getUuid());
for (RestorePoint backup : backups) {
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , getBackupName(backup.getId()));
if (backupMetrics != null) {
usedSize += Long.valueOf(backupMetrics.getDeduplicated());
dataSize += Long.valueOf(backupMetrics.getSize());
// update backup metrics
Backup backupToFind = backupsInDb.stream()
.filter(backupInDb -> backupInDb.getExternalId().contains(backup.getId()))
.findAny()
.orElse(null);
if (backupToFind != null) {
BackupVO backupToUpdate = ((BackupVO) backupToFind);
backupToUpdate.setProtectedSize(usedSize);
backupToUpdate.setSize(dataSize);
backupDao.persist(backupToUpdate);
}
}
}
Metric metric = new Metric(dataSize, usedSize);
logger.debug("Metrics for VM [uuid: {}, name: {}] is [backup size: {}, data size: {}].", vm.getUuid(),
vm.getInstanceName(), metric.getBackupSize(), metric.getDataSize());
metrics.put(vm, metric);
} catch (BackrollApiException | 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;
}
@ -214,7 +310,6 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide
backup.setDomainId(vm.getDomainId());
backup.setZoneId(vm.getDataCenterId());
Boolean result = backupDao.persist(backup) != null;
client.triggerTaskStatus(urlToRequest);
return new Pair<Boolean,Backup>(result, backup);
}
} catch (ParseException | BackrollApiException | IOException e) {
@ -280,7 +375,7 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide
try {
if (backrollClient == null) {
logger.debug("backroll client null - instantiation of new one ");
BackrollHttpClientProvider provider = BackrollHttpClientProvider.createProvider(BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600);
BackrollHttpClientProvider provider = BackrollHttpClientProvider.createProvider(new BackrollHttpClientProvider(), BackrollUrlConfigKey.valueIn(zoneId), BackrollAppNameConfigKey.valueIn(zoneId), BackrollPasswordConfigKey.valueIn(zoneId), true, 300, 600);
backrollClient = new BackrollClient(provider);
}
return backrollClient;
@ -294,7 +389,11 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide
}
private String getBackupName(Backup backup) {
return backup.getExternalId().substring(backup.getExternalId().indexOf(",") + 1);
return getBackupName(backup.getExternalId());
}
private String getBackupName(String externalId) {
return externalId.substring(externalId.indexOf(",") + 1);
}
@Override
@ -327,21 +426,17 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide
backupToInsert.setAccountId(vm.getAccountId());
backupToInsert.setDomainId(vm.getDomainId());
backupToInsert.setZoneId(vm.getDataCenterId());
if(metric == null || metric.getBackupSize().equals(0L)){
try {
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , restorePoint.getId());
if (backupMetrics != null) {
backupToInsert.setSize(backupMetrics.getDeduplicated()); // real size
backupToInsert.setProtectedSize(backupMetrics.getSize()); // total size
}
} catch (BackrollApiException | IOException e) {
logger.error(e);
throw new CloudRuntimeException("Failed to get backup metrics");
try {
BackrollBackupMetrics backupMetrics = client.getBackupMetrics(vm.getUuid() , getBackupName(restorePoint.getId()));
if (backupMetrics != null) {
backupToInsert.setProtectedSize(backupMetrics.getDeduplicated());
backupToInsert.setSize(backupMetrics.getSize());
}
}else{
backupToInsert.setSize(metric.getBackupSize());
backupToInsert.setProtectedSize(metric.getDataSize());
} catch (IOException | BackrollApiException e) {
logger.error(e);
}
backupDao.persist(backupToInsert);
return backupToInsert;
}

View File

@ -168,11 +168,6 @@ 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);
@ -237,7 +232,7 @@ public class BackrollClient {
return backups;
}
private List<BackupInfos> getBackupInfosFromVm(String vmId)
public List<BackupInfos> getBackupInfosFromVm(String vmId)
throws BackrollApiException, IOException {
logger.info("Trying to retrieve all backups for vm {}", vmId);
BackrollTaskRequestResponse requestResponse = httpProvider
@ -260,7 +255,7 @@ public class BackrollClient {
if (backupInfos != null && backupInfos.size() > 0) {
for (BackupInfos infos : backupInfos) {
var dateStart = new DateTime(infos.start);
backups.add(new Backup.RestorePoint(infos.id + "," + infos.name, dateStart.toDate(), "INCREMENTAL"));
backups.add(new Backup.RestorePoint(infos.name, dateStart.toDate(), "INCREMENTAL"));
}
}
return backups;

View File

@ -69,10 +69,10 @@ public class BackrollHttpClientProvider {
private Logger logger = LogManager.getLogger(BackrollClient.class);
public static BackrollHttpClientProvider createProvider(final String url, final String appname, final String password,
public static BackrollHttpClientProvider createProvider(final BackrollHttpClientProvider backrollHttpClientProvider, final String url, final String appname, final String password,
final boolean validateCertificate, final int timeout,
final int restoreTimeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
BackrollHttpClientProvider backrollHttpClientProvider = new BackrollHttpClientProvider();
//BackrollHttpClientProvider backrollHttpClientProvider = new BackrollHttpClientProvider();
backrollHttpClientProvider.apiURI = new URI(url);
backrollHttpClientProvider.appname = appname;
backrollHttpClientProvider.password = password;
@ -232,9 +232,6 @@ public class BackrollHttpClientProvider {
public NotOkBodyException() {
super();
}
public NotOkBodyException(String errorMessage) {
super(errorMessage);
}
}
public String okBody(final CloseableHttpResponse response) throws NotOkBodyException {
@ -257,14 +254,12 @@ public class BackrollHttpClientProvider {
}
default:
try {
HttpEntity bodyEntity2 = response.getEntity();
result = EntityUtils.toString(bodyEntity2);
closeConnection(response);
} catch (IOException e) {
e.printStackTrace();
}
throw new NotOkBodyException("Error ok body, code: " + String.valueOf(response.getStatusLine().getStatusCode()) + " / body response: " + result);
throw new NotOkBodyException();
}
}
@ -276,6 +271,7 @@ public class BackrollHttpClientProvider {
String body = getWithoutParseResponse(url);
if(!StringUtils.isEmpty(body)){
if (!body.contains(TaskState.PENDING)) {
logger.debug("METRICS waitGetWithoutParseResponse : result {}", body);
T result = new ObjectMapper().readValue(body, classOfT);
return result;
}

View File

@ -21,7 +21,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import java.io.IOException;
import java.util.Arrays;
@ -31,12 +30,8 @@ import java.util.UUID;
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.BackrollOffering;
import org.apache.cloudstack.backup.backroll.model.response.TaskState;
import org.apache.cloudstack.backup.Backup.Metric;
import org.apache.cloudstack.backup.Backup.RestorePoint;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.logging.log4j.Logger;
@ -112,8 +107,6 @@ public class BackrollBackupProviderTest {
Mockito.doReturn("/status/f32092e4-3e8a-461b-8733-ed93e23fa782").when(clientMock)
.startBackupJob(Mockito.anyString());
Mockito.doReturn(new BackupVO()).when(backupDao).persist(Mockito.any(BackupVO.class));
Mockito.doNothing().when(clientMock).triggerTaskStatus(Mockito.anyString());
syncBackups_Test();
Pair<Boolean, Backup> result = backupProvider.takeBackup(vmInstanceVO);
assertTrue(result.first());
}
@ -147,6 +140,7 @@ public class BackrollBackupProviderTest {
@Test
public void getBackupMetrics_Test() throws BackrollApiException, IOException{
VMInstanceVO vmInstanceVO = new VMInstanceVO();
vmInstanceVO.setInstanceName("test");
vmInstanceVO.setDataCenterId(1l);
@ -157,18 +151,17 @@ public class BackrollBackupProviderTest {
vmInstanceVO2.setDataCenterId(2l);
vmInstanceVO2.setBackupOfferingId(2l);
VMInstanceVO vmInstanceVO3 = new VMInstanceVO();
vmInstanceVO3.setInstanceName("test3");
vmInstanceVO3.setDataCenterId(3l);
vmInstanceVO3.setBackupOfferingId(3l);
Metric metric = new Metric(2L, 3L);
BackrollBackupMetrics metrics = new BackrollBackupMetrics(5L, 6L);
Mockito.doReturn(metric).when(clientMock).getVirtualMachineMetrics(Mockito.anyString());
Mockito.doReturn(metrics).when(clientMock).getBackupMetrics(Mockito.anyString(), Mockito.anyString());
assertEquals(backupProvider.getBackupMetrics(2L, Arrays.asList(vmInstanceVO, vmInstanceVO2, vmInstanceVO3)).size(), 1);
Mockito.verify(clientMock, times(3)).getVirtualMachineMetrics(Mockito.anyString());
// Mockito.verify(clientMock, times(3)).getBackupMetrics(Mockito.anyString(), Mockito.anyString());
}
@Test
@ -237,57 +230,6 @@ public class BackrollBackupProviderTest {
assertFalse(backupProvider.willDeleteBackupsOnOfferingRemoval());
}
@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);
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<BackrollVmBackup> backupsFromBackroll = Arrays.asList(
new BackrollVmBackup("OK", "OK", new Date()));
List<Backup> 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);
}
@Test
public void getClient_Test() {
BackrollClient client = backupProvider.getClient(2L);
@ -376,8 +318,8 @@ public class BackrollBackupProviderTest {
assertEquals(vm.getAccountId(), result.getAccountId());
assertEquals(vm.getDomainId(), result.getDomainId());
assertEquals(vm.getDataCenterId(), result.getZoneId());
assertEquals((Long)backupMetrics.getDeduplicated(), result.getSize());
assertEquals((Long)backupMetrics.getSize(), result.getProtectedSize());
assertEquals((Long)backupMetrics.getSize(), result.getSize());
assertEquals((Long)backupMetrics.getDeduplicated(), result.getProtectedSize());
Mockito.verify(clientMock).getBackupMetrics(vm.getUuid(), restorePoint.getId());
Mockito.verify(backupDao).persist(Mockito.any(BackupVO.class));
@ -394,14 +336,11 @@ public class BackrollBackupProviderTest {
Backup.Metric metric = new Backup.Metric(150L, 250L);
BackupVO savedBackup = new BackupVO();
Mockito.doReturn(savedBackup).when(backupDao).persist(Mockito.any(BackupVO.class));
Backup result = backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
assertNotNull(result);
assertEquals(vm.getId(), result.getVmId());
assertEquals(restorePoint.getId(), result.getExternalId());
@ -412,15 +351,11 @@ public class BackrollBackupProviderTest {
assertEquals(vm.getAccountId(), result.getAccountId());
assertEquals(vm.getDomainId(), result.getDomainId());
assertEquals(vm.getDataCenterId(), result.getZoneId());
assertEquals(metric.getBackupSize(), result.getSize());
assertEquals(metric.getDataSize(), result.getProtectedSize());
Mockito.verify(clientMock, Mockito.never()).getBackupMetrics(Mockito.anyString(), Mockito.anyString());
Mockito.verify(backupDao).persist(Mockito.any(BackupVO.class));
}
@Test(expected = CloudRuntimeException.class)
@Test
public void createNewBackupEntryForRestorePoint_BackrollApiException_Test()
throws BackrollApiException, IOException {
@ -439,7 +374,7 @@ public class BackrollBackupProviderTest {
backupProvider.createNewBackupEntryForRestorePoint(restorePoint, vm, metric);
}
@Test(expected = CloudRuntimeException.class)
@Test
public void createNewBackupEntryForRestorePoint_IOException_Test() throws BackrollApiException, IOException {
RestorePoint restorePoint = new RestorePoint("restore-500", new Date(), "INCREMENTAL");

View File

@ -22,7 +22,6 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import java.io.IOException;
import java.util.Arrays;
@ -282,49 +281,11 @@ public class BackrollClientTest {
assertEquals(1, restorePoints.size());
Backup.RestorePoint rp1 = restorePoints.get(0);
assertEquals("25d55ad283aa400af464c76d713c07ad7d163abdd3b8fbcdbdc46b827e5e0457", rp1.getId());
assertEquals("ROOT-00000", rp1.getId());
assertEquals(new DateTime("2024-11-08T18:24:48.000000").toDate(), rp1.getCreated());
assertEquals("INCREMENTAL", rp1.getType());
Mockito.verify(backrollHttpClientProviderMock).get(Mockito.matches(".*/virtualmachines/.*"), Mockito.any());
Mockito.verify(backrollHttpClientProviderMock).waitGet(anyString(), Mockito.any());
}
@Test
public void triggerTaskStatus_Test() throws IOException, BackrollApiException {
String urlToRequest = "/api/v1/task/status";
// Simuler le comportement normal sans exception
Mockito.doReturn("ok").when(backrollHttpClientProviderMock).waitGetWithoutParseResponse(urlToRequest);
// Appel de la méthode sous test
client.triggerTaskStatus(urlToRequest);
// Vérifier que la méthode a été appelée une fois avec le bon paramètre
Mockito.verify(backrollHttpClientProviderMock, times(1)).waitGetWithoutParseResponse(urlToRequest);
}
@Test(expected = IOException.class)
public void triggerTaskStatus_IOException_Test() throws IOException, BackrollApiException {
String urlToRequest = "/api/v1/task/status";
// Simuler une exception IOException
Mockito.doThrow(new IOException("IO Error")).when(backrollHttpClientProviderMock)
.waitGetWithoutParseResponse(urlToRequest);
// Appel de la méthode sous test (devrait lancer une IOException)
client.triggerTaskStatus(urlToRequest);
}
@Test(expected = BackrollApiException.class)
public void triggerTaskStatus_BackrollApiException_Test() throws IOException, BackrollApiException {
String urlToRequest = "/api/v1/task/status";
// Simuler une exception BackrollApiException
Mockito.doThrow(new BackrollApiException()).when(backrollHttpClientProviderMock)
.waitGetWithoutParseResponse(urlToRequest);
// Appel de la méthode sous test (devrait lancer une BackrollApiException)
client.triggerTaskStatus(urlToRequest);
}
}

View File

@ -115,7 +115,6 @@ public class BackrollHttpClientProviderTest {
StatusLine statusLine = mock(StatusLine.class);
doReturn(httpClient).when(backupHttpClientProvider).createHttpClient();
doReturn(response).when(httpClient)
.execute(argThat(argument -> argument != null && argument.getURI().toString().contains("login")));
@ -295,15 +294,15 @@ public class BackrollHttpClientProviderTest {
@Test
public void testAuthenticationFailure() throws Exception {
doReturn(false).when(backupHttpClientProvider).isAuthenticated();
doNothing().when(backupHttpClientProvider).login(Mockito.anyString(), Mockito.anyString());
doNothing().when(backupHttpClientProvider).login();
backupHttpClientProvider.loginIfAuthenticationFailed();
verify(backupHttpClientProvider).login(Mockito.anyString(), Mockito.anyString());
verify(backupHttpClientProvider).login();
}
@Test(expected = BackrollApiException.class)
public void testLoginFailure() throws Exception {
doReturn(false).when(backupHttpClientProvider).isAuthenticated();
doThrow(BackrollApiException.class).when(backupHttpClientProvider).login(Mockito.anyString(), Mockito.anyString());
doThrow(BackrollApiException.class).when(backupHttpClientProvider).login();
backupHttpClientProvider.loginIfAuthenticationFailed();
}
@ -311,6 +310,6 @@ public class BackrollHttpClientProviderTest {
public void testLoginSuccess() throws Exception {
doReturn(true).when(backupHttpClientProvider).isAuthenticated();
backupHttpClientProvider.loginIfAuthenticationFailed();
verify(backupHttpClientProvider, times(0)).login(Mockito.anyString(), Mockito.anyString());
verify(backupHttpClientProvider, times(0)).login();
}
}