From eb46332fe0ec0640e0f19d89e4a92f3485126b96 Mon Sep 17 00:00:00 2001 From: Pierre Charton Date: Fri, 20 Dec 2024 17:40:06 +0100 Subject: [PATCH] UT + refactoring to test --- .../backup/BackrollBackupProvider.java | 4 +- .../utils/BackrollHttpClientProvider.java | 22 +-- .../backup/BackrollBackupProviderTest.java | 16 +- .../utils/BackrollHttpClientProviderTest.java | 153 ++++++++++++++++++ 4 files changed, 180 insertions(+), 15 deletions(-) create mode 100644 plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProviderTest.java 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 0386bd437c7..6a112895a77 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 @@ -377,11 +377,11 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide 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 { + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId()); try { if (getClient(backup.getZoneId()).deleteBackup(vm.getUuid(), getBackupName(backup))) { logger.debug("Backup deletion for backup {} complete on backroll side.", backup.getUuid()); @@ -411,7 +411,7 @@ public class BackrollBackupProvider extends AdapterBase implements BackupProvide try { if (backrollClient == null) { logger.debug("backroll client null - instantiation of new one "); - BackrollHttpClientProvider provider = new BackrollHttpClientProvider(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; diff --git a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProvider.java b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProvider.java index 401d0454f02..852f281ce34 100644 --- a/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProvider.java +++ b/plugins/backup/backroll/src/main/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProvider.java @@ -60,7 +60,7 @@ import com.cloud.utils.nio.TrustAllManager; import com.fasterxml.jackson.databind.ObjectMapper; public class BackrollHttpClientProvider { - private final URI apiURI; + private URI apiURI;; private String backrollToken = null; private String appname = null; private String password = null; @@ -69,23 +69,25 @@ public class BackrollHttpClientProvider { private Logger logger = LogManager.getLogger(BackrollClient.class); - public BackrollHttpClientProvider(final String url, final String appname, final String password, + public static BackrollHttpClientProvider createProvider(BackrollHttpClientProvider backrollHttpClientProvider, final String url, final String appname, final String password, final boolean validateCertificate, final int timeout, - final int restoreTimeout) - throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { - this.apiURI = new URI(url); - this.appname = appname; - this.password = password; - this.validateCertificate = validateCertificate; + final int restoreTimeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException { - this.config = RequestConfig.custom() + backrollHttpClientProvider.apiURI = new URI(url); + backrollHttpClientProvider.appname = appname; + backrollHttpClientProvider.password = password; + backrollHttpClientProvider.validateCertificate = validateCertificate; + + backrollHttpClientProvider.config = RequestConfig.custom() .setConnectTimeout(timeout * 1000) .setConnectionRequestTimeout(timeout * 1000) .setSocketTimeout(timeout * 1000) .build(); + + return backrollHttpClientProvider; } - private CloseableHttpClient createHttpClient() throws BackrollApiException { + protected CloseableHttpClient createHttpClient() throws BackrollApiException { if(!validateCertificate) { SSLContext sslContext; try { 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 7e6177185d7..5b66ac5a4f8 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 @@ -50,9 +50,8 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.VirtualMachine; - - import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; public class BackrollBackupProviderTest { @Mock @@ -68,6 +67,15 @@ public class BackrollBackupProviderTest { @Mock VMInstanceDao vmInstanceDao; + @Mock + private ConfigKey BackrollUrlConfigKey; + + @Mock + private ConfigKey BackrollAppNameConfigKey; + + @Mock + private ConfigKey BackrollPasswordConfigKey; + @Mock BackupDao backupDao; @@ -76,8 +84,10 @@ public class BackrollBackupProviderTest { 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)); + backupProvider.BackrollAppNameConfigKey = BackrollAppNameConfigKey; + backupProvider.BackrollPasswordConfigKey = BackrollPasswordConfigKey; + backupProvider.BackrollUrlConfigKey = BackrollUrlConfigKey; } @Test diff --git a/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProviderTest.java b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProviderTest.java new file mode 100644 index 00000000000..cfdf05d7577 --- /dev/null +++ b/plugins/backup/backroll/src/test/java/org/apache/cloudstack/backup/backroll/utils/BackrollHttpClientProviderTest.java @@ -0,0 +1,153 @@ +// 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.backroll.utils; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.http.HttpResponse; + +import org.apache.cloudstack.backup.BackrollBackupProvider; +import org.apache.cloudstack.backup.backroll.BackrollClient; +import org.apache.cloudstack.backup.backroll.model.response.api.LoginApiResponse; +import org.apache.cloudstack.backup.backroll.model.response.metrics.virtualMachineBackups.VirtualMachineBackupsResponse; +import org.apache.cloudstack.backup.backroll.utils.BackrollHttpClientProvider.NotOkBodyException; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpStatus; +import org.apache.http.ParseException; +import org.apache.http.StatusLine; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.logging.log4j.Logger; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class BackrollHttpClientProviderTest { + @Spy + @InjectMocks + BackrollHttpClientProvider backupHttpClientProvider; + + @Mock + private CloseableHttpClient httpClient; + + @Mock + private CloseableHttpResponse response; + + @Before + public void setUp() throws Exception { + Long zoneId = 2L; + MockitoAnnotations.openMocks(this); + backupHttpClientProvider = BackrollHttpClientProvider.createProvider(backupHttpClientProvider, + "http://api.backup.demo.ccc:5050/api/v1", "backroll-api", "VviX8dALauSyYJMqVYJqf3UyZOpO3joS", false, + 300, 600); + } + + private void defaultTestHttpClient(String path) throws BackrollApiException, ClientProtocolException, IOException, NotOkBodyException { + + LoginApiResponse responseLogin = new LoginApiResponse(); + responseLogin.accessToken = "dummyToken"; + responseLogin.expiresIn = 3600; + responseLogin.notBeforePolicy = "dummyNotBeforePolicy"; + responseLogin.refreshExpiresIn = "7200"; + responseLogin.scope = "dummyScope"; + + 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\" } } }"; + + CloseableHttpResponse response2 = mock(CloseableHttpResponse.class); + + StatusLine statusLine = mock(StatusLine.class); + + doReturn(httpClient).when(backupHttpClientProvider).createHttpClient(); + + doReturn(response).when(httpClient) + .execute(argThat(argument -> argument != null && argument.getURI().toString().contains("login"))); + + doReturn(response2).when(httpClient) + .execute(argThat(argument -> argument != null && argument.getURI().toString().contains(path))); + + doReturn(new ObjectMapper().writeValueAsString(responseLogin)).when(backupHttpClientProvider).okBody(response); + doReturn(virtualMachineResponseString).when(backupHttpClientProvider).okBody(response2); + + doReturn(statusLine).when(response).getStatusLine(); + doReturn(HttpStatus.SC_OK).when(statusLine).getStatusCode(); + + doNothing().when(response).close(); + + doReturn(new StringEntity("{\"mockKey\": \"mockValue\"}", ContentType.APPLICATION_JSON)).when(response).getEntity(); + } + + @Test + public void testGet_success() throws Exception, BackrollApiException, IOException { + // Arrange + String path = "/test"; + defaultTestHttpClient(path); + + // Act + VirtualMachineBackupsResponse result = backupHttpClientProvider.get(path, + VirtualMachineBackupsResponse.class); + + // Assert + assertNotNull(result); + verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class)); + verify(httpClient, times(1)).execute(Mockito.any(HttpPost.class)); + verify(httpClient, times(1)).execute(Mockito.any(HttpGet.class)); + verify(response, times(1)).close(); + } + + @Test + public void testPost_success() throws Exception, BackrollApiException, IOException { + // Arrange + String path = "/test"; + JSONObject json = new JSONObject(); + + defaultTestHttpClient(path); + // Act + VirtualMachineBackupsResponse result = backupHttpClientProvider.post(path, json, + VirtualMachineBackupsResponse.class); + + // Assert + assertNotNull(result); + verify(backupHttpClientProvider, times(2)).okBody(Mockito.any(CloseableHttpResponse.class)); + verify(httpClient, times(2)).execute(Mockito.any(HttpPost.class)); + verify(response, times(1)).close(); + } + +}