diff options
author | PatrikBuhr <patrik.buhr@est.tech> | 2020-10-22 10:51:21 +0200 |
---|---|---|
committer | PatrikBuhr <patrik.buhr@est.tech> | 2020-10-26 08:06:04 +0100 |
commit | c655306c67fd9ed6b95d6b111f7bedab79c02f44 (patch) | |
tree | 00f52ce041d7fdb2eaf9cbd9002e2baa496af3be /a1-policy-management | |
parent | c5f81cf8dace9637702d6934db1a9f4ed32ff131 (diff) |
Added support for policy status notifications
Revised the version 2 of the component NBI
Change-Id: I06571bfaa47ea3098ef71ce271e710a45b2d96e3
Issue-ID: CCSDK-2502
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
Diffstat (limited to 'a1-policy-management')
26 files changed, 325 insertions, 295 deletions
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1UriBuilder.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1UriBuilder.java index 08ea0e8c..801cb4d5 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1UriBuilder.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/A1UriBuilder.java @@ -24,7 +24,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.clients; * Builder for A1 influenced REST APIs */ interface A1UriBuilder { - String createPutPolicyUri(String type, String policyId); + String createPutPolicyUri(String type, String policyId, String notificationDestinationUri); String createDeleteUri(String type, String policyId); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1Client.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1Client.java index 3643b8d2..f54dc2e0 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1Client.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/OscA1Client.java @@ -47,7 +47,7 @@ public class OscA1Client implements A1Client { } @Override - public String createPutPolicyUri(String type, String policyId) { + public String createPutPolicyUri(String type, String policyId, String notificationDestinationUri) { return createPolicyUri(type, policyId); } @@ -165,7 +165,7 @@ public class OscA1Client implements A1Client { @Override public Mono<String> putPolicy(Policy policy) { - String policyUri = this.uri.createPutPolicyUri(policy.type().id(), policy.id()); + String policyUri = this.uri.createPutPolicyUri(policy.type().id(), policy.id(), policy.statusNotificationUri()); return restClient.put(policyUri, policy.json()); } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1Client.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1Client.java index 28c27843..88859d37 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1Client.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/SdncOscA1Client.java @@ -166,7 +166,8 @@ public class SdncOscA1Client implements A1Client { @Override public Mono<String> putPolicy(Policy policy) { - String ricUrl = getUriBuilder().createPutPolicyUri(policy.type().id(), policy.id()); + String ricUrl = + getUriBuilder().createPutPolicyUri(policy.type().id(), policy.id(), policy.statusNotificationUri()); return post("putA1Policy", ricUrl, Optional.of(policy.json())); } @@ -216,7 +217,7 @@ public class SdncOscA1Client implements A1Client { if (protocolType == A1ProtocolType.SDNC_OSC_STD_V1_1) { return new StdA1ClientVersion1.UriBuilder(ricConfig); } else if (protocolType == A1ProtocolType.SDNC_OSC_STD_V2_0_0) { - return new StdA1ClientVersion2.UriBuilder(ricConfig); + return new StdA1ClientVersion2.OranV2UriBuilder(ricConfig); } else if (protocolType == A1ProtocolType.SDNC_OSC_OSC_V1) { return new OscA1Client.UriBuilder(ricConfig); } @@ -236,7 +237,7 @@ public class SdncOscA1Client implements A1Client { } private Mono<A1ProtocolType> tryStdProtocolVersion2() { - StdA1ClientVersion2.UriBuilder uriBuilder = new StdA1ClientVersion2.UriBuilder(ricConfig); + StdA1ClientVersion2.OranV2UriBuilder uriBuilder = new StdA1ClientVersion2.OranV2UriBuilder(ricConfig); return post(GET_POLICY_RPC, uriBuilder.createPolicyTypesUri(), Optional.empty()) // .flatMap(x -> Mono.just(A1ProtocolType.SDNC_OSC_STD_V2_0_0)); } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion1.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion1.java index 94567234..a1c5ac7a 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion1.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion1.java @@ -46,7 +46,7 @@ public class StdA1ClientVersion1 implements A1Client { * /A1-P/v1/policies/{policyId} */ @Override - public String createPutPolicyUri(String type, String policyId) { + public String createPutPolicyUri(String type, String policyId, String statusNotificationUri) { return policiesBaseUri() + policyId; } @@ -113,7 +113,8 @@ public class StdA1ClientVersion1 implements A1Client { @Override public Mono<String> putPolicy(Policy policy) { - return restClient.put(uri.createPutPolicyUri(policy.type().id(), policy.id()), policy.json()); + return restClient.put(uri.createPutPolicyUri(policy.type().id(), policy.id(), policy.statusNotificationUri()), + policy.json()); } @Override diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion2.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion2.java index c475b22f..cdf35954 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion2.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientVersion2.java @@ -28,6 +28,8 @@ import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig; import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.util.DefaultUriBuilderFactory; +import org.springframework.web.util.UriBuilderFactory; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -39,16 +41,25 @@ import reactor.core.publisher.Mono; public class StdA1ClientVersion2 implements A1Client { static final int CONCURRENCY_RIC = 1; // How many paralell requests that is sent to one NearRT RIC - public static class UriBuilder implements A1UriBuilder { + public static class OranV2UriBuilder implements A1UriBuilder { private final RicConfig ricConfig; - public UriBuilder(RicConfig ricConfig) { + public OranV2UriBuilder(RicConfig ricConfig) { this.ricConfig = ricConfig; } @Override - public String createPutPolicyUri(String type, String policyId) { - return createPolicyUri(type, policyId); + public String createPutPolicyUri(String type, String policyId, String statusNotificationUri) { + String policyUri = createPolicyUri(type, policyId); + if (statusNotificationUri.isEmpty()) { + return policyUri; + } + UriBuilderFactory builderFactory = new DefaultUriBuilderFactory(policyUri); + return builderFactory.builder() // + .queryParam("notificationDestination", statusNotificationUri) // + .build() // + .normalize() // + .toASCIIString(); } /** @@ -110,7 +121,7 @@ public class StdA1ClientVersion2 implements A1Client { private static final String TITLE = "title"; private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private final AsyncRestClient restClient; - private final UriBuilder uriBuiler; + private final OranV2UriBuilder uriBuiler; public StdA1ClientVersion2(RicConfig ricConfig, AsyncRestClientFactory restClientFactory) { this(ricConfig, restClientFactory.createRestClient("")); @@ -120,7 +131,7 @@ public class StdA1ClientVersion2 implements A1Client { this.restClient = restClient; logger.debug("OscA1Client for ric: {}", ricConfig.ricId()); - uriBuiler = new UriBuilder(ricConfig); + uriBuiler = new OranV2UriBuilder(ricConfig); } public static Mono<String> extractPolicySchema(String policyTypeResponse, String policyTypeId) { @@ -158,7 +169,8 @@ public class StdA1ClientVersion2 implements A1Client { @Override public Mono<String> putPolicy(Policy policy) { - String policyUri = this.uriBuiler.createPutPolicyUri(policy.type().id(), policy.id()); + String policyUri = + this.uriBuiler.createPutPolicyUri(policy.type().id(), policy.id(), policy.statusNotificationUri()); return restClient.put(policyUri, policy.json()); } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyController.java index d5024581..e1d60de3 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/PolicyController.java @@ -91,9 +91,7 @@ public class PolicyController { private Services services; private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - private static Gson gson = new GsonBuilder() // - .serializeNulls() // - .create(); // + private static Gson gson = new GsonBuilder().create(); @GetMapping("/policy_schemas") @ApiOperation(value = "Returns policy type schema definitions") @@ -239,6 +237,7 @@ public class PolicyController { .ownerServiceId(service) // .lastModified(Instant.now()) // .isTransient(isTransient) // + .statusNotificationUri("") // .build(); final boolean isCreate = this.policies.get(policy.id()) == null; diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicRepositoryController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicRepositoryController.java index 31c4f3bf..4e57ada8 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicRepositoryController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/RicRepositoryController.java @@ -54,7 +54,6 @@ public class RicRepositoryController { PolicyTypes types; private static Gson gson = new GsonBuilder() // - .serializeNulls() // .create(); // /** diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java index f11fd0d5..e9a95e1a 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ServiceController.java @@ -58,8 +58,7 @@ public class ServiceController { private final Services services; private final Policies policies; - private static Gson gson = new GsonBuilder() // - .create(); // + private static Gson gson = new GsonBuilder().create(); @Autowired ServiceController(Services services, Policies policies) { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java index 6c9012bc..c18ec81b 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyController.java @@ -58,6 +58,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -94,46 +95,19 @@ public class PolicyController { private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); private static Gson gson = new GsonBuilder() // - .serializeNulls() // .create(); // - @GetMapping(path = Consts.V2_API_ROOT + "/policy-schemas", produces = MediaType.APPLICATION_JSON_VALUE) - @ApiOperation(value = "Returns policy type schema definitions") + @GetMapping(path = Consts.V2_API_ROOT + "/policy-types/{policyTypeId}", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Returns a policy type definition") @ApiResponses(value = { // - @ApiResponse(code = 200, message = "Policy schemas", response = PolicySchemaList.class), // + @ApiResponse(code = 200, message = "Policy type", response = PolicyTypeInfo.class), // @ApiResponse(code = 404, message = "Near-RT RIC is not found", response = ErrorResponse.ErrorInfo.class)}) - public ResponseEntity<Object> getPolicySchemas( // - @ApiParam(name = Consts.RIC_ID_PARAM, required = false, - value = "The identity of the Near-RT RIC to get the definitions for.") // - @RequestParam(name = Consts.RIC_ID_PARAM, required = false) String ricId, - @ApiParam(name = Consts.POLICY_TYPE_ID_PARAM, required = true, - value = "The identity of the policy type to get the definition for. When this parameter is given, max one schema will be returned") // - @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String policyTypeId) { + public ResponseEntity<Object> getPolicyType( // + @PathVariable("policyTypeId") String policyTypeId) { try { - Ric ric = ricId == null ? null : rics.getRic(ricId); - if (ric == null && policyTypeId == null) { - Collection<PolicyType> types = this.policyTypes.getAll(); - return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK); - } else if (ric != null && policyTypeId != null) { - synchronized (ric) { - assertRicStateIdleSync(ric); - Collection<PolicyType> types = new ArrayList<>(); - if (rics.getRic(ricId).isSupportingType(policyTypeId)) { - types.add(policyTypes.getType(policyTypeId)); - } - return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK); - } - } else if (ric != null) { - synchronized (ric) { - assertRicStateIdleSync(ric); - Collection<PolicyType> types = rics.getRic(ricId).getSupportedPolicyTypes(); - return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK); - } - } else { - Collection<PolicyType> types = new ArrayList<>(); - types.add(policyTypes.getType(policyTypeId)); - return new ResponseEntity<>(toPolicyTypeSchemasJson(types), HttpStatus.OK); - } + PolicyType type = policyTypes.getType(policyTypeId); + PolicyTypeInfo info = new PolicyTypeInfo(type.schema()); + return new ResponseEntity<>(gson.toJson(info), HttpStatus.OK); } catch (ServiceException e) { return ErrorResponse.create(e, HttpStatus.NOT_FOUND); } @@ -160,24 +134,23 @@ public class PolicyController { } } - @GetMapping(path = Consts.V2_API_ROOT + "/policy", produces = MediaType.APPLICATION_JSON_VALUE) - @ApiOperation(value = "Returns a policy configuration") // + @GetMapping(path = Consts.V2_API_ROOT + "/policies/{policy_id}", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Returns a policy") // @ApiResponses(value = { // - @ApiResponse(code = 200, message = "Policy found", response = JsonObject.class), // + @ApiResponse(code = 200, message = "Policy found", response = PolicyInfo.class), // @ApiResponse(code = 404, message = "Policy is not found", response = ErrorResponse.ErrorInfo.class)} // ) public ResponseEntity<Object> getPolicy( // - @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") // - @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String id) { + @PathVariable(name = Consts.POLICY_ID_PARAM, required = true) String id) { try { Policy p = policies.getPolicy(id); - return new ResponseEntity<>(p.json(), HttpStatus.OK); + return new ResponseEntity<>(gson.toJson(toPolicyInfo(p)), HttpStatus.OK); } catch (ServiceException e) { return ErrorResponse.create(e, HttpStatus.NOT_FOUND); } } - @DeleteMapping(Consts.V2_API_ROOT + "/policy") + @DeleteMapping(Consts.V2_API_ROOT + "/policies/{policy_id}") @ApiOperation(value = "Delete a policy") @ApiResponses(value = { // @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class), @@ -186,10 +159,9 @@ public class PolicyController { @ApiResponse(code = 423, message = "Near-RT RIC is not operational", response = ErrorResponse.ErrorInfo.class)}) public Mono<ResponseEntity<Object>> deletePolicy( // - @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") // - @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String id) { + @PathVariable(Consts.POLICY_ID_PARAM) String policyId) { try { - Policy policy = policies.getPolicy(id); + Policy policy = policies.getPolicy(policyId); keepServiceAlive(policy.ownerServiceId()); Ric ric = policy.ric(); return ric.getLock().lock(LockType.SHARED) // @@ -206,7 +178,7 @@ public class PolicyController { } } - @PutMapping(path = Consts.V2_API_ROOT + "/policy", produces = MediaType.APPLICATION_JSON_VALUE) + @PutMapping(path = Consts.V2_API_ROOT + "/policies", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Create or update a policy") @ApiResponses(value = { // @ApiResponse(code = 201, message = "Policy created", response = VoidResponse.class), // @@ -216,41 +188,24 @@ public class PolicyController { @ApiResponse(code = 404, message = "Near-RT RIC or policy type is not found", response = ErrorResponse.ErrorInfo.class) // }) - public Mono<ResponseEntity<Object>> putPolicy( // - @ApiParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false, value = "The identity of the policy type.") // - @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false, defaultValue = "") String policyTypeId, // - @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy instance.") // - @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String instanceId, // - @ApiParam(name = Consts.RIC_ID_PARAM, required = true, - value = "The identity of the Near-RT RIC where the policy will be " + // - "created.") // - @RequestParam(name = Consts.RIC_ID_PARAM, required = true) String ricId, // - @ApiParam(name = Consts.SERVICE_ID_PARAM, required = true, - value = "The identity of the service creating the policy.") // - @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceId, // - @ApiParam(name = Consts.TRANSIENT_PARAM, required = false, - value = "If the policy is transient or not (boolean " + // - "defaulted to false). A policy is transient if it will not be recreated in the Near-RT RIC " - + // - "when it has been lost (for instance due to a restart)") // - @RequestParam(name = Consts.TRANSIENT_PARAM, required = false, defaultValue = "false") boolean isTransient, // - @RequestBody Object jsonBody) { - - String jsonString = gson.toJson(jsonBody); - Ric ric = rics.get(ricId); - PolicyType type = policyTypes.get(policyTypeId); - keepServiceAlive(serviceId); + public Mono<ResponseEntity<Object>> putPolicy(@RequestBody PolicyInfo policyInfo) { + + String jsonString = gson.toJson(policyInfo.policyData); + Ric ric = rics.get(policyInfo.ricId); + PolicyType type = policyTypes.get(policyInfo.policyTypeId); + keepServiceAlive(policyInfo.serviceId); if (ric == null || type == null) { return ErrorResponse.createMono("Near-RT RIC or policy type not found", HttpStatus.NOT_FOUND); } Policy policy = ImmutablePolicy.builder() // - .id(instanceId) // + .id(policyInfo.policyId) // .json(jsonString) // .type(type) // .ric(ric) // - .ownerServiceId(serviceId) // + .ownerServiceId(policyInfo.serviceId) // .lastModified(Instant.now()) // - .isTransient(isTransient) // + .isTransient(policyInfo.isTransient) // + .statusNotificationUri(policyInfo.statusNotificationUri == null ? "" : policyInfo.statusNotificationUri) // .build(); final boolean isCreate = this.policies.get(policy.id()) == null; @@ -325,8 +280,8 @@ public class PolicyController { "Returns a list of A1 policies matching given search criteria. <br>" // + "If several query parameters are defined, the policies matching all conditions are returned."; - @GetMapping(path = Consts.V2_API_ROOT + "/policies", produces = MediaType.APPLICATION_JSON_VALUE) - @ApiOperation(value = "Query for existing A1 policies", notes = GET_POLICIES_QUERY_DETAILS) + @GetMapping(path = Consts.V2_API_ROOT + "/policy_instances", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Query for A1 policy instances", notes = GET_POLICIES_QUERY_DETAILS) @ApiResponses(value = { // @ApiResponse(code = 200, message = "Policies", response = PolicyInfoList.class), @ApiResponse(code = 404, message = "Near-RT RIC, policy type or service not found", @@ -353,8 +308,8 @@ public class PolicyController { return new ResponseEntity<>(filteredPolicies, HttpStatus.OK); } - @GetMapping(path = Consts.V2_API_ROOT + "/policy-ids", produces = MediaType.APPLICATION_JSON_VALUE) - @ApiOperation(value = "Query policies, only policy identities are returned", notes = GET_POLICIES_QUERY_DETAILS) + @GetMapping(path = Consts.V2_API_ROOT + "/policies", produces = MediaType.APPLICATION_JSON_VALUE) + @ApiOperation(value = "Query policy identities", notes = GET_POLICIES_QUERY_DETAILS) @ApiResponses(value = { // @ApiResponse(code = 200, message = "Policy identities", response = PolicyIdList.class), @ApiResponse( code = 404, message = "Near-RT RIC or type not found", response = ErrorResponse.ErrorInfo.class)}) @@ -380,27 +335,32 @@ public class PolicyController { return new ResponseEntity<>(policyIdsJson, HttpStatus.OK); } - @GetMapping(path = Consts.V2_API_ROOT + "/policy-status", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(path = Consts.V2_API_ROOT + "/policies/{policy_id}/status", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Returns a policy status") // @ApiResponses(value = { // - @ApiResponse(code = 200, message = "Policy status", response = JsonObject.class), // + @ApiResponse(code = 200, message = "Policy status", response = PolicyStatusInfo.class), // @ApiResponse(code = 404, message = "Policy is not found", response = ErrorResponse.ErrorInfo.class)} // ) public Mono<ResponseEntity<Object>> getPolicyStatus( // - @ApiParam(name = Consts.POLICY_ID_PARAM, required = true, value = "The identity of the policy.") // - @RequestParam(name = Consts.POLICY_ID_PARAM, required = true) String policyId) { + @PathVariable(Consts.POLICY_ID_PARAM) String policyId) { try { Policy policy = policies.getPolicy(policyId); return a1ClientFactory.createA1Client(policy.ric()) // - .flatMap(client -> client.getPolicyStatus(policy)) // - .flatMap(status -> Mono.just(new ResponseEntity<>((Object) status, HttpStatus.OK))) + .flatMap(client -> client.getPolicyStatus(policy).onErrorResume(e -> Mono.just("{}"))) // + .flatMap(status -> createPolicyStatus(policy, status)) // .onErrorResume(this::handleException); } catch (ServiceException e) { return ErrorResponse.createMono(e, HttpStatus.NOT_FOUND); } } + private Mono<ResponseEntity<Object>> createPolicyStatus(Policy policy, String statusFromNearRic) { + PolicyStatusInfo info = new PolicyStatusInfo(policy.lastModified(), fromJson(statusFromNearRic)); + String str = gson.toJson(info); + return Mono.just(new ResponseEntity<>((Object) str, HttpStatus.OK)); + } + private void keepServiceAlive(String name) { Service s = this.services.get(name); if (s != null) { @@ -437,20 +397,27 @@ public class PolicyController { } } + private PolicyInfo toPolicyInfo(Policy p) { + PolicyInfo policyInfo = new PolicyInfo(); + policyInfo.policyId = p.id(); + policyInfo.policyData = fromJson(p.json()); + policyInfo.ricId = p.ric().id(); + policyInfo.policyTypeId = p.type().id(); + policyInfo.serviceId = p.ownerServiceId(); + if (!p.statusNotificationUri().isEmpty()) { + policyInfo.statusNotificationUri = p.statusNotificationUri(); + } + if (!policyInfo.validate()) { + logger.error("BUG, all mandatory fields must be set"); + } + + return policyInfo; + } + private String policiesToJson(Collection<Policy> policies) { List<PolicyInfo> v = new ArrayList<>(policies.size()); for (Policy p : policies) { - PolicyInfo policyInfo = new PolicyInfo(); - policyInfo.policyId = p.id(); - policyInfo.policyData = fromJson(p.json()); - policyInfo.ricId = p.ric().id(); - policyInfo.policyTypeId = p.type().id(); - policyInfo.serviceId = p.ownerServiceId(); - policyInfo.lastModified = p.lastModified().toString(); - if (!policyInfo.validate()) { - logger.error("BUG, all fields must be set"); - } - v.add(policyInfo); + v.add(toPolicyInfo(p)); } PolicyInfoList list = new PolicyInfoList(v); return gson.toJson(list); @@ -460,16 +427,6 @@ public class PolicyController { return gson.fromJson(jsonStr, Object.class); } - private String toPolicyTypeSchemasJson(Collection<PolicyType> types) { - - Collection<String> schemas = new ArrayList<>(); - for (PolicyType t : types) { - schemas.add(t.schema()); - } - PolicySchemaList res = new PolicySchemaList(schemas); - return gson.toJson(res); - } - private String toPolicyTypeIdsJson(Collection<PolicyType> types) { List<String> v = new ArrayList<>(types.size()); for (PolicyType t : types) { diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java index ab812790..0ec2165c 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyInfo.java @@ -32,41 +32,45 @@ import org.immutables.gson.Gson; @ApiModel(value = "policy_info_v2", description = "Information for one A1-P Policy") public class PolicyInfo { - @ApiModelProperty(value = "identity of the policy") - @JsonProperty("policy_id") + @ApiModelProperty(value = "identity of the policy", required = true) + @JsonProperty(value = "policy_id", required = true) @SerializedName("policy_id") public String policyId; - @ApiModelProperty(value = "name of the policy type") + @ApiModelProperty(value = "identity of the policy type", required = true) + @JsonProperty(value = "policy_type_id", required = true) @SerializedName("policy_type_id") - @JsonProperty("policy_type_id") public String policyTypeId; - @ApiModelProperty(value = "identity of the target Near-RT RIC") + @ApiModelProperty(value = "identity of the target Near-RT RIC", required = true) + @JsonProperty(value = "ric_id", required = true) @SerializedName("ric_id") - @JsonProperty("ric_id") public String ricId; - @ApiModelProperty(value = "the configuration of the policy") + @ApiModelProperty(value = "the configuration of the policy", required = true) + @JsonProperty(value = "policy_data", required = true) @SerializedName("policy_data") - @JsonProperty("policy_data") public Object policyData; - @ApiModelProperty(value = "the name of the service owning the policy") + @ApiModelProperty(value = "the name of the service owning the policy", required = true) + @JsonProperty(value = "service_id", required = true) @SerializedName("service_id") - @JsonProperty("service_id") public String serviceId; - @ApiModelProperty(value = "timestamp, last modification time") - @SerializedName("last_modified") - @JsonProperty("last_modified") - public String lastModified; + @ApiModelProperty(value = "the name of the service owning the policy", required = false) + @JsonProperty(value = "transient", required = false) + @SerializedName("transient") + public boolean isTransient; + + @ApiModelProperty(value = "Callback URI for policy status updates", required = false) + @JsonProperty(value = "status_notification_uri", required = false) + @SerializedName("status_notification_uri") + public String statusNotificationUri; PolicyInfo() {} public boolean validate() { - return policyId != null && policyTypeId != null && ricId != null && policyData != null && serviceId != null - && lastModified != null; + return policyId != null && policyTypeId != null && ricId != null && policyData != null && serviceId != null; } } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyStatusInfo.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyStatusInfo.java new file mode 100644 index 00000000..6292f049 --- /dev/null +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyStatusInfo.java @@ -0,0 +1,58 @@ +/*- + * ========================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.controllers.v2; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.annotations.SerializedName; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +import java.time.Instant; + +import org.immutables.gson.Gson; + +@Gson.TypeAdapters +@ApiModel(value = "policy_status_info_v2", description = "Status for one A1-P Policy") +public class PolicyStatusInfo { + + @ApiModelProperty(value = "timestamp, last modification time") + @SerializedName("last_modified") + @JsonProperty("last_modified") + public String lastModified; + + @ApiModelProperty(value = "the Policy status") + @SerializedName("status") + @JsonProperty("status") + public Object status; + + public PolicyStatusInfo() {} + + public PolicyStatusInfo(Instant lastModified, Object statusFromNearRTRic) { + this.lastModified = lastModified.toString(); + this.status = statusFromNearRTRic; + } + + public boolean validate() { + return lastModified != null; + } + +} diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicySchemaList.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java index d550db4e..ff979650 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicySchemaList.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/PolicyTypeInfo.java @@ -28,27 +28,21 @@ import com.google.gson.annotations.SerializedName; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -import java.util.ArrayList; -import java.util.Collection; - import org.immutables.gson.Gson; @Gson.TypeAdapters -@ApiModel(value = "policy_schema_list_v2", description = "Policy type json schemas") -public class PolicySchemaList { +@ApiModel(value = "policy_type_v2", description = "Policy type") +public class PolicyTypeInfo { @ApiModelProperty( - value = "Policy type json schemas. The schema is a json object following http://json-schema.org/draft-07/schema") - @SerializedName("policy_schemas") - @JsonProperty("policy_schemas") - public final Collection<Object> schemas; - - public PolicySchemaList(Collection<String> schemasAsStrings) { - this.schemas = new ArrayList<>(); - for (String str : schemasAsStrings) { - JsonObject jsonObj = JsonParser.parseString(str).getAsJsonObject(); - this.schemas.add(jsonObj); - } + value = "Policy type json scema. The schema is a json object following http://json-schema.org/draft-07/schema") + @SerializedName("policy_schema") + @JsonProperty("policy_schema") + public final Object schema; + + public PolicyTypeInfo(String schemaAsString) { + JsonObject jsonObj = JsonParser.parseString(schemaAsString).getAsJsonObject(); + this.schema = jsonObj; } } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java index a7505016..a77a7e7e 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/RicRepositoryController.java @@ -56,18 +56,17 @@ public class RicRepositoryController { PolicyTypes types; private static Gson gson = new GsonBuilder() // - .serializeNulls() // .create(); // - private static final String GET_RIC_BRIEF = "Returns info for a Near-RT RIC"; + private static final String GET_RIC_BRIEF = "Returns info for one Near-RT RIC"; private static final String GET_RIC_DETAILS = "Either a Near-RT RIC identity or a Mananged Element identity can be specified.<br>" // + "The intention with Mananged Element identity is the ID used in O1 for accessing the traffical element (such as the ID of CU)."; /** - * Example: http://localhost:8081/v2/ric?managed_element_id=kista_1 + * Example: http://localhost:8081/v2/rics/ric?managed_element_id=kista_1 */ - @GetMapping(path = Consts.V2_API_ROOT + "/ric", produces = MediaType.APPLICATION_JSON_VALUE) + @GetMapping(path = Consts.V2_API_ROOT + "/rics/ric", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = GET_RIC_BRIEF, notes = GET_RIC_DETAILS) @ApiResponses(value = { // @ApiResponse(code = 200, message = "Near-RT RIC is found", response = RicInfo.class), // @@ -115,7 +114,9 @@ public class RicRepositoryController { public ResponseEntity<Object> getRics( // @ApiParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false, value = "The identity of a policy type. If given, all Near-RT RICs supporteing the policy type are returned") // - @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String supportingPolicyType) { + @RequestParam(name = Consts.POLICY_TYPE_ID_PARAM, required = false) String supportingPolicyType + + ) { if ((supportingPolicyType != null) && (this.types.get(supportingPolicyType) == null)) { return ErrorResponse.create("Policy type not found", HttpStatus.NOT_FOUND); } diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java index 73e421be..b2fa029a 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ServiceController.java @@ -47,6 +47,7 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; @@ -59,8 +60,7 @@ public class ServiceController { private final Services services; private final Policies policies; - private static Gson gson = new GsonBuilder() // - .create(); // + private static Gson gson = new GsonBuilder().create(); @Autowired ServiceController(Services services, Policies policies) { @@ -102,7 +102,7 @@ public class ServiceController { private void validateRegistrationInfo(ServiceRegistrationInfo registrationInfo) throws ServiceException, MalformedURLException { if (registrationInfo.serviceId.isEmpty()) { - throw new ServiceException("Missing mandatory parameter 'serviceName'"); + throw new ServiceException("Missing mandatory parameter 'service-id'"); } if (registrationInfo.keepAliveIntervalSeconds < 0) { throw new ServiceException("Keepalive interval shoul be greater or equal to 0"); @@ -143,12 +143,11 @@ public class ServiceController { @ApiResponse(code = 204, message = "Service unregistered"), @ApiResponse(code = 200, message = "Not used", response = VoidResponse.class), @ApiResponse(code = 404, message = "Service not found", response = ErrorResponse.ErrorInfo.class)}) - @DeleteMapping(Consts.V2_API_ROOT + "/services") + @DeleteMapping(Consts.V2_API_ROOT + "/services/{serviceId}") public ResponseEntity<Object> deleteService(// - @ApiParam(name = Consts.SERVICE_ID_PARAM, required = true, value = "The idenitity of the service") // - @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceName) { + @PathVariable("serviceId") String serviceId) { try { - Service service = removeService(serviceName); + Service service = removeService(serviceId); // Remove the policies from the repo and let the consistency monitoring // do the rest. removePolicies(service); @@ -164,12 +163,11 @@ public class ServiceController { @ApiResponse(code = 404, message = "The service is not found, needs re-registration", response = ErrorResponse.ErrorInfo.class)}) - @PutMapping(Consts.V2_API_ROOT + "/services/keepalive") + @PutMapping(Consts.V2_API_ROOT + "/services/{service_id}/keepalive") public ResponseEntity<Object> keepAliveService(// - @ApiParam(name = Consts.SERVICE_ID_PARAM, required = true, value = "The identity of the service") // - @RequestParam(name = Consts.SERVICE_ID_PARAM, required = true) String serviceName) { + @PathVariable(Consts.SERVICE_ID_PARAM) String serviceId) { try { - services.getService(serviceName).keepAlive(); + services.getService(serviceId).keepAlive(); return new ResponseEntity<>(HttpStatus.OK); } catch (ServiceException e) { return ErrorResponse.create(e, HttpStatus.NOT_FOUND); diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policy.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policy.java index 752d8dac..efafa684 100644 --- a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policy.java +++ b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/repository/Policy.java @@ -41,4 +41,6 @@ public interface Policy { public Instant lastModified(); public boolean isTransient(); + + public String statusNotificationUri(); } 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 index 92d75b54..83b73d18 100644 --- 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 @@ -192,6 +192,7 @@ class MockPolicyManagementService { .type(unnamedPolicyType) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("statusNotificationUri") // .build(); this.policies.put(policy); } 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 index cec5c2c6..100e95e2 100644 --- 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 @@ -56,6 +56,7 @@ public class A1ClientHelper { } protected static Policy createPolicy(String nearRtRicUrl, String policyId, String json, String type) { + String callbackUrl = "https://test.com"; return ImmutablePolicy.builder() // .id(policyId) // .json(json) // @@ -64,6 +65,7 @@ public class A1ClientHelper { .type(createPolicyType(type)) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri(callbackUrl) // .build(); } 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 index a0e95177..4eca44d4 100644 --- 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 @@ -268,7 +268,8 @@ class SdncOscA1ClientTest { @Test void putPolicy_STD_V2() { - String expUrl = RIC_1_URL + "/A1-P/v2/policytypes/type1/policies/policy1"; + String expUrl = + RIC_1_URL + "/A1-P/v2/policytypes/type1/policies/policy1?notificationDestination=https://test.com"; putPolicy(A1ProtocolType.SDNC_OSC_STD_V2_0_0, expUrl); } diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientV2Test.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientV2Test.java index d9238d64..de55882b 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientV2Test.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/clients/StdA1ClientV2Test.java @@ -23,6 +23,7 @@ package org.onap.ccsdk.oran.a1policymanagementservice.clients; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -35,6 +36,7 @@ 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.ArgumentCaptor; import org.mockito.junit.jupiter.MockitoExtension; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ImmutableRicConfig; import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig; @@ -46,9 +48,9 @@ import reactor.test.StepVerifier; @ExtendWith(MockitoExtension.class) class StdA1ClientV2Test { - private static final String RIC_URL = "RicUrl"; + private static final String RIC_URL = "https://ric.com"; - private static final String RIC_BASE_URL = "RicBaseUrl/A1-P/v2"; + private static final String RIC_BASE_URL = RIC_URL + "/A1-P/v2"; private static final String POLICYTYPES_IDENTITIES_URL = RIC_BASE_URL + "/policytypes"; private static final String POLICIES = "/policies"; @@ -69,7 +71,7 @@ class StdA1ClientV2Test { void init() { RicConfig ricConfig = ImmutableRicConfig.builder() // .ricId("name") // - .baseUrl("RicBaseUrl") // + .baseUrl(RIC_URL) // .managedElementIds(new ArrayList<>()) // .controllerName("") // .build(); @@ -146,8 +148,11 @@ class StdA1ClientV2Test { 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); + ArgumentCaptor<String> urlCaptor = ArgumentCaptor.forClass(String.class); + verify(asyncRestClientMock).put(urlCaptor.capture(), eq(POLICY_JSON_VALID)); + String actualUrl = urlCaptor.getValue(); + String expUrl = POLICYTYPES_URL + POLICY_TYPE_1_ID + POLICIES + "/" + POLICY_1_ID; + assertThat(actualUrl).contains(expUrl); } @Test diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ApplicationTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ApplicationTest.java index 97d0b504..551ed599 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ApplicationTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v1/ApplicationTest.java @@ -119,9 +119,7 @@ class ApplicationTest { @Autowired Services services; - private static Gson gson = new GsonBuilder() // - .serializeNulls() // - .create(); // + private static Gson gson = new GsonBuilder().create(); public static class MockApplicationConfig extends ApplicationConfig { @Override @@ -670,6 +668,7 @@ class ApplicationTest { .type(addPolicyType(typeName, ric)) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("/policy_status?id=XXX") // .build(); policies.put(policy); return policy; diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java index 5128cd52..0fc252d8 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java @@ -122,9 +122,7 @@ class ApplicationTest { @Autowired Services services; - private static Gson gson = new GsonBuilder() // - .serializeNulls() // - .create(); // + private static Gson gson = new GsonBuilder().create(); public static class MockApplicationConfig extends ApplicationConfig { @Override @@ -289,41 +287,42 @@ class ApplicationTest { String managedElementId = "kista_1"; addRic(ricId, managedElementId); - String url = "/ric?managed_element_id=" + managedElementId; + String url = "/rics/ric?managed_element_id=" + managedElementId; String rsp = restClient().get(url).block(); RicInfo ricInfo = gson.fromJson(rsp, RicInfo.class); assertThat(ricInfo.ricId).isEqualTo(ricId); - url = "/ric?ric_id=" + ricId; + url = "/rics/ric?ric_id=" + ricId; rsp = restClient().get(url).block(); ricInfo = gson.fromJson(rsp, RicInfo.class); assertThat(ricInfo.ricId).isEqualTo(ricId); // test GET RIC for ManagedElement that does not exist - url = "/ric?managed_element_id=" + "junk"; + url = "/rics/ric?managed_element_id=" + "junk"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); - url = "/ric"; + url = "/rics/ric"; testErrorCode(restClient().get(url), HttpStatus.BAD_REQUEST); } - private String putPolicyUrl(String serviceName, String ricId, String policyTypeName, String policyInstanceId, + private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId, boolean isTransient) { - String url; - if (policyTypeName.isEmpty()) { - url = "/policy?policy_id=" + policyInstanceId + "&ric_id=" + ricId + "&service_id=" + serviceName; - } else { - url = "/policy?policy_id=" + policyInstanceId + "&ric_id=" + ricId + "&service_id=" + serviceName - + "&policytype_id=" + policyTypeName; - } + PolicyInfo info = new PolicyInfo(); + info.policyId = policyInstanceId; + info.policyTypeId = policyTypeName; + info.ricId = ricId; + info.serviceId = serviceName; + info.policyData = gson.fromJson(jsonString(), Object.class); + if (isTransient) { - url += "&transient=true"; + info.isTransient = isTransient; } - return url; + info.statusNotificationUri = "statusNotificationUri"; + return gson.toJson(info); } - private String putPolicyUrl(String serviceName, String ricId, String policyTypeName, String policyInstanceId) { - return putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId, false); + private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId) { + return putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId, false); } @Test @@ -337,8 +336,8 @@ class ApplicationTest { addPolicyType(policyTypeName, ricId); // PUT a transient policy - String url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId, true); - final String policyBody = jsonString(); + String url = "/policies"; + String policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId, true); this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE); restClient().put(url, policyBody).block(); @@ -351,28 +350,29 @@ class ApplicationTest { assertThat(policy.isTransient()).isTrue(); // Put a non transient policy - url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId); + policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId); restClient().put(url, policyBody).block(); policy = policies.getPolicy(policyInstanceId); assertThat(policy.isTransient()).isFalse(); - url = "/policies"; + url = "/policy_instances"; String rsp = restClient().get(url).block(); assertThat(rsp).as("Response contains policy instance ID.").contains(policyInstanceId); - url = "/policy?policy_id=" + policyInstanceId; + url = "/policies/" + policyInstanceId; rsp = restClient().get(url).block(); - assertThat(rsp).isEqualTo(policyBody); + assertThat(rsp).contains(policyBody); // Test of error codes - url = putPolicyUrl(serviceName, ricId + "XX", policyTypeName, policyInstanceId); + url = "/policies"; + policyBody = putPolicyBody(serviceName, ricId + "XX", policyTypeName, policyInstanceId); testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND); - url = putPolicyUrl(serviceName, ricId, policyTypeName + "XX", policyInstanceId); + policyBody = putPolicyBody(serviceName, ricId, policyTypeName + "XX", policyInstanceId); addPolicyType(policyTypeName + "XX", "otherRic"); testErrorCode(restClient().put(url, policyBody), HttpStatus.NOT_FOUND); - url = putPolicyUrl(serviceName, ricId, policyTypeName, policyInstanceId); + policyBody = putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId); this.rics.getRic(ricId).setState(Ric.RicState.SYNCHRONIZING); testErrorCode(restClient().put(url, policyBody), HttpStatus.LOCKED); this.rics.getRic(ricId).setState(Ric.RicState.AVAILABLE); @@ -389,7 +389,6 @@ class ApplicationTest { 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"; @@ -400,32 +399,25 @@ class ApplicationTest { doReturn(Mono.error(a1Exception)).when(a1Client).putPolicy(any()); // PUT Policy - testErrorCode(restClient().put(url, "{}"), httpStatus, responseBody); + String putBody = putPolicyBody("service1", "ric1", "type1", "id1"); + String url = "/policies"; + testErrorCode(restClient().put(url, putBody), httpStatus, responseBody); // DELETE POLICY this.addPolicy("instance1", "type1", "service1", "ric1"); doReturn(Mono.error(a1Exception)).when(a1Client).deletePolicy(any()); - testErrorCode(restClient().delete("/policy?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?policy_id=instance1"), httpStatus, responseBody); + testErrorCode(restClient().delete("/policies/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?policy_id=instance1"), httpStatus); } @Test void testPutTypelessPolicy() throws Exception { putService("service1"); addPolicyType("", "ric1"); - String url = putPolicyUrl("service1", "ric1", "", "id1"); - restClient().put(url, jsonString()).block(); + String body = putPolicyBody("service1", "ric1", "", "id1"); + restClient().put("/policies", body).block(); - String rsp = restClient().get("/policies").block(); + String rsp = restClient().get("/policy_instances").block(); PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class); assertThat(info.policies).hasSize(1); PolicyInfo policyInfo = info.policies.iterator().next(); @@ -443,17 +435,19 @@ class ApplicationTest { this.addPolicy("instance2", "type1", "service1", "ricXXX"); // Try change ric1 -> ricXXX - String urlWrongRic = putPolicyUrl("service1", "ricXXX", "type1", "instance1"); - testErrorCode(restClient().put(urlWrongRic, jsonString()), HttpStatus.CONFLICT); + String bodyWrongRic = putPolicyBody("service1", "ricXXX", "type1", "instance1"); + testErrorCode(restClient().put("/policies", bodyWrongRic), HttpStatus.CONFLICT); } @Test void testGetPolicy() throws Exception { - String url = "/policy?policy_id=id"; + String url = "/policies/id"; Policy policy = addPolicy("id", "typeName", "service1", "ric1"); { String rsp = restClient().get(url).block(); - assertThat(rsp).isEqualTo(policy.json()); + PolicyInfo info = gson.fromJson(rsp, PolicyInfo.class); + String policyStr = gson.toJson(info.policyData); + assertThat(policyStr).isEqualTo(policy.json()); } { policies.remove(policy); @@ -466,7 +460,7 @@ class ApplicationTest { addPolicy("id", "typeName", "service1", "ric1"); assertThat(policies.size()).isEqualTo(1); - String url = "/policy?policy_id=id"; + String url = "/policies/id"; ResponseEntity<String> entity = restClient().deleteForEntity(url).block(); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); @@ -477,50 +471,19 @@ class ApplicationTest { } @Test - void testGetPolicySchemas() throws Exception { + void testGetPolicyType() throws Exception { addPolicyType("type1", "ric1"); - addPolicyType("type2", "ric2"); waitForRicState("ric1", RicState.AVAILABLE); - waitForRicState("ric2", RicState.AVAILABLE); - String url = "/policy-schemas"; + String url = "/policy-types/type1"; String rsp = this.restClient().get(url).block(); - assertThat(rsp).contains("type1") // - .contains("{\"title\":\"type2\"}"); - - PolicySchemaList info = parseSchemas(rsp); - assertThat(info.schemas).hasSize(2); - - url = "/policy-schemas?ric_id=ric1"; - rsp = restClient().get(url).block(); - assertThat(rsp).contains("type1"); - info = parseSchemas(rsp); - assertThat(info.schemas).hasSize(1); - - // Schema for type - url = "/policy-schemas?policytype_id=type1"; - rsp = restClient().get(url).block(); - assertThat(rsp).contains("type1") // - .contains("title"); - - // Both type and ric specified - url = "/policy-schemas?ric_id=ric1&policytype_id=type1"; - rsp = restClient().get(url).block(); - PolicySchemaList list = gson.fromJson(rsp, PolicySchemaList.class); - assertThat(list.schemas).hasSize(1); - url = "/policy-schemas?ric_id=ric1&policytype_id=type2"; - rsp = restClient().get(url).block(); - list = gson.fromJson(rsp, PolicySchemaList.class); - assertThat(list.schemas).isEmpty(); - - // Get schema for non existing RIC - url = "/policy-schemas?ric_id=ric1XXX"; - testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); + PolicyTypeInfo info = gson.fromJson(rsp, PolicyTypeInfo.class); + assertThat(info.schema).isNotNull(); // Get non existing schema - url = "/policy-schemas?policytype_id=type1XX"; + url = "/policy-types/JUNK"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); } @@ -552,10 +515,10 @@ class ApplicationTest { } @Test - void testGetPolicies() throws Exception { + void testGetPolicyInstances() throws Exception { addPolicy("id1", "type1", "service1"); - String url = "/policies"; + String url = "/policy_instances"; String rsp = restClient().get(url).block(); logger.info(rsp); PolicyInfoList info = gson.fromJson(rsp, PolicyInfoList.class); @@ -568,19 +531,19 @@ class ApplicationTest { } @Test - void testGetPoliciesFilter() throws Exception { + void testGetPolicyInstancesFilter() throws Exception { addPolicy("id1", "type1", "service1"); addPolicy("id2", "type1", "service2"); addPolicy("id3", "type2", "service1"); - String url = "/policies?policytype_id=type1"; + String url = "/policy_instances?policytype_id=type1"; String rsp = restClient().get(url).block(); logger.info(rsp); assertThat(rsp).contains("id1") // .contains("id2") // .doesNotContain("id3"); - url = "/policies?policytype_id=type1&service_id=service2"; + url = "/policy_instances?policytype_id=type1&service_id=service2"; rsp = restClient().get(url).block(); logger.info(rsp); assertThat(rsp).doesNotContain("id1") // @@ -588,11 +551,11 @@ class ApplicationTest { .doesNotContain("id3"); // Test get policies for non existing type - url = "/policies?policytype_id=type1XXX"; + url = "/policy_instances?policytype_id=type1XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); // Test get policies for non existing RIC - url = "/policies?ric_id=XXX"; + url = "/policy_instances?ric_id=XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); } @@ -602,24 +565,24 @@ class ApplicationTest { addPolicy("id2", "type1", "service2", "ric1"); addPolicy("id3", "type2", "service1", "ric1"); - String url = "/policy-ids?policytype_id=type1"; + String url = "/policies?policytype_id=type1"; String rsp = restClient().get(url).block(); logger.info(rsp); assertThat(rsp).contains("id1") // .contains("id2") // .doesNotContain("id3"); - url = "/policy-ids?policytype_id=type1&service_id=service1&ric=ric1"; + url = "/policies?policytype_id=type1&service_id=service1&ric=ric1"; rsp = restClient().get(url).block(); PolicyIdList respList = gson.fromJson(rsp, PolicyIdList.class); assertThat(respList.policyIds.iterator().next()).isEqualTo("id1"); // Test get policy ids for non existing type - url = "/policy-ids?policytype_id=type1XXX"; + url = "/policies?policytype_id=type1XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); // Test get policy ids for non existing RIC - url = "/policy-ids?ric_id=XXX"; + url = "/policies?ric_id=XXX"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); } @@ -646,18 +609,18 @@ class ApplicationTest { logger.info(rsp); // Keep alive - url = "/services/keepalive?service_id=name"; + url = "/services/name/keepalive"; ResponseEntity<?> entity = restClient().putForEntity(url).block(); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); // DELETE service assertThat(services.size()).isEqualTo(1); - url = "/services?service_id=name"; + url = "/services/name"; restClient().delete(url).block(); assertThat(services.size()).isZero(); // Keep alive, no registered service - testErrorCode(restClient().put("/services/keepalive?service_id=name", ""), HttpStatus.NOT_FOUND); + testErrorCode(restClient().put("/services/junk/keepalive", ""), HttpStatus.NOT_FOUND); // PUT service with bad payload testErrorCode(restClient().put("/services", "crap"), HttpStatus.BAD_REQUEST, false); @@ -676,9 +639,8 @@ class ApplicationTest { putService("service1", 1, HttpStatus.CREATED); addPolicyType("type1", "ric1"); - String url = putPolicyUrl("service1", "ric1", "type1", "instance1"); - final String policyBody = jsonString(); - restClient().put(url, policyBody).block(); + String policyBody = putPolicyBody("service1", "ric1", "type1", "instance1"); + restClient().put("/policies", policyBody).block(); assertThat(policies.size()).isEqualTo(1); assertThat(services.size()).isEqualTo(1); @@ -693,13 +655,24 @@ class ApplicationTest { addPolicy("id", "typeName", "service1", "ric1"); assertThat(policies.size()).isEqualTo(1); - String url = "/policy-status?policy_id=id"; + String url = "/policies/id/status"; String rsp = restClient().get(url).block(); - assertThat(rsp).isEqualTo("OK"); + PolicyStatusInfo info = gson.fromJson(rsp, PolicyStatusInfo.class); + assertThat(info.status).isEqualTo("OK"); // GET non existing policy status - url = "/policy-status?policy_id=XXX"; + url = "/policies/XXX/status"; testErrorCode(restClient().get(url), HttpStatus.NOT_FOUND); + + // GET STATUS, the NearRT RIC returns error + MockA1Client a1Client = a1ClientFactory.getOrCreateA1Client("ric1"); + url = "/policies/id/status"; + WebClientResponseException a1Exception = new WebClientResponseException(404, "", null, null, null); + doReturn(Mono.error(a1Exception)).when(a1Client).getPolicyStatus(any()); + rsp = restClient().get(url).block(); + info = gson.fromJson(rsp, PolicyStatusInfo.class); + assertThat(info.status.toString()).isEqualTo("{}"); + } private Policy addPolicy(String id, String typeName, String service, String ric) throws ServiceException { @@ -712,6 +685,7 @@ class ApplicationTest { .type(addPolicyType(typeName, ric)) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("/policy_status?id=XXX") // .build(); policies.put(policy); return policy; @@ -884,7 +858,4 @@ class ApplicationTest { return ric; } - private static PolicySchemaList parseSchemas(String jsonString) { - return gson.fromJson(jsonString, PolicySchemaList.class); - } } diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java index 89a76e95..f8369610 100644 --- a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java +++ b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ConcurrencyTestRunnable.java @@ -20,6 +20,9 @@ package org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import java.time.Instant; import java.util.concurrent.atomic.AtomicInteger; @@ -52,6 +55,8 @@ class ConcurrencyTestRunnable implements Runnable { private final PolicyTypes types; private boolean failed = false; + private static Gson gson = new GsonBuilder().create(); + ConcurrencyTestRunnable(AsyncRestClient client, RicSupervision supervision, MockA1ClientFactory a1ClientFactory, Rics rics, PolicyTypes types) { this.count = nextCount.incrementAndGet(); @@ -85,7 +90,7 @@ class ConcurrencyTestRunnable implements Runnable { createInconsistency(); this.supervision.checkAllRics(); } - String name = "policy:" + count + ":" + i; + String name = "policy_" + count + "_" + i; putPolicy(name); putPolicy(name + "-"); listPolicies(); @@ -115,6 +120,7 @@ class ConcurrencyTestRunnable implements Runnable { .ownerServiceId("") // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("/policy_status?id=XXX") // .build(); } @@ -122,11 +128,10 @@ class ConcurrencyTestRunnable implements Runnable { MockA1Client client = a1ClientFactory.getOrCreateA1Client("ric"); Policy policy = createPolicyObject("junk"); client.putPolicy(policy).block(); - } private void listPolicies() { - String uri = "/policies"; + String uri = "/policy_instances"; webClient.getForEntity(uri).block(); } @@ -136,12 +141,28 @@ class ConcurrencyTestRunnable implements Runnable { } private void putPolicy(String name) { - String putUrl = "/policy?policytype_id=type1&policy_id=" + name + "&ric_id=ric&service_id=service1"; - webClient.putForEntity(putUrl, "{}").block(); + String putUrl = "/policies"; + String body = putPolicyBody("service1", "ric", "type1", name, false); + webClient.putForEntity(putUrl, body).block(); + } + + private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId, + boolean isTransient) { + PolicyInfo info = new PolicyInfo(); + info.policyId = policyInstanceId; + info.policyTypeId = policyTypeName; + info.ricId = ricId; + info.serviceId = serviceName; + info.policyData = gson.fromJson("{}", Object.class); + + if (isTransient) { + info.isTransient = isTransient; + } + return gson.toJson(info); } private void deletePolicy(String name) { - String deleteUrl = "/policy?policy_id=" + name; + String deleteUrl = "/policies/" + name; webClient.delete(deleteUrl).block(); } } 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 index 4cc23607..04951ee7 100644 --- 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 @@ -312,6 +312,7 @@ class RefreshConfigTaskTest { .json("{}") // .ownerServiceId("ownerServiceId") // .isTransient(false) // + .statusNotificationUri("/policy_status?id=XXX") // .build(); return policy; } 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 index ca5a6192..4e72bbf6 100644 --- 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 @@ -81,6 +81,7 @@ class RicSupervisionTest { .type(POLICY_TYPE_1) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("statusNotificationUri") // .build(); private static final Policy POLICY_2 = ImmutablePolicy.builder() // @@ -91,6 +92,7 @@ class RicSupervisionTest { .type(POLICY_TYPE_1) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("statusNotificationUri") // .build(); @Mock 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 index 0ac8fdb0..a50d4ab7 100644 --- 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 @@ -92,6 +92,7 @@ class RicSynchronizationTaskTest { .type(POLICY_TYPE_1) // .lastModified(Instant.now()) // .isTransient(isTransient) // + .statusNotificationUri("statusNotificationUri") // .build(); } 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 index 1a8e9b3e..c8476221 100644 --- 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 @@ -90,6 +90,7 @@ class ServiceSupervisionTest { .type(policyType) // .lastModified(Instant.now()) // .isTransient(false) // + .statusNotificationUri("statusNotificationUri") // .build(); @Test |