From 95db19e2820102db0255ca57407faa333cbb4085 Mon Sep 17 00:00:00 2001 From: PatrikBuhr Date: Mon, 20 Jan 2020 13:27:40 +0100 Subject: [PATCH] Infrastructure for having mutiple RIC APIs RIC (A1) protocol is selected by confuration parameter. Change-Id: I5486955cea9f38b3bb9e6ce3e88d94206bb85a1c Issue-ID: NONRTRIC-84 Signed-off-by: PatrikBuhr --- .../java/org/oransc/policyagent/BeanFactory.java | 7 +-- .../org/oransc/policyagent/clients/A1Client.java | 14 +++-- .../policyagent/clients/A1ClientFactory.java | 67 ++++++++++++++++++++ .../oransc/policyagent/clients/OscA1Client.java | 72 ++++++++++++++++++++++ .../{A1ClientImpl.java => StdA1Client.java} | 58 ++++++++++------- .../configuration/ApplicationConfig.java | 14 ----- .../policyagent/configuration/RicConfig.java | 1 + .../policyagent/controllers/PolicyController.java | 15 +++-- .../controllers/RicRepositoryController.java | 10 +-- .../org/oransc/policyagent/repository/Ric.java | 12 ++++ .../org/oransc/policyagent/repository/Rics.java | 10 +++ .../policyagent/tasks/RepositorySupervision.java | 66 ++++++++++++-------- .../oransc/policyagent/tasks/RicRecoveryTask.java | 48 +++++++++------ .../policyagent/tasks/ServiceSupervision.java | 15 ++--- .../oransc/policyagent/tasks/StartupService.java | 10 +-- .../org/oransc/policyagent/ApplicationTest.java | 26 +++++--- .../org/oransc/policyagent/MockPolicyAgent.java | 12 ++-- ...{A1ClientImplTest.java => StdA1ClientTest.java} | 24 ++++---- .../tasks/RepositorySupervisionTest.java | 29 ++++++--- .../policyagent/tasks/StartupServiceTest.java | 54 ++++++++-------- .../org/oransc/policyagent/utils/MockA1Client.java | 34 +++++----- .../policyagent/utils/MockA1ClientFactory.java | 57 +++++++++++++++++ .../resources/test_application_configuration.json | 2 +- 23 files changed, 461 insertions(+), 196 deletions(-) create mode 100644 policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientFactory.java create mode 100644 policy-agent/src/main/java/org/oransc/policyagent/clients/OscA1Client.java rename policy-agent/src/main/java/org/oransc/policyagent/clients/{A1ClientImpl.java => StdA1Client.java} (67%) rename policy-agent/src/test/java/org/oransc/policyagent/clients/{A1ClientImplTest.java => StdA1ClientTest.java} (91%) create mode 100644 policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1ClientFactory.java diff --git a/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java b/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java index 06b66ca6..f0826e9a 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java @@ -20,8 +20,7 @@ package org.oransc.policyagent; -import org.oransc.policyagent.clients.A1Client; -import org.oransc.policyagent.clients.A1ClientImpl; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.repository.Policies; import org.oransc.policyagent.repository.PolicyTypes; @@ -58,8 +57,8 @@ class BeanFactory { } @Bean - A1Client getA1Client() { - return new A1ClientImpl(); + A1ClientFactory getA1ClientFactory() { + return new A1ClientFactory(); } } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/clients/A1Client.java b/policy-agent/src/main/java/org/oransc/policyagent/clients/A1Client.java index 8d244ee3..31b51429 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/clients/A1Client.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/clients/A1Client.java @@ -27,14 +27,20 @@ import reactor.core.publisher.Mono; public interface A1Client { - public Mono> getPolicyTypeIdentities(String nearRtRicUrl); + public static enum A1ProtocolType { + UNKNOWN, STD_V1 + } - public Mono> getPolicyIdentities(String nearRtRicUrl); + public Mono getProtocolVersion(); - public Mono getPolicyType(String nearRtRicUrl, String policyTypeId); + public Mono> getPolicyTypeIdentities(); + + public Mono> getPolicyIdentities(); + + public Mono getPolicyTypeSchema(String policyTypeId); public Mono putPolicy(Policy policy); - public Mono deletePolicy(String nearRtRicUrl, String policyId); + public Mono deletePolicy(String policyId); } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientFactory.java b/policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientFactory.java new file mode 100644 index 00000000..a3d17bc2 --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientFactory.java @@ -0,0 +1,67 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.oransc.policyagent.clients; + +import org.oransc.policyagent.clients.A1Client.A1ProtocolType; +import org.oransc.policyagent.exceptions.ServiceException; +import org.oransc.policyagent.repository.Ric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +public class A1ClientFactory { + + private static final Logger logger = LoggerFactory.getLogger(A1ClientFactory.class); + + public Mono createA1Client(Ric ric) { + return getProtocolVersion(ric) // + .flatMap(version -> createA1Client(ric, version)); + } + + private Mono createA1Client(Ric ric, A1ProtocolType version) { + if (version == A1ProtocolType.STD_V1) { + return Mono.just(createStdA1ClientImpl(ric)); + } + return Mono.error(new ServiceException("Not supported protocoltype: " + version)); + } + + private Mono getProtocolVersion(Ric ric) { + if (ric.getProtocolVersion() == A1ProtocolType.UNKNOWN) { + return fetchVersion(ric, new OscA1Client(ric.getConfig())) // + .onErrorResume(err -> fetchVersion(ric, createStdA1ClientImpl(ric))) + .doOnNext(version -> ric.setProtocolVersion(version)) + .doOnNext(version -> logger.debug("Recover ric: {}, protocol version:{}", ric.name(), version)) // + .doOnError(t -> logger.warn("Could not get protocol version from RIC: {}", ric.name())); // + } else { + return Mono.just(ric.getProtocolVersion()); + } + } + + protected A1Client createStdA1ClientImpl(Ric ric) { + return new StdA1Client(ric.getConfig()); + } + + private Mono fetchVersion(Ric ric, A1Client a1Client) { + return Mono.just(a1Client) // + .flatMap(client -> a1Client.getProtocolVersion()); + } + +} diff --git a/policy-agent/src/main/java/org/oransc/policyagent/clients/OscA1Client.java b/policy-agent/src/main/java/org/oransc/policyagent/clients/OscA1Client.java new file mode 100644 index 00000000..273f27b8 --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/clients/OscA1Client.java @@ -0,0 +1,72 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.oransc.policyagent.clients; + +import java.lang.invoke.MethodHandles; +import java.util.Collection; + +import org.oransc.policyagent.configuration.RicConfig; +import org.oransc.policyagent.repository.Policy; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +public class OscA1Client implements A1Client { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + private final RicConfig ricConfig; + + public OscA1Client(RicConfig ricConfig) { + this.ricConfig = ricConfig; + logger.debug("OscA1Client for ric: {}", this.ricConfig.name()); + } + + @Override + public Mono> getPolicyTypeIdentities() { + return Mono.error(new Exception("Not impl")); + } + + @Override + public Mono> getPolicyIdentities() { + return Mono.error(new Exception("Not impl")); + } + + @Override + public Mono getPolicyTypeSchema(String policyTypeId) { + return Mono.error(new Exception("Not impl")); + } + + @Override + public Mono putPolicy(Policy policy) { + return Mono.error(new Exception("Not impl")); + } + + @Override + public Mono deletePolicy(String policyId) { + return Mono.error(new Exception("Not impl")); + } + + @Override + public Mono getProtocolVersion() { + return Mono.error(new Exception("Not impl")); + } + +} diff --git a/policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientImpl.java b/policy-agent/src/main/java/org/oransc/policyagent/clients/StdA1Client.java similarity index 67% rename from policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientImpl.java rename to policy-agent/src/main/java/org/oransc/policyagent/clients/StdA1Client.java index e5766385..4eb0c06b 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/clients/A1ClientImpl.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/clients/StdA1Client.java @@ -28,43 +28,46 @@ import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.oransc.policyagent.configuration.RicConfig; import org.oransc.policyagent.repository.Policy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import reactor.core.publisher.Mono; -public class A1ClientImpl implements A1Client { +public class StdA1Client implements A1Client { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private static String getBaseUrl(final String nearRtRicUrl) { - return nearRtRicUrl + "/A1-P/v1"; + private final RicConfig ricConfig; + private final AsyncRestClient restClient; + + public StdA1Client(RicConfig ricConfig) { + this.ricConfig = ricConfig; + this.restClient = new AsyncRestClient(getBaseUrl()); } - protected AsyncRestClient createClient(final String nearRtRicUrl) { - return new AsyncRestClient(getBaseUrl(nearRtRicUrl)); + public StdA1Client(RicConfig ricConfig, AsyncRestClient restClient) { + this.ricConfig = ricConfig; + this.restClient = restClient; } @Override - public Mono> getPolicyTypeIdentities(String nearRtRicUrl) { - logger.debug("getPolicyTypeIdentities nearRtRicUrl = {}", nearRtRicUrl); - AsyncRestClient client = createClient(nearRtRicUrl); - return client.get("/policytypes/identities") // + public Mono> getPolicyTypeIdentities() { + logger.debug("getPolicyTypeIdentities nearRtRicUrl = {}", ricConfig.baseUrl()); + return restClient.get("/policytypes/identities") // .flatMap(this::parseJsonArrayOfString); } @Override - public Mono> getPolicyIdentities(String nearRtRicUrl) { - logger.debug("getPolicyIdentities nearRtRicUrl = {}", nearRtRicUrl); - AsyncRestClient client = createClient(nearRtRicUrl); - return client.get("/policies/identities") // + public Mono> getPolicyIdentities() { + logger.debug("getPolicyIdentities nearRtRicUrl = {}", ricConfig.baseUrl()); + return restClient.get("/policies/identities") // .flatMap(this::parseJsonArrayOfString); } @Override - public Mono getPolicyType(String nearRtRicUrl, String policyTypeId) { - logger.debug("getPolicyType nearRtRicUrl = {}, policyTypeId = {}", nearRtRicUrl, policyTypeId); - AsyncRestClient client = createClient(nearRtRicUrl); - Mono response = client.get("/policytypes/" + policyTypeId); + public Mono getPolicyTypeSchema(String policyTypeId) { + logger.debug("getPolicyType nearRtRicUrl = {}, policyTypeId = {}", ricConfig.baseUrl(), policyTypeId); + Mono response = restClient.get("/policytypes/" + policyTypeId); return response.flatMap(this::createMono); } @@ -72,20 +75,28 @@ public class A1ClientImpl implements A1Client { public Mono putPolicy(Policy policy) { logger.debug("putPolicy nearRtRicUrl = {}, policyId = {}, policyString = {}", // policy.ric().getConfig().baseUrl(), policy.id(), policy.json()); - AsyncRestClient client = createClient(policy.ric().getConfig().baseUrl()); // TODO update when simulator is updated to include policy type // Mono response = client.put("/policies/" + policy.id() + "?policyTypeId=" + policy.type().name(), // policy.json()); - Mono response = client.put("/policies/" + policy.id(), policy.json()); + Mono response = restClient.put("/policies/" + policy.id(), policy.json()); return response.flatMap(this::createMono); } @Override - public Mono deletePolicy(String nearRtRicUrl, String policyId) { - logger.debug("deletePolicy nearRtRicUrl = {}, policyId = {}", nearRtRicUrl, policyId); - AsyncRestClient client = createClient(nearRtRicUrl); - return client.delete("/policies/" + policyId); + public Mono deletePolicy(String policyId) { + logger.debug("deletePolicy nearRtRicUrl = {}, policyId = {}", ricConfig.baseUrl(), policyId); + return restClient.delete("/policies/" + policyId); + } + + @Override + public Mono getProtocolVersion() { + return getPolicyTypeIdentities() // + .flatMap(x -> Mono.just(A1ProtocolType.STD_V1)); + } + + private String getBaseUrl() { + return ricConfig.baseUrl() + "/A1-P/v1"; } private Mono> parseJsonArrayOfString(String inputString) { @@ -112,4 +123,5 @@ public class A1ClientImpl implements A1Client { return Mono.error(ex); } } + } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java b/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java index fee01813..d4f72610 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java @@ -23,7 +23,6 @@ package org.oransc.policyagent.configuration; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Optional; import java.util.Vector; import javax.validation.constraints.NotEmpty; @@ -51,23 +50,10 @@ public class ApplicationConfig { return this.filepath; } - public synchronized void setFilepath(String filepath) { - this.filepath = filepath; - } - public synchronized Collection getRicConfigs() { return this.ricConfigs.values(); } - public synchronized Optional lookupRicConfigForManagedElement(String managedElementId) { - for (RicConfig ricConfig : getRicConfigs()) { - if (ricConfig.managedElementIds().contains(managedElementId)) { - return Optional.of(ricConfig); - } - } - return Optional.empty(); - } - public RicConfig getRic(String ricName) throws ServiceException { for (RicConfig ricConfig : getRicConfigs()) { if (ricConfig.name().equals(ricName)) { diff --git a/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java b/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java index aae9dee2..d446f94c 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java @@ -33,4 +33,5 @@ public interface RicConfig { public String baseUrl(); public Vector managedElementIds(); + } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java index affce2c1..1b2ebb4a 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java @@ -31,7 +31,7 @@ import io.swagger.annotations.ApiResponses; import java.util.Collection; import java.util.Vector; -import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.exceptions.ServiceException; import org.oransc.policyagent.repository.ImmutablePolicy; @@ -59,18 +59,19 @@ public class PolicyController { private final Rics rics; private final PolicyTypes policyTypes; private final Policies policies; - private final A1Client a1Client; + private final A1ClientFactory a1ClientFactory; private static Gson gson = new GsonBuilder() // .serializeNulls() // .create(); // @Autowired - PolicyController(ApplicationConfig config, PolicyTypes types, Policies policies, Rics rics, A1Client a1Client) { + PolicyController(ApplicationConfig config, PolicyTypes types, Policies policies, Rics rics, + A1ClientFactory a1ClientFactory) { this.policyTypes = types; this.policies = policies; this.rics = rics; - this.a1Client = a1Client; + this.a1ClientFactory = a1ClientFactory; } @GetMapping("/policy_schemas") @@ -146,7 +147,8 @@ public class PolicyController { Policy policy = policies.get(id); if (policy != null && policy.ric().state().equals(Ric.RicState.IDLE)) { policies.remove(policy); - return a1Client.deletePolicy(policy.ric().getConfig().baseUrl(), id) // + return a1ClientFactory.createA1Client(policy.ric()) // + .flatMap(client -> client.deletePolicy(id)) // .flatMap(notUsed -> { return Mono.just(new ResponseEntity<>(HttpStatus.NO_CONTENT)); }); @@ -176,7 +178,8 @@ public class PolicyController { .ownerServiceName(service) // .lastModified(getTimeStampUTC()) // .build(); - return a1Client.putPolicy(policy) // + return a1ClientFactory.createA1Client(ric) // + .flatMap(client -> client.putPolicy(policy)) // .doOnNext(notUsed -> policies.put(policy)) // .flatMap(notUsed -> { return Mono.just(new ResponseEntity<>(HttpStatus.CREATED)); diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java index 6b413b2f..0d49833f 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java @@ -32,7 +32,6 @@ import java.util.Optional; import java.util.Vector; import org.oransc.policyagent.configuration.ApplicationConfig; -import org.oransc.policyagent.configuration.RicConfig; import org.oransc.policyagent.repository.Ric; import org.oransc.policyagent.repository.Rics; import org.springframework.beans.factory.annotation.Autowired; @@ -46,8 +45,6 @@ import org.springframework.web.bind.annotation.RestController; @Api(value = "RIC Management API") public class RicRepositoryController { - private final ApplicationConfig appConfig; - @Autowired private Rics rics; @@ -57,7 +54,6 @@ public class RicRepositoryController { @Autowired RicRepositoryController(ApplicationConfig appConfig) { - this.appConfig = appConfig; } /** @@ -73,10 +69,10 @@ public class RicRepositoryController { public ResponseEntity getRic( @RequestParam(name = "managedElementId", required = false, defaultValue = "") String managedElementId) { - Optional config = appConfig.lookupRicConfigForManagedElement(managedElementId); + Optional ric = this.rics.lookupRicForManagedElement(managedElementId); - if (config.isPresent()) { - return new ResponseEntity<>(config.get().name(), HttpStatus.OK); + if (ric.isPresent()) { + return new ResponseEntity<>(ric.get().name(), HttpStatus.OK); } else { return new ResponseEntity<>("", HttpStatus.NOT_FOUND); } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java index 235ee1ab..4169150b 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Vector; +import org.oransc.policyagent.clients.A1Client.A1ProtocolType; import org.oransc.policyagent.configuration.RicConfig; /** @@ -34,6 +35,7 @@ public class Ric { private final RicConfig ricConfig; private RicState state = RicState.UNDEFINED; private Map supportedPolicyTypes = new HashMap<>(); + private A1ProtocolType protocolVersion = A1ProtocolType.UNKNOWN; /** * Creates the Ric. Initial state is {@link RicState.NOT_INITIATED}. @@ -162,4 +164,14 @@ public class Ric { */ RECOVERING } + + public A1ProtocolType getProtocolVersion() { + return protocolVersion; + } + + public void setProtocolVersion(A1ProtocolType version) { + protocolVersion = version; + + } + } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Rics.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Rics.java index bdf99302..6f3b3e84 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Rics.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Rics.java @@ -22,6 +22,7 @@ package org.oransc.policyagent.repository; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import org.oransc.policyagent.exceptions.ServiceException; @@ -62,4 +63,13 @@ public class Rics { public synchronized void clear() { this.rics.clear(); } + + public synchronized Optional lookupRicForManagedElement(String managedElementId) { + for (Ric ric : this.rics.values()) { + if (ric.getConfig().managedElementIds().contains(managedElementId)) { + return Optional.of(ric); + } + } + return Optional.empty(); + } } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/tasks/RepositorySupervision.java b/policy-agent/src/main/java/org/oransc/policyagent/tasks/RepositorySupervision.java index 1a903827..022ca0f6 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/tasks/RepositorySupervision.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/tasks/RepositorySupervision.java @@ -23,6 +23,7 @@ package org.oransc.policyagent.tasks; import java.util.Collection; import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.repository.Policies; import org.oransc.policyagent.repository.PolicyTypes; import org.oransc.policyagent.repository.Ric; @@ -50,15 +51,15 @@ public class RepositorySupervision { private final Rics rics; private final Policies policies; private final PolicyTypes policyTypes; - private final A1Client a1Client; + private final A1ClientFactory a1ClientFactory; private final Services services; @Autowired - public RepositorySupervision(Rics rics, Policies policies, A1Client a1Client, PolicyTypes policyTypes, + public RepositorySupervision(Rics rics, Policies policies, A1ClientFactory a1ClientFactory, PolicyTypes policyTypes, Services services) { this.rics = rics; this.policies = policies; - this.a1Client = a1Client; + this.a1ClientFactory = a1ClientFactory; this.policyTypes = policyTypes; this.services = services; } @@ -72,34 +73,51 @@ public class RepositorySupervision { createTask().subscribe(this::onRicChecked, this::onError, this::onComplete); } - private Flux createTask() { + private Flux createTask() { synchronized (this.rics) { return Flux.fromIterable(rics.getRics()) // - .flatMap(ric -> checkRicState(ric)) // - .flatMap(ric -> checkRicPolicies(ric)) // - .flatMap(ric -> checkRicPolicyTypes(ric)); + .flatMap(ric -> createRicData(ric)) // + .flatMap(ricData -> checkRicState(ricData)) // + .flatMap(ricData -> checkRicPolicies(ricData)) // + .flatMap(ricData -> checkRicPolicyTypes(ricData)); } } - private Mono checkRicState(Ric ric) { - if (ric.state() == RicState.UNDEFINED) { + private static class RicData { + RicData(Ric ric, A1Client a1Client) { + this.ric = ric; + this.a1Client = a1Client; + } + + final Ric ric; + final A1Client a1Client; + } + + private Mono createRicData(Ric ric) { + return Mono.just(ric) // + .flatMap(aRic -> this.a1ClientFactory.createA1Client(ric)) // + .flatMap(a1Client -> Mono.just(new RicData(ric, a1Client))); + } + + private Mono checkRicState(RicData ric) { + if (ric.ric.state() == RicState.UNDEFINED) { return startRecovery(ric); - } else if (ric.state() == RicState.RECOVERING) { + } else if (ric.ric.state() == RicState.RECOVERING) { return Mono.empty(); } else { return Mono.just(ric); } } - private Mono checkRicPolicies(Ric ric) { - return a1Client.getPolicyIdentities(ric.getConfig().baseUrl()) // + private Mono checkRicPolicies(RicData ric) { + return ric.a1Client.getPolicyIdentities() // .onErrorResume(t -> Mono.empty()) // .flatMap(ricP -> validateInstances(ricP, ric)); } - private Mono validateInstances(Collection ricPolicies, Ric ric) { + private Mono validateInstances(Collection ricPolicies, RicData ric) { synchronized (this.policies) { - if (ricPolicies.size() != policies.getForRic(ric.name()).size()) { + if (ricPolicies.size() != policies.getForRic(ric.ric.name()).size()) { return startRecovery(ric); } } @@ -111,34 +129,34 @@ public class RepositorySupervision { return Mono.just(ric); } - private Mono checkRicPolicyTypes(Ric ric) { - return a1Client.getPolicyTypeIdentities(ric.getConfig().baseUrl()) // + private Mono checkRicPolicyTypes(RicData ric) { + return ric.a1Client.getPolicyTypeIdentities() // .onErrorResume(t -> { return Mono.empty(); }) // .flatMap(ricTypes -> validateTypes(ricTypes, ric)); } - private Mono validateTypes(Collection ricTypes, Ric ric) { - if (ricTypes.size() != ric.getSupportedPolicyTypes().size()) { + private Mono validateTypes(Collection ricTypes, RicData ric) { + if (ricTypes.size() != ric.ric.getSupportedPolicyTypes().size()) { return startRecovery(ric); } for (String typeName : ricTypes) { - if (!ric.isSupportingType(typeName)) { + if (!ric.ric.isSupportingType(typeName)) { return startRecovery(ric); } } return Mono.just(ric); } - private Mono startRecovery(Ric ric) { - RicRecoveryTask recovery = new RicRecoveryTask(a1Client, policyTypes, policies, services); - recovery.run(ric); + private Mono startRecovery(RicData ric) { + RicRecoveryTask recovery = new RicRecoveryTask(a1ClientFactory, policyTypes, policies, services); + recovery.run(ric.ric); return Mono.empty(); } - private void onRicChecked(Ric ric) { - logger.info("Ric: " + ric.name() + " checked"); + private void onRicChecked(RicData ric) { + logger.info("Ric: " + ric.ric.name() + " checked"); } private void onError(Throwable t) { diff --git a/policy-agent/src/main/java/org/oransc/policyagent/tasks/RicRecoveryTask.java b/policy-agent/src/main/java/org/oransc/policyagent/tasks/RicRecoveryTask.java index 8b3fadb0..d7e85513 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/tasks/RicRecoveryTask.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/tasks/RicRecoveryTask.java @@ -23,6 +23,7 @@ package org.oransc.policyagent.tasks; import java.util.Vector; import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.clients.AsyncRestClient; import org.oransc.policyagent.exceptions.ServiceException; import org.oransc.policyagent.repository.ImmutablePolicyType; @@ -50,13 +51,14 @@ public class RicRecoveryTask { private static final Logger logger = LoggerFactory.getLogger(RicRecoveryTask.class); - private final A1Client a1Client; + private final A1ClientFactory a1ClientFactory; private final PolicyTypes policyTypes; private final Policies policies; private final Services services; - public RicRecoveryTask(A1Client a1Client, PolicyTypes policyTypes, Policies policies, Services services) { - this.a1Client = a1Client; + public RicRecoveryTask(A1ClientFactory a1ClientFactory, PolicyTypes policyTypes, Policies policies, + Services services) { + this.a1ClientFactory = a1ClientFactory; this.policyTypes = policyTypes; this.policies = policies; this.services = services; @@ -71,16 +73,21 @@ public class RicRecoveryTask { } ric.setState(Ric.RicState.RECOVERING); } - Flux recoverTypes = recoverPolicyTypes(ric); - Flux deletePoliciesInRic = deleteAllPoliciesInRic(ric); - Flux recreatePoliciesInRic = recreateAllPoliciesInRic(ric); - - Flux.concat(recoverTypes, deletePoliciesInRic, recreatePoliciesInRic) // + this.a1ClientFactory.createA1Client(ric)// + .flatMapMany(client -> startRecover(ric, client)) // .subscribe(x -> logger.debug("Recover: " + x), // throwable -> onRecoveryError(ric, throwable), // () -> onRecoveryComplete(ric)); } + private Flux startRecover(Ric ric, A1Client a1Client) { + Flux recoverTypes = recoverPolicyTypes(ric, a1Client); + Flux deletePoliciesInRic = deleteAllPoliciesInRic(ric, a1Client); + Flux recreatePoliciesInRic = recreateAllPoliciesInRic(ric, a1Client); + + return Flux.concat(recoverTypes, deletePoliciesInRic, recreatePoliciesInRic); + } + private void onRecoveryComplete(Ric ric) { logger.debug("Recovery completed for:" + ric.name()); ric.setState(Ric.RicState.IDLE); @@ -104,11 +111,12 @@ public class RicRecoveryTask { private void onRecoveryError(Ric ric, Throwable t) { logger.warn("Recovery failed for: {}, reason: {}", ric.name(), t.getMessage()); - // If recovery fails, try to remove all instances deleteAllPolicies(ric); - Flux recoverTypes = recoverPolicyTypes(ric); - Flux deletePoliciesInRic = deleteAllPoliciesInRic(ric); + Flux recoverTypes = this.a1ClientFactory.createA1Client(ric) // + .flatMapMany(a1Client -> recoverPolicyTypes(ric, a1Client)); + Flux deletePoliciesInRic = this.a1ClientFactory.createA1Client(ric) // + .flatMapMany(a1Client -> deleteAllPoliciesInRic(ric, a1Client)); Flux.merge(recoverTypes, deletePoliciesInRic) // .subscribe(x -> logger.debug("Brute recover: " + x), // @@ -125,16 +133,16 @@ public class RicRecoveryTask { return new AsyncRestClient(url); } - private Flux recoverPolicyTypes(Ric ric) { + private Flux recoverPolicyTypes(Ric ric, A1Client a1Client) { ric.clearSupportedPolicyTypes(); - return a1Client.getPolicyTypeIdentities(ric.getConfig().baseUrl()) // + return a1Client.getPolicyTypeIdentities() // .flatMapMany(types -> Flux.fromIterable(types)) // .doOnNext(typeId -> logger.debug("For ric: {}, handling type: {}", ric.getConfig().name(), typeId)) // - .flatMap((policyTypeId) -> getPolicyType(ric, policyTypeId)) // + .flatMap((policyTypeId) -> getPolicyType(ric, policyTypeId, a1Client)) // .doOnNext(policyType -> ric.addSupportedPolicyType(policyType)); // } - private Mono getPolicyType(Ric ric, String policyTypeId) { + private Mono getPolicyType(Ric ric, String policyTypeId, A1Client a1Client) { if (policyTypes.contains(policyTypeId)) { try { return Mono.just(policyTypes.getType(policyTypeId)); @@ -142,7 +150,7 @@ public class RicRecoveryTask { return Mono.error(e); } } - return a1Client.getPolicyType(ric.getConfig().baseUrl(), policyTypeId) // + return a1Client.getPolicyTypeSchema(policyTypeId) // .flatMap(schema -> createPolicyType(policyTypeId, schema)); } @@ -160,14 +168,14 @@ public class RicRecoveryTask { } } - private Flux deleteAllPoliciesInRic(Ric ric) { - return a1Client.getPolicyIdentities(ric.getConfig().baseUrl()) // + private Flux deleteAllPoliciesInRic(Ric ric, A1Client a1Client) { + return a1Client.getPolicyIdentities() // .flatMapMany(policyIds -> Flux.fromIterable(policyIds)) // .doOnNext(policyId -> logger.debug("Deleting policy: {}, for ric: {}", policyId, ric.getConfig().name())) - .flatMap(policyId -> a1Client.deletePolicy(ric.getConfig().baseUrl(), policyId)); // + .flatMap(policyId -> a1Client.deletePolicy(policyId)); // } - private Flux recreateAllPoliciesInRic(Ric ric) { + private Flux recreateAllPoliciesInRic(Ric ric, A1Client a1Client) { synchronized (policies) { return Flux.fromIterable(new Vector<>(policies.getForRic(ric.name()))) // .doOnNext( diff --git a/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java b/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java index 1e7f2dc7..d75ff4fe 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java @@ -20,7 +20,7 @@ package org.oransc.policyagent.tasks; -import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.repository.Policies; import org.oransc.policyagent.repository.Policy; import org.oransc.policyagent.repository.Service; @@ -41,13 +41,13 @@ public class ServiceSupervision { private static final Logger logger = LoggerFactory.getLogger(ServiceSupervision.class); private final Services services; private final Policies policies; - private A1Client a1Client; + private A1ClientFactory a1ClientFactory; @Autowired - public ServiceSupervision(Services services, Policies policies, A1Client a1Client) { + public ServiceSupervision(Services services, Policies policies, A1ClientFactory a1ClientFactory) { this.services = services; this.policies = policies; - this.a1Client = a1Client; + this.a1ClientFactory = a1ClientFactory; } @Scheduled(fixedRate = 1000 * 60) @@ -86,9 +86,10 @@ public class ServiceSupervision { } private Mono deletePolicyInRic(Policy policy) { - return a1Client.deletePolicy(policy.ric().getConfig().baseUrl(), policy.id()) // - .onErrorResume(exception -> handleDeleteFromRicFailure(policy, exception)) // - .map((nothing) -> policy); + return a1ClientFactory.createA1Client(policy.ric()) // + .flatMap(client -> client.deletePolicy(policy.id()) // + .onErrorResume(exception -> handleDeleteFromRicFailure(policy, exception)) // + .map((nothing) -> policy)); } private Mono handleDeleteFromRicFailure(Policy policy, Throwable e) { diff --git a/policy-agent/src/main/java/org/oransc/policyagent/tasks/StartupService.java b/policy-agent/src/main/java/org/oransc/policyagent/tasks/StartupService.java index 46587a20..c0ffcbdf 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/tasks/StartupService.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/tasks/StartupService.java @@ -20,7 +20,7 @@ package org.oransc.policyagent.tasks; -import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.RicConfig; import org.oransc.policyagent.repository.Policies; @@ -57,7 +57,7 @@ public class StartupService implements ApplicationConfig.Observer { PolicyTypes policyTypes; @Autowired - private A1Client a1Client; + private A1ClientFactory a1ClientFactory; @Autowired private Policies policies; @@ -67,12 +67,12 @@ public class StartupService implements ApplicationConfig.Observer { // Only for unittesting StartupService(ApplicationConfig appConfig, RefreshConfigTask refreshTask, Rics rics, PolicyTypes policyTypes, - A1Client a1Client, Policies policies, Services services) { + A1ClientFactory a1ClientFactory, Policies policies, Services services) { this.applicationConfig = appConfig; this.refreshConfigTask = refreshTask; this.rics = rics; this.policyTypes = policyTypes; - this.a1Client = a1Client; + this.a1ClientFactory = a1ClientFactory; this.policies = policies; this.services = services; } @@ -84,7 +84,7 @@ public class StartupService implements ApplicationConfig.Observer { || event.equals(ApplicationConfig.RicConfigUpdate.CHANGED)) { Ric ric = new Ric(ricConfig); rics.put(ric); - RicRecoveryTask recoveryTask = new RicRecoveryTask(a1Client, policyTypes, policies, services); + RicRecoveryTask recoveryTask = new RicRecoveryTask(a1ClientFactory, policyTypes, policies, services); recoveryTask.run(ric); } else if (event.equals(ApplicationConfig.RicConfigUpdate.REMOVED)) { rics.remove(ricConfig.name()); diff --git a/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java b/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java index 09191541..4270ded6 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java @@ -28,13 +28,11 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; -import java.net.URL; import java.util.List; import java.util.Vector; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.oransc.policyagent.clients.A1Client; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.ImmutableRicConfig; import org.oransc.policyagent.configuration.RicConfig; @@ -53,6 +51,7 @@ import org.oransc.policyagent.repository.Ric; import org.oransc.policyagent.repository.Rics; import org.oransc.policyagent.tasks.RepositorySupervision; import org.oransc.policyagent.utils.MockA1Client; +import org.oransc.policyagent.utils.MockA1ClientFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; @@ -81,7 +80,7 @@ public class ApplicationTest { private PolicyTypes policyTypes; @Autowired - MockA1Client a1Client; + MockA1ClientFactory a1ClientFactory; @Autowired RepositorySupervision supervision; @@ -93,8 +92,7 @@ public class ApplicationTest { public static class MockApplicationConfig extends ApplicationConfig { @Override public String getLocalConfigurationFilePath() { - URL url = MockApplicationConfig.class.getClassLoader().getResource("test_application_configuration.json"); - return url.getFile(); + return ""; // No config file loaded for the test } } @@ -111,8 +109,8 @@ public class ApplicationTest { } @Bean - A1Client getA1Client() { - return new MockA1Client(this.policyTypes); + MockA1ClientFactory getA1ClientFactory() { + return new MockA1ClientFactory(this.policyTypes); } @Bean @@ -161,24 +159,32 @@ public class ApplicationTest { public void testRecovery() throws Exception { reset(); Policy policy = addPolicy("policyId", "typeName", "service", "ric"); // This should be created in the RIC - Policy policy2 = addPolicy("policyId2", "typeName", "service", "ric"); - a1Client.putPolicy("ric", policy2); // put it in the RIC + + getA1Client("ric").putPolicy(policy2); // put it in the RIC policies.remove(policy2); // Remove it from the repo -> should be deleted in the RIC supervision.checkAllRics(); // The created policy should be put in the RIC - Policies ricPolicies = a1Client.getPolicies("ric"); + Policies ricPolicies = getA1Client("ric").getPolicies(); assertThat(ricPolicies.size()).isEqualTo(1); Policy ricPolicy = ricPolicies.get("policyId"); assertThat(ricPolicy.json()).isEqualTo(policy.json()); } + MockA1Client getA1Client(String ricName) throws ServiceException { + return a1ClientFactory.getOrCreateA1Client(ricName); + } + @Test public void testGetRic() throws Exception { reset(); + Ric ric = addRic("ric1"); + ric.addManagedElement("kista_1"); String url = baseUrl() + "/ric?managedElementId=kista_1"; + String rsp = this.restTemplate.getForObject(url, String.class); System.out.println(rsp); + assertThat(rsp).isEqualTo("ric1"); } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/MockPolicyAgent.java b/policy-agent/src/test/java/org/oransc/policyagent/MockPolicyAgent.java index 8adc79a3..bbbc06d2 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/MockPolicyAgent.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/MockPolicyAgent.java @@ -30,14 +30,14 @@ import java.nio.file.Files; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.oransc.policyagent.clients.A1Client; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.repository.ImmutablePolicyType; import org.oransc.policyagent.repository.Policies; import org.oransc.policyagent.repository.PolicyType; import org.oransc.policyagent.repository.PolicyTypes; import org.oransc.policyagent.repository.Rics; -import org.oransc.policyagent.utils.MockA1Client; +import org.oransc.policyagent.utils.MockA1ClientFactory; +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; @@ -49,6 +49,9 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT) public class MockPolicyAgent { + @Autowired + Rics rics; + static class MockApplicationConfig extends ApplicationConfig { @Override public String getLocalConfigurationFilePath() { @@ -73,11 +76,10 @@ public class MockPolicyAgent { } @Bean - public A1Client getA1Client() { + public MockA1ClientFactory getA1ClientFactory() { PolicyTypes ricTypes = new PolicyTypes(); loadTypes(ricTypes); - A1Client client = new MockA1Client(ricTypes); - return client; + return new MockA1ClientFactory(ricTypes); } @Bean diff --git a/policy-agent/src/test/java/org/oransc/policyagent/clients/A1ClientImplTest.java b/policy-agent/src/test/java/org/oransc/policyagent/clients/StdA1ClientTest.java similarity index 91% rename from policy-agent/src/test/java/org/oransc/policyagent/clients/A1ClientImplTest.java rename to policy-agent/src/test/java/org/oransc/policyagent/clients/StdA1ClientTest.java index b3b5f48c..ee1e8df5 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/clients/A1ClientImplTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/clients/StdA1ClientTest.java @@ -21,7 +21,8 @@ package org.oransc.policyagent.clients; 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.when; @@ -33,8 +34,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension; import org.oransc.policyagent.configuration.ImmutableRicConfig; @@ -50,7 +49,7 @@ import reactor.test.StepVerifier; @ExtendWith(MockitoExtension.class) @RunWith(MockitoJUnitRunner.class) -public class A1ClientImplTest { +public class StdA1ClientTest { private static final String RIC_URL = "RicUrl"; private static final String POLICYTYPES_IDENTITIES_URL = "/policytypes/identities"; private static final String POLICIES_IDENTITIES_URL = "/policies/identities"; @@ -67,15 +66,14 @@ public class A1ClientImplTest { private static final String POLICY_JSON_INVALID = "\"policyId\":\"policy1\"}"; private static final String POLICY_TYPE = "typeName"; - @Spy - A1ClientImpl a1Client; + StdA1Client a1Client; - @Mock AsyncRestClient asyncRestClientMock; @BeforeEach public void init() { - doReturn(asyncRestClientMock).when(a1Client).createClient(RIC_URL); + asyncRestClientMock = mock(AsyncRestClient.class); + a1Client = spy(new StdA1Client(createRic(RIC_URL).getConfig(), asyncRestClientMock)); } @Test @@ -83,7 +81,7 @@ public class A1ClientImplTest { Mono policyTypeIds = Mono.just(Arrays.toString(new String[] {POLICY_TYPE_1_NAME, POLICY_TYPE_2_NAME})); when(asyncRestClientMock.get(POLICYTYPES_IDENTITIES_URL)).thenReturn(policyTypeIds); - Mono policyTypeIdsFlux = a1Client.getPolicyTypeIdentities(RIC_URL); + Mono policyTypeIdsFlux = a1Client.getPolicyTypeIdentities(); verify(asyncRestClientMock).get(POLICYTYPES_IDENTITIES_URL); StepVerifier.create(policyTypeIdsFlux).expectNextCount(1).expectComplete().verify(); } @@ -93,7 +91,7 @@ public class A1ClientImplTest { Mono policyIds = Mono.just(Arrays.toString(new String[] {POLICY_1_ID, POLICY_2_ID})); when(asyncRestClientMock.get(POLICIES_IDENTITIES_URL)).thenReturn(policyIds); - Mono policyIdsFlux = a1Client.getPolicyIdentities(RIC_URL); + Mono policyIdsFlux = a1Client.getPolicyIdentities(); verify(asyncRestClientMock).get(POLICIES_IDENTITIES_URL); StepVerifier.create(policyIdsFlux).expectNextCount(1).expectComplete().verify(); } @@ -103,7 +101,7 @@ public class A1ClientImplTest { when(asyncRestClientMock.get(POLICYTYPES_URL + POLICY_TYPE_1_NAME)) .thenReturn(Mono.just(POLICY_TYPE_SCHEMA_VALID)); - Mono policyTypeMono = a1Client.getPolicyType(RIC_URL, POLICY_TYPE_1_NAME); + Mono policyTypeMono = a1Client.getPolicyTypeSchema(POLICY_TYPE_1_NAME); verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_NAME); StepVerifier.create(policyTypeMono).expectNext(POLICY_TYPE_SCHEMA_VALID).expectComplete().verify(); } @@ -113,7 +111,7 @@ public class A1ClientImplTest { when(asyncRestClientMock.get(POLICYTYPES_URL + POLICY_TYPE_1_NAME)) .thenReturn(Mono.just(POLICY_TYPE_SCHEMA_INVALID)); - Mono policyTypeMono = a1Client.getPolicyType(RIC_URL, POLICY_TYPE_1_NAME); + Mono policyTypeMono = a1Client.getPolicyTypeSchema(POLICY_TYPE_1_NAME); verify(asyncRestClientMock).get(POLICYTYPES_URL + POLICY_TYPE_1_NAME); StepVerifier.create(policyTypeMono).expectErrorMatches(throwable -> throwable instanceof JSONException) .verify(); @@ -165,7 +163,7 @@ public class A1ClientImplTest { public void testDeletePolicy() { when(asyncRestClientMock.delete(POLICIES_URL + POLICY_1_ID)).thenReturn(Mono.empty()); - Mono responseMono = a1Client.deletePolicy(RIC_URL, POLICY_1_ID); + Mono responseMono = a1Client.deletePolicy(POLICY_1_ID); verify(asyncRestClientMock).delete(POLICIES_URL + POLICY_1_ID); StepVerifier.create(responseMono).expectComplete().verify(); } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/tasks/RepositorySupervisionTest.java b/policy-agent/src/test/java/org/oransc/policyagent/tasks/RepositorySupervisionTest.java index 1330a14f..4bbe3168 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/tasks/RepositorySupervisionTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/tasks/RepositorySupervisionTest.java @@ -23,14 +23,16 @@ package org.oransc.policyagent.tasks; import static org.awaitility.Awaitility.await; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; import java.util.Arrays; import java.util.Collection; 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.junit.runner.RunWith; @@ -38,6 +40,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension; import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.configuration.ImmutableRicConfig; import org.oransc.policyagent.repository.ImmutablePolicy; import org.oransc.policyagent.repository.ImmutablePolicyType; @@ -57,6 +60,14 @@ public class RepositorySupervisionTest { @Mock A1Client a1ClientMock; + @Mock + A1ClientFactory a1ClientFactory; + + @BeforeEach + public void init() { + doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any()); + } + @Test public void test() { Ric ric1 = new Ric(ImmutableRicConfig.builder() // @@ -99,14 +110,15 @@ public class RepositorySupervisionTest { Services services = new Services(); RepositorySupervision supervisorUnderTest = - new RepositorySupervision(rics, policies, a1ClientMock, types, services); + new RepositorySupervision(rics, policies, a1ClientFactory, types, services); Mono> policyIds = Mono.just(Arrays.asList("policyId1", "policyId2")); - when(a1ClientMock.getPolicyIdentities(anyString())).thenReturn(policyIds); - when(a1ClientMock.deletePolicy(anyString(), anyString())).thenReturn(Mono.empty()); - when(a1ClientMock.getPolicyTypeIdentities(anyString())).thenReturn(policyIds); - when(a1ClientMock.getPolicyType(anyString(), anyString())).thenReturn(Mono.just("schema")); - when(a1ClientMock.putPolicy(any())).thenReturn(Mono.just("OK")); + + doReturn(policyIds).when(a1ClientMock).getPolicyTypeIdentities(); + doReturn(policyIds).when(a1ClientMock).getPolicyIdentities(); + doReturn(Mono.empty()).when(a1ClientMock).deletePolicy(anyString()); + doReturn(Mono.just("schema")).when(a1ClientMock).getPolicyTypeSchema(anyString()); + doReturn(Mono.just("OK")).when(a1ClientMock).putPolicy(any()); supervisorUnderTest.checkAllRics(); @@ -114,8 +126,7 @@ public class RepositorySupervisionTest { await().untilAsserted(() -> RicState.IDLE.equals(ric2.state())); await().untilAsserted(() -> RicState.IDLE.equals(ric3.state())); - verify(a1ClientMock).deletePolicy("baseUrl1", "policyId2"); - verify(a1ClientMock).deletePolicy("baseUrl2", "policyId2"); + verify(a1ClientMock, times(3)).deletePolicy("policyId2"); verifyNoMoreInteractions(a1ClientMock); } } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/tasks/StartupServiceTest.java b/policy-agent/src/test/java/org/oransc/policyagent/tasks/StartupServiceTest.java index 47e7b4d7..9e4701d2 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/tasks/StartupServiceTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/tasks/StartupServiceTest.java @@ -25,8 +25,11 @@ import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +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.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.oransc.policyagent.repository.Ric.RicState.IDLE; @@ -35,13 +38,14 @@ import java.util.Arrays; import java.util.Collection; 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.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.jupiter.MockitoExtension; import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.ImmutableRicConfig; import org.oransc.policyagent.configuration.RicConfig; @@ -69,29 +73,35 @@ public class StartupServiceTest { private static final String POLICY_ID_1 = "policy1"; private static final String POLICY_ID_2 = "policy2"; - @Mock ApplicationConfig appConfigMock; - - @Mock RefreshConfigTask refreshTaskMock; - @Mock A1Client a1ClientMock; + A1ClientFactory a1ClientFactory; + + @BeforeEach + public void init() throws Exception { + a1ClientMock = mock(A1Client.class); + a1ClientFactory = mock(A1ClientFactory.class); + appConfigMock = mock(ApplicationConfig.class); + refreshTaskMock = mock(RefreshConfigTask.class); + doReturn(Mono.just(a1ClientMock)).when(a1ClientFactory).createA1Client(any()); + } @Test public void startup_allOk() { Mono> policyTypes1 = Mono.just(Arrays.asList(POLICY_TYPE_1_NAME)); Mono> policyTypes2 = Mono.just(Arrays.asList(POLICY_TYPE_1_NAME, POLICY_TYPE_2_NAME)); - when(a1ClientMock.getPolicyTypeIdentities(anyString())).thenReturn(policyTypes1).thenReturn(policyTypes2); + doReturn(policyTypes1, policyTypes2).when(a1ClientMock).getPolicyTypeIdentities(); Mono> policies = Mono.just(Arrays.asList(POLICY_ID_1, POLICY_ID_2)); - when(a1ClientMock.getPolicyIdentities(anyString())).thenReturn(policies); - when(a1ClientMock.getPolicyType(anyString(), anyString())).thenReturn(Mono.just("Schema")); - when(a1ClientMock.deletePolicy(anyString(), anyString())).thenReturn(Mono.just("OK")); + doReturn(policies).when(a1ClientMock).getPolicyIdentities(); + doReturn(Mono.just("Schema")).when(a1ClientMock).getPolicyTypeSchema(anyString()); + doReturn(Mono.just("OK")).when(a1ClientMock).deletePolicy(anyString()); Rics rics = new Rics(); PolicyTypes policyTypes = new PolicyTypes(); StartupService serviceUnderTest = new StartupService(appConfigMock, refreshTaskMock, rics, policyTypes, - a1ClientMock, new Policies(), new Services()); + a1ClientFactory, new Policies(), new Services()); serviceUnderTest.startup(); @@ -103,13 +113,9 @@ public class StartupServiceTest { await().untilAsserted(() -> assertThat(policyTypes.size()).isEqualTo(2)); - verify(a1ClientMock).getPolicyTypeIdentities(FIRST_RIC_URL); - verify(a1ClientMock).deletePolicy(FIRST_RIC_URL, POLICY_ID_1); - verify(a1ClientMock).deletePolicy(FIRST_RIC_URL, POLICY_ID_2); - - verify(a1ClientMock).getPolicyTypeIdentities(SECOND_RIC_URL); - verify(a1ClientMock).deletePolicy(SECOND_RIC_URL, POLICY_ID_1); - verify(a1ClientMock).deletePolicy(SECOND_RIC_URL, POLICY_ID_2); + verify(a1ClientMock, times(2)).getPolicyTypeIdentities(); + verify(a1ClientMock, times(2)).deletePolicy(POLICY_ID_1); + verify(a1ClientMock, times(2)).deletePolicy(POLICY_ID_2); assertTrue(policyTypes.contains(POLICY_TYPE_1_NAME), POLICY_TYPE_1_NAME + " not added to PolicyTypes."); assertTrue(policyTypes.contains(POLICY_TYPE_2_NAME), POLICY_TYPE_2_NAME + " not added to PolicyTypes."); @@ -146,13 +152,13 @@ public class StartupServiceTest { @Test public void startup_unableToConnectToGetTypes() { Mono error = Mono.error(new Exception("Unable to contact ric.")); - doReturn(error, error).when(a1ClientMock).getPolicyTypeIdentities(anyString()); - doReturn(error).when(a1ClientMock).getPolicyIdentities(anyString()); + doReturn(error, error).when(a1ClientMock).getPolicyTypeIdentities(); + doReturn(error).when(a1ClientMock).getPolicyIdentities(); Rics rics = new Rics(); PolicyTypes policyTypes = new PolicyTypes(); StartupService serviceUnderTest = new StartupService(appConfigMock, refreshTaskMock, rics, policyTypes, - a1ClientMock, new Policies(), new Services()); + a1ClientFactory, new Policies(), new Services()); serviceUnderTest.startup(); serviceUnderTest.onRicConfigUpdate(getRicConfig(FIRST_RIC_NAME, FIRST_RIC_URL, MANAGED_NODE_A), @@ -165,14 +171,14 @@ public class StartupServiceTest { public void startup_unableToConnectToGetPolicies() { Mono> policyTypes = Mono.just(Arrays.asList(POLICY_TYPE_1_NAME)); - when(a1ClientMock.getPolicyTypeIdentities(anyString())).thenReturn(policyTypes); - when(a1ClientMock.getPolicyType(anyString(), anyString())).thenReturn(Mono.just("Schema")); + when(a1ClientMock.getPolicyTypeIdentities()).thenReturn(policyTypes); + when(a1ClientMock.getPolicyTypeSchema(anyString())).thenReturn(Mono.just("Schema")); Mono error = Mono.error(new Exception("Unable to contact ric.")); - doReturn(error).when(a1ClientMock).getPolicyIdentities(anyString()); + doReturn(error).when(a1ClientMock).getPolicyIdentities(); Rics rics = new Rics(); StartupService serviceUnderTest = new StartupService(appConfigMock, refreshTaskMock, rics, new PolicyTypes(), - a1ClientMock, new Policies(), new Services()); + a1ClientFactory, new Policies(), new Services()); serviceUnderTest.startup(); serviceUnderTest.onRicConfigUpdate(getRicConfig(FIRST_RIC_NAME, FIRST_RIC_URL, MANAGED_NODE_A), diff --git a/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1Client.java b/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1Client.java index bac27393..d6cd533d 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1Client.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1Client.java @@ -21,8 +21,6 @@ package org.oransc.policyagent.utils; import java.util.Collection; -import java.util.HashMap; -import java.util.Map; import java.util.Vector; import org.oransc.policyagent.clients.A1Client; @@ -33,7 +31,7 @@ import org.oransc.policyagent.repository.PolicyTypes; import reactor.core.publisher.Mono; public class MockA1Client implements A1Client { - private final Map policies = new HashMap<>(); + Policies policies = new Policies(); private final PolicyTypes policyTypes; public MockA1Client(PolicyTypes policyTypes) { @@ -41,7 +39,7 @@ public class MockA1Client implements A1Client { } @Override - public Mono> getPolicyTypeIdentities(String nearRtRicUrl) { + public Mono> getPolicyTypeIdentities() { synchronized (this.policyTypes) { Vector result = new Vector<>(); for (PolicyType p : this.policyTypes.getAll()) { @@ -52,13 +50,11 @@ public class MockA1Client implements A1Client { } @Override - public Mono> getPolicyIdentities(String nearRtRicUrl) { + public Mono> getPolicyIdentities() { synchronized (this.policies) { Vector result = new Vector<>(); - for (Policy policy : getPolicies(nearRtRicUrl).getAll()) { - if (policy.ric().getConfig().baseUrl().equals(nearRtRicUrl)) { - result.add(policy.id()); - } + for (Policy policy : policies.getAll()) { + result.add(policy.id()); } return Mono.just(result); @@ -66,7 +62,7 @@ public class MockA1Client implements A1Client { } @Override - public Mono getPolicyType(String nearRtRicUrl, String policyTypeId) { + public Mono getPolicyTypeSchema(String policyTypeId) { try { return Mono.just(this.policyTypes.getType(policyTypeId).schema()); } catch (Exception e) { @@ -76,25 +72,23 @@ public class MockA1Client implements A1Client { @Override public Mono putPolicy(Policy p) { - getPolicies(p.ric().getConfig().baseUrl()).put(p); + this.policies.put(p); return Mono.just("OK"); } @Override - public Mono deletePolicy(String nearRtRicUrl, String policyId) { - getPolicies(nearRtRicUrl).removeId(policyId); + public Mono deletePolicy(String policyId) { + this.policies.removeId(policyId); return Mono.just("OK"); } - public Policies getPolicies(String url) { - if (!policies.containsKey(url)) { - policies.put(url, new Policies()); - } - return policies.get(url); + public Policies getPolicies() { + return this.policies; } - public void putPolicy(String url, Policy policy) { - getPolicies(url).put(policy); + @Override + public Mono getProtocolVersion() { + return Mono.just(A1ProtocolType.STD_V1); } } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1ClientFactory.java b/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1ClientFactory.java new file mode 100644 index 00000000..314c44c1 --- /dev/null +++ b/policy-agent/src/test/java/org/oransc/policyagent/utils/MockA1ClientFactory.java @@ -0,0 +1,57 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.oransc.policyagent.utils; + +import java.lang.invoke.MethodHandles; +import java.util.HashMap; +import java.util.Map; + +import org.oransc.policyagent.clients.A1Client; +import org.oransc.policyagent.clients.A1ClientFactory; +import org.oransc.policyagent.repository.PolicyTypes; +import org.oransc.policyagent.repository.Ric; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MockA1ClientFactory extends A1ClientFactory { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final Map clients = new HashMap<>(); + private final PolicyTypes policyTypes; + + public MockA1ClientFactory(PolicyTypes policyTypes) { + this.policyTypes = policyTypes; + } + + @Override + protected A1Client createStdA1ClientImpl(Ric ric) { + return getOrCreateA1Client(ric.name()); + } + + public MockA1Client getOrCreateA1Client(String ricName) { + if (!clients.containsKey(ricName)) { + logger.debug("Creating client for RIC: {}", ricName); + MockA1Client client = new MockA1Client(policyTypes); + clients.put(ricName, client); + } + return clients.get(ricName); + } + +} diff --git a/policy-agent/src/test/resources/test_application_configuration.json b/policy-agent/src/test/resources/test_application_configuration.json index 924b1dd0..446c0611 100644 --- a/policy-agent/src/test/resources/test_application_configuration.json +++ b/policy-agent/src/test/resources/test_application_configuration.json @@ -20,4 +20,4 @@ } ] } -} +} \ No newline at end of file -- 2.16.6