aboutsummaryrefslogtreecommitdiffstats
path: root/a1-policy-management/src/test/java/org
diff options
context:
space:
mode:
authorRehanRaza <muhammad.rehan.raza@est.tech>2020-08-03 15:56:03 +0200
committerRehanRaza <muhammad.rehan.raza@est.tech>2020-08-04 11:35:30 +0200
commit0e3740a9011f59e18b0e65230d1ba61ec6ab8ba6 (patch)
tree5cb4cccc06d0295a47044c9fba94f5f85e74fef6 /a1-policy-management/src/test/java/org
parent5a2cc540766299ac4fabcdf29aecabf9df71bc9d (diff)
Add seed code for A1 policy management service
Change-Id: I4925a613a85b182aab6d78dafd55ec333acba49d Issue-ID: CCSDK-2617 Signed-off-by: RehanRaza <muhammad.rehan.raza@est.tech>
Diffstat (limited to 'a1-policy-management/src/test/java/org')
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTest.java836
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ConcurrencyTestRunnable.java140
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java212
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/aspect/LogAspectTest.java98
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactoryTest.java167
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientHelper.java80
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java161
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1ClientTest.java179
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOnapA1ClientTest.java271
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1ClientTest.java374
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientTest.java136
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java159
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigTest.java127
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumerTest.java205
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageHandlerTest.java290
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/LockTest.java89
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/EnvironmentProcessorTest.java145
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTaskTest.java386
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervisionTest.java328
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java339
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervisionTest.java186
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/LoggingUtils.java60
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1Client.java144
-rw-r--r--a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1ClientFactory.java88
24 files changed, 5200 insertions, 0 deletions
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTest.java
new file mode 100644
index 00000000..1ec90e3a
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ApplicationTest.java
@@ -0,0 +1,836 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableWebClientConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.PolicyInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceRegistrationInfo;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.ServiceStatus;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RicSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.tasks.ServiceSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+import reactor.util.annotation.Nullable;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@TestPropertySource(
+ properties = { //
+ "server.ssl.key-store=./config/keystore.jks", //
+ "app.webclient.trust-store=./config/truststore.jks"})
+class ApplicationTest {
+ private static final Logger logger = LoggerFactory.getLogger(ApplicationTest.class);
+
+ @Autowired
+ ApplicationContext context;
+
+ @Autowired
+ private Rics rics;
+
+ @Autowired
+ private Policies policies;
+
+ @Autowired
+ private PolicyTypes policyTypes;
+
+ @Autowired
+ MockA1ClientFactory a1ClientFactory;
+
+ @Autowired
+ RicSupervision supervision;
+
+ @Autowired
+ ApplicationConfig applicationConfig;
+
+ @Autowired
+ Services services;
+
+ private static Gson gson = new GsonBuilder() //
+ .serializeNulls() //
+ .create(); //
+
+ public static class MockApplicationConfig extends ApplicationConfig {
+ @Override
+ public String getLocalConfigurationFilePath() {
+ return ""; // No config file loaded for the test
+ }
+ }
+
+ /**
+ * Overrides the BeanFactory.
+ */
+ @TestConfiguration
+ static class TestBeanFactory {
+ private final PolicyTypes policyTypes = new PolicyTypes();
+ private final Services services = new Services();
+ private final Policies policies = new Policies();
+ MockA1ClientFactory a1ClientFactory = null;
+
+ @Bean
+ public ApplicationConfig getApplicationConfig() {
+ return new MockApplicationConfig();
+ }
+
+ @Bean
+ MockA1ClientFactory getA1ClientFactory() {
+ if (a1ClientFactory == null) {
+ this.a1ClientFactory = new MockA1ClientFactory(this.policyTypes);
+ }
+ return this.a1ClientFactory;
+ }
+
+ @Bean
+ public PolicyTypes getPolicyTypes() {
+ return this.policyTypes;
+ }
+
+ @Bean
+ Policies getPolicies() {
+ return this.policies;
+ }
+
+ @Bean
+ Services getServices() {
+ return this.services;
+ }
+
+ @Bean
+ public ServiceSupervision getServiceSupervision() {
+ Duration checkInterval = Duration.ofMillis(1);
+ return new ServiceSupervision(this.services, this.policies, this.getA1ClientFactory(), checkInterval);
+ }
+
+ @Bean
+ public ServletWebServerFactory servletContainer() {
+ return new TomcatServletWebServerFactory();
+ }
+
+ }
+
+ @LocalServerPort
+ private int port;
+
+ @BeforeEach
+ void reset() {
+ rics.clear();
+ policies.clear();
+ policyTypes.clear();
+ services.clear();
+ a1ClientFactory.reset();
+ }
+
+ @AfterEach
+ void verifyNoRicLocks() {
+ for (Ric ric : this.rics.getRics()) {
+ ric.getLock().lockBlocking(LockType.EXCLUSIVE);
+ ric.getLock().unlockBlocking();
+ assertThat(ric.getLock().getLockCounter()).isZero();
+ assertThat(ric.getState()).isEqualTo(Ric.RicState.AVAILABLE);
+ }
+ }
+
+ @Test
+ void testGetRics() throws Exception {
+ addRic("ric1");
+ this.addPolicyType("type1", "ric1");
+ String url = "/rics?policyType=type1";
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).contains("ric1");
+
+ // nameless type for ORAN A1 1.1
+ addRic("ric2");
+ this.addPolicyType("", "ric2");
+ url = "/rics?policyType=";
+
+ // This tests also validation of trusted certs restClient(true)
+ rsp = restClient(true).get(url).block();
+ assertThat(rsp).contains("ric2") //
+ .doesNotContain("ric1") //
+ .contains("AVAILABLE");
+
+ // All RICs
+ rsp = restClient().get("/rics").block();
+ assertThat(rsp).contains("ric2") //
+ .contains("ric1");
+
+ // Non existing policy type
+ url = "/rics?policyType=XXXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testSynchronization() throws Exception {
+ // Two polictypes will be put in the NearRT RICs
+ PolicyTypes nearRtRicPolicyTypes = new PolicyTypes();
+ nearRtRicPolicyTypes.put(createPolicyType("typeName"));
+ nearRtRicPolicyTypes.put(createPolicyType("typeName2"));
+ this.a1ClientFactory.setPolicyTypes(nearRtRicPolicyTypes);
+
+ // One type and one instance added to the Policy Management Service's storage
+ final String ric1Name = "ric1";
+ Ric ric1 = addRic(ric1Name);
+ Policy policy2 = addPolicy("policyId2", "typeName", "service", ric1Name);
+ Ric ric2 = addRic("ric2");
+
+ getA1Client(ric1Name).putPolicy(policy2); // put it in the RIC
+ policies.remove(policy2); // Remove it from the repo -> should be deleted in the RIC
+
+ String policyId = "policyId";
+ Policy policy = addPolicy(policyId, "typeName", "service", ric1Name); // This should be created in the RIC
+ supervision.checkAllRics(); // The created policy should be put in the RIC
+
+ // Wait until synch is completed
+ await().untilAsserted(() -> RicState.SYNCHRONIZING.equals(rics.getRic(ric1Name).getState()));
+ await().untilAsserted(() -> RicState.AVAILABLE.equals(rics.getRic(ric1Name).getState()));
+ await().untilAsserted(() -> RicState.AVAILABLE.equals(rics.getRic("ric2").getState()));
+
+ Policies ricPolicies = getA1Client(ric1Name).getPolicies();
+ assertThat(ricPolicies.size()).isEqualTo(1);
+ Policy ricPolicy = ricPolicies.get(policyId);
+ assertThat(ricPolicy.json()).isEqualTo(policy.json());
+
+ // Both types should be in the Policy Management Service's storage after the synch
+ assertThat(ric1.getSupportedPolicyTypes()).hasSize(2);
+ assertThat(ric2.getSupportedPolicyTypes()).hasSize(2);
+ }
+
+ @Test
+ void testGetRicForManagedElement_thenReturnCorrectRic() throws Exception {
+ String ricName = "ric1";
+ String managedElementId = "kista_1";
+ addRic(ricName, managedElementId);
+
+ String url = "/ric?managedElementId=" + managedElementId;
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo(ricName);
+
+ // test GET RIC for ManagedElement that does not exist
+ url = "/ric?managedElementId=" + "junk";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ private String putPolicyUrl(String serviceName, String ricName, String policyTypeName, String policyInstanceId,
+ boolean isTransient) {
+ String url;
+ if (policyTypeName.isEmpty()) {
+ url = "/policy?id=" + policyInstanceId + "&ric=" + ricName + "&service=" + serviceName;
+ } else {
+ url = "/policy?id=" + policyInstanceId + "&ric=" + ricName + "&service=" + serviceName + "&type="
+ + policyTypeName;
+ }
+ if (isTransient) {
+ url += "&transient=true";
+ }
+ return url;
+ }
+
+ private String putPolicyUrl(String serviceName, String ricName, String policyTypeName, String policyInstanceId) {
+ return putPolicyUrl(serviceName, ricName, policyTypeName, policyInstanceId, false);
+ }
+
+ @Test
+ void testPutPolicy() throws Exception {
+ String serviceName = "service1";
+ String ricName = "ric1";
+ String policyTypeName = "type1";
+ String policyInstanceId = "instance1";
+
+ putService(serviceName);
+ addPolicyType(policyTypeName, ricName);
+
+ // PUT a transient policy
+ String url = putPolicyUrl(serviceName, ricName, policyTypeName, policyInstanceId, true);
+ final String policyBody = jsonString();
+ this.rics.getRic(ricName).setState(Ric.RicState.AVAILABLE);
+
+ restClient().put(url, policyBody).block();
+
+ Policy policy = policies.getPolicy(policyInstanceId);
+ assertThat(policy).isNotNull();
+ assertThat(policy.id()).isEqualTo(policyInstanceId);
+ assertThat(policy.ownerServiceName()).isEqualTo(serviceName);
+ assertThat(policy.ric().name()).isEqualTo("ric1");
+ assertThat(policy.isTransient()).isTrue();
+
+ // Put a non transient policy
+ url = putPolicyUrl(serviceName, ricName, policyTypeName, policyInstanceId);
+ restClient().put(url, policyBody).block();
+ policy = policies.getPolicy(policyInstanceId);
+ assertThat(policy.isTransient()).isFalse();
+
+ url = "/policies";
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).as("Response contains policy instance ID.").contains(policyInstanceId);
+
+ url = "/policy?id=" + policyInstanceId;
+ rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo(policyBody);
+
+ // Test of error codes
+ url = putPolicyUrl(serviceName, ricName + "XX", policyTypeName, policyInstanceId);
+ testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
+
+ url = putPolicyUrl(serviceName, ricName, policyTypeName + "XX", policyInstanceId);
+ addPolicyType(policyTypeName + "XX", "otherRic");
+ testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND);
+
+ url = putPolicyUrl(serviceName, ricName, policyTypeName, policyInstanceId);
+ this.rics.getRic(ricName).setState(Ric.RicState.SYNCHRONIZING);
+ testErrorCode(restClient().put(url, policyBody), HttpStatus.LOCKED);
+ this.rics.getRic(ricName).setState(Ric.RicState.AVAILABLE);
+ }
+
+ @Test
+ /**
+ * Test that HttpStatus and body from failing REST call to A1 is passed on to the caller.
+ *
+ * @throws ServiceException
+ */
+ void testErrorFromRic() throws ServiceException {
+ putService("service1");
+ addPolicyType("type1", "ric1");
+
+ String url = putPolicyUrl("service1", "ric1", "type1", "id1");
+ MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client("ric1");
+ HttpStatus httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
+ String responseBody = "Refused";
+ byte[] responseBodyBytes = responseBody.getBytes(StandardCharsets.UTF_8);
+
+ WebClientResponseException a1Exception = new WebClientResponseException(httpStatus.value(), "statusText", null,
+ responseBodyBytes, StandardCharsets.UTF_8, null);
+ doReturn(Mono.error(a1Exception)).when(a1Client).putPolicy(any());
+
+ // PUT Policy
+ testErrorCode(restClient().put(url, "{}"), httpStatus, responseBody);
+
+ // DELETE POLICY
+ this.addPolicy("instance1", "type1", "service1", "ric1");
+ doReturn(Mono.error(a1Exception)).when(a1Client).deletePolicy(any());
+ testErrorCode(restClient().delete("/policy?id=instance1"), httpStatus, responseBody);
+
+ // GET STATUS
+ this.addPolicy("instance1", "type1", "service1", "ric1");
+ doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any());
+ testErrorCode(restClient().get("/policy_status?id=instance1"), httpStatus, responseBody);
+
+ // Check that empty response body is OK
+ a1Exception = new WebClientResponseException(httpStatus.value(), "", null, null, null, null);
+ doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any());
+ testErrorCode(restClient().get("/policy_status?id=instance1"), httpStatus);
+ }
+
+ @Test
+ void testPutTypelessPolicy() throws Exception {
+ putService("service1");
+ addPolicyType("", "ric1");
+ String url = putPolicyUrl("service1", "ric1", "", "id1");
+ restClient().put(url, jsonString()).block();
+
+ String rsp = restClient().get("/policies").block();
+ List<PolicyInfo> info = parseList(rsp, PolicyInfo.class);
+ assertThat(info).hasSize(1);
+ PolicyInfo policyInfo = info.get(0);
+ assertThat(policyInfo.id).isEqualTo("id1");
+ assertThat(policyInfo.type).isEmpty();
+ }
+
+ @Test
+ void testRefuseToUpdatePolicy() throws Exception {
+ // Test that only the json can be changed for a already created policy
+ // In this case service is attempted to be changed
+ this.addRic("ric1");
+ this.addRic("ricXXX");
+ this.addPolicy("instance1", "type1", "service1", "ric1");
+ this.addPolicy("instance2", "type1", "service1", "ricXXX");
+
+ // Try change ric1 -> ricXXX
+ String urlWrongRic = putPolicyUrl("service1", "ricXXX", "type1", "instance1");
+ testErrorCode(restClient().put(urlWrongRic, jsonString()), HttpStatus.CONFLICT);
+ }
+
+ @Test
+ void testGetPolicy() throws Exception {
+ String url = "/policy?id=id";
+ Policy policy = addPolicy("id", "typeName", "service1", "ric1");
+ {
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo(policy.json());
+ }
+ {
+ policies.remove(policy);
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+ }
+
+ @Test
+ void testDeletePolicy() throws Exception {
+ addPolicy("id", "typeName", "service1", "ric1");
+ assertThat(policies.size()).isEqualTo(1);
+
+ String url = "/policy?id=id";
+ ResponseEntity<String> entity = restClient().deleteForEntity(url).block();
+
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
+ assertThat(policies.size()).isZero();
+
+ // Delete a non existing policy
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testGetPolicySchemas() throws Exception {
+ addPolicyType("type1", "ric1");
+ addPolicyType("type2", "ric2");
+
+ String url = "/policy_schemas";
+ String rsp = this.restClient().get(url).block();
+ assertThat(rsp).contains("type1") //
+ .contains("[{\"title\":\"type2\"}");
+
+ List<String> info = parseSchemas(rsp);
+ assertThat(info).hasSize(2);
+
+ url = "/policy_schemas?ric=ric1";
+ rsp = restClient().get(url).block();
+ assertThat(rsp).contains("type1");
+ info = parseSchemas(rsp);
+ assertThat(info).hasSize(1);
+
+ // Get schema for non existing RIC
+ url = "/policy_schemas?ric=ric1XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testGetPolicySchema() throws Exception {
+ addPolicyType("type1", "ric1");
+ addPolicyType("type2", "ric2");
+
+ String url = "/policy_schema?id=type1";
+ String rsp = restClient().get(url).block();
+ logger.info(rsp);
+ assertThat(rsp).contains("type1") //
+ .contains("title");
+
+ // Get non existing schema
+ url = "/policy_schema?id=type1XX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testGetPolicyTypes() throws Exception {
+ addPolicyType("type1", "ric1");
+ addPolicyType("type2", "ric2");
+
+ String url = "/policy_types";
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo("[\"type2\",\"type1\"]");
+
+ url = "/policy_types?ric=ric1";
+ rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo("[\"type1\"]");
+
+ // Get policy types for non existing RIC
+ url = "/policy_types?ric=ric1XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testGetPolicies() throws Exception {
+ addPolicy("id1", "type1", "service1");
+
+ String url = "/policies";
+ String rsp = restClient().get(url).block();
+ logger.info(rsp);
+ List<PolicyInfo> info = parseList(rsp, PolicyInfo.class);
+ assertThat(info).hasSize(1);
+ PolicyInfo policyInfo = info.get(0);
+ assert (policyInfo.validate());
+ assertThat(policyInfo.id).isEqualTo("id1");
+ assertThat(policyInfo.type).isEqualTo("type1");
+ assertThat(policyInfo.service).isEqualTo("service1");
+ }
+
+ @Test
+ void testGetPoliciesFilter() throws Exception {
+ addPolicy("id1", "type1", "service1");
+ addPolicy("id2", "type1", "service2");
+ addPolicy("id3", "type2", "service1");
+
+ String url = "/policies?type=type1";
+ String rsp = restClient().get(url).block();
+ logger.info(rsp);
+ assertThat(rsp).contains("id1") //
+ .contains("id2") //
+ .doesNotContain("id3");
+
+ url = "/policies?type=type1&service=service2";
+ rsp = restClient().get(url).block();
+ logger.info(rsp);
+ assertThat(rsp).doesNotContain("id1") //
+ .contains("id2") //
+ .doesNotContain("id3");
+
+ // Test get policies for non existing type
+ url = "/policies?type=type1XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+ // Test get policies for non existing RIC
+ url = "/policies?ric=XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testGetPolicyIdsFilter() throws Exception {
+ addPolicy("id1", "type1", "service1", "ric1");
+ addPolicy("id2", "type1", "service2", "ric1");
+ addPolicy("id3", "type2", "service1", "ric1");
+
+ String url = "/policy_ids?type=type1";
+ String rsp = restClient().get(url).block();
+ logger.info(rsp);
+ assertThat(rsp).contains("id1") //
+ .contains("id2") //
+ .doesNotContain("id3");
+
+ url = "/policy_ids?type=type1&service=service1&ric=ric1";
+ rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo("[\"id1\"]");
+
+ // Test get policy ids for non existing type
+ url = "/policy_ids?type=type1XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+
+ // Test get policy ids for non existing RIC
+ url = "/policy_ids?ric=XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testPutAndGetService() throws Exception {
+ // PUT
+ String serviceName = "name";
+ putService(serviceName, 0, HttpStatus.CREATED);
+ putService(serviceName, 0, HttpStatus.OK);
+
+ // GET one service
+ String url = "/services?name=name";
+ String rsp = restClient().get(url).block();
+ List<ServiceStatus> info = parseList(rsp, ServiceStatus.class);
+ assertThat(info).hasSize(1);
+ ServiceStatus status = info.iterator().next();
+ assertThat(status.keepAliveIntervalSeconds).isZero();
+ assertThat(status.serviceName).isEqualTo(serviceName);
+
+ // GET (all)
+ url = "/services";
+ rsp = restClient().get(url).block();
+ assertThat(rsp).as("Response contains service name").contains(serviceName);
+ logger.info(rsp);
+
+ // Keep alive
+ url = "/services/keepalive?name=name";
+ ResponseEntity<String> entity = restClient().putForEntity(url).block();
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
+
+ // DELETE service
+ assertThat(services.size()).isEqualTo(1);
+ url = "/services?name=name";
+ restClient().delete(url).block();
+ assertThat(services.size()).isZero();
+
+ // Keep alive, no registered service
+ testErrorCode(restClient().put("/services/keepalive?name=name", ""), HttpStatus.NOT_FOUND);
+
+ // PUT servive with bad payload
+ testErrorCode(restClient().put("/service", "crap"), HttpStatus.BAD_REQUEST);
+ testErrorCode(restClient().put("/service", "{}"), HttpStatus.BAD_REQUEST);
+ testErrorCode(restClient().put("/service", createServiceJson(serviceName, -123)), HttpStatus.BAD_REQUEST);
+ testErrorCode(restClient().put("/service", createServiceJson(serviceName, 0, "missing.portandprotocol.com")),
+ HttpStatus.BAD_REQUEST);
+
+ // GET non existing service
+ testErrorCode(restClient().get("/services?name=XXX"), HttpStatus.NOT_FOUND);
+ }
+
+ @Test
+ void testServiceSupervision() throws Exception {
+ putService("service1", 1, HttpStatus.CREATED);
+ addPolicyType("type1", "ric1");
+
+ String url = putPolicyUrl("service1", "ric1", "type1", "instance1");
+ final String policyBody = jsonString();
+ restClient().put(url, policyBody).block();
+
+ assertThat(policies.size()).isEqualTo(1);
+ assertThat(services.size()).isEqualTo(1);
+
+ // Timeout after ~1 second
+ await().untilAsserted(() -> assertThat(policies.size()).isZero());
+ assertThat(services.size()).isZero();
+ }
+
+ @Test
+ void testGetPolicyStatus() throws Exception {
+ addPolicy("id", "typeName", "service1", "ric1");
+ assertThat(policies.size()).isEqualTo(1);
+
+ String url = "/policy_status?id=id";
+ String rsp = restClient().get(url).block();
+ assertThat(rsp).isEqualTo("OK");
+
+ // GET non existing policy status
+ url = "/policy_status?id=XXX";
+ testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND);
+ }
+
+ private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException {
+ addRic(ric);
+ Policy policy = ImmutablePolicy.builder() //
+ .id(id) //
+ .json(jsonString()) //
+ .ownerServiceName(service) //
+ .ric(rics.getRic(ric)) //
+ .type(addPolicyType(typeName, ric)) //
+ .lastModified("lastModified") //
+ .isTransient(false) //
+ .build();
+ policies.put(policy);
+ return policy;
+ }
+
+ private Policy addPolicy(String id, String typeName, String service) throws ServiceException {
+ return addPolicy(id, typeName, service, "ric");
+ }
+
+ private String createServiceJson(String name, long keepAliveIntervalSeconds) {
+ return createServiceJson(name, keepAliveIntervalSeconds, "https://examples.javacodegeeks.com/core-java/");
+ }
+
+ private String createServiceJson(String name, long keepAliveIntervalSeconds, String url) {
+ ServiceRegistrationInfo service = new ServiceRegistrationInfo(name, keepAliveIntervalSeconds, url);
+
+ String json = gson.toJson(service);
+ return json;
+ }
+
+ private void putService(String name) {
+ putService(name, 0, null);
+ }
+
+ private void putService(String name, long keepAliveIntervalSeconds, @Nullable HttpStatus expectedStatus) {
+ String url = "/service";
+ String body = createServiceJson(name, keepAliveIntervalSeconds);
+ ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
+ if (expectedStatus != null) {
+ assertEquals(expectedStatus, resp.getStatusCode(), "");
+ }
+ }
+
+ private String baseUrl() {
+ return "https://localhost:" + port;
+ }
+
+ private String jsonString() {
+ return "{\"servingCellNrcgi\":\"1\"}";
+ }
+
+ @Test
+ void testConcurrency() throws Exception {
+ final Instant startTime = Instant.now();
+ List<Thread> threads = new ArrayList<>();
+ a1ClientFactory.setResponseDelay(Duration.ofMillis(1));
+ addRic("ric");
+ addPolicyType("type1", "ric");
+ addPolicyType("type2", "ric");
+
+ for (int i = 0; i < 10; ++i) {
+ Thread thread =
+ new Thread(new ConcurrencyTestRunnable(baseUrl(), supervision, a1ClientFactory, rics, policyTypes),
+ "TestThread_" + i);
+ thread.start();
+ threads.add(thread);
+ }
+ for (Thread t : threads) {
+ t.join();
+ }
+ assertThat(policies.size()).isZero();
+ logger.info("Concurrency test took " + Duration.between(startTime, Instant.now()));
+ }
+
+ private AsyncRestClient restClient(boolean useTrustValidation) {
+ WebClientConfig config = this.applicationConfig.getWebClientConfig();
+ config = ImmutableWebClientConfig.builder() //
+ .keyStoreType(config.keyStoreType()) //
+ .keyStorePassword(config.keyStorePassword()) //
+ .keyStore(config.keyStore()) //
+ .keyPassword(config.keyPassword()) //
+ .isTrustStoreUsed(useTrustValidation) //
+ .trustStore(config.trustStore()) //
+ .trustStorePassword(config.trustStorePassword()) //
+ .build();
+
+ return new AsyncRestClient(baseUrl(), config);
+ }
+
+ private AsyncRestClient restClient() {
+ return restClient(false);
+ }
+
+ private void testErrorCode(Mono<?> request, HttpStatus expStatus) {
+ testErrorCode(request, expStatus, "");
+ }
+
+ private void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
+ StepVerifier.create(request) //
+ .expectSubscription() //
+ .expectErrorMatches(t -> checkWebClientError(t, expStatus, responseContains)) //
+ .verify();
+ }
+
+ private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains) {
+ assertTrue(throwable instanceof WebClientResponseException);
+ WebClientResponseException responseException = (WebClientResponseException) throwable;
+ assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
+ assertThat(responseException.getResponseBodyAsString()).contains(responseContains);
+ return true;
+ }
+
+ private MockA1Client getA1Client(String ricName) throws ServiceException {
+ return a1ClientFactory.getOrCreateA1Client(ricName);
+ }
+
+ private PolicyType createPolicyType(String policyTypeName) {
+ return ImmutablePolicyType.builder() //
+ .name(policyTypeName) //
+ .schema("{\"title\":\"" + policyTypeName + "\"}") //
+ .build();
+ }
+
+ private PolicyType addPolicyType(String policyTypeName, String ricName) {
+ PolicyType type = createPolicyType(policyTypeName);
+ policyTypes.put(type);
+ addRic(ricName).addSupportedPolicyType(type);
+ return type;
+ }
+
+ private Ric addRic(String ricName) {
+ return addRic(ricName, null);
+ }
+
+ private Ric addRic(String ricName, String managedElement) {
+ if (rics.get(ricName) != null) {
+ return rics.get(ricName);
+ }
+ List<String> mes = new ArrayList<>();
+ if (managedElement != null) {
+ mes.add(managedElement);
+ }
+ RicConfig conf = ImmutableRicConfig.builder() //
+ .name(ricName) //
+ .baseUrl(ricName) //
+ .managedElementIds(mes) //
+ .controllerName("") //
+ .build();
+ Ric ric = new Ric(conf);
+ ric.setState(Ric.RicState.AVAILABLE);
+ this.rics.put(ric);
+ return ric;
+ }
+
+ private static <T> List<T> parseList(String jsonString, Class<T> clazz) {
+ List<T> result = new ArrayList<>();
+ JsonArray jsonArr = JsonParser.parseString(jsonString).getAsJsonArray();
+ for (JsonElement jsonElement : jsonArr) {
+ T json = gson.fromJson(jsonElement.toString(), clazz);
+ result.add(json);
+ }
+ return result;
+ }
+
+ private static List<String> parseSchemas(String jsonString) {
+ JsonArray arrayOfSchema = JsonParser.parseString(jsonString).getAsJsonArray();
+ List<String> result = new ArrayList<>();
+ for (JsonElement schemaObject : arrayOfSchema) {
+ result.add(schemaObject.toString());
+ }
+ return result;
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ConcurrencyTestRunnable.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ConcurrencyTestRunnable.java
new file mode 100644
index 00000000..7a882adf
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/ConcurrencyTestRunnable.java
@@ -0,0 +1,140 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.tasks.RicSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+
+/**
+ * Invoke operations over the NBI and start synchronizations in a separate
+ * thread. For test of robustness using concurrent clients.
+ */
+class ConcurrencyTestRunnable implements Runnable {
+ private static final Logger logger = LoggerFactory.getLogger(ConcurrencyTestRunnable.class);
+ private final AsyncRestClient webClient;
+ static AtomicInteger nextCount = new AtomicInteger(0);
+ private final int count;
+ private final RicSupervision supervision;
+ private final MockA1ClientFactory a1ClientFactory;
+ private final Rics rics;
+ private final PolicyTypes types;
+
+ ConcurrencyTestRunnable(String baseUrl, RicSupervision supervision, MockA1ClientFactory a1ClientFactory, Rics rics,
+ PolicyTypes types) {
+ this.count = nextCount.incrementAndGet();
+ this.supervision = supervision;
+ this.a1ClientFactory = a1ClientFactory;
+ this.rics = rics;
+ this.types = types;
+ this.webClient = new AsyncRestClient(baseUrl);
+ }
+
+ private void printStatusInfo() {
+ try {
+ String url = "/actuator/metrics/jvm.threads.live";
+ ResponseEntity<String> result = webClient.getForEntity(url).block();
+ System.out.println(Thread.currentThread() + result.getBody());
+
+ url = "/rics";
+ result = webClient.getForEntity(url).block();
+ System.out.println(Thread.currentThread() + result.getBody());
+
+ } catch (Exception e) {
+ logger.error(Thread.currentThread() + "Concurrency test printStatusInfo exception " + e.toString());
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (int i = 0; i < 500; ++i) {
+ if (i % 100 == 0) {
+ createInconsistency();
+ this.supervision.checkAllRics();
+ }
+ String name = "policy:" + count + ":" + i;
+ putPolicy(name);
+ putPolicy(name + "-");
+ listPolicies();
+ listTypes();
+ deletePolicy(name);
+ deletePolicy(name + "-");
+ }
+ } catch (Exception e) {
+ logger.error("Concurrency test exception " + e.toString());
+ printStatusInfo();
+ }
+ }
+
+ private Policy createPolicyObject(String id) {
+ Ric ric = this.rics.get("ric");
+ PolicyType type = this.types.get("type1");
+ return ImmutablePolicy.builder() //
+ .id(id) //
+ .json("{}") //
+ .type(type) //
+ .ric(ric) //
+ .ownerServiceName("") //
+ .lastModified("") //
+ .isTransient(false) //
+ .build();
+ }
+
+ private void createInconsistency() {
+ MockA1Client client = a1ClientFactory.getOrCreateA1Client("ric");
+ Policy policy = createPolicyObject("junk");
+ client.putPolicy(policy).block();
+
+ }
+
+ private void listPolicies() {
+ String uri = "/policies";
+ webClient.getForEntity(uri).block();
+ }
+
+ private void listTypes() {
+ String uri = "/policy_types";
+ webClient.getForEntity(uri).block();
+ }
+
+ private void putPolicy(String name) {
+ String putUrl = "/policy?type=type1&id=" + name + "&ric=ric&service=service1";
+ webClient.putForEntity(putUrl, "{}").block();
+ }
+
+ private void deletePolicy(String name) {
+ String deleteUrl = "/policy?id=" + name;
+ webClient.delete(deleteUrl).block();
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java
new file mode 100644
index 00000000..aa917cb4
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/MockPolicyManagementService.java
@@ -0,0 +1,212 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice;
+
+import static org.awaitility.Awaitility.await;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.web.server.LocalServerPort;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.util.StringUtils;
+
+@ExtendWith(SpringExtension.class)
+@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
+@TestPropertySource(
+ properties = { //
+ "server.ssl.key-store=./config/keystore.jks", //
+ "app.webclient.trust-store=./config/truststore.jks"})
+class MockPolicyManagementService {
+ private static final Logger logger = LoggerFactory.getLogger(MockPolicyManagementService.class);
+
+ @Autowired
+ Rics rics;
+
+ @Autowired
+ Policies policies;
+
+ @Autowired
+ PolicyTypes policyTypes;
+
+ @Autowired
+ ApplicationConfig applicationConfig;
+
+ static class MockApplicationConfig extends ApplicationConfig {
+ @Override
+ public String getLocalConfigurationFilePath() {
+ URL url = MockApplicationConfig.class.getClassLoader().getResource("test_application_configuration.json");
+ return url.getFile();
+ }
+ }
+
+ /**
+ * Overrides the BeanFactory.
+ */
+ @TestConfiguration
+ static class TestBeanFactory {
+
+ private final Rics rics = new Rics();
+ private final Policies policies = new Policies();
+ private final PolicyTypes policyTypes = new PolicyTypes();
+
+ @Bean
+ public ApplicationConfig getApplicationConfig() {
+ return new MockApplicationConfig();
+ }
+
+ @Bean
+ public MockA1ClientFactory getA1ClientFactory() {
+ PolicyTypes ricTypes = new PolicyTypes();
+ loadTypes(ricTypes);
+ return new MockA1ClientFactory(ricTypes);
+ }
+
+ @Bean
+ public Policies getPolicies() {
+ return this.policies;
+ }
+
+ @Bean
+ public PolicyTypes getPolicyTypes() {
+ return this.policyTypes;
+ }
+
+ @Bean
+ public Rics getRics() {
+ return this.rics;
+ }
+
+ private static File[] getResourceFolderFiles(String folder) {
+ return getFile(folder).listFiles();
+ }
+
+ private static String readFile(File file) throws IOException {
+ return new String(Files.readAllBytes(file.toPath()));
+ }
+
+ private void loadTypes(PolicyTypes policyTypes) {
+ File[] files = getResourceFolderFiles("policy_types/");
+ for (File file : files) {
+ try {
+ String schema = readFile(file);
+ String typeName = title(schema);
+ PolicyType type = ImmutablePolicyType.builder().name(typeName).schema(schema).build();
+ policyTypes.put(type);
+ } catch (Exception e) {
+ logger.error("Could not load json schema ", e);
+ }
+ }
+ policyTypes.put(ImmutablePolicyType.builder().name("").schema("{}").build());
+ }
+ }
+
+ private static File getFile(String path) {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ URL url = loader.getResource(path);
+ return new File(url.getPath());
+ }
+
+ @LocalServerPort
+ private int port;
+
+ private void keepServerAlive() throws InterruptedException, IOException {
+ waitForConfigurationToBeLoaded();
+ loadInstances();
+ logger.info("Keeping server alive!");
+ synchronized (this) {
+ this.wait();
+ }
+ }
+
+ private void waitForConfigurationToBeLoaded() throws IOException {
+ String json = getConfigJsonFromFile();
+ try {
+ int noOfRicsInConfigFile = StringUtils.countOccurrencesOf(json, "baseUrl");
+ await().until(() -> rics.size() == noOfRicsInConfigFile);
+ } catch (Exception e) {
+ logger.info("Loaded rics: {}, and no of rics in config file: {} never matched!", rics.size(),
+ StringUtils.countOccurrencesOf(json, "baseUrl"));
+ }
+ }
+
+ private static String title(String jsonSchema) {
+ JsonObject parsedSchema = (JsonObject) JsonParser.parseString(jsonSchema);
+ String title = parsedSchema.get("title").getAsString();
+ return title;
+ }
+
+ private void loadInstances() throws IOException {
+ PolicyType unnamedPolicyType = policyTypes.get("");
+ Ric ric = rics.get("ric1");
+ String json = getConfigJsonFromFile();
+
+ Policy policy = ImmutablePolicy.builder() //
+ .id("typelessPolicy") //
+ .json(json) //
+ .ownerServiceName("MockPolicyManagementService") //
+ .ric(ric) //
+ .type(unnamedPolicyType) //
+ .lastModified("now") //
+ .isTransient(false) //
+ .build();
+ this.policies.put(policy);
+ }
+
+ private String getConfigJsonFromFile() throws IOException {
+ File jsonFile = getFile("test_application_configuration.json");
+ String json = new String(Files.readAllBytes(jsonFile.toPath()));
+ return json;
+ }
+
+ @Test
+ @SuppressWarnings("squid:S2699") // Tests should include assertions. This test is only for keeping the server
+ // alive, so it will only be confusing to add an assertion.
+ void runMock() throws Exception {
+ keepServerAlive();
+ }
+
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/aspect/LogAspectTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/aspect/LogAspectTest.java
new file mode 100644
index 00000000..339a8252
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/aspect/LogAspectTest.java
@@ -0,0 +1,98 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.aspect;
+
+import static ch.qos.logback.classic.Level.TRACE;
+import static org.assertj.core.api.Assertions.assertThat;
+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 ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.junit.Rule;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+
+@ExtendWith(MockitoExtension.class)
+class LogAspectTest {
+ @Rule
+ MockitoRule mockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ private ProceedingJoinPoint proceedingJoinPoint;
+
+ @Mock
+ private MethodSignature methodSignature;
+
+ private LogAspect sampleAspect = new LogAspect();
+
+ @Test
+ void testExecutetimeTime_shouldLogTime() throws Throwable {
+ when(proceedingJoinPoint.getSignature()).thenReturn(methodSignature);
+ when(methodSignature.getDeclaringType()).thenReturn(this.getClass());
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(LogAspect.class, TRACE);
+
+ sampleAspect.executimeTime(proceedingJoinPoint);
+ // 'proceed()' is called exactly once
+ verify(proceedingJoinPoint, times(1)).proceed();
+ // 'proceed(Object[])' is never called
+ verify(proceedingJoinPoint, never()).proceed(null);
+
+ assertThat(logAppender.list.get(0).getFormattedMessage()).startsWith("Execution time of");
+ }
+
+ @Test
+ void testEntryLog_shouldLogEntry() throws Throwable {
+ when(proceedingJoinPoint.getSignature()).thenReturn(methodSignature);
+ String signature = "signature";
+ when(methodSignature.getName()).thenReturn(signature);
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(LogAspect.class, TRACE);
+
+ sampleAspect.entryLog(proceedingJoinPoint);
+
+ assertThat(logAppender.list.get(0).getFormattedMessage()).isEqualTo("Entering method: " + signature);
+ }
+
+ @Test
+ void testExitLog_shouldLogExit() throws Throwable {
+ when(proceedingJoinPoint.getSignature()).thenReturn(methodSignature);
+ String signature = "signature";
+ when(methodSignature.getName()).thenReturn(signature);
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(LogAspect.class, TRACE);
+
+ sampleAspect.exitLog(proceedingJoinPoint);
+
+ assertThat(logAppender.list.get(0).getFormattedMessage()).isEqualTo("Exiting method: " + signature);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactoryTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactoryTest.java
new file mode 100644
index 00000000..86244e0d
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientFactoryTest.java
@@ -0,0 +1,167 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.Vector;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class A1ClientFactoryTest {
+ private static final String RIC_NAME = "Name";
+ private static final String EXCEPTION_MESSAGE = "Error";
+
+ @Mock
+ private ApplicationConfig applicationConfigMock;
+
+ @Mock
+ A1Client clientMock1;
+
+ @Mock
+ A1Client clientMock2;
+
+ @Mock
+ A1Client clientMock3;
+
+ @Mock
+ A1Client clientMock4;
+
+ private Ric ric;
+ private A1ClientFactory factoryUnderTest;
+
+ private static ImmutableRicConfig ricConfig(String controllerName) {
+ return ImmutableRicConfig.builder() //
+ .name(RIC_NAME) //
+ .baseUrl("baseUrl") //
+ .managedElementIds(new Vector<>()) //
+ .controllerName(controllerName) //
+ .build();
+ }
+
+ @BeforeEach
+ void createFactoryUnderTest() {
+ factoryUnderTest = spy(new A1ClientFactory(applicationConfigMock));
+ this.ric = new Ric(ricConfig(""));
+
+ }
+
+ @Test
+ void getProtocolVersion_ok() throws ServiceException {
+ whenGetProtocolVersionThrowException(clientMock1);
+ whenGetProtocolVersionReturn(clientMock2, A1ProtocolType.STD_V1_1);
+ doReturn(clientMock1, clientMock2).when(factoryUnderTest).createClient(any(), any());
+
+ A1Client client = factoryUnderTest.createA1Client(ric).block();
+
+ assertEquals(clientMock2, client, "Not correct client returned");
+ assertEquals(A1ProtocolType.STD_V1_1, ric.getProtocolVersion(), "Not correct protocol");
+ }
+
+ @Test
+ void getProtocolVersion_ok_Last() throws ServiceException {
+ whenGetProtocolVersionThrowException(clientMock1, clientMock2, clientMock3);
+ whenGetProtocolVersionReturn(clientMock4, A1ProtocolType.STD_V1_1);
+ doReturn(clientMock1, clientMock2, clientMock3, clientMock4).when(factoryUnderTest).createClient(any(), any());
+
+ A1Client client = factoryUnderTest.createA1Client(ric).block();
+
+ assertEquals(clientMock4, client, "Not correct client returned");
+ assertEquals(A1ProtocolType.STD_V1_1, ric.getProtocolVersion(), "Not correct protocol");
+ }
+
+ @Test
+ void getProtocolVersion_error() throws ServiceException {
+ whenGetProtocolVersionThrowException(clientMock1, clientMock2, clientMock3, clientMock4);
+ doReturn(clientMock1, clientMock2, clientMock3, clientMock4).when(factoryUnderTest).createClient(any(), any());
+
+ StepVerifier.create(factoryUnderTest.createA1Client(ric)) //
+ .expectSubscription() //
+ .expectError() //
+ .verify();
+
+ assertEquals(A1ProtocolType.UNKNOWN, ric.getProtocolVersion(), "Protocol negotiation failed for " + ric.name());
+ }
+
+ private A1Client createClient(A1ProtocolType version) throws ServiceException {
+ return factoryUnderTest.createClient(ric, version);
+ }
+
+ @Test
+ void create_check_types() throws ServiceException {
+ assertTrue(createClient(A1ProtocolType.STD_V1_1) instanceof StdA1ClientVersion1);
+ assertTrue(createClient(A1ProtocolType.OSC_V1) instanceof OscA1Client);
+ }
+
+ @Test
+ void create_check_types_controllers() throws ServiceException {
+ this.ric = new Ric(ricConfig("anythingButEmpty"));
+ whenGetGetControllerConfigReturn();
+ assertTrue(createClient(A1ProtocolType.SDNC_ONAP) instanceof SdncOnapA1Client);
+
+ whenGetGetControllerConfigReturn();
+ assertTrue(createClient(A1ProtocolType.SDNC_OSC_STD_V1_1) instanceof SdncOscA1Client);
+
+ whenGetGetControllerConfigReturn();
+ assertTrue(createClient(A1ProtocolType.SDNC_OSC_OSC_V1) instanceof SdncOscA1Client);
+ }
+
+ private void whenGetProtocolVersionThrowException(A1Client... clientMocks) {
+ for (A1Client clientMock : clientMocks) {
+ when(clientMock.getProtocolVersion()).thenReturn(Mono.error(new Exception(EXCEPTION_MESSAGE)));
+ }
+ }
+
+ private void whenGetProtocolVersionReturn(A1Client clientMock, A1ProtocolType protocol) {
+ when(clientMock.getProtocolVersion()).thenReturn(Mono.just(protocol));
+ }
+
+ private void whenGetGetControllerConfigReturn() throws ServiceException {
+ ControllerConfig controllerCfg = ImmutableControllerConfig.builder() //
+ .name("name") //
+ .baseUrl("baseUrl") //
+ .password("pass") //
+ .userName("user") //
+ .build();
+ when(applicationConfigMock.getControllerConfig(any())).thenReturn(controllerCfg);
+ }
+
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientHelper.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientHelper.java
new file mode 100644
index 00000000..d096e0c6
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1ClientHelper.java
@@ -0,0 +1,80 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import java.util.Arrays;
+import java.util.Vector;
+
+import org.json.JSONObject;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import reactor.core.publisher.Mono;
+
+public class A1ClientHelper {
+
+ private A1ClientHelper() {
+ }
+
+ protected static Mono<String> createOutputJsonResponse(String key, String value) {
+ JSONObject paramsJson = new JSONObject();
+ paramsJson.put(key, value);
+ JSONObject responseJson = new JSONObject();
+ responseJson.put("output", paramsJson);
+ return Mono.just(responseJson.toString());
+ }
+
+ protected static Ric createRic(String url) {
+ RicConfig cfg = ImmutableRicConfig.builder().name("ric") //
+ .baseUrl(url) //
+ .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
+ .controllerName("") //
+ .build();
+ return new Ric(cfg);
+ }
+
+ protected static Policy createPolicy(String nearRtRicUrl, String policyId, String json, String type) {
+ return ImmutablePolicy.builder() //
+ .id(policyId) //
+ .json(json) //
+ .ownerServiceName("service") //
+ .ric(createRic(nearRtRicUrl)) //
+ .type(createPolicyType(type)) //
+ .lastModified("now") //
+ .isTransient(false) //
+ .build();
+ }
+
+ protected static PolicyType createPolicyType(String name) {
+ return ImmutablePolicyType.builder().name(name).schema("schema").build();
+ }
+
+ protected static String getCreateSchema(String policyType, String policyTypeId) {
+ JSONObject obj = new JSONObject(policyType);
+ JSONObject schemaObj = obj.getJSONObject("create_schema");
+ schemaObj.put("title", policyTypeId);
+ return schemaObj.toString();
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java
new file mode 100644
index 00000000..28343322
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/AsyncRestClientTest.java
@@ -0,0 +1,161 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import io.netty.util.internal.logging.InternalLoggerFactory;
+import io.netty.util.internal.logging.JdkLoggerFactory;
+
+import java.io.IOException;
+
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+import reactor.util.Loggers;
+
+class AsyncRestClientTest {
+ private static final String BASE_URL = "BaseUrl";
+ private static final String REQUEST_URL = "/test";
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+ private static final String TEST_JSON = "{\"type\":\"type1\"}";
+ private static final int SUCCESS_CODE = 200;
+ private static final int ERROR_CODE = 500;
+
+ private static MockWebServer mockWebServer;
+
+ private static AsyncRestClient clientUnderTest;
+
+ @BeforeAll
+ static void init() {
+ // skip a lot of unnecessary logs from MockWebServer
+ InternalLoggerFactory.setDefaultFactory(JdkLoggerFactory.INSTANCE);
+ Loggers.useJdkLoggers();
+ mockWebServer = new MockWebServer();
+ clientUnderTest = new AsyncRestClient(mockWebServer.url(BASE_URL).toString());
+ }
+
+ @AfterAll
+ static void tearDown() throws IOException {
+ mockWebServer.shutdown();
+ }
+
+ @Test
+ void testGetNoError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(SUCCESS_CODE) //
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) //
+ .setBody(TEST_JSON));
+
+ Mono<String> returnedMono = clientUnderTest.get(REQUEST_URL);
+ StepVerifier.create(returnedMono).expectNext(TEST_JSON).expectComplete().verify();
+ }
+
+ @Test
+ void testGetError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(ERROR_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.get(REQUEST_URL);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+
+ @Test
+ void testPutNoError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(SUCCESS_CODE) //
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) //
+ .setBody(TEST_JSON));
+
+ Mono<String> returnedMono = clientUnderTest.put(REQUEST_URL, TEST_JSON);
+ StepVerifier.create(returnedMono).expectNext(TEST_JSON).expectComplete().verify();
+ }
+
+ @Test
+ void testPutError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(ERROR_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.put(REQUEST_URL, TEST_JSON);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+
+ @Test
+ void testDeleteNoError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(SUCCESS_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.delete(REQUEST_URL);
+ StepVerifier.create(returnedMono).expectNext("").expectComplete().verify();
+ }
+
+ @Test
+ void testDeleteError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(ERROR_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.delete(REQUEST_URL);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+
+ @Test
+ void testPostNoError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(SUCCESS_CODE) //
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) //
+ .setBody(TEST_JSON));
+
+ Mono<String> returnedMono = clientUnderTest.post(REQUEST_URL, TEST_JSON);
+ StepVerifier.create(returnedMono).expectNext(TEST_JSON).expectComplete().verify();
+ }
+
+ @Test
+ void testPostError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(ERROR_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.post(REQUEST_URL, TEST_JSON);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+
+ @Test
+ void testPostWithAuthHeaderNoError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(SUCCESS_CODE) //
+ .setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) //
+ .setBody(TEST_JSON));
+
+ Mono<String> returnedMono = clientUnderTest.postWithAuthHeader(REQUEST_URL, TEST_JSON, USERNAME, PASSWORD);
+ StepVerifier.create(returnedMono).expectNext(TEST_JSON).expectComplete().verify();
+ }
+
+ @Test
+ void testPostWithAuthHeaderError() {
+ mockWebServer.enqueue(new MockResponse().setResponseCode(ERROR_CODE));
+
+ Mono<String> returnedMono = clientUnderTest.postWithAuthHeader(REQUEST_URL, TEST_JSON, USERNAME, PASSWORD);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1ClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1ClientTest.java
new file mode 100644
index 00000000..fe6274c9
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1ClientTest.java
@@ -0,0 +1,179 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.json.JSONException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class OscA1ClientTest {
+
+ private static final String RIC_URL = "RicUrl";
+
+ private static final String RIC_BASE_URL = "RicBaseUrl/a1-p";
+
+ private static final String POLICYTYPES_IDENTITIES_URL = RIC_BASE_URL + "/policytypes";
+ private static final String POLICIES = "/policies";
+ private static final String POLICYTYPES_URL = RIC_BASE_URL + "/policytypes/";
+ private static final String POLICY_TYPE_1_ID = "type1";
+ private static final String POLICY_TYPE_2_ID = "type2";
+ private static final String POLICY_TYPE_SCHEMA_VALID = "{\"type\":\"type1\"}";
+ private static final String POLICY_TYPE_SCHEMA_INVALID = "\"type\":\"type1\"}";
+ private static final String POLICY_1_ID = "policy1";
+ private static final String POLICY_2_ID = "policy2";
+ private static final String POLICY_JSON_VALID = "{\"policyId\":\"policy1\"}";
+
+ OscA1Client clientUnderTest;
+
+ AsyncRestClient asyncRestClientMock;
+
+ @BeforeEach
+ void init() {
+ RicConfig ricConfig = ImmutableRicConfig.builder() //
+ .name("name") //
+ .baseUrl("RicBaseUrl") //
+ .managedElementIds(new ArrayList<>()) //
+ .controllerName("") //
+ .build();
+ asyncRestClientMock = mock(AsyncRestClient.class);
+ clientUnderTest = new OscA1Client(ricConfig, asyncRestClientMock);
+ }
+
+ @Test
+ void testGetPolicyTypeIdentities() {
+ List<String> policyTypeIds = Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID);
+ Mono<String> policyTypeIdsResp = Mono.just(policyTypeIds.toString());
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeIdsResp);
+
+ Mono<List<String>> returnedMono = clientUnderTest.getPolicyTypeIdentities();
+ verify(asyncRestClientMock).get(POLICYTYPES_IDENTITIES_URL);
+ StepVerifier.create(returnedMono).expectNext(policyTypeIds).expectComplete().verify();
+ }
+
+ @Test
+ void testGetPolicyIdentities() {
+ Mono<String> policyTypeIdsResp = Mono.just(Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID).toString());
+ Mono<String> policyIdsType1Resp = Mono.just(Arrays.asList(POLICY_1_ID).toString());
+ Mono<String> policyIdsType2Resp = Mono.just(Arrays.asList(POLICY_2_ID).toString());
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeIdsResp).thenReturn(policyIdsType1Resp)
+ .thenReturn(policyIdsType2Resp);
+
+ List<String> returned = clientUnderTest.getPolicyIdentities().block();
+
+ assertEquals(2, returned.size(), "");
+ verify(asyncRestClientMock).get(POLICYTYPES_IDENTITIES_URL);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_2_ID + POLICIES);
+ }
+
+ @Test
+ void testGetValidPolicyType() {
+ String policyType = "{\"create_schema\": " + POLICY_TYPE_SCHEMA_VALID + "}";
+ Mono<String> policyTypeResp = Mono.just(policyType);
+
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeResp);
+
+ Mono<String> returnedMono = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_ID);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_ID);
+ StepVerifier.create(returnedMono).expectNext(A1ClientHelper.getCreateSchema(policyType, POLICY_TYPE_1_ID))
+ .expectComplete().verify();
+ }
+
+ @Test
+ void testGetInValidPolicyTypeJson() {
+ String policyType = "{\"create_schema\": " + POLICY_TYPE_SCHEMA_INVALID + "}";
+ Mono<String> policyTypeResp = Mono.just(policyType);
+
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeResp);
+
+ Mono<String> returnedMono = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_ID);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_ID);
+ StepVerifier.create(returnedMono).expectErrorMatches(throwable -> throwable instanceof JSONException).verify();
+ }
+
+ @Test
+ void testGetPolicyTypeWithoutCreateSchema() {
+ Mono<String> policyTypeResp = Mono.just(POLICY_TYPE_SCHEMA_VALID);
+
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeResp);
+
+ Mono<String> returnedMono = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_ID);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_ID);
+ StepVerifier.create(returnedMono).expectErrorMatches(throwable -> throwable instanceof Exception).verify();
+ }
+
+ @Test
+ void testPutPolicy() {
+ when(asyncRestClientMock.put(anyString(), anyString())).thenReturn(Mono.empty());
+
+ clientUnderTest
+ .putPolicy(A1ClientHelper.createPolicy(RIC_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID)).block();
+ verify(asyncRestClientMock).put(POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES + "/" + POLICY_1_ID,
+ POLICY_JSON_VALID);
+ }
+
+ @Test
+ void testDeletePolicy() {
+ when(asyncRestClientMock.delete(anyString())).thenReturn(Mono.empty());
+
+ Mono<String> returnedMono = clientUnderTest
+ .deletePolicy(A1ClientHelper.createPolicy(RIC_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID));
+ verify(asyncRestClientMock).delete(POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES + "/" + POLICY_1_ID);
+ StepVerifier.create(returnedMono).expectComplete().verify();
+ }
+
+ @Test
+ void testDeleteAllPolicies() {
+ Mono<String> policyTypeIdsResp = Mono.just(Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID).toString());
+ Mono<String> policyIdsType1Resp = Mono.just(Arrays.asList(POLICY_1_ID).toString());
+ Mono<String> policyIdsType2Resp = Mono.just(Arrays.asList(POLICY_2_ID).toString());
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyTypeIdsResp).thenReturn(policyIdsType1Resp)
+ .thenReturn(policyIdsType2Resp);
+ when(asyncRestClientMock.delete(anyString())).thenReturn(Mono.empty());
+
+ Flux<String> returnedFlux = clientUnderTest.deleteAllPolicies();
+ StepVerifier.create(returnedFlux).expectComplete().verify();
+ verify(asyncRestClientMock).get(POLICYTYPES_IDENTITIES_URL);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES);
+ verify(asyncRestClientMock).delete(POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES + "/" + POLICY_1_ID);
+ verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_2_ID + POLICIES);
+ verify(asyncRestClientMock).delete(POLICYTYPES_URL + POLICY_TYPE_2_ID + POLICIES + "/" + POLICY_2_ID);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOnapA1ClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOnapA1ClientTest.java
new file mode 100644
index 00000000..b1323859
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOnapA1ClientTest.java
@@ -0,0 +1,271 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.json.JSONException;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.stubbing.OngoingStubbing;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class SdncOnapA1ClientTest {
+ private static final String CONTROLLER_USERNAME = "username";
+ private static final String CONTROLLER_PASSWORD = "password";
+ private static final String RIC_1_URL = "RicUrl";
+ private static final String POLICYTYPES_IDENTITIES_URL = "/A1-ADAPTER-API:getPolicyTypes";
+ private static final String POLICIES_IDENTITIES_URL = "/A1-ADAPTER-API:getPolicyInstances";
+ private static final String POLICYTYPES_URL = "/A1-ADAPTER-API:getPolicyType";
+ private static final String PUT_POLICY_URL = "/A1-ADAPTER-API:createPolicyInstance";
+ private static final String DELETE_POLICY_URL = "/A1-ADAPTER-API:deletePolicyInstance";
+
+ private static final String POLICY_TYPE_1_ID = "type1";
+ private static final String POLICY_TYPE_2_ID = "type2";
+ private static final String POLICY_TYPE_SCHEMA_VALID = "{\"type\":\"type1\"}";
+ private static final String POLICY_TYPE_SCHEMA_INVALID = "\"type\":\"type1\"}";
+ private static final String POLICY_1_ID = "policy1";
+ private static final String POLICY_2_ID = "policy2";
+ private static final String POLICY_JSON_VALID = "{\"scope\":{\"ueId\":\"ue1\"}}";
+
+ SdncOnapA1Client clientUnderTest;
+
+ AsyncRestClient asyncRestClientMock;
+
+ @BeforeEach
+ void init() {
+ asyncRestClientMock = mock(AsyncRestClient.class);
+ ControllerConfig controllerCfg = ImmutableControllerConfig.builder() //
+ .name("name") //
+ .baseUrl("baseUrl") //
+ .password(CONTROLLER_PASSWORD) //
+ .userName(CONTROLLER_USERNAME) //
+ .build();
+
+ clientUnderTest =
+ new SdncOnapA1Client(A1ClientHelper.createRic(RIC_1_URL).getConfig(), controllerCfg, asyncRestClientMock);
+ }
+
+ @Test
+ void testGetPolicyTypeIdentities() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .build();
+ String inputJsonString = SdncJsonHelper.createInputJsonString(inputParams);
+
+ List<String> policyTypeIds = Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID);
+ Mono<String> policyTypeIdsResp =
+ A1ClientHelper.createOutputJsonResponse("policy-type-id-list", policyTypeIds.toString());
+ whenAsyncPostThenReturn(policyTypeIdsResp);
+
+ Mono<List<String>> returnedMono = clientUnderTest.getPolicyTypeIdentities();
+ verify(asyncRestClientMock).postWithAuthHeader(POLICYTYPES_IDENTITIES_URL, inputJsonString, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono).expectNext(policyTypeIds).expectComplete().verify();
+ }
+
+ @Test
+ void testGetPolicyIdentities() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .build();
+ String inputJsonStringGetTypeIds = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .build();
+ String inputJsonStringGetPolicyIdsType1 = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_2_ID) //
+ .build();
+ String inputJsonStringGetPolicyIdsType2 = SdncJsonHelper.createInputJsonString(inputParams);
+
+ List<String> policyTypeIds = Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID);
+ Mono<String> policyTypeIdsResp =
+ A1ClientHelper.createOutputJsonResponse("policy-type-id-list", policyTypeIds.toString());
+ List<String> policyIdsType1 = Arrays.asList(POLICY_1_ID);
+ Mono<String> policyIdsType1Resp =
+ A1ClientHelper.createOutputJsonResponse("policy-instance-id-list", policyIdsType1.toString());
+ List<String> policyIdsType2 = Arrays.asList(POLICY_2_ID);
+ Mono<String> policyIdsType2Resp =
+ A1ClientHelper.createOutputJsonResponse("policy-instance-id-list", policyIdsType2.toString());
+ whenAsyncPostThenReturn(policyTypeIdsResp).thenReturn(policyIdsType1Resp).thenReturn(policyIdsType2Resp);
+
+ Mono<List<String>> returnedMono = clientUnderTest.getPolicyIdentities();
+ StepVerifier.create(returnedMono).expectNext(Arrays.asList(POLICY_1_ID, POLICY_2_ID)).expectComplete().verify();
+ verify(asyncRestClientMock).postWithAuthHeader(POLICYTYPES_IDENTITIES_URL, inputJsonStringGetTypeIds,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICIES_IDENTITIES_URL, inputJsonStringGetPolicyIdsType1,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICIES_IDENTITIES_URL, inputJsonStringGetPolicyIdsType2,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void testGetValidPolicyType() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .build();
+ String inputJsonString = SdncJsonHelper.createInputJsonString(inputParams);
+
+ String policyType = "{\"policySchema\": " + POLICY_TYPE_SCHEMA_VALID + ", \"statusSchema\": {} }";
+ Mono<String> policyTypeResp = A1ClientHelper.createOutputJsonResponse("policy-type", policyType);
+ whenAsyncPostThenReturn(policyTypeResp);
+
+ Mono<String> returnedMono = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_ID);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICYTYPES_URL, inputJsonString, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono).expectNext(POLICY_TYPE_SCHEMA_VALID).expectComplete().verify();
+ }
+
+ @Test
+ void testGetInvalidPolicyType() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .build();
+ String inputJsonString = SdncJsonHelper.createInputJsonString(inputParams);
+
+ String policyType = "{\"policySchema\": " + POLICY_TYPE_SCHEMA_INVALID + ", \"statusSchema\": {} }";
+ Mono<String> policyTypeResp = A1ClientHelper.createOutputJsonResponse("policy-type", policyType);
+ whenAsyncPostThenReturn(policyTypeResp);
+
+ Mono<String> returnedMono = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_ID);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICYTYPES_URL, inputJsonString, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono).expectErrorMatches(throwable -> throwable instanceof JSONException).verify();
+ }
+
+ @Test
+ void testPutPolicy() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .policyInstanceId(POLICY_1_ID) //
+ .policyInstance(POLICY_JSON_VALID) //
+ .properties(new ArrayList<String>()) //
+ .build();
+ String inputJsonString = SdncJsonHelper.createInputJsonString(inputParams);
+
+ whenAsyncPostThenReturn(Mono.empty());
+
+ Mono<String> returnedMono = clientUnderTest
+ .putPolicy(A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID));
+ verify(asyncRestClientMock).postWithAuthHeader(PUT_POLICY_URL, inputJsonString, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono).expectComplete().verify();
+ }
+
+ @Test
+ void testDeletePolicy() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .policyInstanceId(POLICY_1_ID) //
+ .build();
+ String inputJsonString = SdncJsonHelper.createInputJsonString(inputParams);
+
+ whenAsyncPostThenReturn(Mono.empty());
+
+ Mono<String> returnedMono = clientUnderTest
+ .deletePolicy(A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID));
+ verify(asyncRestClientMock).postWithAuthHeader(DELETE_POLICY_URL, inputJsonString, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono).expectComplete().verify();
+ }
+
+ @Test
+ void testDeleteAllPolicies() {
+ SdncOnapA1Client.SdncOnapAdapterInput inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .build();
+ String inputJsonStringGetTypeIds = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .build();
+ String inputJsonStringGetPolicyIdsType1 = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_2_ID) //
+ .build();
+ String inputJsonStringGetPolicyIdsType2 = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_1_ID) //
+ .policyInstanceId(POLICY_1_ID) //
+ .build();
+ String inputJsonStringDeletePolicy1 = SdncJsonHelper.createInputJsonString(inputParams);
+ inputParams = ImmutableSdncOnapAdapterInput.builder() //
+ .nearRtRicId(RIC_1_URL) //
+ .policyTypeId(POLICY_TYPE_2_ID) //
+ .policyInstanceId(POLICY_2_ID) //
+ .build();
+ String inputJsonStringDeletePolicy2 = SdncJsonHelper.createInputJsonString(inputParams);
+
+ List<String> policyTypeIds = Arrays.asList(POLICY_TYPE_1_ID, POLICY_TYPE_2_ID);
+ Mono<String> policyTypeIdsResp =
+ A1ClientHelper.createOutputJsonResponse("policy-type-id-list", policyTypeIds.toString());
+ List<String> policyIdsType1 = Arrays.asList(POLICY_1_ID);
+ Mono<String> policyIdsType1Resp =
+ A1ClientHelper.createOutputJsonResponse("policy-instance-id-list", policyIdsType1.toString());
+ List<String> policyIdsType2 = Arrays.asList(POLICY_2_ID);
+ Mono<String> policyIdsType2Resp =
+ A1ClientHelper.createOutputJsonResponse("policy-instance-id-list", policyIdsType2.toString());
+ whenAsyncPostThenReturn(policyTypeIdsResp).thenReturn(policyIdsType1Resp).thenReturn(Mono.empty())
+ .thenReturn(policyIdsType2Resp).thenReturn(Mono.empty());
+
+ Flux<String> returnedFlux = clientUnderTest.deleteAllPolicies();
+ StepVerifier.create(returnedFlux).expectComplete().verify();
+ verify(asyncRestClientMock).postWithAuthHeader(POLICYTYPES_IDENTITIES_URL, inputJsonStringGetTypeIds,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICIES_IDENTITIES_URL, inputJsonStringGetPolicyIdsType1,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(DELETE_POLICY_URL, inputJsonStringDeletePolicy1,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(POLICIES_IDENTITIES_URL, inputJsonStringGetPolicyIdsType2,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ verify(asyncRestClientMock).postWithAuthHeader(DELETE_POLICY_URL, inputJsonStringDeletePolicy2,
+ CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ }
+
+ private OngoingStubbing<Mono<String>> whenAsyncPostThenReturn(Mono<String> response) {
+ return when(asyncRestClientMock.postWithAuthHeader(anyString(), anyString(), anyString(), anyString()))
+ .thenReturn(response);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1ClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1ClientTest.java
new file mode 100644
index 00000000..1fc4a421
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1ClientTest.java
@@ -0,0 +1,374 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.stubbing.OngoingStubbing;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client.A1ProtocolType;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.ImmutableAdapterOutput.Builder;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.SdncOscA1Client.AdapterOutput;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.SdncOscA1Client.AdapterRequest;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableControllerConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class SdncOscA1ClientTest {
+ private static final String CONTROLLER_USERNAME = "username";
+ private static final String CONTROLLER_PASSWORD = "password";
+ private static final String RIC_1_URL = "RicUrl";
+ private static final String GET_A1_POLICY_URL = "/A1-ADAPTER-API:getA1Policy";
+ private static final String PUT_A1_URL = "/A1-ADAPTER-API:putA1Policy";
+ private static final String DELETE_A1_URL = "/A1-ADAPTER-API:deleteA1Policy";
+ private static final String GET_A1_POLICY_STATUS_URL = "/A1-ADAPTER-API:getA1PolicyStatus";
+ private static final String POLICY_TYPE_1_ID = "type1";
+ private static final String POLICY_1_ID = "policy1";
+ private static final String POLICY_2_ID = "policy2";
+ private static final String POLICY_JSON_VALID = "{\"scope\":{\"ueId\":\"ue1\"}}";
+
+ SdncOscA1Client clientUnderTest;
+
+ @Mock
+ AsyncRestClient asyncRestClientMock;
+
+ private ControllerConfig controllerConfig() {
+ return ImmutableControllerConfig.builder() //
+ .name("name") //
+ .baseUrl("baseUrl") //
+ .password(CONTROLLER_PASSWORD) //
+ .userName(CONTROLLER_USERNAME) //
+ .build();
+ }
+
+ @BeforeEach
+ void init() {
+ Ric ric = A1ClientHelper.createRic(RIC_1_URL);
+
+ clientUnderTest = new SdncOscA1Client(A1ProtocolType.SDNC_OSC_STD_V1_1, ric.getConfig(), controllerConfig(),
+ asyncRestClientMock);
+ }
+
+ @Test
+ void createClientWithWrongProtocol_thenErrorIsThrown() {
+ try {
+ new SdncOscA1Client(A1ProtocolType.STD_V1_1, null, null, new AsyncRestClient("", null));
+ fail("Should have thrown exception.");
+ } catch (IllegalArgumentException e) {
+ return;
+ }
+ }
+
+ @Test
+ void getPolicyTypeIdentities_STD() {
+ List<String> policyTypeIds = clientUnderTest.getPolicyTypeIdentities().block();
+ assertEquals(1, policyTypeIds.size(), "should hardcoded to one");
+ assertEquals("", policyTypeIds.get(0), "should hardcoded to empty");
+ }
+
+ @Test
+ void getPolicyTypeIdentities_OSC() {
+ clientUnderTest = new SdncOscA1Client(A1ProtocolType.SDNC_OSC_OSC_V1, //
+ A1ClientHelper.createRic(RIC_1_URL).getConfig(), //
+ controllerConfig(), asyncRestClientMock);
+
+ String response = createOkResponseWithBody(Arrays.asList(POLICY_TYPE_1_ID));
+ whenAsyncPostThenReturn(Mono.just(response));
+
+ List<String> policyTypeIds = clientUnderTest.getPolicyTypeIdentities().block();
+
+ assertEquals(1, policyTypeIds.size());
+ assertEquals(POLICY_TYPE_1_ID, policyTypeIds.get(0));
+
+ String expUrl = RIC_1_URL + "/a1-p/policytypes";
+ ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(expUrl) //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedParams);
+ verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void getTypeSchema_STD() {
+ String policyType = clientUnderTest.getPolicyTypeSchema("").block();
+
+ assertEquals("{}", policyType);
+ }
+
+ @Test
+ void getTypeSchema_OSC() throws IOException {
+ clientUnderTest = new SdncOscA1Client(A1ProtocolType.SDNC_OSC_OSC_V1, //
+ A1ClientHelper.createRic(RIC_1_URL).getConfig(), //
+ controllerConfig(), asyncRestClientMock);
+
+ String ricResponse = loadFile("test_osc_get_schema_response.json");
+ JsonElement elem = gson().fromJson(ricResponse, JsonElement.class);
+ String responseFromController = createOkResponseWithBody(elem);
+ whenAsyncPostThenReturn(Mono.just(responseFromController));
+
+ String response = clientUnderTest.getPolicyTypeSchema("policyTypeId").block();
+
+ JsonElement respJson = gson().fromJson(response, JsonElement.class);
+ assertEquals("policyTypeId", respJson.getAsJsonObject().get("title").getAsString(),
+ "title should be updated to contain policyType ID");
+ }
+
+ @Test
+ void parseJsonArrayOfString() {
+ // One integer and one string
+ String inputString = "[1, \"1\" ]";
+
+ List<String> result = SdncJsonHelper.parseJsonArrayOfString(inputString).collectList().block();
+ assertEquals(2, result.size());
+ assertEquals("1", result.get(0));
+ assertEquals("1", result.get(1));
+ }
+
+ @Test
+ void getPolicyIdentities_STD() {
+
+ String policyIdsResp = createOkResponseWithBody(Arrays.asList(POLICY_1_ID, POLICY_2_ID));
+ whenAsyncPostThenReturn(Mono.just(policyIdsResp));
+
+ List<String> returned = clientUnderTest.getPolicyIdentities().block();
+
+ assertEquals(2, returned.size());
+
+ ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(policiesUrl()) //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedParams);
+ verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+
+ }
+
+ @Test
+ void getPolicyIdentities_OSC() {
+ clientUnderTest = new SdncOscA1Client(A1ProtocolType.SDNC_OSC_OSC_V1, //
+ A1ClientHelper.createRic(RIC_1_URL).getConfig(), //
+ controllerConfig(), asyncRestClientMock);
+
+ String policytypeIdsResp = createOkResponseWithBody(Arrays.asList(POLICY_TYPE_1_ID));
+ String policyIdsResp = createOkResponseWithBody(Arrays.asList(POLICY_1_ID, POLICY_2_ID));
+ whenAsyncPostThenReturn(Mono.just(policytypeIdsResp)).thenReturn(Mono.just(policyIdsResp));
+
+ List<String> returned = clientUnderTest.getPolicyIdentities().block();
+
+ assertEquals(2, returned.size());
+
+ ImmutableAdapterRequest expectedParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(RIC_1_URL + "/a1-p/policytypes/type1/policies") //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedParams);
+ verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_URL, expInput, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void putPolicyValidResponse() {
+ whenPostReturnOkResponse();
+
+ String returned = clientUnderTest
+ .putPolicy(A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID))
+ .block();
+
+ assertEquals("OK", returned);
+ final String expUrl = policiesUrl() + "/" + POLICY_1_ID;
+ AdapterRequest expectedInputParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(expUrl) //
+ .body(POLICY_JSON_VALID) //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedInputParams);
+
+ verify(asyncRestClientMock).postWithAuthHeader(PUT_A1_URL, expInput, CONTROLLER_USERNAME, CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void putPolicyRejected() {
+ final String policyJson = "{}";
+ AdapterOutput adapterOutput = ImmutableAdapterOutput.builder() //
+ .body("NOK") //
+ .httpStatus(HttpStatus.BAD_REQUEST.value()) // ERROR
+ .build();
+
+ String resp = SdncJsonHelper.createOutputJsonString(adapterOutput);
+ whenAsyncPostThenReturn(Mono.just(resp));
+
+ Mono<String> returnedMono = clientUnderTest
+ .putPolicy(A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, policyJson, POLICY_TYPE_1_ID));
+ StepVerifier.create(returnedMono) //
+ .expectSubscription() //
+ .expectErrorMatches(t -> t instanceof WebClientResponseException) //
+ .verify();
+
+ final String expUrl = policiesUrl() + "/" + POLICY_1_ID;
+ AdapterRequest expRequestParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(expUrl) //
+ .body(policyJson) //
+ .build();
+ String expRequest = SdncJsonHelper.createInputJsonString(expRequestParams);
+ verify(asyncRestClientMock).postWithAuthHeader(PUT_A1_URL, expRequest, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ StepVerifier.create(returnedMono)
+ .expectErrorMatches(throwable -> throwable instanceof WebClientResponseException).verify();
+ }
+
+ @Test
+ void deletePolicy() {
+ whenPostReturnOkResponse();
+
+ String returned = clientUnderTest
+ .deletePolicy(A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID))
+ .block();
+
+ assertEquals("OK", returned);
+ final String expUrl = policiesUrl() + "/" + POLICY_1_ID;
+ AdapterRequest expectedInputParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(expUrl) //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedInputParams);
+
+ verify(asyncRestClientMock).postWithAuthHeader(DELETE_A1_URL, expInput, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void getStatus() {
+ whenPostReturnOkResponse();
+
+ Policy policy = A1ClientHelper.createPolicy(RIC_1_URL, POLICY_1_ID, POLICY_JSON_VALID, POLICY_TYPE_1_ID);
+
+ String returnedStatus = clientUnderTest.getPolicyStatus(policy).block();
+
+ assertEquals("OK", returnedStatus, "unexpected status");
+
+ final String expUrl = policiesUrl() + "/" + POLICY_1_ID + "/status";
+ AdapterRequest expectedInputParams = ImmutableAdapterRequest.builder() //
+ .nearRtRicUrl(expUrl) //
+ .build();
+ String expInput = SdncJsonHelper.createInputJsonString(expectedInputParams);
+
+ verify(asyncRestClientMock).postWithAuthHeader(GET_A1_POLICY_STATUS_URL, expInput, CONTROLLER_USERNAME,
+ CONTROLLER_PASSWORD);
+ }
+
+ @Test
+ void getVersion_STD() {
+ whenPostReturnOkResponse();
+
+ A1ProtocolType returnedVersion = clientUnderTest.getProtocolVersion().block();
+
+ assertEquals(A1ProtocolType.SDNC_OSC_STD_V1_1, returnedVersion);
+
+ whenPostReturnOkResponseNoBody();
+
+ returnedVersion = clientUnderTest.getProtocolVersion().block();
+
+ assertEquals(A1ProtocolType.SDNC_OSC_STD_V1_1, returnedVersion);
+ }
+
+ @Test
+ void getVersion_OSC() {
+ clientUnderTest = new SdncOscA1Client(A1ProtocolType.SDNC_OSC_OSC_V1, //
+ A1ClientHelper.createRic(RIC_1_URL).getConfig(), //
+ controllerConfig(), asyncRestClientMock);
+
+ whenAsyncPostThenReturn(Mono.error(new Exception("Error"))).thenReturn(Mono.just(createOkResponseString(true)));
+
+ A1ProtocolType returnedVersion = clientUnderTest.getProtocolVersion().block();
+
+ assertEquals(A1ProtocolType.SDNC_OSC_OSC_V1, returnedVersion);
+ }
+
+ private String policiesUrl() {
+ return RIC_1_URL + "/A1-P/v1/policies";
+ }
+
+ private Gson gson() {
+ return SdncOscA1Client.gson;
+ }
+
+ private String loadFile(String fileName) throws IOException {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ URL url = loader.getResource(fileName);
+ File file = new File(url.getFile());
+ return new String(Files.readAllBytes(file.toPath()));
+ }
+
+ private void whenPostReturnOkResponse() {
+ whenAsyncPostThenReturn(Mono.just(createOkResponseString(true)));
+ }
+
+ private void whenPostReturnOkResponseNoBody() {
+ whenAsyncPostThenReturn(Mono.just(createOkResponseString(false)));
+ }
+
+ private String createOkResponseWithBody(Object body) {
+ AdapterOutput output = ImmutableAdapterOutput.builder() //
+ .body(gson().toJson(body)) //
+ .httpStatus(HttpStatus.OK.value()) //
+ .build();
+ return SdncJsonHelper.createOutputJsonString(output);
+ }
+
+ private String createOkResponseString(boolean withBody) {
+ Builder responseBuilder = ImmutableAdapterOutput.builder().httpStatus(HttpStatus.OK.value());
+ if (withBody) {
+ responseBuilder.body(HttpStatus.OK.name());
+ } else {
+ responseBuilder.body(Optional.empty());
+ }
+ return SdncJsonHelper.createOutputJsonString(responseBuilder.build());
+ }
+
+ private OngoingStubbing<Mono<String>> whenAsyncPostThenReturn(Mono<String> response) {
+ return when(asyncRestClientMock.postWithAuthHeader(anyString(), anyString(), anyString(), anyString()))
+ .thenReturn(response);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientTest.java
new file mode 100644
index 00000000..834a2a2f
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientTest.java
@@ -0,0 +1,136 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.clients;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class StdA1ClientTest {
+ private static final String RIC_URL = "RicUrl";
+ private static final String POLICY_TYPE_1_NAME = "type1";
+ private static final String POLICY_1_ID = "policy1";
+ private static final String POLICY_2_ID = "policy2";
+ private static final String POLICY_JSON = "{\"policyId\":\"policy1\"}";
+ private static final String POLICY_TYPE = "typeName";
+
+ StdA1ClientVersion1 clientUnderTest;
+
+ @Mock
+ AsyncRestClient asyncRestClientMock;
+
+ @Mock
+ RicConfig ricConfigMock;
+
+ @BeforeEach
+ void init() {
+ clientUnderTest = new StdA1ClientVersion1(asyncRestClientMock, ricConfigMock);
+ }
+
+ private String policiesUrl() {
+ return RIC_URL + "/A1-P/v1/policies";
+ }
+
+ private String policiesBaseUrl() {
+ return policiesUrl() + "/";
+ }
+
+ @Test
+ void testGetPolicyTypeIdentities() {
+ List<String> policyTypeIds = clientUnderTest.getPolicyTypeIdentities().block();
+ assertEquals(1, policyTypeIds.size(), "should hardcoded to one");
+ assertEquals("", policyTypeIds.get(0), "should hardcoded to empty");
+ }
+
+ @Test
+ void testGetPolicyIdentities() {
+ doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+ Mono<String> policyIds = Mono.just(Arrays.asList(POLICY_1_ID, POLICY_2_ID).toString());
+ when(asyncRestClientMock.get(anyString())).thenReturn(policyIds);
+
+ List<String> result = clientUnderTest.getPolicyIdentities().block();
+ assertEquals(2, result.size(), "");
+
+ verify(asyncRestClientMock).get(policiesUrl());
+ }
+
+ @Test
+ void testGetValidPolicyType() {
+ String policyType = clientUnderTest.getPolicyTypeSchema(POLICY_TYPE_1_NAME).block();
+ assertEquals("{}", policyType, "");
+ }
+
+ @Test
+ void testPutPolicyValidResponse() {
+ doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+ when(asyncRestClientMock.put(anyString(), anyString())).thenReturn(Mono.just(POLICY_JSON));
+
+ Mono<String> policyMono =
+ clientUnderTest.putPolicy(A1ClientHelper.createPolicy(RIC_URL, POLICY_1_ID, POLICY_JSON, POLICY_TYPE));
+
+ verify(asyncRestClientMock).put(policiesBaseUrl() + POLICY_1_ID, POLICY_JSON);
+ StepVerifier.create(policyMono).expectNext(POLICY_JSON).expectComplete().verify();
+ }
+
+ @Test
+ void testDeletePolicy() {
+ doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+ final String url = policiesBaseUrl() + POLICY_1_ID;
+ when(asyncRestClientMock.delete(url)).thenReturn(Mono.empty());
+
+ Policy policy = A1ClientHelper.createPolicy(RIC_URL, POLICY_1_ID, POLICY_JSON, POLICY_TYPE);
+ Mono<?> responseMono = clientUnderTest.deletePolicy(policy);
+ verify(asyncRestClientMock).delete(url);
+ StepVerifier.create(responseMono).expectComplete().verify();
+ }
+
+ @Test
+ void testDeleteAllPolicies() {
+ doReturn(RIC_URL).when(ricConfigMock).baseUrl();
+ Mono<String> policyIds = Mono.just(Arrays.asList(POLICY_1_ID, POLICY_2_ID).toString());
+ when(asyncRestClientMock.get(policiesUrl())).thenReturn(policyIds);
+ when(asyncRestClientMock.delete(anyString())).thenReturn(Mono.empty());
+
+ Flux<String> responseFlux = clientUnderTest.deleteAllPolicies();
+ StepVerifier.create(responseFlux).expectComplete().verify();
+ verify(asyncRestClientMock).get(policiesUrl());
+ verify(asyncRestClientMock).delete(policiesBaseUrl() + POLICY_1_ID);
+ verify(asyncRestClientMock).delete(policiesBaseUrl() + POLICY_2_ID);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java
new file mode 100644
index 00000000..086af148
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigParserTest.java
@@ -0,0 +1,159 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+
+class ApplicationConfigParserTest {
+
+ ApplicationConfigParser parserUnderTest = new ApplicationConfigParser();
+
+ @Test
+ void whenCorrectConfig() throws Exception {
+ JsonObject jsonRootObject = getJsonRootObject();
+
+ ApplicationConfigParser.ConfigParserResult result = parserUnderTest.parse(jsonRootObject);
+
+ String topicUrl = result.dmaapProducerTopicUrl();
+ assertEquals("http://admin:admin@localhost:6845/events/A1-POLICY-AGENT-WRITE", topicUrl, "controller contents");
+
+ topicUrl = result.dmaapConsumerTopicUrl();
+ assertEquals(
+ "http://admin:admin@localhost:6845/events/A1-POLICY-AGENT-READ/users/policy-agent?timeout=15000&limit=100",
+ topicUrl, "controller contents");
+
+ Map<String, ControllerConfig> controllers = result.controllerConfigs();
+ assertEquals(1, controllers.size(), "size");
+ ImmutableControllerConfig expectedControllerConfig = ImmutableControllerConfig.builder() //
+ .baseUrl("http://localhost:8083/") //
+ .name("controller1") //
+ .userName("user") //
+ .password("password") //
+ .build(); //
+ assertEquals(expectedControllerConfig, controllers.get("controller1"), "controller contents");
+ }
+
+ private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
+ JsonObject rootObject = JsonParser.parseReader(new InputStreamReader(getCorrectJson())).getAsJsonObject();
+ return rootObject;
+ }
+
+ private static InputStream getCorrectJson() throws IOException {
+ URL url = ApplicationConfigParser.class.getClassLoader()
+ .getResource("test_application_configuration_with_dmaap_config.json");
+ String string = Resources.toString(url, Charsets.UTF_8);
+ return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
+ }
+
+ @Test
+ void whenDmaapConfigHasSeveralStreamsPublishing() throws Exception {
+ JsonObject jsonRootObject = getJsonRootObject();
+ JsonObject json = jsonRootObject.getAsJsonObject("config").getAsJsonObject("streams_publishes");
+ JsonObject fake_info_object = new JsonObject();
+ fake_info_object.addProperty("fake_info", "fake");
+ json.add("fake_info_object", new Gson().toJsonTree(fake_info_object));
+ DataPublishing data = new Gson().fromJson(json.toString(), DataPublishing.class);
+ final String expectedMessage =
+ "Invalid configuration. Number of streams must be one, config: " + data.toString();
+
+ Exception actualException = assertThrows(ServiceException.class, () -> parserUnderTest.parse(jsonRootObject));
+
+ assertEquals(expectedMessage, actualException.getMessage(),
+ "Wrong error message when the DMaaP config has several streams publishing");
+ }
+
+ class DataPublishing {
+ private JsonObject dmaap_publisher;
+ private JsonObject fake_info_object;
+
+ @Override
+ public String toString() {
+ return String.format("[dmaap_publisher=%s, fake_info_object=%s]", dmaap_publisher.toString(),
+ fake_info_object.toString());
+ }
+ }
+
+ @Test
+ void whenDmaapConfigHasSeveralStreamsSubscribing() throws Exception {
+ JsonObject jsonRootObject = getJsonRootObject();
+ JsonObject json = jsonRootObject.getAsJsonObject("config").getAsJsonObject("streams_subscribes");
+ JsonObject fake_info_object = new JsonObject();
+ fake_info_object.addProperty("fake_info", "fake");
+ json.add("fake_info_object", new Gson().toJsonTree(fake_info_object));
+ DataSubscribing data = new Gson().fromJson(json.toString(), DataSubscribing.class);
+ final String expectedMessage =
+ "Invalid configuration. Number of streams must be one, config: " + data.toString();
+
+ Exception actualException = assertThrows(ServiceException.class, () -> parserUnderTest.parse(jsonRootObject));
+
+ assertEquals(expectedMessage, actualException.getMessage(),
+ "Wrong error message when the DMaaP config has several streams subscribing");
+ }
+
+ private class DataSubscribing {
+ private JsonObject dmaap_subscriber;
+ private JsonObject fake_info_object;
+
+ @Override
+ public String toString() {
+ return String.format("[dmaap_subscriber=%s, fake_info_object=%s]", dmaap_subscriber.toString(),
+ fake_info_object.toString());
+ }
+ }
+
+ @Test
+ void whenWrongMemberNameInObject() throws Exception {
+ JsonObject jsonRootObject = getJsonRootObject();
+ JsonObject json = jsonRootObject.getAsJsonObject("config");
+ json.remove("ric");
+ final String message = "Could not find member: 'ric' in: " + json;
+
+ Exception actualException = assertThrows(ServiceException.class, () -> parserUnderTest.parse(jsonRootObject));
+
+ assertEquals(message, actualException.getMessage(), "Wrong error message when wrong member name in object");
+ }
+
+ JsonObject getDmaapInfo(JsonObject jsonRootObject, String streamsPublishesOrSubscribes,
+ String dmaapPublisherOrSubscriber) throws Exception {
+ return jsonRootObject.getAsJsonObject("config").getAsJsonObject(streamsPublishesOrSubscribes)
+ .getAsJsonObject(dmaapPublisherOrSubscriber).getAsJsonObject("dmaap_info");
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigTest.java
new file mode 100644
index 00000000..f7bf2e8b
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/configuration/ApplicationConfigTest.java
@@ -0,0 +1,127 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser.ConfigParserResult;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+
+@ExtendWith(MockitoExtension.class)
+class ApplicationConfigTest {
+
+ private static final ImmutableRicConfig RIC_CONFIG_1 = ImmutableRicConfig.builder() //
+ .name("ric1") //
+ .baseUrl("ric1_url") //
+ .managedElementIds(new Vector<>()) //
+ .controllerName("") //
+ .build();
+
+ ConfigParserResult configParserResult(RicConfig... rics) {
+ return ImmutableConfigParserResult.builder() //
+ .ricConfigs(Arrays.asList(rics)) //
+ .dmaapConsumerTopicUrl("dmaapConsumerTopicUrl") //
+ .dmaapProducerTopicUrl("dmaapProducerTopicUrl") //
+ .controllerConfigs(new HashMap<>()) //
+ .build();
+ }
+
+ @Test
+ void gettingNotAddedRicShouldThrowException() {
+ ApplicationConfig appConfigUnderTest = new ApplicationConfig();
+
+ appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1));
+
+ Exception exception = assertThrows(ServiceException.class, () -> {
+ appConfigUnderTest.getRic("name");
+ });
+
+ assertEquals("Could not find ric configuration: name", exception.getMessage());
+ }
+
+ @Test
+ void addRicShouldNotifyAllObserversOfRicAdded() throws Exception {
+ ApplicationConfig appConfigUnderTest = new ApplicationConfig();
+
+ RicConfigUpdate update = appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1)).blockFirst();
+ assertEquals(RicConfigUpdate.Type.ADDED, update.getType());
+ assertTrue(appConfigUnderTest.getRicConfigs().contains(RIC_CONFIG_1), "Ric not added to configurations.");
+
+ assertEquals(RIC_CONFIG_1, appConfigUnderTest.getRic(RIC_CONFIG_1.name()),
+ "Not correct Ric retrieved from configurations.");
+
+ update = appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1)).blockFirst();
+ assertNull(update, "Nothing should be updated");
+ assertTrue(appConfigUnderTest.getRicConfigs().contains(RIC_CONFIG_1), "Ric should remain.");
+
+ }
+
+ @Test
+ void changedRicShouldNotifyAllObserversOfRicChanged() throws Exception {
+ ApplicationConfig appConfigUnderTest = new ApplicationConfig();
+
+ appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1));
+
+ ImmutableRicConfig changedRicConfig = ImmutableRicConfig.builder() //
+ .name("ric1") //
+ .baseUrl("changed_ric1_url") //
+ .managedElementIds(new Vector<>()) //
+ .controllerName("") //
+ .build();
+
+ RicConfigUpdate update = appConfigUnderTest.setConfiguration(configParserResult(changedRicConfig)).blockFirst();
+
+ assertEquals(RicConfigUpdate.Type.CHANGED, update.getType());
+ assertEquals(changedRicConfig, appConfigUnderTest.getRic(RIC_CONFIG_1.name()),
+ "Changed Ric not retrieved from configurations.");
+ }
+
+ @Test
+ void removedRicShouldNotifyAllObserversOfRicRemoved() {
+ ApplicationConfig appConfigUnderTest = new ApplicationConfig();
+
+ ImmutableRicConfig ricConfig2 = ImmutableRicConfig.builder() //
+ .name("ric2") //
+ .baseUrl("ric2_url") //
+ .managedElementIds(new Vector<>()) //
+ .controllerName("") //
+ .build();
+
+ appConfigUnderTest.setConfiguration(configParserResult(RIC_CONFIG_1, ricConfig2));
+
+ RicConfigUpdate update = appConfigUnderTest.setConfiguration(configParserResult(ricConfig2)).blockFirst();
+
+ assertEquals(RicConfigUpdate.Type.REMOVED, update.getType());
+ assertEquals(1, appConfigUnderTest.getRicConfigs().size(), "Ric not deleted from configurations.");
+ }
+
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumerTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumerTest.java
new file mode 100644
index 00000000..cc9efa07
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageConsumerTest.java
@@ -0,0 +1,205 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.dmaap;
+
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import java.time.Duration;
+import java.util.LinkedList;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import reactor.core.publisher.Mono;
+
+@ExtendWith(MockitoExtension.class)
+class DmaapMessageConsumerTest {
+ @Mock
+ private ApplicationConfig applicationConfigMock;
+ @Mock
+ private AsyncRestClient messageRouterConsumerMock;
+ @Mock
+ private DmaapMessageHandler messageHandlerMock;
+
+ private DmaapMessageConsumer messageConsumerUnderTest;
+
+ @AfterEach
+ void resetLogging() {
+ LoggingUtils.getLogListAppender(DmaapMessageConsumer.class);
+ }
+
+ @Test
+ void dmaapNotConfigured_thenSleepAndRetryUntilConfig() throws Exception {
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ doNothing().when(messageConsumerUnderTest).sleep(any(Duration.class));
+ doReturn(false, false, false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(false, true, true).when(messageConsumerUnderTest).isDmaapConfigured();
+ doReturn(new LinkedList<>()).when(messageConsumerUnderTest).fetchAllMessages();
+
+ messageConsumerUnderTest.start().join();
+
+ InOrder orderVerifier = inOrder(messageConsumerUnderTest);
+ orderVerifier.verify(messageConsumerUnderTest).sleep(DmaapMessageConsumer.TIME_BETWEEN_DMAAP_RETRIES);
+ orderVerifier.verify(messageConsumerUnderTest).fetchAllMessages();
+ }
+
+ @Test
+ void dmaapConfigurationRemoved_thenStopPollingDmaapSleepAndRetry() throws Exception {
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ doNothing().when(messageConsumerUnderTest).sleep(any(Duration.class));
+ doReturn(false, false, false, false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(true, true, false).when(messageConsumerUnderTest).isDmaapConfigured();
+ doReturn(new LinkedList<>()).when(messageConsumerUnderTest).fetchAllMessages();
+
+ messageConsumerUnderTest.start().join();
+
+ InOrder orderVerifier = inOrder(messageConsumerUnderTest);
+ orderVerifier.verify(messageConsumerUnderTest).fetchAllMessages();
+ orderVerifier.verify(messageConsumerUnderTest).sleep(DmaapMessageConsumer.TIME_BETWEEN_DMAAP_RETRIES);
+ }
+
+ @Test
+ void dmaapConfiguredAndNoMessages_thenPollOnce() throws Exception {
+ setUpMrConfig();
+
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ Mono<ResponseEntity<String>> response = Mono.empty();
+
+ doReturn(false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(messageRouterConsumerMock).when(messageConsumerUnderTest).getMessageRouterConsumer();
+ doReturn(response).when(messageRouterConsumerMock).getForEntity(any());
+
+ messageConsumerUnderTest.start().join();
+
+ verify(messageRouterConsumerMock).getForEntity(any());
+ verifyNoMoreInteractions(messageRouterConsumerMock);
+ }
+
+ @Test
+ void dmaapConfiguredAndErrorGettingMessages_thenLogWarningAndSleep() throws Exception {
+ setUpMrConfig();
+
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ doNothing().when(messageConsumerUnderTest).sleep(any(Duration.class));
+ doReturn(false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(messageRouterConsumerMock).when(messageConsumerUnderTest).getMessageRouterConsumer();
+
+ Mono<ResponseEntity<String>> response = Mono.just(new ResponseEntity<>("Error", HttpStatus.BAD_REQUEST));
+ when(messageRouterConsumerMock.getForEntity(any())).thenReturn(response);
+
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(DmaapMessageConsumer.class, WARN);
+
+ messageConsumerUnderTest.start().join();
+
+ assertThat(logAppender.list.get(0).getFormattedMessage())
+ .isEqualTo("Cannot fetch because of Error respons: 400 BAD_REQUEST Error");
+
+ verify(messageConsumerUnderTest).sleep(DmaapMessageConsumer.TIME_BETWEEN_DMAAP_RETRIES);
+ }
+
+ @Test
+ void dmaapConfiguredAndOneMessage_thenPollOnceAndProcessMessage() throws Exception {
+ // The message from MR is here an array of Json objects
+ setUpMrConfig();
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ String message = "{\"apiVersion\":\"1.0\"," //
+ + "\"operation\":\"GET\"," //
+ + "\"correlationId\":\"1592341013115594000\"," //
+ + "\"originatorId\":\"849e6c6b420\"," //
+ + "\"payload\":{}," //
+ + "\"requestId\":\"23343221\", " //
+ + "\"target\":\"policy-management-service\"," //
+ + "\"timestamp\":\"2020-06-16 20:56:53.115665\"," //
+ + "\"type\":\"request\"," //
+ + "\"url\":\"/rics\"}";
+ String messages = "[" + message + "]";
+
+ doReturn(false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(messageRouterConsumerMock).when(messageConsumerUnderTest).getMessageRouterConsumer();
+
+ Mono<ResponseEntity<String>> response = Mono.just(new ResponseEntity<>(messages, HttpStatus.OK));
+ when(messageRouterConsumerMock.getForEntity(any())).thenReturn(response);
+
+ doReturn(messageHandlerMock).when(messageConsumerUnderTest).getDmaapMessageHandler();
+
+ messageConsumerUnderTest.start().join();
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(messageHandlerMock).handleDmaapMsg(captor.capture());
+ String messageAfterJsonParsing = captor.getValue();
+ assertThat(messageAfterJsonParsing).contains("apiVersion");
+
+ verifyNoMoreInteractions(messageHandlerMock);
+ }
+
+ @Test
+ void dmaapConfiguredAndOneMessage_thenPollOnceAndProcessMessage2() throws Exception {
+ // The message from MR is here an array of String (which is the case when the MR
+ // simulator is used)
+ setUpMrConfig();
+ messageConsumerUnderTest = spy(new DmaapMessageConsumer(applicationConfigMock));
+
+ doReturn(false, true).when(messageConsumerUnderTest).isStopped();
+ doReturn(messageRouterConsumerMock).when(messageConsumerUnderTest).getMessageRouterConsumer();
+
+ Mono<ResponseEntity<String>> response = Mono.just(new ResponseEntity<>("[\"aMessage\"]", HttpStatus.OK));
+ when(messageRouterConsumerMock.getForEntity(any())).thenReturn(response);
+
+ doReturn(messageHandlerMock).when(messageConsumerUnderTest).getDmaapMessageHandler();
+
+ messageConsumerUnderTest.start().join();
+
+ verify(messageHandlerMock).handleDmaapMsg("aMessage");
+ verifyNoMoreInteractions(messageHandlerMock);
+ }
+
+ private void setUpMrConfig() {
+ when(applicationConfigMock.getDmaapConsumerTopicUrl()).thenReturn("url");
+ when(applicationConfigMock.getDmaapProducerTopicUrl()).thenReturn("url");
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageHandlerTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageHandlerTest.java
new file mode 100644
index 00000000..dfa132d8
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/dmaap/DmaapMessageHandlerTest.java
@@ -0,0 +1,290 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.dmaap;
+
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonObject;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.dmaap.DmaapRequestMessage.Operation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+class DmaapMessageHandlerTest {
+ private static final Logger logger = LoggerFactory.getLogger(DmaapMessageHandlerTest.class);
+ private static final String URL = "url";
+
+ private final AsyncRestClient dmaapClient = mock(AsyncRestClient.class);
+ private final AsyncRestClient pmsClient = mock(AsyncRestClient.class);
+ private DmaapMessageHandler testedObject;
+ private static Gson gson = new GsonBuilder() //
+ .create(); //
+
+ @BeforeEach
+ private void setUp() throws Exception {
+ testedObject = spy(new DmaapMessageHandler(dmaapClient, pmsClient));
+ }
+
+ static JsonObject payloadAsJson() {
+ return gson.fromJson(payloadAsString(), JsonObject.class);
+ }
+
+ static String payloadAsString() {
+ PolicyType pt = ImmutablePolicyType.builder().name("name").schema("schema").build();
+ return gson.toJson(pt);
+ }
+
+ DmaapRequestMessage dmaapRequestMessage(Operation operation) {
+ Optional<JsonObject> payload =
+ ((operation == Operation.PUT || operation == Operation.POST) ? Optional.of(payloadAsJson())
+ : Optional.empty());
+ return ImmutableDmaapRequestMessage.builder() //
+ .apiVersion("apiVersion") //
+ .correlationId("correlationId") //
+ .operation(operation) //
+ .originatorId("originatorId") //
+ .payload(payload) //
+ .requestId("requestId") //
+ .target("target") //
+ .timestamp("timestamp") //
+ .url(URL) //
+ .build();
+ }
+
+ private String dmaapInputMessage(Operation operation) {
+ return gson.toJson(dmaapRequestMessage(operation));
+ }
+
+ private Mono<ResponseEntity<String>> okResponse() {
+ ResponseEntity<String> entity = new ResponseEntity<>("OK", HttpStatus.OK);
+ return Mono.just(entity);
+ }
+
+ private Mono<ResponseEntity<String>> notOkResponse() {
+ ResponseEntity<String> entity = new ResponseEntity<>("NOK", HttpStatus.BAD_GATEWAY);
+ return Mono.just(entity);
+ }
+
+ @Test
+ void testMessageParsing() {
+ String message = dmaapInputMessage(Operation.DELETE);
+ logger.info(message);
+ DmaapRequestMessage parsedMessage = gson.fromJson(message, ImmutableDmaapRequestMessage.class);
+ assertNotNull(parsedMessage);
+ assertFalse(parsedMessage.payload().isPresent());
+
+ message = dmaapInputMessage(Operation.PUT);
+ logger.info(message);
+ parsedMessage = gson.fromJson(message, ImmutableDmaapRequestMessage.class);
+ assertNotNull(parsedMessage);
+ assertTrue(parsedMessage.payload().isPresent());
+ }
+
+ @Test
+ void unparseableMessage_thenWarning() {
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(DmaapMessageHandler.class, WARN);
+
+ String msg = "bad message";
+ testedObject.handleDmaapMsg(msg);
+
+ assertThat(logAppender.list.get(0).getFormattedMessage()).startsWith(
+ "handleDmaapMsg failure org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException: Received unparsable "
+ + "message from DMAAP: \"" + msg + "\", reason: ");
+ }
+
+ @Test
+ void successfulDelete() throws IOException {
+ doReturn(okResponse()).when(pmsClient).deleteForEntity(anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ String message = dmaapInputMessage(Operation.DELETE);
+
+ StepVerifier //
+ .create(testedObject.createTask(message)) //
+ .expectSubscription() //
+ .expectNext("OK") //
+ .verifyComplete(); //
+
+ verify(pmsClient).deleteForEntity(URL);
+ verifyNoMoreInteractions(pmsClient);
+
+ verify(dmaapClient).post(anyString(), anyString());
+
+ verifyNoMoreInteractions(dmaapClient);
+ }
+
+ @Test
+ void successfulGet() throws IOException {
+ doReturn(okResponse()).when(pmsClient).getForEntity(anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ StepVerifier //
+ .create(testedObject.createTask(dmaapInputMessage(Operation.GET))) //
+ .expectSubscription() //
+ .expectNext("OK") //
+ .verifyComplete(); //
+
+ verify(pmsClient).getForEntity(URL);
+ verifyNoMoreInteractions(pmsClient);
+
+ verify(dmaapClient).post(anyString(), anyString());
+ verifyNoMoreInteractions(dmaapClient);
+ }
+
+ @Test
+ void exceptionFromPmsWhenGet_thenPostError() throws IOException {
+ String errorBody = "Unavailable";
+ WebClientResponseException webClientResponseException = new WebClientResponseException(
+ HttpStatus.SERVICE_UNAVAILABLE.value(), "", (HttpHeaders) null, errorBody.getBytes(), (Charset) null);
+ doReturn(Mono.error(webClientResponseException)).when(pmsClient).getForEntity(anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ StepVerifier //
+ .create(testedObject.createTask(dmaapInputMessage(Operation.GET))) //
+ .expectSubscription() //
+ .verifyComplete(); //
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(dmaapClient).post(anyString(), captor.capture());
+ String actualMessage = captor.getValue();
+ assertThat(actualMessage).contains(HttpStatus.SERVICE_UNAVAILABLE.toString()) //
+ .contains(errorBody);
+ }
+
+ @Test
+ void successfulPut() throws IOException {
+ doReturn(okResponse()).when(pmsClient).putForEntity(anyString(), anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ StepVerifier //
+ .create(testedObject.createTask(dmaapInputMessage(Operation.PUT))) //
+ .expectSubscription() //
+ .expectNext("OK") //
+ .verifyComplete(); //
+
+ verify(pmsClient).putForEntity(URL, payloadAsString());
+ verifyNoMoreInteractions(pmsClient);
+
+ verify(dmaapClient).post(anyString(), anyString());
+ verifyNoMoreInteractions(dmaapClient);
+ }
+
+ @Test
+ void successfulPost() throws IOException {
+ doReturn(okResponse()).when(pmsClient).postForEntity(anyString(), anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ StepVerifier //
+ .create(testedObject.createTask(dmaapInputMessage(Operation.POST))) //
+ .expectSubscription() //
+ .expectNext("OK") //
+ .verifyComplete(); //
+
+ verify(pmsClient).postForEntity(URL, payloadAsString());
+ verifyNoMoreInteractions(pmsClient);
+
+ verify(dmaapClient).post(anyString(), anyString());
+ verifyNoMoreInteractions(dmaapClient);
+ }
+
+ @Test
+ void exceptionWhenCallingPms_thenNotFoundResponse() throws IOException {
+
+ doReturn(notOkResponse()).when(pmsClient).putForEntity(anyString(), anyString());
+ doReturn(Mono.just("OK")).when(dmaapClient).post(anyString(), anyString());
+
+ testedObject.createTask(dmaapInputMessage(Operation.PUT)).block();
+
+ verify(pmsClient).putForEntity(anyString(), anyString());
+ verifyNoMoreInteractions(pmsClient);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(dmaapClient).post(anyString(), captor.capture());
+ String actualMessage = captor.getValue();
+ assertThat(actualMessage).as("Message \"%s\" sent to DMaaP contains %s", actualMessage, HttpStatus.BAD_GATEWAY)
+ .contains(HttpStatus.BAD_GATEWAY.toString());
+
+ verifyNoMoreInteractions(dmaapClient);
+ }
+
+ @Test
+ void unsupportedOperationInMessage_thenNotFoundResponseWithNotImplementedOperation() throws Exception {
+ String message = dmaapInputMessage(Operation.PUT).toString();
+ String badOperation = "BAD";
+ message = message.replace(Operation.PUT.toString(), badOperation);
+
+ testedObject.handleDmaapMsg(message);
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
+ verify(dmaapClient).post(anyString(), captor.capture());
+ String actualMessage = captor.getValue();
+ assertThat(actualMessage).contains("Not implemented operation") //
+ .contains("BAD_REQUEST");
+ }
+
+ @Test
+ void putWithoutPayload_thenNotFoundResponseWithWarning() throws Exception {
+ String message = dmaapInputMessage(Operation.PUT).toString();
+ message = message.replace(",\"payload\":{\"name\":\"name\",\"schema\":\"schema\"}", "");
+
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(DmaapMessageHandler.class, WARN);
+
+ testedObject.handleDmaapMsg(message);
+
+ assertThat(logAppender.list.get(0).getFormattedMessage())
+ .startsWith("Expected payload in message from DMAAP: ");
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/LockTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/LockTest.java
new file mode 100644
index 00000000..520e5c7a
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/LockTest.java
@@ -0,0 +1,89 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.repository;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
+
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class LockTest {
+
+ @SuppressWarnings("squid:S2925") // "Thread.sleep" should not be used in tests.
+ private void sleep() {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ // Do nothing.
+ }
+ }
+
+ private void asynchUnlock(Lock lock) {
+ Thread thread = new Thread(() -> {
+ sleep();
+ lock.unlockBlocking();
+ });
+ thread.start();
+ }
+
+ @Test
+ void testLock() throws IOException, ServiceException {
+ Lock lock = new Lock();
+ lock.lockBlocking(LockType.SHARED);
+ lock.unlockBlocking();
+
+ lock.lockBlocking(LockType.EXCLUSIVE);
+ asynchUnlock(lock);
+
+ lock.lockBlocking(LockType.SHARED);
+ lock.unlockBlocking();
+
+ assertThat(lock.getLockCounter()).isZero();
+ }
+
+ @Test
+ void testReactiveLock() {
+ Lock lock = new Lock();
+
+ Mono<Lock> seq = lock.lock(LockType.EXCLUSIVE) //
+ .flatMap(l -> lock.lock(LockType.EXCLUSIVE)) //
+ .flatMap(l -> lock.unlock());
+
+ asynchUnlock(lock);
+ StepVerifier.create(seq) //
+ .expectSubscription() //
+ .expectNext(lock) //
+ .verifyComplete();
+
+ assertThat(lock.getLockCounter()).isZero();
+
+ }
+
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/EnvironmentProcessorTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/EnvironmentProcessorTest.java
new file mode 100644
index 00000000..e2bc8700
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/EnvironmentProcessorTest.java
@@ -0,0 +1,145 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
+
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import java.util.Properties;
+
+import org.junit.jupiter.api.Test;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.EnvironmentLoaderException;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties;
+import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.ImmutableEnvProperties;
+import reactor.test.StepVerifier;
+
+class EnvironmentProcessorTest {
+ private static final String CONSUL_HOST = "CONSUL_HOST";
+ private static final String CONSUL_HOST_VALUE = "consulHost";
+
+ private static final String CONFIG_BINDING_SERVICE = "CONFIG_BINDING_SERVICE";
+ private static final String CONFIG_BINDING_SERVICE_VALUE = "configBindingService";
+
+ private static final String HOSTNAME = "HOSTNAME";
+ private static final String HOSTNAME_VALUE = "hostname";
+
+ @Test
+ void allPropertiesAvailableWithHostname_thenAllPropertiesAreReturnedWithGivenConsulPort() {
+ Properties systemEnvironment = new Properties();
+ String consulPort = "8080";
+ systemEnvironment.put(CONSUL_HOST, CONSUL_HOST_VALUE);
+ systemEnvironment.put("CONSUL_PORT", consulPort);
+ systemEnvironment.put(CONFIG_BINDING_SERVICE, CONFIG_BINDING_SERVICE_VALUE);
+ systemEnvironment.put(HOSTNAME, HOSTNAME_VALUE);
+
+ EnvProperties expectedEnvProperties = ImmutableEnvProperties.builder() //
+ .consulHost(CONSUL_HOST_VALUE) //
+ .consulPort(Integer.valueOf(consulPort)) //
+ .cbsName(CONFIG_BINDING_SERVICE_VALUE) //
+ .appName(HOSTNAME_VALUE) //
+ .build();
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectNext(expectedEnvProperties).expectComplete();
+ }
+
+ @Test
+ void consulHostMissing_thenExceptionReturned() {
+ Properties systemEnvironment = new Properties();
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectErrorMatches(throwable -> throwable instanceof EnvironmentLoaderException
+ && throwable.getMessage().equals("$CONSUL_HOST environment has not been defined"))
+ .verify();
+ }
+
+ @Test
+ void withAllPropertiesExceptConsulPort_thenAllPropertiesAreReturnedWithDefaultConsulPortAndWarning() {
+ Properties systemEnvironment = new Properties();
+ systemEnvironment.put(CONSUL_HOST, CONSUL_HOST_VALUE);
+ systemEnvironment.put(CONFIG_BINDING_SERVICE, CONFIG_BINDING_SERVICE_VALUE);
+ systemEnvironment.put(HOSTNAME, HOSTNAME_VALUE);
+
+ String defaultConsulPort = "8500";
+ EnvProperties expectedEnvProperties = ImmutableEnvProperties.builder() //
+ .consulHost(CONSUL_HOST_VALUE) //
+ .consulPort(Integer.valueOf(defaultConsulPort)) //
+ .cbsName(CONFIG_BINDING_SERVICE_VALUE) //
+ .appName(HOSTNAME_VALUE) //
+ .build();
+
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(EnvironmentProcessor.class, WARN);
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectNext(expectedEnvProperties).expectComplete();
+
+ assertThat(logAppender.list.get(0).getFormattedMessage())
+ .isEqualTo("$CONSUL_PORT variable will be set to default port " + defaultConsulPort);
+ }
+
+ @Test
+ void configBindingServiceMissing_thenExceptionReturned() {
+ Properties systemEnvironment = new Properties();
+ systemEnvironment.put(CONSUL_HOST, CONSUL_HOST_VALUE);
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectErrorMatches(throwable -> throwable instanceof EnvironmentLoaderException
+ && throwable.getMessage().equals("$CONFIG_BINDING_SERVICE environment has not been defined"))
+ .verify();
+ }
+
+ @Test
+ void allPropertiesAvailableWithServiceName_thenAllPropertiesAreReturned() {
+ Properties systemEnvironment = new Properties();
+ String consulPort = "8080";
+ systemEnvironment.put(CONSUL_HOST, CONSUL_HOST_VALUE);
+ systemEnvironment.put("CONSUL_PORT", consulPort);
+ systemEnvironment.put(CONFIG_BINDING_SERVICE, CONFIG_BINDING_SERVICE_VALUE);
+ systemEnvironment.put("SERVICE_NAME", HOSTNAME_VALUE);
+
+ EnvProperties expectedEnvProperties = ImmutableEnvProperties.builder() //
+ .consulHost(CONSUL_HOST_VALUE) //
+ .consulPort(Integer.valueOf(consulPort)) //
+ .cbsName(CONFIG_BINDING_SERVICE_VALUE) //
+ .appName(HOSTNAME_VALUE) //
+ .build();
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectNext(expectedEnvProperties).expectComplete();
+ }
+
+ @Test
+ void serviceNameAndHostnameMissing_thenExceptionIsReturned() {
+ Properties systemEnvironment = new Properties();
+ systemEnvironment.put(CONSUL_HOST, CONSUL_HOST_VALUE);
+ systemEnvironment.put(CONFIG_BINDING_SERVICE, CONFIG_BINDING_SERVICE_VALUE);
+
+ StepVerifier.create(EnvironmentProcessor.readEnvironmentVariables(systemEnvironment))
+ .expectErrorMatches(throwable -> throwable instanceof EnvironmentLoaderException && throwable.getMessage()
+ .equals("Neither $HOSTNAME/$SERVICE_NAME have not been defined as system environment"))
+ .verify();
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTaskTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTaskTest.java
new file mode 100644
index 00000000..be2fabdf
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RefreshConfigTaskTest.java
@@ -0,0 +1,386 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
+
+import static ch.qos.logback.classic.Level.ERROR;
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Vector;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig.RicConfigUpdate.Type;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfigParser.ConfigParserResult;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableConfigParserResult;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.CbsClient;
+import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties;
+import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.ImmutableEnvProperties;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+@ExtendWith(MockitoExtension.class)
+class RefreshConfigTaskTest {
+
+ private static final boolean CONFIG_FILE_EXISTS = true;
+ private static final boolean CONFIG_FILE_DOES_NOT_EXIST = false;
+
+ private RefreshConfigTask refreshTaskUnderTest;
+
+ @Spy
+ ApplicationConfig appConfig;
+
+ @Mock
+ CbsClient cbsClient;
+
+ private static final String RIC_1_NAME = "ric1";
+ private static final ImmutableRicConfig CORRECT_RIC_CONIFG = ImmutableRicConfig.builder() //
+ .name(RIC_1_NAME) //
+ .baseUrl("http://localhost:8080/") //
+ .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
+ .controllerName("") //
+ .build();
+
+ private static EnvProperties properties() {
+ return ImmutableEnvProperties.builder() //
+ .consulHost("host") //
+ .consulPort(123) //
+ .cbsName("cbsName") //
+ .appName("appName") //
+ .build();
+ }
+
+ private RefreshConfigTask createTestObject(boolean configFileExists) {
+ return createTestObject(configFileExists, new Rics(), new Policies(), true);
+ }
+
+ private RefreshConfigTask createTestObject(boolean configFileExists, Rics rics, Policies policies,
+ boolean stubConfigFileExists) {
+ RefreshConfigTask obj = spy(new RefreshConfigTask(appConfig, rics, policies, new Services(), new PolicyTypes(),
+ new A1ClientFactory(appConfig)));
+ if (stubConfigFileExists) {
+ doReturn(configFileExists).when(obj).fileExists(any());
+ }
+ return obj;
+ }
+
+ @Test
+ void startWithStubbedRefresh_thenTerminationLogged() {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST, null, null, false);
+ doReturn(Flux.empty()).when(refreshTaskUnderTest).createRefreshTask();
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(RefreshConfigTask.class, ERROR);
+
+ refreshTaskUnderTest.start();
+
+ assertThat(logAppender.list.get(0).getFormattedMessage()).isEqualTo("Configuration refresh terminated");
+ }
+
+ @Test
+ void startWithStubbedRefreshReturnError_thenErrorAndTerminationLogged() {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST, null, null, false);
+ String errorMessage = "Error";
+ doReturn(Flux.error(new Exception(errorMessage))).when(refreshTaskUnderTest).createRefreshTask();
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(RefreshConfigTask.class, ERROR);
+
+ refreshTaskUnderTest.start();
+
+ ILoggingEvent event = logAppender.list.get(0);
+ assertThat(event.getFormattedMessage())
+ .isEqualTo("Configuration refresh terminated due to exception java.lang.Exception: " + errorMessage);
+ }
+
+ @Test
+ void stop_thenTaskIsDisposed() throws Exception {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST, null, null, false);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+
+ refreshTaskUnderTest.start();
+ refreshTaskUnderTest.stop();
+
+ assertThat(refreshTaskUnderTest.getRefreshTask().isDisposed()).as("Refresh task is disposed").isTrue();
+ }
+
+ @Test
+ void whenTheConfigurationFits_thenConfiguredRicsArePutInRepository() throws Exception {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_EXISTS);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+ // When
+ doReturn(getCorrectJson()).when(refreshTaskUnderTest).createInputStream(any());
+ doReturn("fileName").when(appConfig).getLocalConfigurationFilePath();
+
+ StepVerifier //
+ .create(refreshTaskUnderTest.createRefreshTask()) //
+ .expectSubscription() //
+ .expectNext(Type.ADDED) //
+ .expectNext(Type.ADDED) //
+ .thenCancel() //
+ .verify();
+
+ // Then
+ verify(refreshTaskUnderTest).loadConfigurationFromFile();
+
+ verify(refreshTaskUnderTest, times(2)).runRicSynchronization(any(Ric.class));
+
+ Iterable<RicConfig> ricConfigs = appConfig.getRicConfigs();
+ RicConfig ricConfig = ricConfigs.iterator().next();
+ assertThat(ricConfigs).isNotNull();
+ assertThat(ricConfig).isEqualTo(CORRECT_RIC_CONIFG);
+ }
+
+ @Test
+ void whenFileExistsButJsonIsIncorrect_thenNoRicsArePutInRepositoryAndErrorIsLogged() throws Exception {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_EXISTS);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+
+ // When
+ doReturn(getIncorrectJson()).when(refreshTaskUnderTest).createInputStream(any());
+ doReturn("fileName").when(appConfig).getLocalConfigurationFilePath();
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(RefreshConfigTask.class, ERROR);
+
+ StepVerifier //
+ .create(refreshTaskUnderTest.createRefreshTask()) //
+ .expectSubscription() //
+ .expectNoEvent(Duration.ofMillis(100)) //
+ .thenCancel() //
+ .verify();
+
+ // Then
+ verify(refreshTaskUnderTest).loadConfigurationFromFile();
+ assertThat(appConfig.getRicConfigs()).isEmpty();
+
+ await().until(() -> logAppender.list.size() > 0);
+ assertThat(logAppender.list.get(0).getFormattedMessage())
+ .startsWith("Local configuration file not loaded: fileName, ");
+ }
+
+ @Test
+ void whenPeriodicConfigRefreshNoConsul_thenErrorIsLogged() {
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+
+ EnvProperties props = properties();
+ doReturn(Mono.just(props)).when(refreshTaskUnderTest).getEnvironment(any());
+
+ doReturn(Mono.just(cbsClient)).when(refreshTaskUnderTest).createCbsClient(props);
+ when(cbsClient.get(any())).thenReturn(Mono.error(new IOException()));
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(RefreshConfigTask.class, WARN);
+
+ StepVerifier //
+ .create(refreshTaskUnderTest.createRefreshTask()) //
+ .expectSubscription() //
+ .expectNoEvent(Duration.ofMillis(1000)) //
+ .thenCancel() //
+ .verify();
+
+ await().until(() -> logAppender.list.size() > 0);
+ assertThat(logAppender.list.get(0).getFormattedMessage())
+ .isEqualTo("Could not refresh application configuration. java.io.IOException");
+ }
+
+ @Test
+ void whenPeriodicConfigRefreshSuccess_thenNewConfigIsCreatedAndRepositoryUpdated() throws Exception {
+ Rics rics = new Rics();
+ Policies policies = new Policies();
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST, rics, policies, false);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+
+ RicConfig changedRicConfig = getRicConfig(RIC_1_NAME);
+ rics.put(new Ric(changedRicConfig));
+ RicConfig removedRicConfig = getRicConfig("removed");
+ Ric removedRic = new Ric(removedRicConfig);
+ rics.put(removedRic);
+ appConfig.setConfiguration(configParserResult(changedRicConfig, removedRicConfig));
+
+ Policy policy = getPolicy(removedRic);
+ policies.put(policy);
+
+ EnvProperties props = properties();
+ doReturn(Mono.just(props)).when(refreshTaskUnderTest).getEnvironment(any());
+ doReturn(Mono.just(cbsClient)).when(refreshTaskUnderTest).createCbsClient(props);
+
+ JsonObject configAsJson = getJsonRootObject(true);
+ String newBaseUrl = "newBaseUrl";
+ modifyTheRicConfiguration(configAsJson, newBaseUrl);
+ when(cbsClient.get(any())).thenReturn(Mono.just(configAsJson));
+ doNothing().when(refreshTaskUnderTest).runRicSynchronization(any(Ric.class));
+
+ StepVerifier //
+ .create(refreshTaskUnderTest.createRefreshTask()) //
+ .expectSubscription() //
+ .expectNext(Type.CHANGED) //
+ .expectNext(Type.ADDED) //
+ .expectNext(Type.REMOVED) //
+ .thenCancel() //
+ .verify();
+
+ assertThat(appConfig.getRicConfigs()).hasSize(2);
+ assertThat(appConfig.getRic(RIC_1_NAME).baseUrl()).isEqualTo(newBaseUrl);
+ String ric2Name = "ric2";
+ assertThat(appConfig.getRic(ric2Name)).isNotNull();
+
+ assertThat(rics.size()).isEqualTo(2);
+ assertThat(rics.get(RIC_1_NAME).getConfig().baseUrl()).isEqualTo(newBaseUrl);
+ assertThat(rics.get(ric2Name)).isNotNull();
+
+ assertThat(policies.size()).isZero();
+ }
+
+ @Test
+ void whenPeriodicConfigRefreshInvalidJson_thenErrorIsLogged() throws Exception {
+ Rics rics = new Rics();
+ Policies policies = new Policies();
+ refreshTaskUnderTest = this.createTestObject(CONFIG_FILE_DOES_NOT_EXIST, rics, policies, false);
+ refreshTaskUnderTest.systemEnvironment = new Properties();
+
+ appConfig.setConfiguration(configParserResult());
+
+ EnvProperties props = properties();
+ doReturn(Mono.just(props)).when(refreshTaskUnderTest).getEnvironment(any());
+ doReturn(Mono.just(cbsClient)).when(refreshTaskUnderTest).createCbsClient(props);
+
+ JsonObject configAsJson = getJsonRootObject(false);
+ when(cbsClient.get(any())).thenReturn(Mono.just(configAsJson));
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(RefreshConfigTask.class, ERROR);
+
+ StepVerifier //
+ .create(refreshTaskUnderTest.createRefreshTask()) //
+ .expectSubscription() //
+ .expectNoEvent(Duration.ofMillis(1000)) //
+ .thenCancel() //
+ .verify();
+
+ await().until(() -> logAppender.list.size() > 0);
+ assertThat(logAppender.list.get(0).getFormattedMessage()).startsWith(
+ "Could not parse configuration org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException: ");
+ }
+
+ private RicConfig getRicConfig(String name) {
+ RicConfig ricConfig = ImmutableRicConfig.builder() //
+ .name(name) //
+ .baseUrl("url") //
+ .managedElementIds(Collections.emptyList()) //
+ .controllerName("controllerName") //
+ .build();
+ return ricConfig;
+ }
+
+ private Policy getPolicy(Ric ric) {
+ ImmutablePolicyType type = ImmutablePolicyType.builder() //
+ .name("type") //
+ .schema("{}") //
+ .build();
+ Policy policy = ImmutablePolicy.builder() //
+ .id("id") //
+ .type(type) //
+ .lastModified("lastModified") //
+ .ric(ric) //
+ .json("{}") //
+ .ownerServiceName("ownerServiceName") //
+ .isTransient(false) //
+ .build();
+ return policy;
+ }
+
+ ConfigParserResult configParserResult(RicConfig... rics) {
+ return ImmutableConfigParserResult.builder() //
+ .ricConfigs(Arrays.asList(rics)) //
+ .dmaapConsumerTopicUrl("") //
+ .dmaapProducerTopicUrl("") //
+ .controllerConfigs(new HashMap<>()) //
+ .build();
+ }
+
+ private void modifyTheRicConfiguration(JsonObject configAsJson, String newBaseUrl) {
+ ((JsonObject) configAsJson.getAsJsonObject("config") //
+ .getAsJsonArray("ric").get(0)) //
+ .addProperty("baseUrl", newBaseUrl);
+ }
+
+ private JsonObject getJsonRootObject(boolean valid) throws JsonIOException, JsonSyntaxException, IOException {
+ JsonObject rootObject = JsonParser
+ .parseReader(new InputStreamReader(valid ? getCorrectJson() : getIncorrectJson())).getAsJsonObject();
+ return rootObject;
+ }
+
+ private static InputStream getCorrectJson() throws IOException {
+ URL url = ApplicationConfigParser.class.getClassLoader().getResource("test_application_configuration.json");
+ String string = Resources.toString(url, Charsets.UTF_8);
+ return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
+ }
+
+ private static InputStream getIncorrectJson() {
+ String string = "{}"; //
+ return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervisionTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervisionTest.java
new file mode 100644
index 00000000..6df6e6d6
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSupervisionTest.java
@@ -0,0 +1,328 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Lock.LockType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import reactor.core.publisher.Mono;
+
+@ExtendWith(MockitoExtension.class)
+class RicSupervisionTest {
+ private static final String POLICY_TYPE_1_NAME = "type1";
+ private static final PolicyType POLICY_TYPE_1 = ImmutablePolicyType.builder() //
+ .name(POLICY_TYPE_1_NAME) //
+ .schema("") //
+ .build();
+
+ private static final Ric RIC_1 = new Ric(ImmutableRicConfig.builder() //
+ .name("RIC_1") //
+ .baseUrl("baseUrl1") //
+ .managedElementIds(new Vector<String>(Arrays.asList("kista_1", "kista_2"))) //
+ .controllerName("controllerName") //
+ .build());
+
+ private static final String POLICY_1_ID = "policyId1";
+ private static final Policy POLICY_1 = ImmutablePolicy.builder() //
+ .id(POLICY_1_ID) //
+ .json("") //
+ .ownerServiceName("service") //
+ .ric(RIC_1) //
+ .type(POLICY_TYPE_1) //
+ .lastModified("now") //
+ .isTransient(false) //
+ .build();
+
+ private static final Policy POLICY_2 = ImmutablePolicy.builder() //
+ .id("policyId2") //
+ .json("") //
+ .ownerServiceName("service") //
+ .ric(RIC_1) //
+ .type(POLICY_TYPE_1) //
+ .lastModified("now") //
+ .isTransient(false) //
+ .build();
+
+ @Mock
+ private A1Client a1ClientMock;
+
+ @Mock
+ private A1ClientFactory a1ClientFactory;
+
+ @Mock
+ private RicSynchronizationTask synchronizationTaskMock;
+
+ private final PolicyTypes types = new PolicyTypes();
+ private Policies policies = new Policies();
+ private Rics rics = new Rics();
+
+ @BeforeEach
+ void init() {
+ types.clear();
+ policies.clear();
+ rics.clear();
+ RIC_1.setState(RicState.UNAVAILABLE);
+ RIC_1.clearSupportedPolicyTypes();
+ }
+
+ @AfterEach
+ void verifyNoRicLocks() {
+ for (Ric ric : this.rics.getRics()) {
+ ric.getLock().lockBlocking(LockType.EXCLUSIVE);
+ ric.getLock().unlockBlocking();
+ assertThat(ric.getLock().getLockCounter()).isZero();
+ }
+ }
+
+ @Test
+ void whenRicIdleAndNoChangedPoliciesOrPolicyTypes_thenNoSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+ rics.put(RIC_1);
+
+ types.put(POLICY_TYPE_1);
+
+ policies.put(POLICY_1);
+
+ setUpGetPolicyIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_1_ID)));
+ setUpGetPolicyTypeIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_TYPE_1_NAME)));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicUndefined_thenSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.UNAVAILABLE);
+ rics.put(RIC_1);
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verify(supervisorUnderTest).createSynchronizationTask();
+ verify(synchronizationTaskMock).run(RIC_1);
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicSynchronizing_thenNoSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.SYNCHRONIZING);
+ rics.put(RIC_1);
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicIdleAndErrorGettingPolicyIdentities_thenNoSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+ rics.put(RIC_1);
+
+ setUpGetPolicyIdentitiesToReturn(new Exception("Failed"));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verifyNoMoreInteractions(supervisorUnderTest);
+ assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
+ }
+
+ @Test
+ void whenRicIdleAndNotSameAmountOfPolicies_thenSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ rics.put(RIC_1);
+
+ policies.put(POLICY_1);
+ policies.put(POLICY_2);
+
+ setUpGetPolicyIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_1_ID)));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verify(supervisorUnderTest).createSynchronizationTask();
+ verify(synchronizationTaskMock).run(RIC_1);
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicIdleAndSameAmountOfPoliciesButNotSamePolicies_thenSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ rics.put(RIC_1);
+
+ policies.put(POLICY_1);
+ policies.put(POLICY_2);
+
+ setUpGetPolicyIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_1_ID, "Another_policy")));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verify(supervisorUnderTest).createSynchronizationTask();
+ verify(synchronizationTaskMock).run(RIC_1);
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicIdleAndErrorGettingPolicyTypes_thenNoSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+ rics.put(RIC_1);
+
+ setUpGetPolicyIdentitiesToReturn(Collections.emptyList());
+ setUpGetPolicyTypeIdentitiesToReturn(new Exception("Failed"));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicIdleAndNotSameAmountOfPolicyTypes_thenSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ RIC_1.setState(RicState.AVAILABLE);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+ rics.put(RIC_1);
+
+ types.put(POLICY_TYPE_1);
+
+ setUpGetPolicyIdentitiesToReturn(Collections.emptyList());
+ setUpGetPolicyTypeIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_TYPE_1_NAME, "another_policy_type")));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verify(supervisorUnderTest).createSynchronizationTask();
+ verify(synchronizationTaskMock).run(RIC_1);
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @Test
+ void whenRicIdleAndSameAmountOfPolicyTypesButNotSameTypes_thenSynchronization() {
+ doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any(Ric.class));
+ PolicyType policyType2 = ImmutablePolicyType.builder() //
+ .name("policyType2") //
+ .schema("") //
+ .build();
+
+ RIC_1.setState(RicState.AVAILABLE);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+ RIC_1.addSupportedPolicyType(policyType2);
+ rics.put(RIC_1);
+
+ setUpGetPolicyIdentitiesToReturn(Collections.emptyList());
+ setUpGetPolicyTypeIdentitiesToReturn(new ArrayList<>(Arrays.asList(POLICY_TYPE_1_NAME, "another_policy_type")));
+
+ RicSupervision supervisorUnderTest = spy(new RicSupervision(rics, policies, a1ClientFactory, types, null));
+
+ doReturn(synchronizationTaskMock).when(supervisorUnderTest).createSynchronizationTask();
+
+ supervisorUnderTest.checkAllRics();
+
+ verify(supervisorUnderTest).checkAllRics();
+ verify(supervisorUnderTest).createSynchronizationTask();
+ verify(synchronizationTaskMock).run(RIC_1);
+ verifyNoMoreInteractions(supervisorUnderTest);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void setUpGetPolicyIdentitiesToReturn(Object returnValue) {
+ if (returnValue instanceof List<?>) {
+ when(a1ClientMock.getPolicyIdentities()).thenReturn(Mono.just((List<String>) returnValue));
+ } else if (returnValue instanceof Exception) {
+ when(a1ClientMock.getPolicyIdentities()).thenReturn(Mono.error((Exception) returnValue));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void setUpGetPolicyTypeIdentitiesToReturn(Object returnValue) {
+ if (returnValue instanceof List<?>) {
+ when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(Mono.just((List<String>) returnValue));
+ } else if (returnValue instanceof Exception) {
+ when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(Mono.error((Exception) returnValue));
+ }
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java
new file mode 100644
index 00000000..0a84995b
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/RicSynchronizationTaskTest.java
@@ -0,0 +1,339 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
+
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric.RicState;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+@ExtendWith(MockitoExtension.class)
+class RicSynchronizationTaskTest {
+ private static final String POLICY_TYPE_1_NAME = "type1";
+ private static final PolicyType POLICY_TYPE_1 = ImmutablePolicyType.builder() //
+ .name(POLICY_TYPE_1_NAME) //
+ .schema("") //
+ .build();
+
+ private static final String RIC_1_NAME = "ric1";
+ private static final Ric RIC_1 = new Ric(ImmutableRicConfig.builder() //
+ .name(RIC_1_NAME) //
+ .baseUrl("baseUrl1") //
+ .managedElementIds(Collections.emptyList()) //
+ .controllerName("controllerName") //
+ .build());
+
+ private static Policy createPolicy(String policyId, boolean isTransient) {
+ return ImmutablePolicy.builder() //
+ .id(policyId) //
+ .json("") //
+ .ownerServiceName("service") //
+ .ric(RIC_1) //
+ .type(POLICY_TYPE_1) //
+ .lastModified("now") //
+ .isTransient(isTransient) //
+ .build();
+ }
+
+ private static final Policy POLICY_1 = createPolicy("policyId1", false);
+
+ private static final String SERVICE_1_NAME = "service1";
+ private static final String SERVICE_1_CALLBACK_URL = "callbackUrl";
+ private static final Service SERVICE_1 = new Service(SERVICE_1_NAME, Duration.ofSeconds(1), SERVICE_1_CALLBACK_URL);
+
+ @Mock
+ private A1Client a1ClientMock;
+
+ @Mock
+ private A1ClientFactory a1ClientFactoryMock;
+
+ private PolicyTypes policyTypes;
+ private Policies policies;
+ private Services services;
+
+ @BeforeEach
+ void init() {
+ policyTypes = new PolicyTypes();
+ policies = new Policies();
+ services = new Services();
+ RIC_1.setState(RicState.UNAVAILABLE);
+ RIC_1.clearSupportedPolicyTypes();
+ }
+
+ @Test
+ void ricAlreadySynchronizing_thenNoSynchronization() {
+ RIC_1.setState(RicState.SYNCHRONIZING);
+ RIC_1.addSupportedPolicyType(POLICY_TYPE_1);
+
+ policyTypes.put(POLICY_TYPE_1);
+ policies.put(POLICY_1);
+
+ RicSynchronizationTask synchronizerUnderTest =
+ new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services);
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verifyNoInteractions(a1ClientMock);
+
+ assertThat(policyTypes.size()).isEqualTo(1);
+ assertThat(policies.size()).isEqualTo(1);
+ assertThat(RIC_1.getState()).isEqualTo(RicState.SYNCHRONIZING);
+ assertThat(RIC_1.getSupportedPolicyTypeNames()).hasSize(1);
+ }
+
+ @Test
+ void ricIdlePolicyTypeInRepo_thenSynchronizationWithReuseOfTypeFromRepoAndCorrectServiceNotified() {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ policyTypes.put(POLICY_TYPE_1);
+
+ services.put(SERVICE_1);
+ Service serviceWithoutCallbackUrlShouldNotBeNotified = new Service("service2", Duration.ofSeconds(1), "");
+ services.put(serviceWithoutCallbackUrlShouldNotBeNotified);
+
+ setUpCreationOfA1Client();
+ simulateRicWithOnePolicyType();
+
+ RicSynchronizationTask synchronizerUnderTest =
+ spy(new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services));
+
+ AsyncRestClient restClientMock = setUpCreationOfAsyncRestClient(synchronizerUnderTest);
+ when(restClientMock.put(anyString(), anyString())).thenReturn(Mono.just("Ok"));
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verify(a1ClientMock, times(1)).getPolicyTypeIdentities();
+ verifyNoMoreInteractions(a1ClientMock);
+
+ verify(synchronizerUnderTest).run(RIC_1);
+ verify(synchronizerUnderTest).createNotificationClient(SERVICE_1_CALLBACK_URL);
+ verifyNoMoreInteractions(synchronizerUnderTest);
+
+ verify(restClientMock).put("", "Synchronization completed for:" + RIC_1_NAME);
+ verifyNoMoreInteractions(restClientMock);
+
+ assertThat(policyTypes.size()).isEqualTo(1);
+ assertThat(policies.size()).isZero();
+ assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE);
+ }
+
+ @Test
+ void ricIdlePolicyTypeNotInRepo_thenSynchronizationWithTypeFromRic() throws Exception {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ setUpCreationOfA1Client();
+ simulateRicWithOnePolicyType();
+ String typeSchema = "schema";
+ when(a1ClientMock.getPolicyTypeSchema(POLICY_TYPE_1_NAME)).thenReturn(Mono.just(typeSchema));
+
+ RicSynchronizationTask synchronizerUnderTest =
+ new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services);
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verify(a1ClientMock).getPolicyTypeIdentities();
+ verifyNoMoreInteractions(a1ClientMock);
+
+ assertThat(policyTypes.size()).isEqualTo(1);
+ assertThat(policyTypes.getType(POLICY_TYPE_1_NAME).schema()).isEqualTo(typeSchema);
+ assertThat(policies.size()).isZero();
+ assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE);
+ }
+
+ @Test
+ void ricIdleAndHavePolicies_thenSynchronizationWithRecreationOfPolicies() {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ Policy transientPolicy = createPolicy("transientPolicyId", true);
+
+ policies.put(transientPolicy);
+ policies.put(POLICY_1);
+
+ setUpCreationOfA1Client();
+ simulateRicWithNoPolicyTypes();
+
+ when(a1ClientMock.deleteAllPolicies()).thenReturn(Flux.just("OK"));
+ when(a1ClientMock.putPolicy(any(Policy.class))).thenReturn(Mono.just("OK"));
+
+ RicSynchronizationTask synchronizerUnderTest =
+ new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services);
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verify(a1ClientMock).deleteAllPolicies();
+ verify(a1ClientMock).putPolicy(POLICY_1);
+ verifyNoMoreInteractions(a1ClientMock);
+
+ assertThat(policyTypes.size()).isZero();
+ assertThat(policies.size()).isEqualTo(1); // The transient policy shall be deleted
+ assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE);
+ }
+
+ @Test
+ void ricIdleAndErrorDeletingPoliciesFirstTime_thenSynchronizationWithDeletionOfPolicies() {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ policies.put(POLICY_1);
+
+ setUpCreationOfA1Client();
+ simulateRicWithNoPolicyTypes();
+
+ when(a1ClientMock.deleteAllPolicies()) //
+ .thenReturn(Flux.error(new Exception("Exception"))) //
+ .thenReturn(Flux.just("OK"));
+
+ RicSynchronizationTask synchronizerUnderTest =
+ new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services);
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verify(a1ClientMock, times(2)).deleteAllPolicies();
+ verifyNoMoreInteractions(a1ClientMock);
+
+ assertThat(policyTypes.size()).isZero();
+ assertThat(policies.size()).isZero();
+ assertThat(RIC_1.getState()).isEqualTo(RicState.AVAILABLE);
+ }
+
+ @Test
+ void ricIdleAndErrorDeletingPoliciesAllTheTime_thenSynchronizationWithFailedRecovery() {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ policies.put(POLICY_1);
+
+ setUpCreationOfA1Client();
+ simulateRicWithNoPolicyTypes();
+
+ String originalErrorMessage = "Exception";
+ when(a1ClientMock.deleteAllPolicies()).thenReturn(Flux.error(new Exception(originalErrorMessage)));
+
+ RicSynchronizationTask synchronizerUnderTest =
+ new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services);
+
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(RicSynchronizationTask.class, WARN);
+
+ synchronizerUnderTest.run(RIC_1);
+
+ verifyCorrectLogMessage(0, logAppender,
+ "Synchronization failure for ric: " + RIC_1_NAME + ", reason: " + originalErrorMessage);
+
+ verify(a1ClientMock, times(2)).deleteAllPolicies();
+ verifyNoMoreInteractions(a1ClientMock);
+
+ assertThat(policyTypes.size()).isZero();
+ assertThat(policies.size()).isZero();
+ assertThat(RIC_1.getState()).isEqualTo(RicState.UNAVAILABLE);
+ }
+
+ @Test
+ void ricIdlePolicyTypeInRepo_thenSynchronizationWithErrorOnServiceNotificationErrorLogged() {
+ RIC_1.setState(RicState.AVAILABLE);
+
+ policyTypes.put(POLICY_TYPE_1);
+
+ services.put(SERVICE_1);
+
+ setUpCreationOfA1Client();
+ simulateRicWithOnePolicyType();
+
+ final ListAppender<ILoggingEvent> logAppender =
+ LoggingUtils.getLogListAppender(RicSynchronizationTask.class, WARN);
+
+ RicSynchronizationTask synchronizerUnderTest =
+ spy(new RicSynchronizationTask(a1ClientFactoryMock, policyTypes, policies, services));
+
+ AsyncRestClient restClientMock = setUpCreationOfAsyncRestClient(synchronizerUnderTest);
+ String originalErrorMessage = "Exception";
+ when(restClientMock.put(anyString(), anyString())).thenReturn(Mono.error(new Exception(originalErrorMessage)));
+
+ synchronizerUnderTest.run(RIC_1);
+
+ ILoggingEvent loggingEvent = logAppender.list.get(0);
+ assertThat(loggingEvent.getLevel()).isEqualTo(WARN);
+ verifyCorrectLogMessage(0, logAppender,
+ "Service notification failed for service: " + SERVICE_1_NAME + ". Cause: " + originalErrorMessage);
+ }
+
+ private void setUpCreationOfA1Client() {
+ when(a1ClientFactoryMock.createA1Client(any(Ric.class))).thenReturn(Mono.just(a1ClientMock));
+ doReturn(Flux.empty()).when(a1ClientMock).deleteAllPolicies();
+ }
+
+ private AsyncRestClient setUpCreationOfAsyncRestClient(RicSynchronizationTask synchronizerUnderTest) {
+ AsyncRestClient restClientMock = mock(AsyncRestClient.class);
+ doReturn(restClientMock).when(synchronizerUnderTest).createNotificationClient(anyString());
+ return restClientMock;
+ }
+
+ private void simulateRicWithOnePolicyType() {
+ when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(Mono.just(Arrays.asList(POLICY_TYPE_1_NAME)));
+ }
+
+ private void simulateRicWithNoPolicyTypes() {
+ when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(Mono.just(Collections.emptyList()));
+ }
+
+ private void verifyCorrectLogMessage(int messageIndex, ListAppender<ILoggingEvent> logAppender,
+ String expectedMessage) {
+ ILoggingEvent loggingEvent = logAppender.list.get(messageIndex);
+ assertThat(loggingEvent.getFormattedMessage()).isEqualTo(expectedMessage);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervisionTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervisionTest.java
new file mode 100644
index 00000000..5fb26977
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/tasks/ServiceSupervisionTest.java
@@ -0,0 +1,186 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.tasks;
+
+import static ch.qos.logback.classic.Level.WARN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import java.time.Duration;
+import java.util.Collections;
+
+import org.awaitility.Durations;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.ImmutablePolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Service;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.LoggingUtils;
+import reactor.core.publisher.Mono;
+
+@ExtendWith(MockitoExtension.class)
+class ServiceSupervisionTest {
+
+ private static final String SERVICE_NAME = "Service name";
+ private static final String RIC_NAME = "name";
+ private static final String POLICY_ID = "policy";
+
+ @Mock
+ A1ClientFactory a1ClientFactoryMock;
+ @Mock
+ A1Client a1ClientMock;
+
+ private Services services;
+ private Service service;
+ private Policies policies;
+ private RicConfig ricConfig = ImmutableRicConfig.builder() //
+ .name(RIC_NAME) //
+ .baseUrl("baseUrl") //
+ .managedElementIds(Collections.emptyList()) //
+ .controllerName("") //
+ .build();
+ private Ric ric = new Ric(ricConfig);
+ private PolicyType policyType = ImmutablePolicyType.builder() //
+ .name("plicyTypeName") //
+ .schema("schema") //
+ .build();
+ private Policy policy = ImmutablePolicy.builder() //
+ .id(POLICY_ID) //
+ .json("json") //
+ .ownerServiceName(SERVICE_NAME) //
+ .ric(ric) //
+ .type(policyType) //
+ .lastModified("lastModified") //
+ .isTransient(false) //
+ .build();
+
+ @Test
+ void serviceExpired_policyAndServiceAreDeletedInRepoAndPolicyIsDeletedInRic() {
+ setUpRepositoryWithKeepAliveInterval(Duration.ofSeconds(2));
+
+ setUpCreationOfA1Client();
+ when(a1ClientMock.deletePolicy(any(Policy.class))).thenReturn(Mono.just("Policy deleted"));
+
+ ServiceSupervision serviceSupervisionUnderTest =
+ new ServiceSupervision(services, policies, a1ClientFactoryMock);
+
+ await().atMost(Durations.FIVE_SECONDS).with().pollInterval(Durations.ONE_SECOND).until(service::isExpired);
+
+ serviceSupervisionUnderTest.checkAllServices().blockLast();
+
+ assertThat(policies.size()).isZero();
+ assertThat(services.size()).isZero();
+
+ verify(a1ClientMock).deletePolicy(policy);
+ verifyNoMoreInteractions(a1ClientMock);
+ }
+
+ @Test
+ void serviceExpiredButDeleteInRicFails_policyAndServiceAreDeletedInRepoAndErrorLoggedForRic() {
+ setUpRepositoryWithKeepAliveInterval(Duration.ofSeconds(2));
+
+ setUpCreationOfA1Client();
+ String originalErrorMessage = "Failed";
+ when(a1ClientMock.deletePolicy(any(Policy.class))).thenReturn(Mono.error(new Exception(originalErrorMessage)));
+
+ ServiceSupervision serviceSupervisionUnderTest =
+ new ServiceSupervision(services, policies, a1ClientFactoryMock);
+
+ await().atMost(Durations.FIVE_SECONDS).with().pollInterval(Durations.ONE_SECOND).until(service::isExpired);
+
+ final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(ServiceSupervision.class, WARN);
+
+ serviceSupervisionUnderTest.checkAllServices().blockLast();
+
+ assertThat(policies.size()).isZero();
+ assertThat(services.size()).isZero();
+
+ ILoggingEvent loggingEvent = logAppender.list.get(0);
+ assertThat(loggingEvent.getLevel()).isEqualTo(WARN);
+ String expectedLogMessage =
+ "Could not delete policy: " + POLICY_ID + " from ric: " + RIC_NAME + ". Cause: " + originalErrorMessage;
+ assertThat(loggingEvent.getFormattedMessage()).isEqualTo(expectedLogMessage);
+ }
+
+ @Test
+ void serviceNotExpired_shouldNotBeChecked() {
+ setUpRepositoryWithKeepAliveInterval(Duration.ofSeconds(2));
+
+ ServiceSupervision serviceSupervisionUnderTest =
+ new ServiceSupervision(services, policies, a1ClientFactoryMock);
+
+ serviceSupervisionUnderTest.checkAllServices().blockLast();
+
+ assertThat(policies.size()).isEqualTo(1);
+ assertThat(services.size()).isEqualTo(1);
+
+ verifyNoInteractions(a1ClientFactoryMock);
+ verifyNoInteractions(a1ClientMock);
+ }
+
+ @Test
+ void serviceWithoutKeepAliveInterval_shouldNotBeChecked() {
+ setUpRepositoryWithKeepAliveInterval(Duration.ofSeconds(0));
+
+ ServiceSupervision serviceSupervisionUnderTest =
+ new ServiceSupervision(services, policies, a1ClientFactoryMock);
+
+ serviceSupervisionUnderTest.checkAllServices().blockLast();
+
+ assertThat(policies.size()).isEqualTo(1);
+ assertThat(services.size()).isEqualTo(1);
+
+ verifyNoInteractions(a1ClientFactoryMock);
+ verifyNoInteractions(a1ClientMock);
+ }
+
+ private void setUpCreationOfA1Client() {
+ when(a1ClientFactoryMock.createA1Client(any(Ric.class))).thenReturn(Mono.just(a1ClientMock));
+ }
+
+ private void setUpRepositoryWithKeepAliveInterval(Duration keepAliveInterval) {
+ services = new Services();
+ service = new Service(SERVICE_NAME, keepAliveInterval, "callbackUrl");
+ services.put(service);
+
+ policies = new Policies();
+ policies.put(policy);
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/LoggingUtils.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/LoggingUtils.java
new file mode 100644
index 00000000..2f7d7a65
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/LoggingUtils.java
@@ -0,0 +1,60 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.utils;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+
+import org.slf4j.LoggerFactory;
+
+public class LoggingUtils {
+
+ /**
+ * Returns a ListAppender that contains all logging events. Call this method right before calling the tested
+ * method.
+ *
+ * @return the log list appender for the given class.
+ */
+ public static ListAppender<ILoggingEvent> getLogListAppender(Class<?> logClass) {
+ return getLogListAppender(logClass, Level.ALL);
+ }
+
+ /**
+ * Returns a ListAppender that contains events for the given level. Call this method right before calling the tested
+ * method.
+ *
+ * @param logClass class whose appender is wanted.
+ * @param level the log level to log at.
+ *
+ * @return the log list appender for the given class logging on the given level.
+ */
+ public static ListAppender<ILoggingEvent> getLogListAppender(Class<?> logClass, Level level) {
+ Logger logger = (Logger) LoggerFactory.getLogger(logClass);
+ logger.setLevel(level);
+ ListAppender<ILoggingEvent> listAppender = new ListAppender<>();
+ listAppender.start();
+ logger.addAppender(listAppender);
+
+ return listAppender;
+ }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1Client.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1Client.java
new file mode 100644
index 00000000..4a781be8
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1Client.java
@@ -0,0 +1,144 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.List;
+import java.util.Vector;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.MonoSink;
+
+public class MockA1Client implements A1Client {
+ Policies policies = new Policies();
+ private final PolicyTypes policyTypes;
+ private final Duration asynchDelay;
+
+ public MockA1Client(PolicyTypes policyTypes, Duration asynchDelay) {
+ this.policyTypes = policyTypes;
+ this.asynchDelay = asynchDelay;
+ }
+
+ @Override
+ public Mono<List<String>> getPolicyTypeIdentities() {
+ List<String> result = new Vector<>();
+ for (PolicyType p : this.policyTypes.getAll()) {
+ result.add(p.name());
+ }
+ return mono(result);
+ }
+
+ @Override
+ public Mono<List<String>> getPolicyIdentities() {
+ Vector<String> result = new Vector<>();
+ for (Policy policy : policies.getAll()) {
+ result.add(policy.id());
+ }
+
+ return mono(result);
+ }
+
+ @Override
+ public Mono<String> getPolicyTypeSchema(String policyTypeId) {
+ try {
+ return mono(this.policyTypes.getType(policyTypeId).schema());
+ } catch (Exception e) {
+ return Mono.error(e);
+ }
+ }
+
+ @Override
+ public Mono<String> putPolicy(Policy p) {
+ this.policies.put(p);
+ return mono("OK");
+
+ }
+
+ @Override
+ public Mono<String> deletePolicy(Policy policy) {
+ this.policies.remove(policy);
+ return mono("OK");
+ }
+
+ public Policies getPolicies() {
+ return this.policies;
+ }
+
+ @Override
+ public Mono<A1ProtocolType> getProtocolVersion() {
+ return mono(A1ProtocolType.STD_V1_1);
+ }
+
+ @Override
+ public Flux<String> deleteAllPolicies() {
+ this.policies.clear();
+ return mono("OK") //
+ .flatMapMany(Flux::just);
+ }
+
+ @Override
+ public Mono<String> getPolicyStatus(Policy policy) {
+ return mono("OK");
+ }
+
+ private <T> Mono<T> mono(T value) {
+ if (this.asynchDelay.isZero()) {
+ return Mono.just(value);
+ } else {
+ return Mono.create(monoSink -> asynchResponse(monoSink, value));
+ }
+ }
+
+ Mono<String> monoError(String responseBody, HttpStatus status) {
+ byte[] responseBodyBytes = responseBody.getBytes(StandardCharsets.UTF_8);
+ WebClientResponseException a1Exception = new WebClientResponseException(status.value(),
+ status.getReasonPhrase(), null, responseBodyBytes, StandardCharsets.UTF_8, null);
+ return Mono.error(a1Exception);
+ }
+
+ @SuppressWarnings("squid:S2925") // "Thread.sleep" should not be used in tests.
+ private void sleep() {
+ try {
+ Thread.sleep(this.asynchDelay.toMillis());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private <T> void asynchResponse(MonoSink<T> callback, T str) {
+ Thread thread = new Thread(() -> {
+ sleep(); // Simulate a network delay
+ callback.success(str);
+ });
+ thread.start();
+ }
+
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1ClientFactory.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1ClientFactory.java
new file mode 100644
index 00000000..61407a40
--- /dev/null
+++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/MockA1ClientFactory.java
@@ -0,0 +1,88 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.utils;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import java.lang.invoke.MethodHandles;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1Client;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Mono;
+
+public class MockA1ClientFactory extends A1ClientFactory {
+ private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private final Map<String, MockA1Client> clients = new HashMap<>();
+ private PolicyTypes policyTypes;
+ private Duration asynchDelay = Duration.ofSeconds(0);
+
+ public MockA1ClientFactory(PolicyTypes policyTypes) {
+ super(mock(ApplicationConfig.class));
+ this.policyTypes = policyTypes;
+ }
+
+ @Override
+ public Mono<A1Client> createA1Client(Ric ric) {
+ return Mono.just(getOrCreateA1Client(ric.name()));
+ }
+
+ public MockA1Client getOrCreateA1Client(String ricName) {
+ if (!clients.containsKey(ricName)) {
+ logger.debug("Creating client for RIC: {}", ricName);
+ MockA1Client client = spy(new MockA1Client(policyTypes, asynchDelay));
+ clients.put(ricName, client);
+ }
+ return clients.get(ricName);
+ }
+
+ public void setPolicyTypes(PolicyTypes policyTypes) {
+ this.policyTypes = policyTypes;
+ }
+
+ /**
+ * Simulate network latency. The REST responses will be generated by separate
+ * threads
+ *
+ * @param delay the delay between the request and the response
+ */
+ public void setResponseDelay(Duration delay) {
+ this.asynchDelay = delay;
+ }
+
+ public void reset() {
+ this.asynchDelay = Duration.ofSeconds(0);
+ clients.clear();
+ }
+
+ public PolicyTypes getPolicyTypes() {
+ return this.policyTypes;
+ }
+
+}