From 0c4fc775af4f2d3065b275b191986673470d7384 Mon Sep 17 00:00:00 2001 From: Grzegorz Wielgosinski Date: Mon, 21 Feb 2022 14:18:54 +0100 Subject: Add synchronization DTO and implement multicloud client Issue-ID: SO-3845 Signed-off-by: Grzegorz Wielgosinski Signed-off-by: Lukasz Rajewski Change-Id: I397c3592fe96af98405acf8fe43d87ea325f1745 --- .../so/adapters/cnf/client/MulticloudApiUrl.java | 6 +- .../so/adapters/cnf/client/MulticloudClient.java | 78 ++++++++++- .../model/synchronization/NotificationRequest.java | 75 ++++++++++ .../model/synchronization/SubscriptionRequest.java | 85 ++++++++++++ .../synchronization/SubscriptionResponse.java | 118 ++++++++++++++++ .../onap/so/adapters/cnf/rest/CnfAdapterRest.java | 13 +- .../cnf/rest/SubscriptionNotifyController.java | 81 +++++++++++ .../so/adapters/cnf/service/CnfAdapterService.java | 16 +-- .../SubscriptionsRecoveryProvider.java | 29 ++++ .../synchrornization/SynchronizationService.java | 151 +++++++++++++++++++++ .../adapters/cnf/client/MulticloudClientTest.java | 99 +++++++++++++- .../cnf/service/CnfAdapterServiceTest.java | 44 ++---- .../SubscriptionsRecoveryProvider.java | 17 +++ .../SynchronizationServiceTest.java | 96 +++++++++++++ 14 files changed, 859 insertions(+), 49 deletions(-) create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/NotificationRequest.java create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionRequest.java create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionResponse.java create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/SubscriptionNotifyController.java create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java create mode 100644 so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationService.java create mode 100644 so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java create mode 100644 so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationServiceTest.java (limited to 'so-cnf-adapter-application/src') diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudApiUrl.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudApiUrl.java index d21b97a..617eef7 100644 --- a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudApiUrl.java +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudApiUrl.java @@ -13,7 +13,11 @@ class MulticloudApiUrl { } String apiUrl(String instanceId) { - return multicloudConfiguration.getMulticloudUrl() + "/v1/instance/" + instanceId; + String url = multicloudConfiguration.getMulticloudUrl() + "/v1/instance"; + if (!instanceId.isEmpty()) { + url += "/" + instanceId; + } + return url; } } \ No newline at end of file diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudClient.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudClient.java index 5edb34c..0f5df15 100644 --- a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudClient.java +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/client/MulticloudClient.java @@ -23,11 +23,13 @@ package org.onap.so.adapters.cnf.client; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import org.onap.so.adapters.cnf.MulticloudConfiguration; +import org.onap.so.adapters.cnf.model.InstanceResponse; import org.onap.so.adapters.cnf.model.MulticloudInstanceRequest; import org.onap.so.adapters.cnf.model.healthcheck.K8sRbInstanceHealthCheck; import org.onap.so.adapters.cnf.model.healthcheck.K8sRbInstanceHealthCheckSimple; import org.onap.so.adapters.cnf.model.statuscheck.K8sRbInstanceStatus; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionRequest; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionResponse; import org.onap.so.client.exception.BadResponseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,9 +39,11 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static org.springframework.http.HttpMethod.DELETE; @@ -61,6 +65,78 @@ public class MulticloudClient { this.objectMapper = new ObjectMapper(); } + public List getAllInstances() throws BadResponseException { + String endpoint = multicloudApiUrl.apiUrl(""); + ResponseEntity result = restTemplate.exchange(endpoint, GET, getHttpEntity(), String.class); + checkResponseStatusCode(result); + log.info("getAllInstances response status: {}", result.getStatusCode()); + String body = result.getBody(); + log.debug("getAllInstances response body: {}", body); + + try { + return Arrays.asList(objectMapper.readValue(body, InstanceResponse[].class)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public SubscriptionResponse registerSubscription(String instanceId, SubscriptionRequest subscriptionRequest) throws BadResponseException { + String endpoint = multicloudApiUrl.apiUrl(instanceId) + "/status/subscription"; + ResponseEntity result = restTemplate.exchange(endpoint, POST, getHttpEntity(subscriptionRequest), String.class); + checkResponseStatusCode(result); + log.info("registerSubscription response status: {}", result.getStatusCode()); + String body = result.getBody(); + log.debug("registerSubscription response body: {}", body); + + try { + return objectMapper.readValue(body, SubscriptionResponse.class); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public Boolean hasSubscription(String instanceId, String subscriptionId) throws BadResponseException { + String endpoint = multicloudApiUrl.apiUrl(instanceId) + "/status/subscription/" + subscriptionId; + try { + ResponseEntity result = restTemplate.exchange(endpoint, GET, getHttpEntity(), String.class); + checkResponseStatusCode(result); + log.info("hasSubscription response status: {}", result.getStatusCode()); + return true; + } catch (HttpServerErrorException e) { + if (e.getMessage().contains("no documents")) { + log.info("hasSubscription response status: {}", 500); + return false; + } else + throw e; + } + } + + public SubscriptionResponse getSubscription(String instanceId, String subscriptionId) throws BadResponseException { + String endpoint = multicloudApiUrl.apiUrl(instanceId) + "/status/subscription/" + subscriptionId; + try { + ResponseEntity result = restTemplate.exchange(endpoint, GET, getHttpEntity(), String.class); + checkResponseStatusCode(result); + log.info("getSubscription response status: {}", result.getStatusCode()); + String body = result.getBody(); + log.debug("getSubscription response body: {}", body); + return objectMapper.readValue(body, SubscriptionResponse.class); + } catch (HttpServerErrorException e) { + if (e.getMessage().contains("no documents")) { + throw new BadResponseException("Multicloud response status error 404"); + } else + throw e; + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + public void deleteSubscription(String instanceId, String subscriptionId) throws BadResponseException { + String endpoint = multicloudApiUrl.apiUrl(instanceId) + "/status/subscription/" + subscriptionId; + ResponseEntity result = restTemplate.exchange(endpoint, DELETE, getHttpEntity(), String.class); + checkResponseStatusCode(result); + log.info("deleteSubscription response status: {}", result.getStatusCode()); + } + public String upgradeInstance(String instanceId, MulticloudInstanceRequest upgradeRequest) throws BadResponseException { String endpoint = multicloudApiUrl.apiUrl(instanceId) + "/upgrade"; ResponseEntity result = restTemplate.exchange(endpoint, POST, getHttpEntity(upgradeRequest), String.class); diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/NotificationRequest.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/NotificationRequest.java new file mode 100644 index 0000000..e0b021f --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/NotificationRequest.java @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.model.synchronization; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; + +import java.util.Map; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(value = "true") +public class NotificationRequest { + + @JsonProperty("instance-id") + private String instanceId; + @JsonProperty("subscription-name") + private String subscriptionName; + @JsonProperty("metadata") + private AaiRequest metadata; + + public NotificationRequest() { } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(String instanceId) { + this.instanceId = instanceId; + } + + public String getSubscriptionName() { + return subscriptionName; + } + + public void setSubscriptionName(String subscriptionName) { + this.subscriptionName = subscriptionName; + } + + public AaiRequest getMetadata() { + return metadata; + } + + public void setMetadata(AaiRequest metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return "NotificationRequest{" + + "instanceId='" + instanceId + '\'' + + ", subscriptionName='" + subscriptionName + '\'' + + ", metadata=" + metadata + + '}'; + } +} diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionRequest.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionRequest.java new file mode 100644 index 0000000..238eef5 --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionRequest.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.model.synchronization; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(value = "true") +public class SubscriptionRequest { + + @JsonProperty(value = "name") + private String name; + + @JsonProperty(value = "callback-url") + private String callbackUrl; + + @JsonProperty(value = "min-notify-interval") + private int minNotifyInterval; + + @JsonProperty(value = "metadata") + private AaiRequest metadata; + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getMinNotifyInterval() { + return minNotifyInterval; + } + + public void setMinNotifyInterval(int minNotifyInterval) { + this.minNotifyInterval = minNotifyInterval; + } + + public AaiRequest getMetadata() { + return metadata; + } + + public void setMetadata(AaiRequest metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return "SubscriptionRequest{" + + "callbackUrl='" + callbackUrl + '\'' + + ", name='" + name + '\'' + + ", minNotifyInterval=" + minNotifyInterval + + ", metadata='" + metadata + '\'' + + '}'; + } +} diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionResponse.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionResponse.java new file mode 100644 index 0000000..5f05126 --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/model/synchronization/SubscriptionResponse.java @@ -0,0 +1,118 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.model.synchronization; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.Date; + +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +public class SubscriptionResponse { + + @JsonProperty("callback-url") + private String callbackUrl; + @JsonProperty("name") + private String name; + @JsonProperty("last-update-time") + private Date lastUpdateTime; + @JsonProperty("last-notify-time") + private Date lastNotifyTime; + @JsonProperty("last-notify-status") + private int lastNotifyStatus; + @JsonProperty("min-notify-interval") + private int minNotifyInterval; + @JsonProperty("metadata ") + private String metadata; + + public SubscriptionResponse() { } + + public String getCallbackUrl() { + return callbackUrl; + } + + public void setCallbackUrl(String callbackUrl) { + this.callbackUrl = callbackUrl; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Date getLastUpdateTime() { + return lastUpdateTime; + } + + public void setLastUpdateTime(Date lastUpdateTime) { + this.lastUpdateTime = lastUpdateTime; + } + + public Date getLastNotifyTime() { + return lastNotifyTime; + } + + public void setLastNotifyTime(Date lastNotifyTime) { + this.lastNotifyTime = lastNotifyTime; + } + + public int getLastNotifyStatus() { + return lastNotifyStatus; + } + + public void setLastNotifyStatus(int lastNotifyStatus) { + this.lastNotifyStatus = lastNotifyStatus; + } + + public int getMinNotifyInterval() { + return minNotifyInterval; + } + + public void setMinNotifyInterval(int minNotifyInterval) { + this.minNotifyInterval = minNotifyInterval; + } + + public String getMetadata() { + return metadata; + } + + public void setMetadata(String metadata) { + this.metadata = metadata; + } + + @Override + public String toString() { + return "SubscriptionResponse{" + + "callbackUrl='" + callbackUrl + '\'' + + ", name='" + name + '\'' + + ", lastUpdateTime=" + lastUpdateTime + + ", lastNotifyTime=" + lastNotifyTime + + ", lastNotifyStatus=" + lastNotifyStatus + + ", minNotifyInterval=" + minNotifyInterval + + ", metadata='" + metadata + '\'' + + '}'; + } +} diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/CnfAdapterRest.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/CnfAdapterRest.java index 3272ad9..df674f8 100644 --- a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/CnfAdapterRest.java +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/CnfAdapterRest.java @@ -59,6 +59,7 @@ import org.onap.so.adapters.cnf.service.CnfAdapterService; import org.onap.so.adapters.cnf.service.aai.AaiService; import org.onap.so.adapters.cnf.service.healthcheck.HealthCheckService; import org.onap.so.adapters.cnf.service.statuscheck.SimpleStatusCheckService; +import org.onap.so.adapters.cnf.service.synchrornization.SynchronizationService; import org.onap.so.adapters.cnf.service.upgrade.InstanceUpgradeService; import org.onap.so.client.exception.BadResponseException; import org.slf4j.Logger; @@ -89,6 +90,7 @@ public class CnfAdapterRest { private final CnfAdapterService cnfAdapterService; private final SoCallbackClient callbackClient; private final AaiService aaiService; + private final SynchronizationService synchronizationService; private final String uri; @Autowired @@ -98,6 +100,7 @@ public class CnfAdapterRest { CnfAdapterService cnfAdapterService, SoCallbackClient callbackClient, AaiService aaiService, + SynchronizationService synchronizationService, MulticloudConfiguration multicloudConfiguration) { this.simpleStatusCheckService = simpleStatusCheckService; this.healthCheckService = healthCheckService; @@ -105,6 +108,7 @@ public class CnfAdapterRest { this.cnfAdapterService = cnfAdapterService; this.aaiService = aaiService; this.callbackClient = callbackClient; + this.synchronizationService = synchronizationService; this.uri = multicloudConfiguration.getMulticloudUrl(); } @@ -154,6 +158,7 @@ public class CnfAdapterRest { AaiCallbackResponse callbackResponse = new AaiCallbackResponse(); try { aaiService.aaiUpdate(aaiRequest); + synchronizationService.createSubscriptionIfNotExists(aaiRequest); callbackResponse.setCompletionStatus(AaiCallbackResponse.CompletionStatus.COMPLETED); } catch (Exception e) { logger.warn("Failed to create resource in AAI", e); @@ -178,6 +183,7 @@ public class CnfAdapterRest { logger.info("Processing aai delete"); AaiCallbackResponse callbackResponse = new AaiCallbackResponse(); try { + synchronizationService.deleteSubscriptionIfExists(aaiRequest); aaiService.aaiDelete(aaiRequest); callbackResponse.setCompletionStatus(AaiCallbackResponse.CompletionStatus.COMPLETED); } catch (Exception e) { @@ -218,9 +224,7 @@ public class CnfAdapterRest { @ResponseBody @RequestMapping(value = {"/api/cnf-adapter/v1/instance"}, method = RequestMethod.POST, produces = "application/json", consumes = "application/json") - public String createInstance(@RequestBody BpmnInstanceRequest bpmnInstanceRequest) - throws JsonParseException, JsonMappingException, IOException { - + public String createInstance(@RequestBody BpmnInstanceRequest bpmnInstanceRequest) throws BadResponseException { logger.info("createInstance called."); return cnfAdapterService.createInstance(bpmnInstanceRequest); } @@ -294,8 +298,7 @@ public class CnfAdapterRest { @ResponseBody @RequestMapping(value = {"/api/cnf-adapter/v1/instance/{instID}"}, method = RequestMethod.DELETE, produces = "application/json") - public String deleteInstanceByInstanceId(@PathVariable("instID") String instanceID) - throws JsonParseException, JsonMappingException, IOException { + public String deleteInstanceByInstanceId(@PathVariable("instID") String instanceID) throws BadResponseException { logger.info("deleteInstanceByInstanceId called."); if (instanceID == null || instanceID.isEmpty() || instanceID.equals("null")) { diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/SubscriptionNotifyController.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/SubscriptionNotifyController.java new file mode 100644 index 0000000..88df42b --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/rest/SubscriptionNotifyController.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.rest; + + +import com.google.gson.Gson; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; +import org.onap.so.adapters.cnf.model.synchronization.NotificationRequest; +import org.onap.so.adapters.cnf.service.aai.AaiService; +import org.onap.so.adapters.cnf.service.synchrornization.SynchronizationService; +import org.onap.so.client.exception.BadResponseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class SubscriptionNotifyController { + + private static final Logger logger = LoggerFactory.getLogger(SubscriptionNotifyController.class); + private final static Gson gson = new Gson(); + + private final AaiService aaiService; + private final SynchronizationService synchronizationService; + + public SubscriptionNotifyController(AaiService aaiService, SynchronizationService synchronizationService) { + this.aaiService = aaiService; + this.synchronizationService = synchronizationService; + } + + @PostMapping(value = "/api/cnf-adapter/v1/instance/{instanceId}/status/notify") + public ResponseEntity subscriptionNotifyEndpoint(@PathVariable String instanceId, + @RequestBody NotificationRequest body) throws BadResponseException { + String subscriptionName = synchronizationService.getSubscriptionName(instanceId); + boolean isSubscriptionActive = synchronizationService.isSubscriptionActive(subscriptionName); + if (isSubscriptionActive) { + logger.info("AAI update- START"); + aaiService.aaiUpdate(body.getMetadata()); + return ResponseEntity + .accepted() + .build(); + } else { + return ResponseEntity + .badRequest() + .body(String.format("Cannot handle notification. Subscription %s not exists", subscriptionName)); + } + } + + private AaiRequest convertMetadataToAaiRequest(Map metadata) { + String json = gson.toJsonTree(metadata) + .getAsJsonObject() + .get("metadata") + .toString(); + + return gson.fromJson(json, AaiRequest.class); + } + +} diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/CnfAdapterService.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/CnfAdapterService.java index 7e667a0..6d84911 100644 --- a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/CnfAdapterService.java +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/CnfAdapterService.java @@ -24,14 +24,15 @@ package org.onap.so.adapters.cnf.service; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; +import com.google.gson.Gson; import org.apache.http.HttpStatus; +import org.json.JSONObject; import org.onap.so.adapters.cnf.MulticloudConfiguration; import org.onap.so.adapters.cnf.model.BpmnInstanceRequest; -import org.onap.so.adapters.cnf.model.CheckInstanceRequest; import org.onap.so.adapters.cnf.model.MulticloudInstanceRequest; -import org.onap.so.adapters.cnf.model.healthcheck.HealthCheckResponse; -import org.onap.so.adapters.cnf.service.healthcheck.HealthCheckService; -import org.onap.so.adapters.cnf.service.statuscheck.SimpleStatusCheckService; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; +import org.onap.so.adapters.cnf.service.synchrornization.SynchronizationService; +import org.onap.so.client.exception.BadResponseException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -66,8 +67,7 @@ public class CnfAdapterService { this.uri = multicloudConfiguration.getMulticloudUrl(); } - public String createInstance(BpmnInstanceRequest bpmnInstanceRequest) - throws JsonParseException, JsonMappingException, IOException { + public String createInstance(BpmnInstanceRequest bpmnInstanceRequest) { try { logger.info("CnfAdapterService createInstance called"); MulticloudInstanceRequest multicloudInstanceRequest = new MulticloudInstanceRequest(); @@ -262,8 +262,7 @@ public class CnfAdapterService { } } - public String deleteInstanceByInstanceId(String instanceId) - throws JsonParseException, JsonMappingException, IOException { + public String deleteInstanceByInstanceId(String instanceId) { logger.info("CnfAdapterService deleteInstanceByInstanceId called"); ResponseEntity result = null; @@ -278,6 +277,7 @@ public class CnfAdapterService { logger.info("request: " + requestEntity); result = restTemplate.exchange(endpoint, HttpMethod.DELETE, requestEntity, String.class); logger.info("response: " + result); + return result.getBody(); } catch (HttpClientErrorException e) { logger.error("Error Calling Multicloud, e"); diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java new file mode 100644 index 0000000..68b49a8 --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java @@ -0,0 +1,29 @@ +package org.onap.so.adapters.cnf.service.synchrornization; + +import org.onap.so.adapters.cnf.client.MulticloudClient; +import org.onap.so.adapters.cnf.model.InstanceResponse; +import org.onap.so.client.exception.BadResponseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Set; +import java.util.stream.Collectors; + +@Component +public class SubscriptionsRecoveryProvider { + + private final MulticloudClient multicloudClient; + + public SubscriptionsRecoveryProvider(MulticloudClient multicloudClient) { + this.multicloudClient = multicloudClient; + } + + public Set getInstanceList() throws BadResponseException { + Set instanceIds; + instanceIds = multicloudClient.getAllInstances().stream() + .map(InstanceResponse::getId) + .collect(Collectors.toSet()); + return instanceIds; + } +} diff --git a/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationService.java b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationService.java new file mode 100644 index 0000000..643977e --- /dev/null +++ b/so-cnf-adapter-application/src/main/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationService.java @@ -0,0 +1,151 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.service.synchrornization; + +import org.apache.http.client.utils.URIBuilder; +import org.onap.so.adapters.cnf.client.MulticloudClient; +import org.onap.so.adapters.cnf.model.InstanceResponse; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionRequest; +import org.onap.so.client.exception.BadResponseException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.net.URISyntaxException; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class SynchronizationService { + + private static final Logger logger = LoggerFactory.getLogger(SynchronizationService.class); + + private static final String PROTOCOL = "http"; + private static final String HOST = "so-cnf-adapter"; + private static final int PORT = 8090; + + private final Set subscriptions = new HashSet<>(); + private final MulticloudClient multicloudClient; + private final SubscriptionsRecoveryProvider recoveryProvider; + + public SynchronizationService(MulticloudClient multicloudClient, SubscriptionsRecoveryProvider recoveryProvider) { + this.multicloudClient = multicloudClient; + this.recoveryProvider = recoveryProvider; + } + + @PostConstruct + private void postConstruct() { + recoverSubscriptions(); + } + + private void recoverSubscriptions() { + if (subscriptions.isEmpty()) { + Set instanceIds; + try { + + instanceIds = recoveryProvider.getInstanceList(); + + instanceIds.forEach(this::addSubscriptionIfSubscriptionFound); + } catch (BadResponseException e) { + logger.error("Instances not found", e); + } + } + } + + private void addSubscriptionIfSubscriptionFound(String instanceId) { + String subscriptionName = getSubscriptionName(instanceId); + try { + if (multicloudClient.hasSubscription(instanceId, subscriptionName)) + subscriptions.add(subscriptionName); + } catch (BadResponseException e) { + logger.warn("Subscriptions not found instanceId={} subscriptionName={}", instanceId, subscriptionName); + } + } + + public void createSubscriptionIfNotExists(AaiRequest aaiRequest) throws BadResponseException { + logger.debug("createSubscriptionIfNotExists- START"); + String instanceId = aaiRequest.getInstanceId(); + String subscriptionName = getSubscriptionName(instanceId); + String callbackUrl = generateCallbackUrl(instanceId); + + if (isSubscriptionActive(subscriptionName)) { + logger.info("Subscription: {} already exits", subscriptionName); + } else { + multicloudClient.registerSubscription(instanceId, getSubscriptionRequest(subscriptionName, callbackUrl, aaiRequest)); + subscriptions.add(subscriptionName); + logger.info("Subscription: {} registered", subscriptionName); + } + logger.debug("createSubscriptionIfNotExists- END"); + } + + public void deleteSubscriptionIfExists(AaiRequest aaiRequest) throws BadResponseException { + logger.debug("deleteSubscriptionIfExists - START"); + String instanceId = aaiRequest.getInstanceId(); + String subscriptionName = getSubscriptionName(instanceId); + + if (isSubscriptionActive(subscriptionName)) { + multicloudClient.deleteSubscription(instanceId, subscriptionName); + subscriptions.remove(subscriptionName); + logger.info("Subscription: {} removed", subscriptionName); + } else { + logger.info("Subscription: {} already removed or was not present", subscriptionName); + } + logger.debug("deleteSubscriptionIfExists - END"); + } + + public boolean isSubscriptionActive(String subscriptionName) { + return subscriptions.contains(subscriptionName); + } + + public String getSubscriptionName(String instanceId) { + return instanceId + "-cnf-adapter"; + } + + private SubscriptionRequest getSubscriptionRequest(String name, String endpoint, AaiRequest aaiRequest) { + SubscriptionRequest subscriptionRequest = new SubscriptionRequest(); + + subscriptionRequest.setName(name); + subscriptionRequest.setCallbackUrl(endpoint); + subscriptionRequest.setMinNotifyInterval(30); + + return subscriptionRequest; + } + + private String generateCallbackUrl(String instanceId) { + String path = String.format("/api/cnf-adapter/v1/instance/%s/status/notify", instanceId); + + URIBuilder uriBuilder = new URIBuilder(); + try { + return uriBuilder + .setScheme(PROTOCOL) + .setHost(HOST) + .setPort(PORT) + .setPath(path) + .build() + .toString(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/client/MulticloudClientTest.java b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/client/MulticloudClientTest.java index 738c184..87b0853 100644 --- a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/client/MulticloudClientTest.java +++ b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/client/MulticloudClientTest.java @@ -27,17 +27,21 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; +import org.onap.so.adapters.cnf.model.InstanceResponse; import org.onap.so.adapters.cnf.model.MulticloudInstanceRequest; import org.onap.so.adapters.cnf.model.healthcheck.K8sRbInstanceHealthCheck; import org.onap.so.adapters.cnf.model.healthcheck.K8sRbInstanceHealthCheckSimple; import org.onap.so.adapters.cnf.model.statuscheck.K8sRbInstanceStatus; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionRequest; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionResponse; import org.onap.so.client.exception.BadResponseException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.client.RestTemplate; +import java.util.List; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; @@ -65,10 +69,72 @@ public class MulticloudClientTest { private ArgumentCaptor instanceIdCaptor; + @Test + public void shouldRegisterSubscription() throws BadResponseException { + // given + SubscriptionRequest request = mock(SubscriptionRequest.class); + ResponseEntity result = mock(ResponseEntity.class); + String body = "{\"name\":\"name\"}"; + + // when + when(multicloudApiUrl.apiUrl(instanceId)).thenReturn(endpoint); + when(restTemplate.exchange(eq(getUrl("/status/subscription")), eq(POST), any(), eq(String.class))).thenReturn(result); + when(result.getStatusCode()).thenReturn(HttpStatus.OK); + when(result.getBody()).thenReturn(body); + + // then + SubscriptionResponse actual = tested.registerSubscription(instanceId, request); + + assertEquals("name", actual.getName()); + verify(multicloudApiUrl).apiUrl(instanceIdCaptor.capture()); + assertInstanceIdCaperedValue(instanceIdCaptor.getValue()); + } + + @Test + public void shouldGetSubscription() throws BadResponseException { + // given + String request = "subscriptionId"; + ResponseEntity result = mock(ResponseEntity.class); + String body = "{\"name\":\"name\"}"; + + // when + when(multicloudApiUrl.apiUrl(instanceId)).thenReturn(endpoint); + when(restTemplate.exchange(eq(getUrl("/status/subscription/" + request)), eq(GET), any(), eq(String.class))).thenReturn(result); + when(result.getStatusCode()).thenReturn(HttpStatus.OK); + when(result.getBody()).thenReturn(body); + + // then + SubscriptionResponse actual = tested.getSubscription(instanceId, request); + + assertEquals("name", actual.getName()); + verify(multicloudApiUrl).apiUrl(instanceIdCaptor.capture()); + assertInstanceIdCaperedValue(instanceIdCaptor.getValue()); + } + + @Test + public void shouldDeleteSubscription() throws BadResponseException { + // given + String request = "subscriptionId"; + ResponseEntity result = mock(ResponseEntity.class); + String body = "{\"name\":\"name\"}"; + + // when + when(multicloudApiUrl.apiUrl(instanceId)).thenReturn(endpoint); + when(restTemplate.exchange(eq(getUrl("/status/subscription/" + request)), eq(DELETE), any(), eq(String.class))).thenReturn(result); + when(result.getStatusCode()).thenReturn(HttpStatus.OK); + when(result.getBody()).thenReturn(body); + + // then + tested.deleteSubscription(instanceId, request); + + verify(multicloudApiUrl).apiUrl(instanceIdCaptor.capture()); + assertInstanceIdCaperedValue(instanceIdCaptor.getValue()); + } + @Test public void shouldUpgradeInstance() throws BadResponseException { // given - MulticloudInstanceRequest upgradeRequest = mock(MulticloudInstanceRequest.class); + MulticloudInstanceRequest request = mock(MulticloudInstanceRequest.class); ResponseEntity result = mock(ResponseEntity.class); String body = "body"; @@ -79,7 +145,7 @@ public class MulticloudClientTest { when(result.getBody()).thenReturn(body); // then - String actual = tested.upgradeInstance(instanceId, upgradeRequest); + String actual = tested.upgradeInstance(instanceId, request); assertEquals(body, actual); verify(multicloudApiUrl).apiUrl(instanceIdCaptor.capture()); @@ -135,7 +201,7 @@ public class MulticloudClientTest { // when when(multicloudApiUrl.apiUrl(instanceId)).thenReturn(endpoint); - when(restTemplate.exchange(eq(getUrl("/healthcheck/"+healthCheckInstance)), eq(GET), any(), eq(String.class))).thenReturn(result); + when(restTemplate.exchange(eq(getUrl("/healthcheck/" + healthCheckInstance)), eq(GET), any(), eq(String.class))).thenReturn(result); when(result.getStatusCode()).thenReturn(HttpStatus.OK); when(result.getBody()).thenReturn(body); @@ -156,7 +222,7 @@ public class MulticloudClientTest { // when when(multicloudApiUrl.apiUrl(instanceId)).thenReturn(endpoint); - when(restTemplate.exchange(eq(getUrl("/healthcheck/"+healthCheckInstance)), eq(DELETE), any(), eq(String.class))).thenReturn(result); + when(restTemplate.exchange(eq(getUrl("/healthcheck/" + healthCheckInstance)), eq(DELETE), any(), eq(String.class))).thenReturn(result); when(result.getStatusCode()).thenReturn(HttpStatus.OK); when(result.getBody()).thenReturn(body); @@ -167,6 +233,29 @@ public class MulticloudClientTest { assertInstanceIdCaperedValue(instanceIdCaptor.getValue()); } + @Test + public void shouldGetAllInstances() throws BadResponseException { + // given + ResponseEntity result = mock(ResponseEntity.class); + String body = "[{\"id\":\"clever_proskuriakova\",\"release-name\":\"rel-1-apache\",\"namespace\":\"test-cnf\"}]"; + + // when + when(multicloudApiUrl.apiUrl("")).thenReturn(endpoint); + when(restTemplate.exchange(eq(getUrl("")), eq(GET), any(), eq(String.class))).thenReturn(result); + when(result.getStatusCode()).thenReturn(HttpStatus.OK); + when(result.getBody()).thenReturn(body); + + // then + List actual = tested.getAllInstances(); + + verify(multicloudApiUrl).apiUrl(instanceIdCaptor.capture()); + assertEquals("", instanceIdCaptor.getValue()); + assertEquals(1, actual.size()); + assertEquals("clever_proskuriakova", actual.get(0).getId()); + assertEquals("rel-1-apache", actual.get(0).getReleaseName()); + assertEquals("test-cnf", actual.get(0).getNamespace()); + } + private void assertInstanceIdCaperedValue(String instanceIdCapturedValue) { assertEquals(instanceId, instanceIdCapturedValue); } diff --git a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/CnfAdapterServiceTest.java b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/CnfAdapterServiceTest.java index 06e93e1..d50f633 100644 --- a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/CnfAdapterServiceTest.java +++ b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/CnfAdapterServiceTest.java @@ -17,7 +17,6 @@ * limitations under the License. * ============LICENSE_END========================================================= */ - package org.onap.so.adapters.cnf.service; import lombok.Data; @@ -30,7 +29,8 @@ import org.onap.so.adapters.cnf.MulticloudConfiguration; import org.onap.so.adapters.cnf.model.BpmnInstanceRequest; import org.onap.so.adapters.cnf.service.healthcheck.HealthCheckService; import org.onap.so.adapters.cnf.service.statuscheck.SimpleStatusCheckService; -import org.springframework.boot.test.context.SpringBootTest; +import org.onap.so.adapters.cnf.service.synchrornization.SynchronizationService; +import org.onap.so.client.exception.BadResponseException; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.test.context.junit4.SpringRunner; @@ -49,7 +49,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; -@SpringBootTest @RunWith(SpringRunner.class) public class CnfAdapterServiceTest { @@ -66,6 +65,9 @@ public class CnfAdapterServiceTest { @Mock SimpleStatusCheckService simpleStatusCheckService; + @Mock + SynchronizationService synchronizationService; + @Before public void setUp() { @@ -85,25 +87,17 @@ public class CnfAdapterServiceTest { } @Test(expected = EntityNotFoundException.class) - public void testcreateInstanceHttpException() { + public void testcreateInstanceHttpException() throws BadResponseException { doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)).when(restTemplate).exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), ArgumentMatchers.>any()); - try { - cnfAdapterService.createInstance(getBpmnInstanceRequest()); - } catch (IOException e) { - e.printStackTrace(); - } + cnfAdapterService.createInstance(getBpmnInstanceRequest()); } @Test(expected = HttpStatusCodeException.class) - public void testcreateInstanceHttpStatusCodeException() { + public void testCreateInstanceHttpStatusCodeException() throws BadResponseException { doThrow(new HttpServerErrorException(HttpStatus.CONFLICT)).when(restTemplate).exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), ArgumentMatchers.>any()); - try { - cnfAdapterService.createInstance(getBpmnInstanceRequest()); - } catch (IOException e) { - e.printStackTrace(); - } + cnfAdapterService.createInstance(getBpmnInstanceRequest()); } @Test @@ -215,25 +209,17 @@ public class CnfAdapterServiceTest { } @Test(expected = EntityNotFoundException.class) - public void testdeleteInstanceByInstanceIdHttpException() { + public void testdeleteInstanceByInstanceIdHttpException() throws BadResponseException { doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)).when(restTemplate).exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), ArgumentMatchers.>any()); - try { - cnfAdapterService.deleteInstanceByInstanceId(INSTANCE_ID); - } catch (IOException e) { - e.printStackTrace(); - } + cnfAdapterService.deleteInstanceByInstanceId(INSTANCE_ID); } @Test(expected = HttpStatusCodeException.class) - public void testdeleteInstanceByInstanceIdException() { + public void testDeleteInstanceByInstanceIdException() throws BadResponseException { doThrow(new HttpServerErrorException(HttpStatus.CONFLICT)).when(restTemplate).exchange(ArgumentMatchers.anyString(), ArgumentMatchers.any(HttpMethod.class), ArgumentMatchers.any(), ArgumentMatchers.>any()); - try { - cnfAdapterService.deleteInstanceByInstanceId(INSTANCE_ID); - } catch (IOException e) { - e.printStackTrace(); - } + cnfAdapterService.deleteInstanceByInstanceId(INSTANCE_ID); } @Test @@ -269,9 +255,9 @@ public class CnfAdapterServiceTest { } private BpmnInstanceRequest getBpmnInstanceRequest() { - Map labels = new HashMap(); + Map labels = new HashMap<>(); labels.put("custom-label-1", "label1"); - Map overrideValues = new HashMap(); + Map overrideValues = new HashMap<>(); overrideValues.put("a", "b"); labels.put("image.tag", "latest"); labels.put("dcae_collector_ip", "1.2.3.4"); diff --git a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java new file mode 100644 index 0000000..32feb78 --- /dev/null +++ b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SubscriptionsRecoveryProvider.java @@ -0,0 +1,17 @@ +package org.onap.so.adapters.cnf.service.synchrornization; + +import org.onap.so.client.exception.BadResponseException; +import org.springframework.context.annotation.Primary; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.Set; + +@Component +@Primary +public class SubscriptionsRecoveryProvider { + + public Set getInstanceList() throws BadResponseException { + return Collections.emptySet(); + } +} \ No newline at end of file diff --git a/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationServiceTest.java b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationServiceTest.java new file mode 100644 index 0000000..4a159bc --- /dev/null +++ b/so-cnf-adapter-application/src/test/java/org/onap/so/adapters/cnf/service/synchrornization/SynchronizationServiceTest.java @@ -0,0 +1,96 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - SO + * ================================================================================ + * Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + * Modifications Copyright (C) 2021 Samsung Technologies Co. + * ================================================================================ + * 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.so.adapters.cnf.service.synchrornization; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.MethodSorters; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.onap.so.adapters.cnf.client.MulticloudClient; +import org.onap.so.adapters.cnf.model.aai.AaiRequest; +import org.onap.so.adapters.cnf.model.synchronization.SubscriptionRequest; +import org.onap.so.client.exception.BadResponseException; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(SpringRunner.class) +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class SynchronizationServiceTest { + + private static final String INSTANCE_ID = "INSTANCE_ID"; + private static final String SUFFIX = "-cnf-adapter"; + private static final String SUBSCRIPTION_NAME = INSTANCE_ID + SUFFIX; + + @InjectMocks + private SynchronizationService tested; + + @Mock + private MulticloudClient multicloudClient; + @Captor + private ArgumentCaptor subscriptionRequestCaptor; + + @Test + public void shouldCreateSubscription() throws BadResponseException { + // given + String callbackUrl = "http://so-cnf-adapter:8090/api/cnf-adapter/v1/instance/INSTANCE_ID/status/notify"; + AaiRequest aaiRequest = mock(AaiRequest.class); + + // when + when(aaiRequest.getInstanceId()).thenReturn(INSTANCE_ID); + + // then + tested.createSubscriptionIfNotExists(aaiRequest); + + verify(multicloudClient).registerSubscription(eq(INSTANCE_ID), subscriptionRequestCaptor.capture()); + SubscriptionRequest subscriptionRequest = subscriptionRequestCaptor.getValue(); + assertEquals(SUBSCRIPTION_NAME, subscriptionRequest.getName()); + assertEquals(callbackUrl, subscriptionRequest.getCallbackUrl()); + assertEquals(30, subscriptionRequest.getMinNotifyInterval()); + } + + @Test + public void shouldGetSubscriptionName() { + // given + // when + // then + String actual = tested.getSubscriptionName(INSTANCE_ID); + assertEquals(SUBSCRIPTION_NAME, actual); + } + + @Test + public void shouldCheckIfSubscriptionActive() { + // given + // when + // then + boolean subscriptionActive = tested.isSubscriptionActive(INSTANCE_ID); + assertFalse(subscriptionActive); + } +} \ No newline at end of file -- cgit 1.2.3-korg