Implementing Create Policy for V3 08/137808/6
authorraviteja.karumuri <raviteja.karumuri@est.tech>
Thu, 28 Mar 2024 18:22:42 +0000 (18:22 +0000)
committerraviteja.karumuri <raviteja.karumuri@est.tech>
Wed, 29 May 2024 16:09:25 +0000 (17:09 +0100)
Issue-ID: CCSDK-4003
Change-Id: I0da2525c8ef273f23519e9bb4332f64e92e23cb8
Signed-off-by: Raviteja Karumuri <raviteja.karumuri@est.tech>
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/Consts.java
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerV3.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/AuthorizationService.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/ErrorHandlingService.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyService.java [new file with mode: 0644]
a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/Helper.java [new file with mode: 0644]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/config/TestConfig.java [new file with mode: 0644]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v2/ApplicationTest.java
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerTest.java [new file with mode: 0644]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyServiceTest.java [new file with mode: 0644]
a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/v3/TestHelper.java [new file with mode: 0644]

index c554dbd..21da2f7 100644 (file)
@@ -32,6 +32,8 @@ public class Consts {
 
     public static final String V2_API_ROOT = "/a1-policy/v2";
 
+    public static final String V3_API_ROOT = "/a1policymanagement/v1";
+
     public static final String V2_API_SERVICE_CALLBACKS_NAME = "Service callbacks";
     public static final String V2_API_SERVICE_CALLBACKS_DESCRIPTION = "";
 
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerV3.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerV3.java
new file mode 100644 (file)
index 0000000..36da71d
--- /dev/null
@@ -0,0 +1,95 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.v3;
+
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.api.v3.A1PolicyManagementApi;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.Consts;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyController;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyTypeInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Ric;
+import org.onap.ccsdk.oran.a1policymanagementservice.service.v3.PolicyService;
+import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.Helper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+@RestController("PolicyControllerV3")
+@Tag(//
+        name = PolicyController.API_NAME, //
+        description = PolicyController.API_DESCRIPTION //
+)
+@RequestMapping(Consts.V3_API_ROOT)
+public class PolicyControllerV3 implements A1PolicyManagementApi {
+    public static final String API_NAME = "A1 Policy Management";
+    public static final String API_DESCRIPTION = "API to create,update and get policies or policy definitions";
+    @Autowired
+    private PolicyService policyService;
+
+    @Autowired
+    private Helper helper;
+
+    private PolicyType policyType;
+
+    private Ric ric;
+    @Override
+    public Mono<ResponseEntity<PolicyObjectInformation>> createPolicy(Mono<PolicyObjectInformation> policyObjectInformation, ServerWebExchange exchange) {
+        return policyObjectInformation.flatMap(policyObjectInfo -> {
+            return policyService.createPolicyService(policyObjectInfo, exchange);
+        });
+    }
+
+    @Override
+    public Mono<ResponseEntity<Void>> deletePolicy(String policyId, String accept, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+
+    @Override
+    public Mono<ResponseEntity<Object>> getPolicy(String policyId, String accept, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+
+    @Override
+    public Mono<ResponseEntity<Flux<PolicyInformation>>> getPolicyIds(String policyTypeId, String nearRtRicId, String serviceId, String typeName, String accept, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+
+    @Override
+    public Mono<ResponseEntity<Object>> getPolicyTypeDefinition(String policyTypeId, String accept, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+
+    @Override
+    public Mono<ResponseEntity<Flux<PolicyTypeInformation>>> getPolicyTypes(String nearRtRicId, String typeName, String compatibleWithVersion, String accept, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+
+    @Override
+    public Mono<ResponseEntity<Object>> putPolicy(String policyId, Mono<Object> body, ServerWebExchange exchange) throws Exception {
+        return null;
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/AuthorizationService.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/AuthorizationService.java
new file mode 100644 (file)
index 0000000..ac4320a
--- /dev/null
@@ -0,0 +1,42 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.service.v3;
+
+
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.AuthorizationCheck;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest.Input.AccessType;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+@Service
+public class AuthorizationService {
+
+    @Autowired
+    private AuthorizationCheck authorization;
+
+    public Mono<Policy> authCheck (ServerWebExchange serverWebExchange, Policy policy, AccessType accessType){
+        return authorization.doAccessControl(serverWebExchange.getRequest().getHeaders().toSingleValueMap(),
+                policy, AccessType.WRITE);
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/ErrorHandlingService.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/ErrorHandlingService.java
new file mode 100644 (file)
index 0000000..693ae51
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.service.v3;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.PolicyController;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.ProblemDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.reactive.function.client.WebClientException;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+import reactor.core.publisher.Mono;
+
+import java.lang.invoke.MethodHandles;
+import java.math.BigDecimal;
+
+@Service
+public class ErrorHandlingService {
+
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+    public Mono<ResponseEntity<ProblemDetails>> handleError(Throwable throwable) {
+        if (throwable instanceof WebClientResponseException) {
+            WebClientResponseException e = (WebClientResponseException) throwable;
+            return createErrorResponse(e.getResponseBodyAsString(), e.getStatusCode());
+        } else if (throwable instanceof WebClientException) {
+            WebClientException e = (WebClientException) throwable;
+            return createErrorResponse(e.getMessage(), HttpStatus.BAD_GATEWAY);
+        } else if (throwable instanceof ServiceException) {
+            ServiceException e = (ServiceException) throwable;
+            return createErrorResponse(e.getMessage(), e.getHttpStatus());
+        } else {
+            return createErrorResponse(throwable.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
+        }
+    }
+
+    public Mono<ResponseEntity<ProblemDetails>> createErrorResponse(String errorBody, HttpStatusCode statusCode) {
+        logger.debug("Error content: {}, with status code {}", errorBody, statusCode);
+        ProblemDetails problemDetail = new ProblemDetails().type("about:blank");
+        problemDetail.setDetail(errorBody);
+        problemDetail.setStatus(new BigDecimal(statusCode.value()));
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_PROBLEM_JSON);
+        return Mono.just(new ResponseEntity<>(problemDetail, headers, statusCode));
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyService.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyService.java
new file mode 100644 (file)
index 0000000..6c994b4
--- /dev/null
@@ -0,0 +1,96 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.service.v3;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.authorization.PolicyAuthorizationRequest.Input.AccessType;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.*;
+import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.Helper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+@Service
+public class PolicyService {
+
+    @Autowired
+    private Helper helper;
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    private PolicyTypes policyTypes;
+
+    @Autowired
+    private Policies policies;
+
+    @Autowired
+    private AuthorizationService authorizationService;
+
+    @Autowired
+    private A1ClientFactory a1ClientFactory;
+
+    @Autowired
+    private ErrorHandlingService errorHandlingService;
+
+    public Mono<ResponseEntity<PolicyObjectInformation>> createPolicyService
+            (PolicyObjectInformation policyObjectInfo, ServerWebExchange serverWebExchange) {
+        try {
+            if (!helper.jsonSchemaValidation(policyObjectInfo.getPolicyObject()))
+                return Mono.error(new ServiceException("Schema validation failed", HttpStatus.BAD_REQUEST));
+            Ric ric = rics.getRic(policyObjectInfo.getNearRtRicId());
+            PolicyType policyType = policyTypes.getType(policyObjectInfo.getPolicyTypeId());
+            Policy policy = helper.buildPolicy(policyObjectInfo, policyType, ric, helper.policyIdGeneration());
+            return helper.isPolicyAlreadyCreated(policy,policies)
+                    .doOnError(error -> errorHandlingService.handleError(error))
+                    .flatMap(policyBuilt -> authorizationService.authCheck(serverWebExchange, policy, AccessType.WRITE))
+                    .doOnError(error -> errorHandlingService.handleError(error))
+                    .flatMap(policyNotUsed -> ric.getLock().lock(Lock.LockType.SHARED, "createPolicy"))
+                    .flatMap(grant -> postPolicy(policy, grant))
+                    .map(locationHeaderValue ->
+                            new ResponseEntity<PolicyObjectInformation>(policyObjectInfo,helper.createHttpHeaders(
+                                    "location",helper.buildURI(policy.getId(), serverWebExchange)), HttpStatus.CREATED))
+                    .doOnError(error -> errorHandlingService.handleError(error));
+        } catch (Exception ex) {
+            return Mono.error(ex);
+        }
+
+    }
+
+    private Mono<String> postPolicy(Policy policy, Lock.Grant grant) {
+        return  helper.checkRicStateIdle(policy.getRic())
+                .doOnError(error -> errorHandlingService.handleError(error))
+                .flatMap(ric -> helper.checkSupportedType(ric, policy.getType()))
+                .doOnError(error -> errorHandlingService.handleError(error))
+                .flatMap(ric -> a1ClientFactory.createA1Client(ric))
+                .flatMap(a1Client -> a1Client.putPolicy(policy))
+                .doOnError(error -> errorHandlingService.handleError(error))
+                .doOnNext(policyString -> policies.put(policy))
+                .doFinally(releaseLock -> grant.unlockBlocking())
+                .doOnError(error -> errorHandlingService.handleError(error));
+    }
+}
diff --git a/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/Helper.java b/a1-policy-management/src/main/java/org/onap/ccsdk/oran/a1policymanagementservice/util/v3/Helper.java
new file mode 100644 (file)
index 0000000..11edbfd
--- /dev/null
@@ -0,0 +1,128 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.util.v3;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.util.UriComponentsBuilder;
+import reactor.core.publisher.Mono;
+
+import java.lang.invoke.MethodHandles;
+import java.time.Instant;
+import java.util.UUID;
+
+@Component
+public class Helper {
+
+    @Autowired
+    private Services services;
+
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    private static Gson gson = new GsonBuilder().create();
+    public void keepServiceAlive(String name) {
+        Service s = this.services.get(name);
+        if (s != null) {
+            s.keepAlive();
+        }
+    }
+
+    public Mono<Ric> checkRicStateIdle(Ric ric) {
+        if (ric.getState() == Ric.RicState.AVAILABLE) {
+            return Mono.just(ric);
+        } else {
+            logger.debug("Request rejected Near-RT RIC not IDLE, ric: {}", ric);
+            ServiceException e = new ServiceException(
+                    "Near-RT RIC: is not operational, id: " + ric.id() + ", state: " + ric.getState(),
+                    HttpStatus.LOCKED);
+            return Mono.error(e);
+        }
+    }
+
+    public Mono<Ric> checkSupportedType(Ric ric, PolicyType type) {
+        if (!ric.isSupportingType(type.getId())) {
+            logger.debug("Request rejected, type not supported, RIC: {}", ric);
+            ServiceException e = new ServiceException(
+                    "Type: " + type.getId() + " not supported by RIC: " + ric.id(), HttpStatus.BAD_REQUEST);
+            return Mono.error(e);
+        }
+        return Mono.just(ric);
+    }
+
+    public Policy buildPolicy(PolicyObjectInformation policyObjectInformation, PolicyType policyType, Ric ric, String policyId) {
+        return Policy.builder()
+                .id(policyId)
+                .json(toJson(policyObjectInformation.getPolicyObject()))
+                .type(policyType)
+                .ric(ric)
+                .ownerServiceId(policyObjectInformation.getServiceId() == null ? ""
+                        : policyObjectInformation.getServiceId())
+                .lastModified(Instant.now())
+                .isTransient(policyObjectInformation.getTransient())
+                .statusNotificationUri(policyObjectInformation.getStatusNotificationUri() == null ? ""
+                        : policyObjectInformation.getStatusNotificationUri())
+                .build();
+    }
+
+    public Boolean jsonSchemaValidation(Object jsonObject) {
+        String jsonString = toJson(jsonObject);
+        return true;
+    }
+
+    public String policyIdGeneration() {
+        return UUID.randomUUID().toString();
+    }
+
+    public String toJson(Object jsonObject) {
+        return gson.toJson(jsonObject);
+    }
+
+    public HttpHeaders createHttpHeaders(String headerName, String headerValue) {
+        HttpHeaders httpHeaders = new HttpHeaders();
+        httpHeaders.add(headerName, headerValue);
+        return httpHeaders;
+    }
+
+    public String buildURI(String policyId, ServerWebExchange serverWebExchange) {
+        return UriComponentsBuilder.fromHttpRequest(serverWebExchange.getRequest())
+                .path("/{id}")
+                .buildAndExpand(policyId)
+                .toString();
+    }
+
+    public Mono<Policy> isPolicyAlreadyCreated(Policy policy, Policies policies) {
+        if (policies.get(policy.getId()) != null) {
+            return Mono.error(new ServiceException
+                    ("Policy already created with ID: " + policy.getId(), HttpStatus.CONFLICT));
+        }
+            return Mono.just(policy);
+    }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/config/TestConfig.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/config/TestConfig.java
new file mode 100644 (file)
index 0000000..19e4d79
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.config;
+
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.tasks.ServiceSupervision;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
+import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+
+import java.time.Duration;
+
+@TestConfiguration
+public class TestConfig {
+
+    @Bean
+    A1ClientFactory getA1ClientFactory(@Autowired ApplicationConfig appConfig, @Autowired PolicyTypes types) {
+        return new MockA1ClientFactory(appConfig, types);
+    }
+
+    @Bean
+    public ServiceSupervision getServiceSupervision(@Autowired Services services,
+                                                    @Autowired A1ClientFactory a1ClientFactory, @Autowired Policies policies) {
+        Duration checkInterval = Duration.ofMillis(1);
+        return new ServiceSupervision(services, policies, a1ClientFactory, checkInterval);
+    }
+
+    @Bean
+    public ServletWebServerFactory servletContainer() {
+        return new TomcatServletWebServerFactory();
+    }
+}
\ No newline at end of file
index 2ff4416..4f3fa5f 100644 (file)
@@ -497,19 +497,6 @@ class ApplicationTest {
         return objectMapper.writeValueAsString(policyInfo);
     }
 
-    private String putPolicyBod(String serviceName, String ricId, String policyTypeName, String policyInstanceId,
-                                       boolean isTransient, String statusNotificationUri) throws JsonProcessingException {
-        PolicyInfo policyInfo = new PolicyInfo();
-        policyInfo.setPolicyId(policyInstanceId);
-        policyInfo.setPolicytypeId(policyTypeName);
-        policyInfo.setRicId(ricId);
-        policyInfo.setServiceId(serviceName);
-        policyInfo.setPolicyData(jsonString());
-        policyInfo.setTransient(isTransient);
-        policyInfo.setStatusNotificationUri(statusNotificationUri);
-        return objectMapper.writeValueAsString(policyInfo);
-    }
-
     private String putPolicyBody(String serviceName, String ricId, String policyTypeName, String policyInstanceId) throws JsonProcessingException {
         return putPolicyBody(serviceName, ricId, policyTypeName, policyInstanceId, false, "statusUri");
     }
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/controllers/v3/PolicyControllerTest.java
new file mode 100644 (file)
index 0000000..b8404a6
--- /dev/null
@@ -0,0 +1,180 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.v3;
+
+import org.junit.jupiter.api.*;
+import org.mockito.Mockito;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
+import org.onap.ccsdk.oran.a1policymanagementservice.config.TestConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.OpenPolicyAgentSimulatorController;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.RappSimulatorController;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Services;
+import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.Helper;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.MockA1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.v3.TestHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.util.FileSystemUtils;
+import reactor.core.publisher.Mono;
+
+import java.lang.invoke.MethodHandles;
+import java.nio.file.Path;
+
+import static org.mockito.Mockito.when;
+
+@TestMethodOrder(MethodOrderer.MethodName.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ContextConfiguration(classes = TestConfig.class)
+@TestPropertySource(properties = { //
+        "server.ssl.key-store=./config/keystore.jks", //
+        "app.webclient.trust-store=./config/truststore.jks", //
+        "app.webclient.trust-store-used=true", //
+        "app.vardata-directory=/tmp/pmstestv3", //
+        "app.filepath=", //
+        "app.s3.bucket=" // If this is set, S3 will be used to store data.
+})
+public class PolicyControllerTest {
+    private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+    @Autowired
+    private ApplicationConfig applicationConfig;
+    @Autowired
+    private TestHelper testHelper;
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    private Policies policies;
+
+    @Autowired
+    private PolicyTypes policyTypes;
+
+    @Autowired
+    private Services services;
+
+    @Autowired
+    private MockA1ClientFactory a1ClientFactory;
+
+    @Autowired
+    private RappSimulatorController rAppSimulator;
+
+    @Autowired
+    private SecurityContext securityContext;
+
+    @Autowired
+    private OpenPolicyAgentSimulatorController openPolicyAgentSimulatorController;
+
+    @LocalServerPort
+    private int port;
+
+    @SpyBean
+    private Helper helper;
+
+    @BeforeEach
+    void init() {
+        testHelper.port = port;
+        this.applicationConfig.setAuthProviderUrl(testHelper.baseUrl() + OpenPolicyAgentSimulatorController.ACCESS_CONTROL_URL);
+    }
+
+    @AfterEach
+    void reset() {
+        rics.clear();
+        policies.clear();
+        policyTypes.clear();
+        services.clear();
+        a1ClientFactory.reset();
+        this.rAppSimulator.getTestResults().clear();
+        this.a1ClientFactory.setPolicyTypes(policyTypes); // Default same types in RIC and in this app
+        this.securityContext.setAuthTokenFilePath(null);
+        this.openPolicyAgentSimulatorController.getTestResults().reset();
+    }
+
+    @AfterAll
+    static void clearTestDir() {
+        try {
+            FileSystemUtils.deleteRecursively(Path.of("/tmp/pmstestv3"));
+        } catch (Exception e) {
+            logger.warn("Could test directory : {}", e.getMessage());
+        }
+    }
+
+    @Test
+    @DisplayName("test Create Policy")
+    void testPostPolicy() throws Exception {
+        String nonRtRicId = "ric.1";
+        String policyTypeName = "type1_1.2.3";
+        String url = "/policies";
+        testHelper.addPolicyType(policyTypeName, nonRtRicId);
+        String policyBody = testHelper.postPolicyBody(nonRtRicId, policyTypeName);
+        Mono<ResponseEntity<String>> responseMono = testHelper.restClientV3().postForEntity(url, policyBody);
+        testHelper.testSuccessResponse(responseMono, HttpStatus.CREATED, "{\"servingCellNrcgi\":\"1\"}");
+    }
+
+    @Test
+    @DisplayName("test Create Policy schema validation fail case")
+    void testPolicySchemaValidationFail() throws Exception {
+        String nonRtRicId = "ric.1";
+        String policyTypeName = "type1_1.2.3";
+        String url = "/policies";
+        testHelper.addPolicyType(policyTypeName, nonRtRicId);
+
+        when(helper.jsonSchemaValidation(Mockito.any())).thenReturn(Boolean.FALSE);
+        String policyBody = testHelper.postPolicyBody(nonRtRicId, policyTypeName);
+        Mono<ResponseEntity<String>> responseMono = testHelper.restClientV3().postForEntity(url, policyBody);
+        testHelper.testErrorCode(responseMono, HttpStatus.BAD_REQUEST, " Schema validation failed");
+    }
+
+    @Test
+    @DisplayName("test Create Policy No Ric fail case")
+    void testCreatePolicyNoRic() throws Exception {
+        String policyTypeName = "type1_1.2.3";
+        String url = "/policies";
+        testHelper.addPolicyType(policyTypeName, " ");
+        String policyBody = testHelper.postPolicyBody("noRic", policyTypeName);
+        Mono<ResponseEntity<String>> responseMono = testHelper.restClientV3().postForEntity(url, policyBody);
+        testHelper.testErrorCode(responseMono, HttpStatus.NOT_FOUND, " Could not find ric: noRic");
+    }
+
+    @Test
+    @DisplayName("test Create Policy with No Policy Type fail case")
+    void testCreatePolicyNoPolicyType() throws Exception {
+        String policyTypeName = "type1_1.2.3";
+        String nonRtRicId = "ricOne";
+        String url = "/policies";
+        testHelper.addPolicyType(policyTypeName, nonRtRicId);
+        String policyBody = testHelper.postPolicyBody(nonRtRicId, "noPolicyType");
+        Mono<ResponseEntity<String>> responseMono = testHelper.restClientV3().postForEntity(url, policyBody);
+        testHelper.testErrorCode(responseMono, HttpStatus.NOT_FOUND, "Could not find type: noPolicyType");
+    }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyServiceTest.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/service/v3/PolicyServiceTest.java
new file mode 100644 (file)
index 0000000..a67a0bb
--- /dev/null
@@ -0,0 +1,106 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. 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.service.v3;
+
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.mockito.Mockito;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.A1ClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.exceptions.ServiceException;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policies;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Policy;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.PolicyTypes;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.Rics;
+import org.onap.ccsdk.oran.a1policymanagementservice.util.v3.Helper;
+import org.onap.ccsdk.oran.a1policymanagementservice.utils.v3.TestHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.server.ServerWebExchange;
+import org.springframework.web.server.adapter.DefaultServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+@TestMethodOrder(MethodOrderer.MethodName.class)
+@SpringBootTest()
+public class PolicyServiceTest {
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    private PolicyTypes policyTypes;
+
+    @Autowired
+    private Policies policies;
+
+    @Autowired
+    private A1ClientFactory a1ClientFactory;
+
+    @Autowired
+    private ErrorHandlingService errorHandlingService;
+
+    @Autowired
+    private PolicyService policyService;
+
+    @Autowired
+    private TestHelper testHelper;
+
+    @MockBean
+    private Helper helper;
+
+    @MockBean
+    private AuthorizationService authorizationService;
+
+    @Test
+    public void testPolicyAlreadyCreatedFail() {
+
+        String policyTypeName = "uri_type_123";
+        String nonRtRicId = "Ric_347";
+        testHelper.addPolicyType(policyTypeName, nonRtRicId);
+        ServerWebExchange serverWebExchange = Mockito.mock(DefaultServerWebExchange.class);
+        when(helper.jsonSchemaValidation(any())).thenReturn(Boolean.TRUE);
+        when(helper.isPolicyAlreadyCreated(any(), any())).thenReturn(Mono.error(new ServiceException
+                ("Policy already created", HttpStatus.CONFLICT)));
+        Mono<ResponseEntity<PolicyObjectInformation>> responseMono = policyService.createPolicyService(testHelper.policyObjectInfo(nonRtRicId, policyTypeName), serverWebExchange);
+        testHelper.verifyMockError(responseMono, "Policy already created");
+    }
+
+    @Test
+    public void testPolicyNotAuthorizedFail() {
+
+        String policyTypeName = "uri_type_123";
+        String nonRtRicId = "Ric_347";
+        testHelper.addPolicyType(policyTypeName, nonRtRicId);
+        ServerWebExchange serverWebExchange = Mockito.mock(DefaultServerWebExchange.class);
+        when(helper.jsonSchemaValidation(any())).thenReturn(Boolean.TRUE);
+        when(helper.isPolicyAlreadyCreated(any(), any())).thenReturn(Mono.just(Policy.builder().build()));
+        when(authorizationService.authCheck(any(), any(), any())).thenReturn(Mono.error(new ServiceException("Not authorized", HttpStatus.UNAUTHORIZED)));
+        Mono<ResponseEntity<PolicyObjectInformation>> responseMono = policyService.createPolicyService(testHelper.policyObjectInfo(nonRtRicId, policyTypeName), serverWebExchange);
+        testHelper.verifyMockError(responseMono, "Not authorized");
+    }
+}
diff --git a/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/v3/TestHelper.java b/a1-policy-management/src/test/java/org/onap/ccsdk/oran/a1policymanagementservice/utils/v3/TestHelper.java
new file mode 100644 (file)
index 0000000..bfad88a
--- /dev/null
@@ -0,0 +1,267 @@
+/*-
+ * ========================LICENSE_START=================================
+ * ONAP : ccsdk oran
+ * ======================================================================
+ * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
+ * ======================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.onap.ccsdk.oran.a1policymanagementservice.utils.v3;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClient;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.AsyncRestClientFactory;
+import org.onap.ccsdk.oran.a1policymanagementservice.clients.SecurityContext;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.ApplicationConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.RicConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.configuration.WebClientConfig;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.Consts;
+import org.onap.ccsdk.oran.a1policymanagementservice.controllers.v2.RappSimulatorController;
+import org.onap.ccsdk.oran.a1policymanagementservice.models.v3.PolicyObjectInformation;
+import org.onap.ccsdk.oran.a1policymanagementservice.repository.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.WebClientResponseException;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+import reactor.util.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.*;
+
+@Component
+public class TestHelper {
+
+    @Autowired
+    ApplicationConfig applicationConfig;
+
+    @Autowired
+    ApplicationContext context;
+
+    @Autowired
+    private Rics rics;
+
+    @Autowired
+    private Policies policies;
+
+    @Autowired
+    private PolicyTypes policyTypes;
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    public int port;
+
+    public AsyncRestClient restClientV3() {
+        return restClientV3(false);
+    }
+
+    public AsyncRestClient restClient() {
+        return restClient(false);
+    }
+
+    public AsyncRestClient restClient(String baseUrl, boolean useTrustValidation) {
+        WebClientConfig config = this.applicationConfig.getWebClientConfig();
+        config = WebClientConfig.builder()
+                .keyStoreType(config.getKeyStoreType())
+                .keyStorePassword(config.getKeyStorePassword())
+                .keyStore(config.getKeyStore())
+                .keyPassword(config.getKeyPassword())
+                .isTrustStoreUsed(useTrustValidation)
+                .trustStore(config.getTrustStore())
+                .trustStorePassword(config.getTrustStorePassword())
+                .httpProxyConfig(config.getHttpProxyConfig())
+                .build();
+
+        AsyncRestClientFactory f = new AsyncRestClientFactory(config, new SecurityContext(""));
+        return f.createRestClientNoHttpProxy(baseUrl);
+
+    }
+
+    public String baseUrl() {
+        return "https://localhost:" + port;
+    }
+
+    public AsyncRestClient restClientV3(boolean useTrustValidation) {
+        return restClient(baseUrl() + Consts.V3_API_ROOT, useTrustValidation);
+    }
+
+    public AsyncRestClient restClient(boolean useTrustValidation) {
+        return restClient(baseUrl() + Consts.V2_API_ROOT, useTrustValidation);
+    }
+
+    public void putService(String name) throws JsonProcessingException {
+        putService(name, 0, null);
+    }
+
+    public void putService(String name, long keepAliveIntervalSeconds, @Nullable HttpStatus expectedStatus) throws JsonProcessingException {
+        String url = "/services";
+        String body = createServiceJson(name, keepAliveIntervalSeconds);
+        ResponseEntity<String> resp = restClient().putForEntity(url, body).block();
+        if (expectedStatus != null) {
+            assertNotNull(resp);
+            assertEquals(expectedStatus, resp.getStatusCode(), "");
+        }
+    }
+
+    public PolicyType createPolicyType(String policyTypeName) {
+        return PolicyType.builder()
+                .id(policyTypeName)
+                .schema("{\"title\":\"" + policyTypeName + "\"}")
+                .build();
+    }
+
+    public Ric addRic(String ricId) {
+        return addRic(ricId, null);
+    }
+
+    public RicConfig ricConfig(String ricId, String managedElement) {
+        List<String> mes = new ArrayList<>();
+        if (managedElement != null) {
+            mes.add(managedElement);
+        }
+        return RicConfig.builder()
+                .ricId(ricId)
+                .baseUrl(ricId)
+                .managedElementIds(mes)
+                .build();
+    }
+    public Ric addRic(String ricId, String managedElement) {
+        if (rics.get(ricId) != null) {
+            return rics.get(ricId);
+        }
+
+        RicConfig conf = ricConfig(ricId, managedElement);
+        Ric ric = new Ric(conf);
+        ric.setState(Ric.RicState.AVAILABLE);
+        this.rics.put(ric);
+        return ric;
+    }
+    public PolicyType addPolicyType(String policyTypeName, String ricId) {
+        PolicyType type = createPolicyType(policyTypeName);
+        policyTypes.put(type);
+        addRic(ricId).addSupportedPolicyType(type);
+        return type;
+    }
+
+    public Map<String,String> jsonString() {
+        Map<String,String> policyDataInMap = new HashMap<>();
+        policyDataInMap.put("servingCellNrcgi","1");
+        return policyDataInMap;
+    }
+
+    public String postPolicyBody(String nearRtRicId, String policyTypeName) throws JsonProcessingException {
+        PolicyObjectInformation policyObjectInfo = new PolicyObjectInformation(nearRtRicId, jsonString());
+        policyObjectInfo.setPolicyTypeId(policyTypeName);
+        policyObjectInfo.setPolicyObject(dummyPolicyObject());
+        return objectMapper.writeValueAsString(policyObjectInfo);
+    }
+
+    public PolicyObjectInformation policyObjectInfo(String nearRtRicId, String policyTypeName) {
+        PolicyObjectInformation policyObjectInfo = new PolicyObjectInformation(nearRtRicId, jsonString());
+        policyObjectInfo.setPolicyTypeId(policyTypeName);
+        policyObjectInfo.setPolicyObject(dummyPolicyObject());
+        return policyObjectInfo;
+    }
+
+    private Map<String,String> dummyPolicyObject() {
+        Map<String,String> policyDataInMap = new HashMap<>();
+        policyDataInMap.put("servingCellNrcgi","1");
+        return policyDataInMap;
+    }
+
+    public String createServiceJson(String name, long keepAliveIntervalSeconds) throws JsonProcessingException {
+        String callbackUrl = baseUrl() + RappSimulatorController.SERVICE_CALLBACK_URL;
+        return createServiceJson(name, keepAliveIntervalSeconds, callbackUrl);
+    }
+
+    public String createServiceJson(String name, long keepAliveIntervalSeconds, String url) throws JsonProcessingException {
+        org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceRegistrationInfo service = new org.onap.ccsdk.oran.a1policymanagementservice.models.v2.ServiceRegistrationInfo(name)
+                .keepAliveIntervalSeconds(keepAliveIntervalSeconds)
+                .callbackUrl(url);
+
+        return objectMapper.writeValueAsString(service);
+    }
+
+    public void testSuccessResponse(Mono<ResponseEntity<String>> responseEntityMono, HttpStatus httpStatusCode,
+                                    String responseContains) {
+        StepVerifier.create(responseEntityMono)
+                .expectNextMatches(responseEntity -> {
+                    // Assert status code
+                    HttpStatusCode status = responseEntity.getStatusCode();
+                    String res = responseEntity.getBody();
+                    assertThat(res).contains(responseContains);
+                    return status.value() == httpStatusCode.value();
+                })
+                .expectComplete()
+                .verify();
+    }
+
+    public void testErrorCode(Mono<?> request, HttpStatus expStatus) {
+        testErrorCode(request, expStatus, "", true);
+    }
+
+    public void testErrorCode(Mono<?> request, HttpStatus expStatus, boolean expectApplicationProblemJsonMediaType) {
+        testErrorCode(request, expStatus, "", expectApplicationProblemJsonMediaType);
+    }
+
+    public void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains) {
+        testErrorCode(request, expStatus, responseContains, true);
+    }
+
+    public void testErrorCode(Mono<?> request, HttpStatus expStatus, String responseContains,
+                               boolean expectApplicationProblemJsonMediaType) {
+        StepVerifier.create(request)
+                .expectSubscription()
+                .expectErrorMatches(
+                        t -> checkWebClientError(t, expStatus, responseContains, expectApplicationProblemJsonMediaType))
+                .verify();
+    }
+
+    private boolean checkWebClientError(Throwable throwable, HttpStatus expStatus, String responseContains,
+                                        boolean expectApplicationProblemJsonMediaType) {
+        assertTrue(throwable instanceof WebClientResponseException);
+        WebClientResponseException responseException = (WebClientResponseException) throwable;
+        String body = responseException.getResponseBodyAsString();
+        assertThat(body).contains(responseContains);
+        assertThat(responseException.getStatusCode()).isEqualTo(expStatus);
+
+        if (expectApplicationProblemJsonMediaType) {
+            assertThat(responseException.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_PROBLEM_JSON);
+        }
+        return true;
+    }
+
+    public void verifyMockError(Mono<?> responseMono, String responseCheck) {
+        StepVerifier.create(responseMono)
+                .expectSubscription()
+                .expectErrorMatches(response -> {
+                    String status = response.getMessage();
+                    return status.contains(responseCheck);
+                })
+                .verify();
+    }
+}