From 735cc72cdf706de32e4b55848da1d5242ba1be26 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Tue, 9 Jul 2024 12:41:59 +0100 Subject: Refactor remaining classes package structure -Introduced org.onap.cps.ncmp.config for all config type classes like http, kafka etc. -Introduced org.onap.cps.ncmp.impl.dmi for dmi specif classes like DmiRestClient etc. -Moved most exception classes to org.onap.cps.ncmp.api.exceptions (only two were 'internal' i.e. NOT used in REST so left in org.onap.cps.ncmp.exceptions) -Deleted unused DateNodeHelper class (and related testware) -Moved some classes to org.onap.cps.ncmp.impl.utils -Moved messaging test base classes to org.onap.cps.ncmp.impl.utils.events -All imports were reorganised automatically by IntelliJ -did NOT update any copyright dates (seems incorrect to me anyway) Issue-ID: CPS-2257 Change-Id: Ie28b1777ea278064b46c6a1c3a28f4d0696565e2 Signed-off-by: ToineSiebelink --- .../api/exceptions/DmiClientRequestException.java | 54 ++++++ .../ncmp/api/exceptions/DmiRequestException.java | 37 ++++ .../ncmp/api/exceptions/InvalidTopicException.java | 40 +++++ .../cps/ncmp/api/exceptions/NcmpException.java | 47 +++++ .../api/exceptions/PayloadTooLargeException.java | 31 ++++ .../ncmp/api/exceptions/ServerNcmpException.java | 37 ++++ .../cps/ncmp/api/impl/client/DmiRestClient.java | 188 ------------------- .../cps/ncmp/api/impl/config/DmiProperties.java | 55 ------ .../api/impl/config/DmiWebClientConfiguration.java | 121 ------------- .../api/impl/config/HttpClientConfiguration.java | 72 -------- .../ncmp/api/impl/config/OpenTelemetryConfig.java | 111 ------------ .../ncmp/api/impl/config/kafka/KafkaConfig.java | 198 --------------------- .../impl/exception/DmiClientRequestException.java | 54 ------ .../api/impl/exception/DmiRequestException.java | 37 ---- .../cps/ncmp/api/impl/exception/NcmpException.java | 47 ----- .../api/impl/exception/NcmpStartUpException.java | 37 ---- .../api/impl/exception/ServerNcmpException.java | 37 ---- .../cps/ncmp/api/impl/utils/DataNodeHelper.java | 100 ----------- .../api/impl/utils/DmiServiceNameOrganizer.java | 64 ------- .../api/impl/utils/EventDateTimeFormatter.java | 47 ----- .../impl/utils/context/CpsApplicationContext.java | 51 ------ .../url/builder/DmiServiceUrlTemplateBuilder.java | 137 -------------- .../utils/url/builder/UrlTemplateParameters.java | 30 ---- .../inventory/models/DmiPluginRegistration.java | 4 +- .../cps/ncmp/config/CpsApplicationContext.java | 51 ++++++ .../cps/ncmp/config/HttpClientConfiguration.java | 72 ++++++++ .../java/org/onap/cps/ncmp/config/KafkaConfig.java | 198 +++++++++++++++++++++ .../onap/cps/ncmp/config/OpenTelemetryConfig.java | 111 ++++++++++++ .../cps/ncmp/exceptions/InvalidTopicException.java | 40 ----- .../cps/ncmp/exceptions/NcmpStartUpException.java | 39 ++++ .../NoAlternateIdMatchFoundException.java | 2 +- .../ncmp/exceptions/PayloadTooLargeException.java | 31 ---- .../onap/cps/ncmp/impl/data/DmiDataOperations.java | 10 +- .../NcmpPassthroughResourceRequestHandler.java | 2 +- .../impl/data/utils/DmiDataOperationsHelper.java | 4 +- .../impl/datajobs/DmiSubJobRequestHandler.java | 8 +- .../org/onap/cps/ncmp/impl/dmi/DmiProperties.java | 55 ++++++ .../org/onap/cps/ncmp/impl/dmi/DmiRestClient.java | 186 +++++++++++++++++++ .../cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java | 64 +++++++ .../impl/dmi/DmiServiceUrlTemplateBuilder.java | 137 ++++++++++++++ .../ncmp/impl/dmi/DmiWebClientConfiguration.java | 122 +++++++++++++ .../cps/ncmp/impl/dmi/UrlTemplateParameters.java | 30 ++++ .../impl/inventory/sync/DmiModelOperations.java | 8 +- .../impl/inventory/sync/lcm/LcmEventsCreator.java | 2 +- .../trustlevel/DmiPluginTrustLevelWatchDog.java | 6 +- .../ncmp/impl/utils/EventDateTimeFormatter.java | 47 +++++ .../onap/cps/ncmp/init/AbstractModelLoader.java | 2 +- .../ncmp/init/CmDataSubscriptionModelLoader.java | 2 +- .../org/onap/cps/ncmp/utils/events/NcmpEvent.java | 4 +- .../onap/cps/ncmp/utils/events/TopicValidator.java | 2 +- .../ncmp/api/impl/DataJobServiceImplSpec.groovy | 86 --------- .../api/impl/DmiSubJobRequestHandlerSpec.groovy | 41 ----- .../ncmp/api/impl/WriteRequestExaminerSpec.groovy | 63 ------- .../ncmp/api/impl/client/DmiRestClientSpec.groovy | 168 ----------------- .../ncmp/api/impl/config/DmiPropertiesSpec.groovy | 37 ---- .../config/DmiWebClientConfigurationSpec.groovy | 75 -------- .../impl/config/HttpClientConfigurationSpec.groovy | 74 -------- ...etryCmNotificationSubscriptionConfigSpec.groovy | 81 --------- .../api/impl/config/kafka/KafkaConfigSpec.groovy | 64 ------- .../ncmp/api/impl/utils/DataNodeBaseSpec.groovy | 54 ------ .../ncmp/api/impl/utils/DataNodeHelperSpec.groovy | 85 --------- .../impl/utils/EventDateTimeFormatterSpec.groovy | 45 ----- .../utils/context/CpsApplicationContextSpec.groovy | 39 ---- .../DmiServiceUrlTemplateBuilderSpec.groovy | 63 ------- .../cps/ncmp/api/kafka/ConsumerBaseSpec.groovy | 43 ----- .../cps/ncmp/api/kafka/MessagingBaseSpec.groovy | 75 -------- .../ncmp/config/CpsApplicationContextSpec.groovy | 39 ++++ .../ncmp/config/HttpClientConfigurationSpec.groovy | 75 ++++++++ .../onap/cps/ncmp/config/KafkaConfigSpec.groovy | 64 +++++++ ...etryCmNotificationSubscriptionConfigSpec.groovy | 81 +++++++++ .../cps/ncmp/impl/DmiOperationsBaseSpec.groovy | 76 -------- .../cache/DmiCacheHandlerSpec.groovy | 2 +- .../cmavc/CmAvcEventConsumerSpec.groovy | 2 +- .../dmi/DmiOutEventConsumerSpec.groovy | 2 +- .../ncmp/NcmpInEventConsumerSpec.groovy | 2 +- .../ncmp/impl/data/DmiDataOperationsSpec.groovy | 10 +- .../data/NcmpDatastoreRequestHandlerSpec.groovy | 2 +- ...AsyncRequestResponseEventIntegrationSpec.groovy | 2 +- .../async/DataOperationEventConsumerSpec.groovy | 2 +- .../async/FilterStrategiesIntegrationSpec.groovy | 4 +- .../data/async/SerializationIntegrationSpec.groovy | 4 +- .../data/utils/DmiDataOperationsHelperSpec.groovy | 4 +- .../impl/datajobs/DataJobServiceImplSpec.groovy | 83 +++++++++ .../datajobs/DmiSubJobRequestHandlerSpec.groovy | 40 +++++ .../impl/datajobs/WriteRequestExaminerSpec.groovy | 63 +++++++ .../cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy | 75 ++++++++ .../cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy | 38 ++++ .../cps/ncmp/impl/dmi/DmiRestClientSpec.groovy | 166 +++++++++++++++++ .../dmi/DmiServiceUrlTemplateBuilderSpec.groovy | 64 +++++++ .../impl/dmi/DmiWebClientConfigurationSpec.groovy | 77 ++++++++ .../CmHandleRegistrationServiceSpec.groovy | 2 +- .../inventory/sync/DmiModelOperationsSpec.groovy | 6 +- .../sync/lcm/LcmEventsPublisherSpec.groovy | 2 +- .../DmiPluginTrustLevelWatchDogSpec.groovy | 4 +- .../impl/utils/EventDateTimeFormatterSpec.groovy | 46 +++++ .../cps/ncmp/init/AbstractModelLoaderSpec.groovy | 6 +- .../init/CmDataSubscriptionModelLoaderSpec.groovy | 2 +- .../utils/events/CmAvcEventPublisherSpec.groovy | 3 +- .../cps/ncmp/utils/events/ConsumerBaseSpec.groovy | 44 +++++ .../cps/ncmp/utils/events/MessagingBaseSpec.groovy | 75 ++++++++ .../ncmp/utils/events/TopicValidatorSpec.groovy | 2 +- 101 files changed, 2447 insertions(+), 2686 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/HttpClientConfiguration.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/KafkaConfig.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/InvalidTopicException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/PayloadTooLargeException.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilder.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfiguration.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/UrlTemplateParameters.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/WriteRequestExaminerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiPropertiesSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatterSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/HttpClientConfigurationSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/KafkaConfigSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/DmiOperationsBaseSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilderSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfigurationSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy (limited to 'cps-ncmp-service') diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java new file mode 100644 index 0000000000..65ccba8018 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiClientRequestException.java @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +import lombok.Getter; +import org.onap.cps.ncmp.api.NcmpResponseStatus; + +/** + * Http Client Request exception from dmi service. + */ +@Getter +public class DmiClientRequestException extends NcmpException { + + private static final long serialVersionUID = 6659897770659834797L; + final NcmpResponseStatus ncmpResponseStatus; + final String message; + final String responseBodyAsString; + final int httpStatusCode; + + /** + * Constructor to form exception for dmi service response. + * + * @param httpStatusCode http response code from the client + * @param message response message from the client + * @param responseBodyAsString response body from the client + * @param ncmpResponseStatus ncmp status message and code + */ + public DmiClientRequestException(final int httpStatusCode, final String message, final String responseBodyAsString, + final NcmpResponseStatus ncmpResponseStatus) { + super(message, responseBodyAsString); + this.httpStatusCode = httpStatusCode; + this.message = message; + this.responseBodyAsString = responseBodyAsString; + this.ncmpResponseStatus = ncmpResponseStatus; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java new file mode 100644 index 0000000000..b2cfbc01be --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/DmiRequestException.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +/** + * Client Based Network CM Proxy exception. + */ +public class DmiRequestException extends NcmpException { + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public DmiRequestException(final String message, final String details) { + super(message, details); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java new file mode 100644 index 0000000000..07b186dae4 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/InvalidTopicException.java @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +import lombok.Getter; + +public class InvalidTopicException extends RuntimeException { + + @Getter + final String details; + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public InvalidTopicException(final String message, final String details) { + super(message); + this.details = details; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java new file mode 100644 index 0000000000..6754965866 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/NcmpException.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +import lombok.Getter; + +/** + * Network CM Proxy exception. + */ +public class NcmpException extends RuntimeException { + + private static final long serialVersionUID = 1482619410918497467L; + + @Getter + final String details; + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public NcmpException(final String message, final String details) { + super(message); + this.details = details; + } + +} + diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java new file mode 100644 index 0000000000..edb295dbbf --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PayloadTooLargeException.java @@ -0,0 +1,31 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +public class PayloadTooLargeException extends RuntimeException { + + /** + * Instantiates a new payload too large exception. + */ + public PayloadTooLargeException(final String message) { + super(message); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java new file mode 100644 index 0000000000..03dc3bc8dd --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/ServerNcmpException.java @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.api.exceptions; + +/** + * Server Based Network CM Proxy exception. + */ +public class ServerNcmpException extends NcmpException { + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public ServerNcmpException(final String message, final String details) { + super(message, details); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java deleted file mode 100644 index ac7728da92..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/client/DmiRestClient.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation - * Modifications Copyright (C) 2022 Bell Canada - * ================================================================================ - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.client; - -import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR; -import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; -import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT; - -import com.fasterxml.jackson.databind.JsonNode; -import java.util.Locale; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.data.models.OperationType; -import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; -import org.onap.cps.ncmp.impl.models.RequiredDmiService; -import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.web.client.HttpServerErrorException; -import org.springframework.web.reactive.function.BodyInserters; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.WebClientRequestException; -import org.springframework.web.reactive.function.client.WebClientResponseException; -import reactor.core.publisher.Mono; - -@Component -@RequiredArgsConstructor -@Slf4j -public class DmiRestClient { - - private static final String NOT_SPECIFIED = ""; - private static final String NO_AUTHORIZATION = null; - - private final DmiProperties dmiProperties; - private final JsonObjectMapper jsonObjectMapper; - @Qualifier("dataServicesWebClient") - private final WebClient dataServicesWebClient; - @Qualifier("modelServicesWebClient") - private final WebClient modelServicesWebClient; - @Qualifier("healthChecksWebClient") - private final WebClient healthChecksWebClient; - - /** - * Sends a synchronous (blocking) POST operation to the DMI with a JSON body containing module references. - * - * @param requiredDmiService Determines if the required service is for a data or model operation. - * @param urlTemplateParameters The DMI resource URL template with variables. - * @param requestBodyAsJsonString JSON data body. - * @param operationType The type of operation being executed (for error reporting only). - * @param authorization Contents of the Authorization header, or null if not present. - * @return ResponseEntity containing the response from the DMI. - * @throws DmiClientRequestException If there is an error during the DMI request. - */ - public ResponseEntity synchronousPostOperationWithJsonData(final RequiredDmiService requiredDmiService, - final UrlTemplateParameters - urlTemplateParameters, - final String requestBodyAsJsonString, - final OperationType operationType, - final String authorization) { - final Mono> responseEntityMono = - asynchronousPostOperationWithJsonData(requiredDmiService, - urlTemplateParameters, - requestBodyAsJsonString, - operationType, - authorization); - return responseEntityMono.block(); - } - - /** - * Asynchronously performs an HTTP POST operation with the given JSON data. - * - * @param requiredDmiService The service object required for retrieving or configuring the WebClient. - * @param urlTemplateParameters The URL template with variables for the POST request. - * @param requestBodyAsJsonString The JSON string that will be sent as the request body. - * @param operationType An enumeration or object that holds information about the type of operation - * being performed. - * @param authorization The authorization token to be added to the request headers. - * @return A Mono emitting the response entity containing the server's response. - */ - public Mono> asynchronousPostOperationWithJsonData(final RequiredDmiService - requiredDmiService, - final UrlTemplateParameters - urlTemplateParameters, - final String requestBodyAsJsonString, - final OperationType operationType, - final String authorization) { - final WebClient webClient = getWebClient(requiredDmiService); - return webClient.post() - .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) - .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization)) - .body(BodyInserters.fromValue(requestBodyAsJsonString)) - .retrieve() - .toEntity(Object.class) - .onErrorMap(throwable -> handleDmiClientException(throwable, operationType.getOperationName())); - } - - /** - * Retrieves the health status of the DMI plugin. - * This method performs an HTTP GET request to the DMI health check endpoint specified by the URL template - * parameters. If the response status code indicates a client error (4xx) or a server error (5xx), it logs a warning - * and returns an empty Mono. In case of an error during the request, it logs the exception and returns a default - * value of "NOT_SPECIFIED". If the response body contains a JSON node with a "status" field, the value of this - * field is returned. - * - * @param urlTemplateParameters the URL template parameters for the DMI health check endpoint - * @return a Mono emitting the health status as a String, or "NOT_SPECIFIED" if an error occurs - */ - public Mono getDmiHealthStatus(final UrlTemplateParameters urlTemplateParameters) { - return healthChecksWebClient.get() - .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) - .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION)) - .retrieve() - .bodyToMono(JsonNode.class) - .map(responseHealthStatus -> responseHealthStatus.path("status").asText()) - .onErrorResume(Exception.class, ex -> { - log.warn("Failed to retrieve health status from {}. Status: {}", - urlTemplateParameters.urlTemplate(), ex.getMessage()); - return Mono.empty(); - }) - .defaultIfEmpty(NOT_SPECIFIED); - } - - private WebClient getWebClient(final RequiredDmiService requiredDmiService) { - return requiredDmiService.equals(RequiredDmiService.DATA) ? dataServicesWebClient : modelServicesWebClient; - } - - private void configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) { - if (dmiProperties.isDmiBasicAuthEnabled()) { - httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword()); - } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) { - httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization); - } - } - - private DmiClientRequestException handleDmiClientException(final Throwable throwable, final String operationType) { - if (throwable instanceof WebClientResponseException webClientResponseException) { - if (webClientResponseException.getStatusCode().isSameCodeAs(REQUEST_TIMEOUT)) { - throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(), - webClientResponseException.getMessage(), - jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()), - DMI_SERVICE_NOT_RESPONDING); - } - throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(), - webClientResponseException.getMessage(), - jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()), - UNABLE_TO_READ_RESOURCE_DATA); - - } - final String exceptionMessage = "Unable to " + operationType + " resource data."; - if (throwable instanceof WebClientRequestException webClientRequestException) { - throw new DmiClientRequestException(HttpStatus.SERVICE_UNAVAILABLE.value(), - webClientRequestException.getMessage(), - exceptionMessage, DMI_SERVICE_NOT_RESPONDING); - } - if (throwable instanceof HttpServerErrorException httpServerErrorException) { - throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage, - httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING); - } - throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, throwable.getMessage(), - UNKNOWN_ERROR); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java deleted file mode 100644 index 5453efecd0..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiProperties.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config; - -import lombok.AccessLevel; -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Getter -@Component -public class DmiProperties { - @Value("${ncmp.dmi.auth.username}") - private String authUsername; - @Value("${ncmp.dmi.auth.password}") - private String authPassword; - @Getter(AccessLevel.NONE) - @Value("${ncmp.dmi.api.base-path}") - private String dmiBasePath; - @Value("${ncmp.dmi.auth.enabled}") - private boolean dmiBasicAuthEnabled; - - /** - * Removes both leading and trailing slashes if they are present. - * - * @return dmi base path without any slashes ("/") - */ - public String getDmiBasePath() { - if (dmiBasePath.startsWith("/")) { - dmiBasePath = dmiBasePath.substring(1); - } - if (dmiBasePath.endsWith("/")) { - dmiBasePath = dmiBasePath.substring(0, dmiBasePath.length() - 1); - } - return dmiBasePath; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java deleted file mode 100644 index be46105d13..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfiguration.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config; - -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.netty.channel.ChannelOption; -import io.netty.handler.timeout.ReadTimeoutHandler; -import io.netty.handler.timeout.WriteTimeoutHandler; -import io.netty.resolver.DefaultAddressResolverGroup; -import java.time.Duration; -import java.util.concurrent.TimeUnit; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.client.reactive.ReactorClientHttpConnector; -import org.springframework.web.reactive.function.client.WebClient; -import reactor.netty.http.client.HttpClient; -import reactor.netty.resources.ConnectionProvider; - -/** - * Configures and creates WebClient beans for various DMI services including data, model, and health check services. - * The configuration utilizes Netty-based HttpClient with custom connection settings, read and write timeouts, - * and initializes WebClient with these settings to ensure optimal performance and resource management. - */ -@Configuration -@RequiredArgsConstructor -public class DmiWebClientConfiguration { - - private final HttpClientConfiguration httpClientConfiguration; - private static final Duration DEFAULT_RESPONSE_TIMEOUT = Duration.ofSeconds(30); - - /** - * Configures and creates a web client bean for DMI data services. - * - * @param webClientBuilder The builder instance to create the WebClient. - * @return a WebClient instance configured for data services. - */ - @Bean - public WebClient dataServicesWebClient(final WebClient.Builder webClientBuilder) { - return configureWebClient(webClientBuilder, httpClientConfiguration.getDataServices()); - } - - /** - * Configures and creates a web client bean for DMI model services. - * - * @param webClientBuilder The builder instance to create the WebClient. - * @return a WebClient instance configured for model services. - */ - @Bean - public WebClient modelServicesWebClient(final WebClient.Builder webClientBuilder) { - return configureWebClient(webClientBuilder, httpClientConfiguration.getModelServices()); - } - - /** - * Configures and creates a web client bean for DMI health check services. - * - * @param webClientBuilder The builder instance to create the WebClient. - * @return a WebClient instance configured for health check services. - */ - @Bean - public WebClient healthChecksWebClient(final WebClient.Builder webClientBuilder) { - return configureWebClient(webClientBuilder, httpClientConfiguration.getHealthCheckServices()); - } - - private WebClient configureWebClient(final WebClient.Builder webClientBuilder, - final HttpClientConfiguration.ServiceConfig serviceConfig) { - final ConnectionProvider connectionProvider = getConnectionProvider(serviceConfig); - final HttpClient httpClient = createHttpClient(serviceConfig, connectionProvider); - return buildAndGetWebClient(webClientBuilder, httpClient, serviceConfig.getMaximumInMemorySizeInMegabytes()); - } - - private static HttpClient createHttpClient(final HttpClientConfiguration.ServiceConfig serviceConfig, - final ConnectionProvider connectionProvider) { - return HttpClient.create(connectionProvider) - .responseTimeout(DEFAULT_RESPONSE_TIMEOUT) - .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, serviceConfig.getConnectionTimeoutInSeconds() * 1000) - .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler( - serviceConfig.getReadTimeoutInSeconds(), TimeUnit.SECONDS)).addHandlerLast( - new WriteTimeoutHandler(serviceConfig.getWriteTimeoutInSeconds(), TimeUnit.SECONDS))) - .resolver(DefaultAddressResolverGroup.INSTANCE) - .compress(true); - } - - @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE") - private static ConnectionProvider getConnectionProvider(final HttpClientConfiguration.ServiceConfig serviceConfig) { - return ConnectionProvider.builder(serviceConfig.getConnectionProviderName()) - .maxConnections(serviceConfig.getMaximumConnectionsTotal()) - .pendingAcquireMaxCount(serviceConfig.getPendingAcquireMaxCount()) - .build(); - } - - private WebClient buildAndGetWebClient(final WebClient.Builder webClientBuilder, final HttpClient httpClient, - final int maximumInMemorySizeInMegabytes) { - return webClientBuilder - .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) - .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)) - .clientConnector(new ReactorClientHttpConnector(httpClient)) - .codecs(configurer -> configurer.defaultCodecs() - .maxInMemorySize(maximumInMemorySizeInMegabytes * 1024 * 1024)).build(); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java deleted file mode 100644 index 0acbabbbaf..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/HttpClientConfiguration.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config; - -import lombok.Getter; -import lombok.Setter; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Getter -@Setter -@Configuration -@ConfigurationProperties(prefix = "ncmp.dmi.httpclient") -public class HttpClientConfiguration { - - private final DataServices dataServices = new DataServices(); - private final ModelServices modelServices = new ModelServices(); - private final HealthCheckServices healthCheckServices = new HealthCheckServices(); - - @Getter - @Setter - public static class DataServices extends ServiceConfig { - private String connectionProviderName = "dataConnectionPool"; - } - - @Getter - @Setter - public static class ModelServices extends ServiceConfig { - private String connectionProviderName = "modelConnectionPool"; - } - - @Getter - @Setter - public static class HealthCheckServices extends ServiceConfig { - private String connectionProviderName = "healthConnectionPool"; - private int maximumConnectionsTotal = 10; - private int pendingAcquireMaxCount = 5; - } - - /** - * Base configuration properties for all services. - */ - @Getter - @Setter - public static class ServiceConfig { - private String connectionProviderName = "cpsConnectionPool"; - private int maximumConnectionsTotal = 100; - private int pendingAcquireMaxCount = 50; - private Integer connectionTimeoutInSeconds = 30; - private long readTimeoutInSeconds = 30; - private long writeTimeoutInSeconds = 30; - private int maximumInMemorySizeInMegabytes = 1; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfig.java deleted file mode 100644 index bcbacbd421..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/OpenTelemetryConfig.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config; - -import io.micrometer.observation.ObservationPredicate; -import io.micrometer.observation.ObservationRegistry; -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; -import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; -import io.opentelemetry.sdk.trace.samplers.Sampler; -import java.time.Duration; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.server.observation.ServerRequestObservationContext; -import org.springframework.util.AntPathMatcher; -import org.springframework.util.PathMatcher; - -@Configuration -public class OpenTelemetryConfig { - - public static final int JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND = 30; - - @Value("${spring.application.name:cps-application}") - private String serviceId; - - @Value("${cps.tracing.exporter.endpoint:http://onap-otel-collector:4317}") - private String tracingExporterEndpointUrl; - - @Value("${cps.tracing.sampler.jaeger_remote.endpoint:http://onap-otel-collector:14250}") - private String jaegerRemoteSamplerUrl; - - /** - * OTLP Exporter with Grpc exporter protocol. - */ - @Bean - @ConditionalOnExpression( - "${cps.tracing.enabled} && 'grpc'.equals('${cps.tracing.exporter.protocol}')") - public OtlpGrpcSpanExporter createOtlpExporterGrpc() { - return OtlpGrpcSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build(); - } - - /** - * OTLP Exporter with HTTP exporter protocol. - */ - @Bean - @ConditionalOnExpression( - "${cps.tracing.enabled} && 'http'.equals('${cps.tracing.exporter.protocol}')") - public OtlpHttpSpanExporter createOtlpExporterHttp() { - return OtlpHttpSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build(); - } - - /** - * Jaeger Remote Sampler. - */ - @Bean - @ConditionalOnProperty("cps.tracing.enabled") - public JaegerRemoteSampler createJaegerRemoteSampler() { - return JaegerRemoteSampler.builder() - .setEndpoint(jaegerRemoteSamplerUrl) - .setPollingInterval(Duration.ofSeconds(JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND)) - .setInitialSampler(Sampler.alwaysOff()) - .setServiceName(serviceId) - .build(); - } - - /** - * Excluding /actuator/** endpoints. - */ - @Bean - @ConditionalOnProperty("cps.tracing.enabled") - ObservationRegistryCustomizer skipActuatorEndpointsFromObservation() { - final PathMatcher pathMatcher = new AntPathMatcher("/"); - return registry -> - registry.observationConfig().observationPredicate(observationPredicate(pathMatcher)); - } - - /** - * Excluding /actuator/** endpoints. - */ - static ObservationPredicate observationPredicate(final PathMatcher pathMatcher) { - return (name, context) -> { - if (context instanceof ServerRequestObservationContext observationContext) { - return !pathMatcher.match("/actuator/**", observationContext.getCarrier().getRequestURI()); - } else { - return true; - } - }; - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java deleted file mode 100644 index cf6f1c5b17..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfig.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config.kafka; - -import io.cloudevents.CloudEvent; -import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingConsumerInterceptor; -import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingProducerInterceptor; -import java.time.Duration; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import org.apache.kafka.clients.consumer.ConsumerConfig; -import org.apache.kafka.clients.producer.ProducerConfig; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.autoconfigure.kafka.KafkaProperties; -import org.springframework.boot.ssl.SslBundles; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.kafka.annotation.EnableKafka; -import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; -import org.springframework.kafka.core.ConsumerFactory; -import org.springframework.kafka.core.DefaultKafkaConsumerFactory; -import org.springframework.kafka.core.DefaultKafkaProducerFactory; -import org.springframework.kafka.core.KafkaTemplate; -import org.springframework.kafka.core.ProducerFactory; -import org.springframework.kafka.support.serializer.JsonDeserializer; -import org.springframework.kafka.support.serializer.JsonSerializer; - -/** - * kafka Configuration for legacy and cloud events. - * - * @param valid legacy event to be published over the wire. - */ -@Configuration -@EnableKafka -@RequiredArgsConstructor -public class KafkaConfig { - - private final KafkaProperties kafkaProperties; - - @Value("${cps.tracing.enabled:false}") - private boolean tracingEnabled; - - private static final SslBundles NO_SSL = null; - - /** - * This sets the strategy for creating legacy Kafka producer instance from kafka properties defined into - * application.yml and replaces value-serializer by JsonSerializer. - * - * @return legacy event producer instance. - */ - @Bean - public ProducerFactory legacyEventProducerFactory() { - final Map producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); - producerConfigProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); - if (tracingEnabled) { - producerConfigProperties.put( - ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName()); - } - return new DefaultKafkaProducerFactory<>(producerConfigProperties); - } - - /** - * The ConsumerFactory implementation is to produce new legacy instance for provided kafka properties defined - * into application.yml and replaces deserializer-value by JsonDeserializer. - * - * @return an instance of legacy consumer factory. - */ - @Bean - public ConsumerFactory legacyEventConsumerFactory() { - final Map consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); - consumerConfigProperties.put("spring.deserializer.value.delegate.class", JsonDeserializer.class); - if (tracingEnabled) { - consumerConfigProperties.put( - ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName()); - } - return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); - } - - /** - * A legacy Kafka event template for executing high-level operations. The legacy producer factory ensure this. - * - * @return an instance of legacy Kafka template. - */ - @Bean - @Primary - public KafkaTemplate legacyEventKafkaTemplate() { - final KafkaTemplate kafkaTemplate = new KafkaTemplate<>(legacyEventProducerFactory()); - kafkaTemplate.setConsumerFactory(legacyEventConsumerFactory()); - if (tracingEnabled) { - kafkaTemplate.setObservationEnabled(true); - } - return kafkaTemplate; - } - - /** - * A legacy concurrent kafka listener container factory. - * - * @return instance of Concurrent kafka listener factory - */ - @Bean - public ConcurrentKafkaListenerContainerFactory legacyEventConcurrentKafkaListenerContainerFactory() { - final ConcurrentKafkaListenerContainerFactory containerFactory = - new ConcurrentKafkaListenerContainerFactory<>(); - containerFactory.setConsumerFactory(legacyEventConsumerFactory()); - containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10)); - if (tracingEnabled) { - containerFactory.getContainerProperties().setObservationEnabled(true); - } - return containerFactory; - } - - /** - * This sets the strategy for creating cloud Kafka producer instance from kafka properties defined into - * application.yml with CloudEventSerializer. - * - * @return cloud event producer instance. - */ - @Bean - public ProducerFactory cloudEventProducerFactory() { - final Map producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); - if (tracingEnabled) { - producerConfigProperties.put( - ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName()); - } - return new DefaultKafkaProducerFactory<>(producerConfigProperties); - } - - /** - * The ConsumerFactory implementation to produce new legacy instance for provided kafka properties defined - * into application.yml having CloudEventDeserializer as deserializer-value. - * - * @return an instance of cloud consumer factory. - */ - @Bean - public ConsumerFactory cloudEventConsumerFactory() { - final Map consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); - if (tracingEnabled) { - consumerConfigProperties.put( - ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName()); - } - return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); - } - - - /** - * A cloud Kafka event template for executing high-level operations. The cloud producer factory ensure this. - * - * @return an instance of cloud Kafka template. - */ - @Bean - public KafkaTemplate cloudEventKafkaTemplate() { - final KafkaTemplate kafkaTemplate = - new KafkaTemplate<>(cloudEventProducerFactory()); - kafkaTemplate.setConsumerFactory(cloudEventConsumerFactory()); - if (tracingEnabled) { - kafkaTemplate.setObservationEnabled(true); - } - return kafkaTemplate; - } - - /** - * A Concurrent CloudEvent kafka listener container factory. - * - * @return instance of Concurrent kafka listener factory - */ - @Bean - public ConcurrentKafkaListenerContainerFactory - cloudEventConcurrentKafkaListenerContainerFactory() { - final ConcurrentKafkaListenerContainerFactory containerFactory = - new ConcurrentKafkaListenerContainerFactory<>(); - containerFactory.setConsumerFactory(cloudEventConsumerFactory()); - containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10)); - if (tracingEnabled) { - containerFactory.getContainerProperties().setObservationEnabled(true); - } - return containerFactory; - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java deleted file mode 100644 index ab0fa68938..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiClientRequestException.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.exception; - -import lombok.Getter; -import org.onap.cps.ncmp.api.NcmpResponseStatus; - -/** - * Http Client Request exception from dmi service. - */ -@Getter -public class DmiClientRequestException extends NcmpException { - - private static final long serialVersionUID = 6659897770659834797L; - final NcmpResponseStatus ncmpResponseStatus; - final String message; - final String responseBodyAsString; - final int httpStatusCode; - - /** - * Constructor to form exception for dmi service response. - * - * @param httpStatusCode http response code from the client - * @param message response message from the client - * @param responseBodyAsString response body from the client - * @param ncmpResponseStatus ncmp status message and code - */ - public DmiClientRequestException(final int httpStatusCode, final String message, final String responseBodyAsString, - final NcmpResponseStatus ncmpResponseStatus) { - super(message, responseBodyAsString); - this.httpStatusCode = httpStatusCode; - this.message = message; - this.responseBodyAsString = responseBodyAsString; - this.ncmpResponseStatus = ncmpResponseStatus; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java deleted file mode 100644 index d41ca70bca..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/DmiRequestException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.exception; - -/** - * Client Based Network CM Proxy exception. - */ -public class DmiRequestException extends NcmpException { - - /** - * Constructor. - * - * @param message the error message - * @param details the error details - */ - public DmiRequestException(final String message, final String details) { - super(message, details); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java deleted file mode 100644 index 2c75b5d992..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.exception; - -import lombok.Getter; - -/** - * Network CM Proxy exception. - */ -public class NcmpException extends RuntimeException { - - private static final long serialVersionUID = 1482619410918497467L; - - @Getter - final String details; - - /** - * Constructor. - * - * @param message the error message - * @param details the error details - */ - public NcmpException(final String message, final String details) { - super(message); - this.details = details; - } - -} - diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java deleted file mode 100644 index 7ac26f54fd..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/NcmpStartUpException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.exception; - -/** - * NCMP start up exception. - */ -public class NcmpStartUpException extends NcmpException { - - /** - * Constructor. - * - * @param message the error message - * @param details the error details - */ - public NcmpStartUpException(final String message, final String details) { - super(message, details); - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java deleted file mode 100644 index a03a2d3e6c..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/exception/ServerNcmpException.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.exception; - -/** - * Server Based Network CM Proxy exception. - */ -public class ServerNcmpException extends NcmpException { - - /** - * Constructor. - * - * @param message the error message - * @param details the error details - */ - public ServerNcmpException(final String message, final String details) { - super(message, details); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java deleted file mode 100644 index c032d1e8a4..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DataNodeHelper.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.onap.cps.spi.model.DataNode; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class DataNodeHelper { - - /** - * The nested DataNode object is being flattened. - * - * @param dataNode object. - * @return DataNode as stream. - */ - public static Stream flatten(final DataNode dataNode) { - return Stream.concat(Stream.of(dataNode), - dataNode.getChildDataNodes().stream().flatMap(DataNodeHelper::flatten)); - } - - /** - * The leaves for each DataNode is listed as map. - * - * @param dataNodes as collection - * @return list of map for the all leaves - */ - public static List> getDataNodeLeaves(final Collection dataNodes) { - return dataNodes.stream() - .flatMap(DataNodeHelper::flatten) - .map(DataNode::getLeaves) - .collect(Collectors.toList()); - } - - /** - * Extracts the mapping of cm handle id to status with details from nodes leaves. - * - * @param dataNodeLeaves as a list of map - * @return cm handle id to status and details mapping - */ - public static Map> cmHandleIdToStatusAndDetailsAsMap( - final List> dataNodeLeaves) { - return dataNodeLeaves.stream() - .filter(entryset -> entryset.values().contains("PENDING") - || entryset.values().contains("ACCEPTED") - || entryset.values().contains("REJECTED")) - .collect( - HashMap>::new, - (result, entry) -> { - final String cmHandleId = (String) entry.get("cmHandleId"); - final String status = (String) entry.get("status"); - final String details = (String) entry.get("details"); - - if (cmHandleId != null && status != null) { - result.put(cmHandleId, new HashMap<>()); - result.get(cmHandleId).put("status", status); - result.get(cmHandleId).put("details", details == null ? "" : details); - } - }, - HashMap::putAll - ); - } - - /** - * Extracts the mapping of cm handle id to status with details from data node collection. - * - * @param dataNodes as a collection - * @return cm handle id to status and details mapping - */ - public static Map> cmHandleIdToStatusAndDetailsAsMapFromDataNode( - final Collection dataNodes) { - return cmHandleIdToStatusAndDetailsAsMap(getDataNodeLeaves(dataNodes)); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java deleted file mode 100644 index 67880648bc..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceNameOrganizer.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; -import org.onap.cps.ncmp.impl.models.RequiredDmiService; - -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class DmiServiceNameOrganizer { - - /** - * organizes a map with dmi service name as key for cm handle with its properties. - * - * @param yangModelCmHandles list of cm handle model - */ - public static Map>> getDmiPropertiesPerCmHandleIdPerServiceName( - final Collection yangModelCmHandles) { - final Map>> dmiPropertiesPerCmHandleIdPerServiceName - = new HashMap<>(); - yangModelCmHandles.forEach(yangModelCmHandle -> { - final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); - if (!dmiPropertiesPerCmHandleIdPerServiceName.containsKey(dmiServiceName)) { - final Map> cmHandleDmiPropertiesMap = new HashMap<>(); - cmHandleDmiPropertiesMap.put(yangModelCmHandle.getId(), - dmiPropertiesAsMap(yangModelCmHandle.getDmiProperties())); - dmiPropertiesPerCmHandleIdPerServiceName.put(dmiServiceName, cmHandleDmiPropertiesMap); - } else { - dmiPropertiesPerCmHandleIdPerServiceName.get(dmiServiceName) - .put(yangModelCmHandle.getId(), dmiPropertiesAsMap(yangModelCmHandle.getDmiProperties())); - } - }); - return dmiPropertiesPerCmHandleIdPerServiceName; - } - - private static Map dmiPropertiesAsMap(final List dmiProperties) { - return dmiProperties.stream().collect( - Collectors.toMap(YangModelCmHandle.Property::getName, YangModelCmHandle.Property::getValue)); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java deleted file mode 100644 index 5dd6827126..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils; - -import java.time.OffsetDateTime; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import org.apache.commons.lang3.StringUtils; - -public interface EventDateTimeFormatter { - - String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; - - DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN); - - /** - * Gets current date time. - * - * @return the current date time - */ - static String getCurrentIsoFormattedDateTime() { - return ZonedDateTime.now().format(ISO_TIMESTAMP_FORMATTER); - } - - static OffsetDateTime toIsoOffsetDateTime(final String dateTimestampAsString) { - return StringUtils.isNotBlank(dateTimestampAsString) - ? OffsetDateTime.parse(dateTimestampAsString, ISO_TIMESTAMP_FORMATTER) : null; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java deleted file mode 100644 index b14cf0d0db..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContext.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils.context; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -@Component -public class CpsApplicationContext implements ApplicationContextAware { - - private static ApplicationContext applicationContext; - - /** - * Returns the spring managed cps bean instance of the given class type if it exists. - * Returns null otherwise. - * - * @param cpsBeanClass cps class type - * @return requested bean instance - */ - public static T getCpsBean(final Class cpsBeanClass) { - return applicationContext.getBean(cpsBeanClass); - } - - @Override - public void setApplicationContext(final ApplicationContext cpsApplicationContext) { - setCpsApplicationContext(cpsApplicationContext); - } - - private static synchronized void setCpsApplicationContext(final ApplicationContext cpsApplicationContext) { - CpsApplicationContext.applicationContext = cpsApplicationContext; - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java deleted file mode 100644 index b89b7b3221..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilder.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils.url.builder; - -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import lombok.NoArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.apache.logging.log4j.util.Strings; -import org.springframework.web.util.UriComponentsBuilder; - -@NoArgsConstructor -public class DmiServiceUrlTemplateBuilder { - - private final UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); - private static final String FIXED_PATH_SEGMENT = null; - private static final String VERSION_SEGMENT = "v1"; - private final Map pathSegments = new LinkedHashMap<>(); - private final Map queryParameters = new LinkedHashMap<>(); - - /** - * Static factory method to create a new instance of DmiServiceUrlTemplateBuilder. - * - * @return a new instance of DmiServiceUrlTemplateBuilder - */ - public static DmiServiceUrlTemplateBuilder newInstance() { - return new DmiServiceUrlTemplateBuilder(); - } - - /** - * Add a fixed pathSegment to the URL. - * - * @param pathSegment the path segment - * @return this builder instance - */ - public DmiServiceUrlTemplateBuilder fixedPathSegment(final String pathSegment) { - pathSegments.put(pathSegment, FIXED_PATH_SEGMENT); - return this; - } - - /** - * Add a variable pathSegment to the URL. - * Do NOT add { } braces. the builder will take care of that - * - * @param pathSegment the name of the variable path segment (with { and } - * @param value the value to be insert in teh URL for the given variable path segment - * @return this builder instance - */ - public DmiServiceUrlTemplateBuilder variablePathSegment(final String pathSegment, final String value) { - pathSegments.put(pathSegment, value); - return this; - } - - /** - * Add a query parameter to the URL. - * Do NOT encode as the builder wil take care of encoding - * - * @param queryParameterName the name of the variable - * @param queryParameterValue the value of the variable (only Strings are supported). - * - * @return this builder instance - */ - public DmiServiceUrlTemplateBuilder queryParameter(final String queryParameterName, - final String queryParameterValue) { - if (Strings.isNotBlank(queryParameterValue)) { - queryParameters.put(queryParameterName, queryParameterValue); - } - return this; - } - - /** - * Constructs a URL template with variables based on the accumulated path segments and query parameters. - * - * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". - * @param dmiBasePath the base path of the DMI service - * @return a UrlTemplateParameters instance containing the complete URL template and URL variables - */ - public UrlTemplateParameters createUrlTemplateParameters(final String dmiServiceBaseUrl, final String dmiBasePath) { - this.uriComponentsBuilder.pathSegment(dmiBasePath) - .pathSegment(VERSION_SEGMENT); - - final Map urlTemplateVariables = new HashMap<>(); - - pathSegments.forEach((pathSegmentName, variablePathValue) -> { - if (StringUtils.equals(variablePathValue, FIXED_PATH_SEGMENT)) { - this.uriComponentsBuilder.pathSegment(pathSegmentName); - } else { - this.uriComponentsBuilder.pathSegment("{" + pathSegmentName + "}"); - urlTemplateVariables.put(pathSegmentName, variablePathValue); - } - }); - - queryParameters.forEach((paramName, paramValue) -> { - this.uriComponentsBuilder.queryParam(paramName, "{" + paramName + "}"); - urlTemplateVariables.put(paramName, paramValue); - }); - - final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); - return new UrlTemplateParameters(urlTemplate, urlTemplateVariables); - } - - /** - * Constructs a URL for DMI health check based on the given base URL. - * - * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". - * @return a {@link UrlTemplateParameters} instance containing the complete URL template and empty URL variables, - * suitable for DMI health check. - */ - public UrlTemplateParameters createUrlTemplateParametersForHealthCheck(final String dmiServiceBaseUrl) { - this.uriComponentsBuilder.pathSegment("actuator") - .pathSegment("health"); - - final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); - return new UrlTemplateParameters(urlTemplate, Collections.emptyMap()); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java deleted file mode 100644 index edf56197b5..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/url/builder/UrlTemplateParameters.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils.url.builder; - -import java.util.Map; - -/** - * Represents a URL template with associated variables for dynamic substitution. - * This record encapsulates a URL template string and a map of variables used for substitution within the template. - */ -public record UrlTemplateParameters(String urlTemplate, Map urlVariables) { -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java index a5002e7909..44e2ebe320 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/DmiPluginRegistration.java @@ -27,8 +27,8 @@ import java.util.Collections; import java.util.List; import lombok.Getter; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.exception.DmiRequestException; -import org.onap.cps.ncmp.api.impl.exception.NcmpException; +import org.onap.cps.ncmp.api.exceptions.DmiRequestException; +import org.onap.cps.ncmp.api.exceptions.NcmpException; /** * Dmi Registry request object. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java new file mode 100644 index 0000000000..fbc31adcf3 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/CpsApplicationContext.java @@ -0,0 +1,51 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +@Component +public class CpsApplicationContext implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + /** + * Returns the spring managed cps bean instance of the given class type if it exists. + * Returns null otherwise. + * + * @param cpsBeanClass cps class type + * @return requested bean instance + */ + public static T getCpsBean(final Class cpsBeanClass) { + return applicationContext.getBean(cpsBeanClass); + } + + @Override + public void setApplicationContext(final ApplicationContext cpsApplicationContext) { + setCpsApplicationContext(cpsApplicationContext); + } + + private static synchronized void setCpsApplicationContext(final ApplicationContext cpsApplicationContext) { + CpsApplicationContext.applicationContext = cpsApplicationContext; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/HttpClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/HttpClientConfiguration.java new file mode 100644 index 0000000000..583d4bb6ad --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/HttpClientConfiguration.java @@ -0,0 +1,72 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Getter +@Setter +@Configuration +@ConfigurationProperties(prefix = "ncmp.dmi.httpclient") +public class HttpClientConfiguration { + + private final DataServices dataServices = new DataServices(); + private final ModelServices modelServices = new ModelServices(); + private final HealthCheckServices healthCheckServices = new HealthCheckServices(); + + @Getter + @Setter + public static class DataServices extends ServiceConfig { + private String connectionProviderName = "dataConnectionPool"; + } + + @Getter + @Setter + public static class ModelServices extends ServiceConfig { + private String connectionProviderName = "modelConnectionPool"; + } + + @Getter + @Setter + public static class HealthCheckServices extends ServiceConfig { + private String connectionProviderName = "healthConnectionPool"; + private int maximumConnectionsTotal = 10; + private int pendingAcquireMaxCount = 5; + } + + /** + * Base configuration properties for all services. + */ + @Getter + @Setter + public static class ServiceConfig { + private String connectionProviderName = "cpsConnectionPool"; + private int maximumConnectionsTotal = 100; + private int pendingAcquireMaxCount = 50; + private Integer connectionTimeoutInSeconds = 30; + private long readTimeoutInSeconds = 30; + private long writeTimeoutInSeconds = 30; + private int maximumInMemorySizeInMegabytes = 1; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/KafkaConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/KafkaConfig.java new file mode 100644 index 0000000000..3d3c3db482 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/KafkaConfig.java @@ -0,0 +1,198 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config; + +import io.cloudevents.CloudEvent; +import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingConsumerInterceptor; +import io.opentelemetry.instrumentation.kafkaclients.v2_6.TracingProducerInterceptor; +import java.time.Duration; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.kafka.KafkaProperties; +import org.springframework.boot.ssl.SslBundles; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.kafka.annotation.EnableKafka; +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory; +import org.springframework.kafka.core.ConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaConsumerFactory; +import org.springframework.kafka.core.DefaultKafkaProducerFactory; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.core.ProducerFactory; +import org.springframework.kafka.support.serializer.JsonDeserializer; +import org.springframework.kafka.support.serializer.JsonSerializer; + +/** + * kafka Configuration for legacy and cloud events. + * + * @param valid legacy event to be published over the wire. + */ +@Configuration +@EnableKafka +@RequiredArgsConstructor +public class KafkaConfig { + + private final KafkaProperties kafkaProperties; + + @Value("${cps.tracing.enabled:false}") + private boolean tracingEnabled; + + private static final SslBundles NO_SSL = null; + + /** + * This sets the strategy for creating legacy Kafka producer instance from kafka properties defined into + * application.yml and replaces value-serializer by JsonSerializer. + * + * @return legacy event producer instance. + */ + @Bean + public ProducerFactory legacyEventProducerFactory() { + final Map producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); + producerConfigProperties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class); + if (tracingEnabled) { + producerConfigProperties.put( + ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName()); + } + return new DefaultKafkaProducerFactory<>(producerConfigProperties); + } + + /** + * The ConsumerFactory implementation is to produce new legacy instance for provided kafka properties defined + * into application.yml and replaces deserializer-value by JsonDeserializer. + * + * @return an instance of legacy consumer factory. + */ + @Bean + public ConsumerFactory legacyEventConsumerFactory() { + final Map consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); + consumerConfigProperties.put("spring.deserializer.value.delegate.class", JsonDeserializer.class); + if (tracingEnabled) { + consumerConfigProperties.put( + ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName()); + } + return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); + } + + /** + * A legacy Kafka event template for executing high-level operations. The legacy producer factory ensure this. + * + * @return an instance of legacy Kafka template. + */ + @Bean + @Primary + public KafkaTemplate legacyEventKafkaTemplate() { + final KafkaTemplate kafkaTemplate = new KafkaTemplate<>(legacyEventProducerFactory()); + kafkaTemplate.setConsumerFactory(legacyEventConsumerFactory()); + if (tracingEnabled) { + kafkaTemplate.setObservationEnabled(true); + } + return kafkaTemplate; + } + + /** + * A legacy concurrent kafka listener container factory. + * + * @return instance of Concurrent kafka listener factory + */ + @Bean + public ConcurrentKafkaListenerContainerFactory legacyEventConcurrentKafkaListenerContainerFactory() { + final ConcurrentKafkaListenerContainerFactory containerFactory = + new ConcurrentKafkaListenerContainerFactory<>(); + containerFactory.setConsumerFactory(legacyEventConsumerFactory()); + containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10)); + if (tracingEnabled) { + containerFactory.getContainerProperties().setObservationEnabled(true); + } + return containerFactory; + } + + /** + * This sets the strategy for creating cloud Kafka producer instance from kafka properties defined into + * application.yml with CloudEventSerializer. + * + * @return cloud event producer instance. + */ + @Bean + public ProducerFactory cloudEventProducerFactory() { + final Map producerConfigProperties = kafkaProperties.buildProducerProperties(NO_SSL); + if (tracingEnabled) { + producerConfigProperties.put( + ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingProducerInterceptor.class.getName()); + } + return new DefaultKafkaProducerFactory<>(producerConfigProperties); + } + + /** + * The ConsumerFactory implementation to produce new legacy instance for provided kafka properties defined + * into application.yml having CloudEventDeserializer as deserializer-value. + * + * @return an instance of cloud consumer factory. + */ + @Bean + public ConsumerFactory cloudEventConsumerFactory() { + final Map consumerConfigProperties = kafkaProperties.buildConsumerProperties(NO_SSL); + if (tracingEnabled) { + consumerConfigProperties.put( + ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, TracingConsumerInterceptor.class.getName()); + } + return new DefaultKafkaConsumerFactory<>(consumerConfigProperties); + } + + + /** + * A cloud Kafka event template for executing high-level operations. The cloud producer factory ensure this. + * + * @return an instance of cloud Kafka template. + */ + @Bean + public KafkaTemplate cloudEventKafkaTemplate() { + final KafkaTemplate kafkaTemplate = + new KafkaTemplate<>(cloudEventProducerFactory()); + kafkaTemplate.setConsumerFactory(cloudEventConsumerFactory()); + if (tracingEnabled) { + kafkaTemplate.setObservationEnabled(true); + } + return kafkaTemplate; + } + + /** + * A Concurrent CloudEvent kafka listener container factory. + * + * @return instance of Concurrent kafka listener factory + */ + @Bean + public ConcurrentKafkaListenerContainerFactory + cloudEventConcurrentKafkaListenerContainerFactory() { + final ConcurrentKafkaListenerContainerFactory containerFactory = + new ConcurrentKafkaListenerContainerFactory<>(); + containerFactory.setConsumerFactory(cloudEventConsumerFactory()); + containerFactory.getContainerProperties().setAuthExceptionRetryInterval(Duration.ofSeconds(10)); + if (tracingEnabled) { + containerFactory.getContainerProperties().setObservationEnabled(true); + } + return containerFactory; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java new file mode 100644 index 0000000000..cff3187966 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/config/OpenTelemetryConfig.java @@ -0,0 +1,111 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config; + +import io.micrometer.observation.ObservationPredicate; +import io.micrometer.observation.ObservationRegistry; +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler; +import io.opentelemetry.sdk.trace.samplers.Sampler; +import java.time.Duration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.server.observation.ServerRequestObservationContext; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +@Configuration +public class OpenTelemetryConfig { + + public static final int JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND = 30; + + @Value("${spring.application.name:cps-application}") + private String serviceId; + + @Value("${cps.tracing.exporter.endpoint:http://onap-otel-collector:4317}") + private String tracingExporterEndpointUrl; + + @Value("${cps.tracing.sampler.jaeger_remote.endpoint:http://onap-otel-collector:14250}") + private String jaegerRemoteSamplerUrl; + + /** + * OTLP Exporter with Grpc exporter protocol. + */ + @Bean + @ConditionalOnExpression( + "${cps.tracing.enabled} && 'grpc'.equals('${cps.tracing.exporter.protocol}')") + public OtlpGrpcSpanExporter createOtlpExporterGrpc() { + return OtlpGrpcSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build(); + } + + /** + * OTLP Exporter with HTTP exporter protocol. + */ + @Bean + @ConditionalOnExpression( + "${cps.tracing.enabled} && 'http'.equals('${cps.tracing.exporter.protocol}')") + public OtlpHttpSpanExporter createOtlpExporterHttp() { + return OtlpHttpSpanExporter.builder().setEndpoint(tracingExporterEndpointUrl).build(); + } + + /** + * Jaeger Remote Sampler. + */ + @Bean + @ConditionalOnProperty("cps.tracing.enabled") + public JaegerRemoteSampler createJaegerRemoteSampler() { + return JaegerRemoteSampler.builder() + .setEndpoint(jaegerRemoteSamplerUrl) + .setPollingInterval(Duration.ofSeconds(JAEGER_REMOTE_SAMPLER_POLLING_INTERVAL_IN_SECOND)) + .setInitialSampler(Sampler.alwaysOff()) + .setServiceName(serviceId) + .build(); + } + + /** + * Excluding /actuator/** endpoints. + */ + @Bean + @ConditionalOnProperty("cps.tracing.enabled") + ObservationRegistryCustomizer skipActuatorEndpointsFromObservation() { + final PathMatcher pathMatcher = new AntPathMatcher("/"); + return registry -> + registry.observationConfig().observationPredicate(observationPredicate(pathMatcher)); + } + + /** + * Excluding /actuator/** endpoints. + */ + static ObservationPredicate observationPredicate(final PathMatcher pathMatcher) { + return (name, context) -> { + if (context instanceof ServerRequestObservationContext observationContext) { + return !pathMatcher.match("/actuator/**", observationContext.getCarrier().getRequestURI()); + } else { + return true; + } + }; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/InvalidTopicException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/InvalidTopicException.java deleted file mode 100644 index fcf2a28ccc..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/InvalidTopicException.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.exceptions; - -import lombok.Getter; - -public class InvalidTopicException extends RuntimeException { - - @Getter - final String details; - - /** - * Constructor. - * - * @param message the error message - * @param details the error details - */ - public InvalidTopicException(final String message, final String details) { - super(message); - this.details = details; - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java new file mode 100644 index 0000000000..7ffbe2e5cb --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NcmpStartUpException.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.exceptions; + +import org.onap.cps.ncmp.api.exceptions.NcmpException; + +/** + * NCMP start up exception. + */ +public class NcmpStartUpException extends NcmpException { + + /** + * Constructor. + * + * @param message the error message + * @param details the error details + */ + public NcmpStartUpException(final String message, final String details) { + super(message, details); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java index 510a6f51a0..7c5fc3be2b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/NoAlternateIdMatchFoundException.java @@ -21,7 +21,7 @@ package org.onap.cps.ncmp.exceptions; import java.io.Serial; -import org.onap.cps.ncmp.api.impl.exception.NcmpException; +import org.onap.cps.ncmp.api.exceptions.NcmpException; public class NoAlternateIdMatchFoundException extends NcmpException { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/PayloadTooLargeException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/PayloadTooLargeException.java deleted file mode 100644 index dc7057af79..0000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/exceptions/PayloadTooLargeException.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.exceptions; - -public class PayloadTooLargeException extends RuntimeException { - - /** - * Instantiates a new payload too large exception. - */ - public PayloadTooLargeException(final String message) { - super(message); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java index efe0335e8c..b902fe2767 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java @@ -37,15 +37,15 @@ import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.data.models.CmResourceAddress; import org.onap.cps.ncmp.api.data.models.DataOperationRequest; import org.onap.cps.ncmp.api.data.models.OperationType; -import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException; -import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; +import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException; import org.onap.cps.ncmp.impl.data.models.DmiDataOperation; import org.onap.cps.ncmp.impl.data.models.DmiDataOperationRequest; import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle; import org.onap.cps.ncmp.impl.data.utils.DmiDataOperationsHelper; +import org.onap.cps.ncmp.impl.dmi.DmiProperties; +import org.onap.cps.ncmp.impl.dmi.DmiRestClient; +import org.onap.cps.ncmp.impl.dmi.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java index be2dde2308..a21210c376 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpPassthroughResourceRequestHandler.java @@ -32,7 +32,7 @@ import org.onap.cps.ncmp.api.data.models.CmResourceAddress; import org.onap.cps.ncmp.api.data.models.DataOperationRequest; import org.onap.cps.ncmp.api.data.models.DatastoreType; import org.onap.cps.ncmp.api.data.models.OperationType; -import org.onap.cps.ncmp.exceptions.PayloadTooLargeException; +import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException; import org.onap.cps.ncmp.utils.events.TopicValidator; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java index ab2f106449..3104be5539 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelper.java @@ -39,10 +39,10 @@ import org.onap.cps.events.EventsPublisher; import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.data.models.DataOperationDefinition; import org.onap.cps.ncmp.api.data.models.DataOperationRequest; -import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer; -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; +import org.onap.cps.ncmp.config.CpsApplicationContext; import org.onap.cps.ncmp.impl.data.models.DmiDataOperation; import org.onap.cps.ncmp.impl.data.models.DmiOperationCmHandle; +import org.onap.cps.ncmp.impl.dmi.DmiServiceNameOrganizer; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.springframework.util.LinkedMultiValueMap; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java index 973a2a9b2d..3d1c5237d6 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandler.java @@ -31,10 +31,10 @@ import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation; import org.onap.cps.ncmp.api.datajobs.models.ProducerKey; import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteRequest; import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse; -import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; +import org.onap.cps.ncmp.impl.dmi.DmiProperties; +import org.onap.cps.ncmp.impl.dmi.DmiRestClient; +import org.onap.cps.ncmp.impl.dmi.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters; import org.onap.cps.ncmp.impl.models.RequiredDmiService; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.http.ResponseEntity; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java new file mode 100644 index 0000000000..2f60460da3 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiProperties.java @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import lombok.AccessLevel; +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Getter +@Component +public class DmiProperties { + @Value("${ncmp.dmi.auth.username}") + private String authUsername; + @Value("${ncmp.dmi.auth.password}") + private String authPassword; + @Getter(AccessLevel.NONE) + @Value("${ncmp.dmi.api.base-path}") + private String dmiBasePath; + @Value("${ncmp.dmi.auth.enabled}") + private boolean dmiBasicAuthEnabled; + + /** + * Removes both leading and trailing slashes if they are present. + * + * @return dmi base path without any slashes ("/") + */ + public String getDmiBasePath() { + if (dmiBasePath.startsWith("/")) { + dmiBasePath = dmiBasePath.substring(1); + } + if (dmiBasePath.endsWith("/")) { + dmiBasePath = dmiBasePath.substring(0, dmiBasePath.length() - 1); + } + return dmiBasePath; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java new file mode 100644 index 0000000000..7ac85cbf84 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiRestClient.java @@ -0,0 +1,186 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021-2024 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; +import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.Locale; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.data.models.OperationType; +import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.reactive.function.client.WebClientRequestException; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import reactor.core.publisher.Mono; + +@Component +@RequiredArgsConstructor +@Slf4j +public class DmiRestClient { + + private static final String NOT_SPECIFIED = ""; + private static final String NO_AUTHORIZATION = null; + + private final DmiProperties dmiProperties; + private final JsonObjectMapper jsonObjectMapper; + @Qualifier("dataServicesWebClient") + private final WebClient dataServicesWebClient; + @Qualifier("modelServicesWebClient") + private final WebClient modelServicesWebClient; + @Qualifier("healthChecksWebClient") + private final WebClient healthChecksWebClient; + + /** + * Sends a synchronous (blocking) POST operation to the DMI with a JSON body containing module references. + * + * @param requiredDmiService Determines if the required service is for a data or model operation. + * @param urlTemplateParameters The DMI resource URL template with variables. + * @param requestBodyAsJsonString JSON data body. + * @param operationType The type of operation being executed (for error reporting only). + * @param authorization Contents of the Authorization header, or null if not present. + * @return ResponseEntity containing the response from the DMI. + * @throws DmiClientRequestException If there is an error during the DMI request. + */ + public ResponseEntity synchronousPostOperationWithJsonData(final RequiredDmiService requiredDmiService, + final UrlTemplateParameters + urlTemplateParameters, + final String requestBodyAsJsonString, + final OperationType operationType, + final String authorization) { + final Mono> responseEntityMono = + asynchronousPostOperationWithJsonData(requiredDmiService, + urlTemplateParameters, + requestBodyAsJsonString, + operationType, + authorization); + return responseEntityMono.block(); + } + + /** + * Asynchronously performs an HTTP POST operation with the given JSON data. + * + * @param requiredDmiService The service object required for retrieving or configuring the WebClient. + * @param urlTemplateParameters The URL template with variables for the POST request. + * @param requestBodyAsJsonString The JSON string that will be sent as the request body. + * @param operationType An enumeration or object that holds information about the type of operation + * being performed. + * @param authorization The authorization token to be added to the request headers. + * @return A Mono emitting the response entity containing the server's response. + */ + public Mono> asynchronousPostOperationWithJsonData(final RequiredDmiService + requiredDmiService, + final UrlTemplateParameters + urlTemplateParameters, + final String requestBodyAsJsonString, + final OperationType operationType, + final String authorization) { + final WebClient webClient = getWebClient(requiredDmiService); + return webClient.post() + .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) + .headers(httpHeaders -> configureHttpHeaders(httpHeaders, authorization)) + .body(BodyInserters.fromValue(requestBodyAsJsonString)) + .retrieve() + .toEntity(Object.class) + .onErrorMap(throwable -> handleDmiClientException(throwable, operationType.getOperationName())); + } + + /** + * Retrieves the health status of the DMI plugin. + * This method performs an HTTP GET request to the DMI health check endpoint specified by the URL template + * parameters. If the response status code indicates a client error (4xx) or a server error (5xx), it logs a warning + * and returns an empty Mono. In case of an error during the request, it logs the exception and returns a default + * value of "NOT_SPECIFIED". If the response body contains a JSON node with a "status" field, the value of this + * field is returned. + * + * @param urlTemplateParameters the URL template parameters for the DMI health check endpoint + * @return a Mono emitting the health status as a String, or "NOT_SPECIFIED" if an error occurs + */ + public Mono getDmiHealthStatus(final UrlTemplateParameters urlTemplateParameters) { + return healthChecksWebClient.get() + .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) + .headers(httpHeaders -> configureHttpHeaders(httpHeaders, NO_AUTHORIZATION)) + .retrieve() + .bodyToMono(JsonNode.class) + .map(responseHealthStatus -> responseHealthStatus.path("status").asText()) + .onErrorResume(Exception.class, ex -> { + log.warn("Failed to retrieve health status from {}. Status: {}", + urlTemplateParameters.urlTemplate(), ex.getMessage()); + return Mono.empty(); + }) + .defaultIfEmpty(NOT_SPECIFIED); + } + + private WebClient getWebClient(final RequiredDmiService requiredDmiService) { + return requiredDmiService.equals(RequiredDmiService.DATA) ? dataServicesWebClient : modelServicesWebClient; + } + + private void configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) { + if (dmiProperties.isDmiBasicAuthEnabled()) { + httpHeaders.setBasicAuth(dmiProperties.getAuthUsername(), dmiProperties.getAuthPassword()); + } else if (authorization != null && authorization.toLowerCase(Locale.getDefault()).startsWith("bearer ")) { + httpHeaders.add(HttpHeaders.AUTHORIZATION, authorization); + } + } + + private DmiClientRequestException handleDmiClientException(final Throwable throwable, final String operationType) { + if (throwable instanceof WebClientResponseException webClientResponseException) { + if (webClientResponseException.getStatusCode().isSameCodeAs(REQUEST_TIMEOUT)) { + throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(), + webClientResponseException.getMessage(), + jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()), + DMI_SERVICE_NOT_RESPONDING); + } + throw new DmiClientRequestException(webClientResponseException.getStatusCode().value(), + webClientResponseException.getMessage(), + jsonObjectMapper.asJsonString(webClientResponseException.getResponseBodyAsString()), + UNABLE_TO_READ_RESOURCE_DATA); + + } + final String exceptionMessage = "Unable to " + operationType + " resource data."; + if (throwable instanceof WebClientRequestException webClientRequestException) { + throw new DmiClientRequestException(HttpStatus.SERVICE_UNAVAILABLE.value(), + webClientRequestException.getMessage(), + exceptionMessage, DMI_SERVICE_NOT_RESPONDING); + } + if (throwable instanceof HttpServerErrorException httpServerErrorException) { + throw new DmiClientRequestException(httpServerErrorException.getStatusCode().value(), exceptionMessage, + httpServerErrorException.getResponseBodyAsString(), DMI_SERVICE_NOT_RESPONDING); + } + throw new DmiClientRequestException(INTERNAL_SERVER_ERROR.value(), exceptionMessage, throwable.getMessage(), + UNKNOWN_ERROR); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java new file mode 100644 index 0000000000..37e982d8cb --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceNameOrganizer.java @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class DmiServiceNameOrganizer { + + /** + * organizes a map with dmi service name as key for cm handle with its properties. + * + * @param yangModelCmHandles list of cm handle model + */ + public static Map>> getDmiPropertiesPerCmHandleIdPerServiceName( + final Collection yangModelCmHandles) { + final Map>> dmiPropertiesPerCmHandleIdPerServiceName + = new HashMap<>(); + yangModelCmHandles.forEach(yangModelCmHandle -> { + final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); + if (!dmiPropertiesPerCmHandleIdPerServiceName.containsKey(dmiServiceName)) { + final Map> cmHandleDmiPropertiesMap = new HashMap<>(); + cmHandleDmiPropertiesMap.put(yangModelCmHandle.getId(), + dmiPropertiesAsMap(yangModelCmHandle.getDmiProperties())); + dmiPropertiesPerCmHandleIdPerServiceName.put(dmiServiceName, cmHandleDmiPropertiesMap); + } else { + dmiPropertiesPerCmHandleIdPerServiceName.get(dmiServiceName) + .put(yangModelCmHandle.getId(), dmiPropertiesAsMap(yangModelCmHandle.getDmiProperties())); + } + }); + return dmiPropertiesPerCmHandleIdPerServiceName; + } + + private static Map dmiPropertiesAsMap(final List dmiProperties) { + return dmiProperties.stream().collect( + Collectors.toMap(YangModelCmHandle.Property::getName, YangModelCmHandle.Property::getValue)); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilder.java new file mode 100644 index 0000000000..e7dbea83f2 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilder.java @@ -0,0 +1,137 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.util.Strings; +import org.springframework.web.util.UriComponentsBuilder; + +@NoArgsConstructor +public class DmiServiceUrlTemplateBuilder { + + private final UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.newInstance(); + private static final String FIXED_PATH_SEGMENT = null; + private static final String VERSION_SEGMENT = "v1"; + private final Map pathSegments = new LinkedHashMap<>(); + private final Map queryParameters = new LinkedHashMap<>(); + + /** + * Static factory method to create a new instance of DmiServiceUrlTemplateBuilder. + * + * @return a new instance of DmiServiceUrlTemplateBuilder + */ + public static DmiServiceUrlTemplateBuilder newInstance() { + return new DmiServiceUrlTemplateBuilder(); + } + + /** + * Add a fixed pathSegment to the URL. + * + * @param pathSegment the path segment + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder fixedPathSegment(final String pathSegment) { + pathSegments.put(pathSegment, FIXED_PATH_SEGMENT); + return this; + } + + /** + * Add a variable pathSegment to the URL. + * Do NOT add { } braces. the builder will take care of that + * + * @param pathSegment the name of the variable path segment (with { and } + * @param value the value to be insert in teh URL for the given variable path segment + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder variablePathSegment(final String pathSegment, final String value) { + pathSegments.put(pathSegment, value); + return this; + } + + /** + * Add a query parameter to the URL. + * Do NOT encode as the builder wil take care of encoding + * + * @param queryParameterName the name of the variable + * @param queryParameterValue the value of the variable (only Strings are supported). + * + * @return this builder instance + */ + public DmiServiceUrlTemplateBuilder queryParameter(final String queryParameterName, + final String queryParameterValue) { + if (Strings.isNotBlank(queryParameterValue)) { + queryParameters.put(queryParameterName, queryParameterValue); + } + return this; + } + + /** + * Constructs a URL template with variables based on the accumulated path segments and query parameters. + * + * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". + * @param dmiBasePath the base path of the DMI service + * @return a UrlTemplateParameters instance containing the complete URL template and URL variables + */ + public UrlTemplateParameters createUrlTemplateParameters(final String dmiServiceBaseUrl, final String dmiBasePath) { + this.uriComponentsBuilder.pathSegment(dmiBasePath) + .pathSegment(VERSION_SEGMENT); + + final Map urlTemplateVariables = new HashMap<>(); + + pathSegments.forEach((pathSegmentName, variablePathValue) -> { + if (StringUtils.equals(variablePathValue, FIXED_PATH_SEGMENT)) { + this.uriComponentsBuilder.pathSegment(pathSegmentName); + } else { + this.uriComponentsBuilder.pathSegment("{" + pathSegmentName + "}"); + urlTemplateVariables.put(pathSegmentName, variablePathValue); + } + }); + + queryParameters.forEach((paramName, paramValue) -> { + this.uriComponentsBuilder.queryParam(paramName, "{" + paramName + "}"); + urlTemplateVariables.put(paramName, paramValue); + }); + + final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); + return new UrlTemplateParameters(urlTemplate, urlTemplateVariables); + } + + /** + * Constructs a URL for DMI health check based on the given base URL. + * + * @param dmiServiceBaseUrl the base URL of the DMI service, e.g., "http://dmi-service.com". + * @return a {@link UrlTemplateParameters} instance containing the complete URL template and empty URL variables, + * suitable for DMI health check. + */ + public UrlTemplateParameters createUrlTemplateParametersForHealthCheck(final String dmiServiceBaseUrl) { + this.uriComponentsBuilder.pathSegment("actuator") + .pathSegment("health"); + + final String urlTemplate = dmiServiceBaseUrl + this.uriComponentsBuilder.build().toUriString(); + return new UrlTemplateParameters(urlTemplate, Collections.emptyMap()); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfiguration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfiguration.java new file mode 100644 index 0000000000..c176e40226 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfiguration.java @@ -0,0 +1,122 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import io.netty.channel.ChannelOption; +import io.netty.handler.timeout.ReadTimeoutHandler; +import io.netty.handler.timeout.WriteTimeoutHandler; +import io.netty.resolver.DefaultAddressResolverGroup; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.config.HttpClientConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.client.reactive.ReactorClientHttpConnector; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.netty.http.client.HttpClient; +import reactor.netty.resources.ConnectionProvider; + +/** + * Configures and creates WebClient beans for various DMI services including data, model, and health check services. + * The configuration utilizes Netty-based HttpClient with custom connection settings, read and write timeouts, + * and initializes WebClient with these settings to ensure optimal performance and resource management. + */ +@Configuration +@RequiredArgsConstructor +public class DmiWebClientConfiguration { + + private final HttpClientConfiguration httpClientConfiguration; + private static final Duration DEFAULT_RESPONSE_TIMEOUT = Duration.ofSeconds(30); + + /** + * Configures and creates a web client bean for DMI data services. + * + * @param webClientBuilder The builder instance to create the WebClient. + * @return a WebClient instance configured for data services. + */ + @Bean + public WebClient dataServicesWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getDataServices()); + } + + /** + * Configures and creates a web client bean for DMI model services. + * + * @param webClientBuilder The builder instance to create the WebClient. + * @return a WebClient instance configured for model services. + */ + @Bean + public WebClient modelServicesWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getModelServices()); + } + + /** + * Configures and creates a web client bean for DMI health check services. + * + * @param webClientBuilder The builder instance to create the WebClient. + * @return a WebClient instance configured for health check services. + */ + @Bean + public WebClient healthChecksWebClient(final WebClient.Builder webClientBuilder) { + return configureWebClient(webClientBuilder, httpClientConfiguration.getHealthCheckServices()); + } + + private WebClient configureWebClient(final WebClient.Builder webClientBuilder, + final HttpClientConfiguration.ServiceConfig serviceConfig) { + final ConnectionProvider connectionProvider = getConnectionProvider(serviceConfig); + final HttpClient httpClient = createHttpClient(serviceConfig, connectionProvider); + return buildAndGetWebClient(webClientBuilder, httpClient, serviceConfig.getMaximumInMemorySizeInMegabytes()); + } + + private static HttpClient createHttpClient(final HttpClientConfiguration.ServiceConfig serviceConfig, + final ConnectionProvider connectionProvider) { + return HttpClient.create(connectionProvider) + .responseTimeout(DEFAULT_RESPONSE_TIMEOUT) + .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, serviceConfig.getConnectionTimeoutInSeconds() * 1000) + .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler( + serviceConfig.getReadTimeoutInSeconds(), TimeUnit.SECONDS)).addHandlerLast( + new WriteTimeoutHandler(serviceConfig.getWriteTimeoutInSeconds(), TimeUnit.SECONDS))) + .resolver(DefaultAddressResolverGroup.INSTANCE) + .compress(true); + } + + @SuppressFBWarnings("BC_UNCONFIRMED_CAST_OF_RETURN_VALUE") + private static ConnectionProvider getConnectionProvider(final HttpClientConfiguration.ServiceConfig serviceConfig) { + return ConnectionProvider.builder(serviceConfig.getConnectionProviderName()) + .maxConnections(serviceConfig.getMaximumConnectionsTotal()) + .pendingAcquireMaxCount(serviceConfig.getPendingAcquireMaxCount()) + .build(); + } + + private WebClient buildAndGetWebClient(final WebClient.Builder webClientBuilder, final HttpClient httpClient, + final int maximumInMemorySizeInMegabytes) { + return webClientBuilder + .defaultHeaders(header -> header.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)) + .defaultHeaders(header -> header.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)) + .clientConnector(new ReactorClientHttpConnector(httpClient)) + .codecs(configurer -> configurer.defaultCodecs() + .maxInMemorySize(maximumInMemorySizeInMegabytes * 1024 * 1024)).build(); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/UrlTemplateParameters.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/UrlTemplateParameters.java new file mode 100644 index 0000000000..f51511116a --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/dmi/UrlTemplateParameters.java @@ -0,0 +1,30 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi; + +import java.util.Map; + +/** + * Represents a URL template with associated variables for dynamic substitution. + * This record encapsulates a URL template string and a map of variables used for substitution within the template. + */ +public record UrlTemplateParameters(String urlTemplate, Map urlVariables) { +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java index c1f89b3440..433c67f100 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java @@ -33,11 +33,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.DmiProperties; -import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; import org.onap.cps.ncmp.api.inventory.models.YangResource; +import org.onap.cps.ncmp.impl.dmi.DmiProperties; +import org.onap.cps.ncmp.impl.dmi.DmiRestClient; +import org.onap.cps.ncmp.impl.dmi.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.models.DmiRequestBody; import org.onap.cps.spi.model.ModuleReference; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java index 3ce6b91590..5137515758 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCreator.java @@ -26,12 +26,12 @@ import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.events.lcm.v1.Event; import org.onap.cps.ncmp.events.lcm.v1.LcmEvent; import org.onap.cps.ncmp.events.lcm.v1.LcmEventHeader; import org.onap.cps.ncmp.events.lcm.v1.Values; +import org.onap.cps.ncmp.impl.utils.EventDateTimeFormatter; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java index 8be8ead44c..c81e9b7840 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java @@ -24,10 +24,10 @@ import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.utils.url.builder.DmiServiceUrlTemplateBuilder; -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; +import org.onap.cps.ncmp.impl.dmi.DmiRestClient; +import org.onap.cps.ncmp.impl.dmi.DmiServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters; import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.annotation.Scheduled; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java new file mode 100644 index 0000000000..9284c0fab7 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatter.java @@ -0,0 +1,47 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.utils; + +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import org.apache.commons.lang3.StringUtils; + +public interface EventDateTimeFormatter { + + String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; + + DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN); + + /** + * Gets current date time. + * + * @return the current date time + */ + static String getCurrentIsoFormattedDateTime() { + return ZonedDateTime.now().format(ISO_TIMESTAMP_FORMATTER); + } + + static OffsetDateTime toIsoOffsetDateTime(final String dateTimestampAsString) { + return StringUtils.isNotBlank(dateTimestampAsString) + ? OffsetDateTime.parse(dateTimestampAsString, ISO_TIMESTAMP_FORMATTER) : null; + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java index 554501127c..6d51eb48b8 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/AbstractModelLoader.java @@ -33,7 +33,7 @@ import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; -import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException; +import org.onap.cps.ncmp.exceptions.NcmpStartUpException; import org.onap.cps.spi.CascadeDeleteAllowed; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.utils.JsonObjectMapper; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java index 2592703449..780b240b6c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoader.java @@ -30,7 +30,7 @@ import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.ncmp.api.data.models.DatastoreType; -import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException; +import org.onap.cps.ncmp.exceptions.NcmpStartUpException; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.springframework.stereotype.Service; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java index 67128bd159..8d3190eb00 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpEvent.java @@ -27,8 +27,8 @@ import java.util.Map; import java.util.UUID; import lombok.Builder; import org.apache.commons.lang3.StringUtils; -import org.onap.cps.ncmp.api.impl.utils.EventDateTimeFormatter; -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext; +import org.onap.cps.ncmp.config.CpsApplicationContext; +import org.onap.cps.ncmp.impl.utils.EventDateTimeFormatter; import org.onap.cps.utils.JsonObjectMapper; @Builder diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java index a7ad86cda5..07da7f76a0 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/TopicValidator.java @@ -23,7 +23,7 @@ package org.onap.cps.ncmp.utils.events; import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.NoArgsConstructor; -import org.onap.cps.ncmp.exceptions.InvalidTopicException; +import org.onap.cps.ncmp.api.exceptions.InvalidTopicException; @NoArgsConstructor(access = AccessLevel.PRIVATE) public class TopicValidator { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy deleted file mode 100644 index 9cee2bdbad..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DataJobServiceImplSpec.groovy +++ /dev/null @@ -1,86 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl - -import ch.qos.logback.classic.Level -import ch.qos.logback.classic.Logger -import ch.qos.logback.classic.spi.ILoggingEvent -import ch.qos.logback.core.read.ListAppender -import org.onap.cps.ncmp.impl.datajobs.DataJobServiceImpl -import org.onap.cps.ncmp.impl.datajobs.DmiSubJobRequestHandler -import org.onap.cps.ncmp.impl.datajobs.WriteRequestExaminer -import org.slf4j.LoggerFactory -import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest -import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest -import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata -import org.onap.cps.ncmp.api.datajobs.models.ReadOperation -import org.onap.cps.ncmp.api.datajobs.models.WriteOperation -import spock.lang.Specification - -class DataJobServiceImplSpec extends Specification { - - def mockWriteRequestExaminer = Mock(WriteRequestExaminer) - def mockDmiSubJobRequestHandler = Mock(DmiSubJobRequestHandler) - - def objectUnderTest = new DataJobServiceImpl(mockDmiSubJobRequestHandler, mockWriteRequestExaminer) - - def myDataJobMetadata = new DataJobMetadata('', '', '') - - def logger = Spy(ListAppender) - - def setup() { - setupLogger() - } - - def cleanup() { - ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)).detachAndStopAllAppenders() - } - - def 'Read data job request.'() { - when: 'read data job request is processed' - def readOperation = new ReadOperation('', '', '', [], [], '', '', 1) - objectUnderTest.readDataJob('my-job-id', myDataJobMetadata, new DataJobReadRequest([readOperation])) - then: 'the data job id is correctly logged' - def loggingEvent = logger.list[0] - assert loggingEvent.level == Level.INFO - assert loggingEvent.formattedMessage.contains('data job id for read operation is: my-job-id') - } - - def 'Write data-job request.'() { - given: 'data job metadata and write request' - def dataJobWriteRequest = new DataJobWriteRequest([new WriteOperation('', '', '', null)]) - and: 'a map of producer key and dmi 3gpp write operation' - def dmiWriteOperationsPerProducerKey = [:] - when: 'write data job request is processed' - objectUnderTest.writeDataJob('my-job-id', myDataJobMetadata, dataJobWriteRequest) - then: 'the examiner service is called and a map is returned' - 1 * mockWriteRequestExaminer.splitDmiWriteOperationsFromRequest('my-job-id', dataJobWriteRequest) >> dmiWriteOperationsPerProducerKey - and: 'the dmi request handler is called with the result from the examiner' - 1 * mockDmiSubJobRequestHandler.sendRequestsToDmi('my-job-id', myDataJobMetadata, dmiWriteOperationsPerProducerKey) - } - - def setupLogger() { - def setupLogger = ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)) - setupLogger.setLevel(Level.DEBUG) - setupLogger.addAppender(logger) - logger.start() - } -} \ No newline at end of file diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy deleted file mode 100644 index 6dcd022c0a..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/DmiSubJobRequestHandlerSpec.groovy +++ /dev/null @@ -1,41 +0,0 @@ -package org.onap.cps.ncmp.api.impl - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.data.models.OperationType -import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata -import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation -import org.onap.cps.ncmp.api.datajobs.models.ProducerKey -import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse -import org.onap.cps.ncmp.api.impl.client.DmiRestClient -import org.onap.cps.ncmp.api.impl.config.DmiProperties -import org.onap.cps.ncmp.impl.datajobs.DmiSubJobRequestHandler -import org.onap.cps.ncmp.impl.models.RequiredDmiService -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.http.HttpStatus -import org.springframework.http.ResponseEntity -import spock.lang.Specification - -class DmiSubJobRequestHandlerSpec extends Specification { - - def mockDmiRestClient = Mock(DmiRestClient) - def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - def mockDmiProperties = Mock(DmiProperties) - def static NO_AUTH = null - def objectUnderTest = new DmiSubJobRequestHandler(mockDmiRestClient, mockDmiProperties, jsonObjectMapper) - - def 'Send a sub-job request to the DMI Plugin.'() { - given: 'a data job id, metadata and a map of producer keys and write operations to create a request' - def dataJobId = 'some-job-id' - def dataJobMetadata = new DataJobMetadata('', '', '') - def dmiWriteOperation = new DmiWriteOperation('', '', '', null, '', [:]) - def dmiWriteOperationsPerProducerKey = [new ProducerKey('', ''): [dmiWriteOperation]] - def response = new ResponseEntity<>(new SubJobWriteResponse('my-sub-job-id', '', ''), HttpStatus.OK) - when: 'sending request to DMI invoked' - objectUnderTest.sendRequestsToDmi(dataJobId, dataJobMetadata, dmiWriteOperationsPerProducerKey) - then: 'the dmi rest client is called' - 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(RequiredDmiService.DATA, _, _, OperationType.CREATE, NO_AUTH) >> response - and: 'the result contains the expected sub-job write responses' - def result = response.body - assert result.subJobId() == 'my-sub-job-id' - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/WriteRequestExaminerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/WriteRequestExaminerSpec.groovy deleted file mode 100644 index 84eb78b751..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/WriteRequestExaminerSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ - -package org.onap.cps.ncmp.impl.datajobs - -import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest -import org.onap.cps.ncmp.api.datajobs.models.WriteOperation -import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher -import org.onap.cps.spi.model.DataNode -import spock.lang.Specification - -class WriteRequestExaminerSpec extends Specification { - - def mockAlternateIdMatcher = Mock(AlternateIdMatcher) - def objectUnderTest = new WriteRequestExaminer(mockAlternateIdMatcher) - - def setup() { - def ch1 = new DataNode(leaves: [id: 'ch1', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1']) - def ch2 = new DataNode(leaves: [id: 'ch2', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1']) - def ch3 = new DataNode(leaves: [id: 'ch3', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p2']) - def ch4 = new DataNode(leaves: [id: 'ch4', 'dmi-service-name': 'dmiB', 'data-producer-identifier': 'p1']) - mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn1', '/') >> ch1 - mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn2', '/') >> ch2 - mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn3', '/') >> ch3 - mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn4', '/') >> ch4 - } - - def 'Create a map of dmi write requests per producer key with #scenario.'() { - given: 'a write request with some write operations' - def writeOperations = writeOperationFdns.collect { - new WriteOperation(it, '', '', null) - } - and: 'operations are wrapped in a write request' - def dataJobWriteRequest = new DataJobWriteRequest(writeOperations) - when: 'the DMI write operations are split from the request' - def dmiWriteOperationsPerProducerKey = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest) - then: 'we get the expected number of keys and values.' - def producerKeysAsStrings = dmiWriteOperationsPerProducerKey.keySet().collect { - it.toString() - } - assert producerKeysAsStrings.size() == expectedKeys.size() - assert expectedKeys.containsAll(producerKeysAsStrings) - where: - scenario | writeOperationFdns || expectedKeys - 'one fdn' | ['fdn1'] || ['dmiA#p1'] - 'a duplicated target' | ['fdn1','fdn1'] || ['dmiA#p1'] - 'two different targets' | ['fdn1','fdn2'] || ['dmiA#p1'] - 'two different targets and different producer keys' | ['fdn1','fdn3'] || ['dmiA#p1', 'dmiA#p2'] - 'two different targets and different DMI services' | ['fdn1','fdn4'] || ['dmiA#p1', 'dmiB#p1'] - 'many targets with different dmi service names and producer keys' | ['fdn1', 'fdn2', 'fdn3', 'fdn4'] || ['dmiA#p1', 'dmiA#p2', 'dmiB#p1'] - } - - def 'Validate the ordering of the created sub jobs.'() { - given: 'a few write operations for the same producer' - def writeOperations = (1..3).collect { - new WriteOperation('fdn1', '', it.toString(), null) - } - and: 'operation is wrapped in a write request' - def dataJobWriteRequest = new DataJobWriteRequest(writeOperations) - when: 'the DMI write operations are split from the request' - def dmiWriteOperations = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest).values().iterator().next() - then: 'we get the operation ids in the expected order.' - assert dmiWriteOperations.operationId == ['1', '2', '3'] - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy deleted file mode 100644 index a935d70ce6..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/client/DmiRestClientSpec.groovy +++ /dev/null @@ -1,168 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation - * Modifications Copyright (C) 2022 Bell Canada - * ================================================================================ - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.client - -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.node.ObjectNode -import org.onap.cps.ncmp.api.impl.config.DmiProperties -import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters -import org.onap.cps.ncmp.utils.TestUtils -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpStatus -import org.springframework.http.HttpStatusCode -import org.springframework.http.ResponseEntity -import org.springframework.web.client.HttpServerErrorException -import org.springframework.web.reactive.function.client.WebClient -import org.springframework.web.reactive.function.client.WebClientRequestException -import org.springframework.web.reactive.function.client.WebClientResponseException -import reactor.core.publisher.Mono -import spock.lang.Specification - -import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA -import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR -import static org.onap.cps.ncmp.api.data.models.OperationType.READ -import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA -import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL - -class DmiRestClientSpec extends Specification { - - static final NO_AUTH_HEADER = null - static final BASIC_AUTH_HEADER = 'Basic c29tZSB1c2VyOnNvbWUgcGFzc3dvcmQ=' - static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token' - static final urlTemplateParameters = new UrlTemplateParameters('/{pathParam1}/{pathParam2}', ['pathParam1': 'my', 'pathParam2': 'url']) - - def mockDataServicesWebClient = Mock(WebClient) - def mockModelServicesWebClient = Mock(WebClient) - def mockHealthChecksWebClient = Mock(WebClient) - - def mockRequestBody = Mock(WebClient.RequestBodyUriSpec) - def mockResponse = Mock(WebClient.ResponseSpec) - - def mockDmiProperties = Mock(DmiProperties) - - JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) - - DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient) - - def setup() { - mockRequestBody.uri(_,_) >> mockRequestBody - mockRequestBody.headers(_) >> mockRequestBody - mockRequestBody.body(_) >> mockRequestBody - mockRequestBody.retrieve() >> mockResponse - } - - def 'DMI POST Operation with JSON for DMI Data Service '() { - given: 'the Data web client returns a valid response entity for the expected parameters' - mockDataServicesWebClient.post() >> mockRequestBody - mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Data service', HttpStatus.I_AM_A_TEAPOT)) - when: 'POST operation is invoked fro Data Service' - def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) - then: 'the output of the method is equal to the output from the test template' - assert response.statusCode == HttpStatus.I_AM_A_TEAPOT - assert response.body == 'from Data service' - } - - def 'DMI POST Operation with JSON for DMI Model Service '() { - given: 'the Model web client returns a valid response entity for the expected parameters' - mockModelServicesWebClient.post() >> mockRequestBody - mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Model service', HttpStatus.I_AM_A_TEAPOT)) - when: 'POST operation is invoked for Model Service' - def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) - then: 'the output of the method is equal to the output from the test template' - assert response.statusCode == HttpStatus.I_AM_A_TEAPOT - assert response.body == 'from Model service' - } - - def 'Dmi service sends client error response when #scenario'() { - given: 'the web client unable to return response entity but error' - mockDataServicesWebClient.post() >> mockRequestBody - mockResponse.toEntity(Object.class) >> Mono.error(exceptionType) - when: 'POST operation is invoked' - objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) - then: 'a http client exception is thrown' - def thrown = thrown(DmiClientRequestException) - and: 'the exception has the relevant details from the error response' - assert thrown.ncmpResponseStatus == expectedNcmpResponseStatusCode - assert thrown.httpStatusCode == httpStatusCode - where: 'the following errors occur' - scenario | httpStatusCode | exceptionType || expectedNcmpResponseStatusCode - 'dmi service unavailable' | 503 | new WebClientRequestException(new RuntimeException('some-error'), null, null, new HttpHeaders()) || DMI_SERVICE_NOT_RESPONDING - 'dmi request timeout' | 408 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || DMI_SERVICE_NOT_RESPONDING - 'dmi server error' | 500 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || UNABLE_TO_READ_RESOURCE_DATA - 'dmi service unavailable' | 503 | new HttpServerErrorException(HttpStatusCode.valueOf(503)) || DMI_SERVICE_NOT_RESPONDING - 'unknown error' | 500 | new Throwable('message') || UNKNOWN_ERROR - } - - def 'Dmi trust level is determined by spring boot health status'() { - given: 'a health check response' - def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json') - def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class) - ((ObjectNode) jsonNode).put('status', 'my status') - mockHealthChecksWebClient.get() >> mockRequestBody - mockResponse.onStatus(_,_)>> mockResponse - mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode) - when: 'get trust level of the dmi plugin' - def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) - def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() - then: 'the status value from the json is returned' - assert result == 'my status' - } - - def 'Failing to get dmi plugin health status #scenario'() { - given: 'web client instance with #scenario' - mockHealthChecksWebClient.get() >> mockRequestBody - mockResponse.onStatus(_, _) >> mockResponse - mockResponse.bodyToMono(_) >> Mono.error(exceptionType) - when: 'attempt to get health status of the dmi plugin' - def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) - def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() - then: 'result will be empty' - assert result == '' - where: 'the following responses are used' - scenario | exceptionType - 'dmi request timeout' | new WebClientResponseException('some-message', 408, 'some-text', null, null, null) - 'dmi service unavailable' | new HttpServerErrorException(HttpStatus.SERVICE_UNAVAILABLE) - } - - def 'DMI auth header #scenario'() { - when: 'Specific dmi properties are provided' - mockDmiProperties.dmiBasicAuthEnabled >> authEnabled - mockDmiProperties.authUsername >> 'some user' - mockDmiProperties.authPassword >> 'some password' - then: 'http headers to conditionally have Authorization header' - def httpHeaders = new HttpHeaders() - objectUnderTest.configureHttpHeaders(httpHeaders, ncmpAuthHeader) - def outputAuthHeader = (httpHeaders.Authorization == null ? null : httpHeaders.Authorization[0]) - assert outputAuthHeader == expectedAuthHeader - where: 'the following configurations are used' - scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader - 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER - 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER - 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER - 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER - 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiPropertiesSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiPropertiesSpec.groovy deleted file mode 100644 index c763c522c9..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiPropertiesSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config - -import spock.lang.Specification - -class DmiPropertiesSpec extends Specification { - - def objectUnderTest = new DmiProperties() - - def 'Geting dmi base path.'() { - given: 'base path of #dmiBasePath' - objectUnderTest.dmiBasePath = dmiBasePath - expect: 'Preceding and trailing slash wil be removed' - assert objectUnderTest.getDmiBasePath() == 'test' - where: 'the following dmi base paths are used' - dmiBasePath << [ 'test' , '/test', 'test/', '/test/' ] - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy deleted file mode 100644 index fa995aa7c3..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/DmiWebClientConfigurationSpec.groovy +++ /dev/null @@ -1,75 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config - -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ContextConfiguration -import org.springframework.test.context.TestPropertySource -import org.springframework.web.reactive.function.client.WebClient -import spock.lang.Specification - -@SpringBootTest -@ContextConfiguration(classes = [HttpClientConfiguration]) -@TestPropertySource(properties = ['ncmp.dmi.httpclient.data-services.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.model-services.maximumInMemorySizeInMegabytes=1']) -@EnableConfigurationProperties -class DmiWebClientConfigurationSpec extends Specification { - - def webClientBuilder = Mock(WebClient.Builder) { - defaultHeaders(_) >> it - clientConnector(_) >> it - codecs(_) >> it - build() >> Mock(WebClient) - } - - def httpClientConfiguration = Spy(HttpClientConfiguration.class) - - def objectUnderTest = new DmiWebClientConfiguration(httpClientConfiguration) - - def 'Web Client Configuration construction.'() { - expect: 'the system can create an instance' - new DmiWebClientConfiguration(httpClientConfiguration) != null - } - - def 'Creating a web client instance data service.'() { - given: 'Web client configuration is invoked' - def dataServicesWebClient = objectUnderTest.dataServicesWebClient(webClientBuilder) - expect: 'the system can create an instance for data service' - assert dataServicesWebClient != null - assert dataServicesWebClient instanceof WebClient - } - - def 'Creating a web client instance model service.'() { - given: 'Web client configuration invoked' - def modelServicesWebClient = objectUnderTest.modelServicesWebClient(webClientBuilder) - expect: 'the system can create an instance for model service' - assert modelServicesWebClient != null - assert modelServicesWebClient instanceof WebClient - } - - def 'Creating a web client instance health service.'() { - given: 'Web client configuration invoked' - def healthChecksWebClient = objectUnderTest.healthChecksWebClient(webClientBuilder) - expect: 'the system can create an instance for health service' - assert healthChecksWebClient != null - assert healthChecksWebClient instanceof WebClient - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy deleted file mode 100644 index 228f412779..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/HttpClientConfigurationSpec.groovy +++ /dev/null @@ -1,74 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ContextConfiguration -import org.springframework.test.context.TestPropertySource -import spock.lang.Specification - -@SpringBootTest -@ContextConfiguration(classes = [HttpClientConfiguration]) -@EnableConfigurationProperties(HttpClientConfiguration.class) -@TestPropertySource(properties = ["ncmp.dmi.httpclient.data-services.readTimeoutInSeconds=789", "ncmp.dmi.httpclient.model-services.maximumConnectionsTotal=111"]) -class HttpClientConfigurationSpec extends Specification { - - @Autowired - private HttpClientConfiguration httpClientConfiguration - - def 'Test http client configuration properties of data with custom and default values'() { - expect: 'properties are populated correctly for data' - with(httpClientConfiguration.dataServices) { - assert connectionTimeoutInSeconds == 123 - assert readTimeoutInSeconds == 789 - assert writeTimeoutInSeconds == 30 - assert maximumConnectionsTotal == 100 - assert pendingAcquireMaxCount == 22 - assert maximumInMemorySizeInMegabytes == 7 - } - } - - def 'Test http client configuration properties of model with custom and default values'() { - expect: 'properties are populated correctly for model' - with(httpClientConfiguration.modelServices) { - assert connectionTimeoutInSeconds == 456 - assert readTimeoutInSeconds == 30 - assert writeTimeoutInSeconds == 30 - assert maximumConnectionsTotal == 111 - assert pendingAcquireMaxCount == 44 - assert maximumInMemorySizeInMegabytes == 8 - } - } - - def 'Test http client configuration properties of health with default values'() { - expect: 'properties are populated correctly for health' - with(httpClientConfiguration.healthCheckServices) { - assert connectionTimeoutInSeconds == 30 - assert readTimeoutInSeconds == 30 - assert writeTimeoutInSeconds == 30 - assert maximumConnectionsTotal == 10 - assert pendingAcquireMaxCount == 5 - assert maximumInMemorySizeInMegabytes == 1 - } - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy deleted file mode 100644 index 07395cf5bc..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy +++ /dev/null @@ -1,81 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config - -import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter -import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler -import org.spockframework.spring.SpringBean -import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer -import spock.lang.Shared -import spock.lang.Specification - -class OpenTelemetryConfigSpec extends Specification{ - - @Shared - @SpringBean - OpenTelemetryConfig openTelemetryConfig = new OpenTelemetryConfig() - - def setupSpec() { - openTelemetryConfig.tracingExporterEndpointUrl="http://tracingExporterEndpointUrl" - openTelemetryConfig.jaegerRemoteSamplerUrl="http://jaegerremotesamplerurl" - openTelemetryConfig.serviceId ="cps-application" - } - - def 'OpenTelemetryConfig Construction.'() { - expect: 'the system can create an instance' - new OpenTelemetryConfig() != null - } - - def 'OTLP Exporter creation with Grpc protocol'(){ - when: 'an OTLP exporter is created' - def result = openTelemetryConfig.createOtlpExporterGrpc() - then: 'an OTLP Exporter is created' - assert result instanceof OtlpGrpcSpanExporter - } - - def 'OTLP Exporter creation with HTTP protocol'(){ - when: 'an OTLP exporter is created' - def result = openTelemetryConfig.createOtlpExporterHttp() - then: 'an OTLP Exporter is created' - assert result instanceof OtlpHttpSpanExporter - and: - assert result.builder.endpoint=="http://tracingExporterEndpointUrl" - } - - def 'Jaeger Remote Sampler Creation'(){ - when: 'an OTLP exporter is created' - def result = openTelemetryConfig.createJaegerRemoteSampler() - then: 'an OTLP Exporter is created' - assert result instanceof JaegerRemoteSampler - and: - assert result.delegate.type=="remoteSampling" - and: - assert result.delegate.url.toString().startsWith("http://jaegerremotesamplerurl") - } - - def 'Skipping Acutator endpoints'(){ - when: 'an OTLP exporter is created' - def result = openTelemetryConfig.skipActuatorEndpointsFromObservation() - then: 'an OTLP Exporter is created' - assert result instanceof ObservationRegistryCustomizer - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy deleted file mode 100644 index 4d3fd6616b..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/kafka/KafkaConfigSpec.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.config.kafka - -import io.cloudevents.CloudEvent -import io.cloudevents.kafka.CloudEventDeserializer -import io.cloudevents.kafka.CloudEventSerializer -import org.spockframework.spring.EnableSharedInjection -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.kafka.KafkaProperties -import org.springframework.boot.context.properties.EnableConfigurationProperties -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.kafka.support.serializer.JsonDeserializer -import org.springframework.kafka.support.serializer.JsonSerializer -import org.springframework.test.context.TestPropertySource -import spock.lang.Shared -import spock.lang.Specification - -@SpringBootTest(classes = [KafkaProperties, KafkaConfig]) -@EnableSharedInjection -@EnableConfigurationProperties -@TestPropertySource(properties = ["cps.tracing.enabled=true"]) -class KafkaConfigSpec extends Specification { - - @Shared - @Autowired - KafkaTemplate legacyEventKafkaTemplate - - @Shared - @Autowired - KafkaTemplate cloudEventKafkaTemplate - - def 'Verify kafka template serializer and deserializer configuration for #eventType.'() { - expect: 'kafka template is instantiated' - assert kafkaTemplateInstance.properties['beanName'] == beanName - and: 'verify event key and value serializer' - assert kafkaTemplateInstance.properties['producerFactory'].configs['value.serializer'].asType(String.class).contains(valueSerializer.getCanonicalName()) - and: 'verify event key and value deserializer' - assert kafkaTemplateInstance.properties['consumerFactory'].configs['spring.deserializer.value.delegate.class'].asType(String.class).contains(delegateDeserializer.getCanonicalName()) - where: 'the following event type is used' - eventType | kafkaTemplateInstance || beanName | valueSerializer | delegateDeserializer - 'legacy event' | legacyEventKafkaTemplate || 'legacyEventKafkaTemplate' | JsonSerializer | JsonDeserializer - 'cloud event' | cloudEventKafkaTemplate || 'cloudEventKafkaTemplate' | CloudEventSerializer | CloudEventDeserializer - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy deleted file mode 100644 index 2e04694301..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeBaseSpec.groovy +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils - -import org.onap.cps.spi.model.DataNodeBuilder -import spock.lang.Specification - -import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME - -class DataNodeBaseSpec extends Specification { - - def leaves1 = [status:'PENDING', cmHandleId:'CMHandle3', details:'Subscription forwarded to dmi plugin'] as Map - def dataNode1 = createDataNodeWithLeaves(leaves1) - - def leaves2 = [status:'ACCEPTED', cmHandleId:'CMHandle2', details:''] as Map - def dataNode2 = createDataNodeWithLeaves(leaves2) - - def leaves3 = [status:'REJECTED', cmHandleId:'CMHandle1', details:'Cm handle does not exist'] as Map - def dataNode3 = createDataNodeWithLeaves(leaves3) - - def leaves4 = [datastore:'passthrough-running'] as Map - def dataNode4 = createDataNodeWithLeavesAndChildDataNodes(leaves4, [dataNode1, dataNode2, dataNode3]) - - static def createDataNodeWithLeaves(leaves) { - return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves(leaves).build() - } - - static def createDataNodeWithLeavesAndChildDataNodes(leaves, dataNodes) { - return new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves(leaves).withChildDataNodes(dataNodes) - .build() - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy deleted file mode 100644 index 9481613d41..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DataNodeHelperSpec.groovy +++ /dev/null @@ -1,85 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils - -import org.onap.cps.spi.model.DataNodeBuilder - -import static org.onap.cps.ncmp.impl.inventory.NcmpPersistence.NCMP_DATASPACE_NAME - -class DataNodeHelperSpec extends DataNodeBaseSpec { - - def 'Get data node leaves as expected from a nested data node.'() { - given: 'a nested data node' - def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001']) - .withChildDataNodes([dataNode4]).build() - when: 'the nested data node is flatten and retrieves the leaves ' - def result = DataNodeHelper.getDataNodeLeaves([dataNode]) - then: 'the result list size is 5' - result.size() == 5 - and: 'all the leaves result list are equal to given leaves of data nodes' - result[0] == [clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001'] - result[1] == [datastore:'passthrough-running'] - result[2] == [status:'PENDING', cmHandleId:'CMHandle3', details:'Subscription forwarded to dmi plugin'] - result[3] == [status:'ACCEPTED', cmHandleId:'CMHandle2', details:''] - result[4] == [status:'REJECTED', cmHandleId:'CMHandle1', details:'Cm handle does not exist'] - } - - def 'Get cm handle id to status as expected from a nested data node.'() { - given: 'a nested data node' - def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001']) - .withChildDataNodes([dataNode4]).build() - and: 'the nested data node is flatten and retrieves the leaves ' - def leaves = DataNodeHelper.getDataNodeLeaves([dataNode]) - when:'cm handle id to status is retrieved' - def result = DataNodeHelper.cmHandleIdToStatusAndDetailsAsMap(leaves) - then: 'the result list size is 3' - result.size() == 3 - and: 'the result contains expected values' - result == [ - CMHandle3: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map, - CMHandle2: [details:'',status:'ACCEPTED'] as Map, - CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map - ] as Map - - } - - def 'Get cm handle id to status map as expected from a nested data node.'() { - given: 'a nested data node' - def dataNode = new DataNodeBuilder().withDataspace(NCMP_DATASPACE_NAME) - .withAnchor('AVC-Subscriptions').withXpath('/subscription-registry/subscription') - .withLeaves([clientID:'SCO-9989752', isTagged:false, subscriptionName:'cm-subscription-001']) - .withChildDataNodes([dataNode4]).build() - when:'cm handle id to status is being extracted' - def result = DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode([dataNode]); - then: 'the result list size is 3' - result.size() == 3 - and: 'the result contains expected values' - result == [ - CMHandle3: [details:'Subscription forwarded to dmi plugin',status:'PENDING'] as Map, - CMHandle2: [details:'',status:'ACCEPTED'] as Map, - CMHandle1: [details:'Cm handle does not exist',status:'REJECTED'] as Map - ] as Map - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatterSpec.groovy deleted file mode 100644 index c72eb9e4c9..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/EventDateTimeFormatterSpec.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils - -import spock.lang.Specification -import java.time.Year - -class EventDateTimeFormatterSpec extends Specification { - - def 'Get ISO formatted date and time.' () { - expect: 'iso formatted date and time starts with current year' - assert EventDateTimeFormatter.getCurrentIsoFormattedDateTime().startsWith(String.valueOf(Year.now())) - } - - def 'Convert date time from string to OffsetDateTime type.'() { - when: 'date time as a string is converted to OffsetDateTime type' - def result = EventDateTimeFormatter.toIsoOffsetDateTime('2024-05-28T18:28:02.869+0100') - then: 'the result convert back back to a string is the same as the original timestamp (except the format of timezone offset)' - assert result.toString() == '2024-05-28T18:28:02.869+01:00' - } - - def 'Convert blank string.' () { - expect: 'converting a blank string result in null' - assert EventDateTimeFormatter.toIsoOffsetDateTime(' ') == null - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy deleted file mode 100644 index ee117160c1..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/context/CpsApplicationContextSpec.groovy +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (c) 2023-2024 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils.context - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ContextConfiguration -import spock.lang.Specification; - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -@ContextConfiguration(classes = [CpsApplicationContext.class]) -class CpsApplicationContextSpec extends Specification { - - def 'Verify if cps application context contains a requested bean.'() { - when: 'cps bean is requested from application context' - def jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class) - then: 'requested bean of JsonObjectMapper is not null' - assert jsonObjectMapper != null - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy deleted file mode 100644 index 6d56f432d3..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/url/builder/DmiServiceUrlTemplateBuilderSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.impl.utils.url.builder - -import spock.lang.Specification - -class DmiServiceUrlTemplateBuilderSpec extends Specification { - - def objectUnderTest = new DmiServiceUrlTemplateBuilder() - - def 'Build URL template parameters with (variable) path segments and query parameters.'() { - given: 'the URL details are given to the builder' - objectUnderTest.fixedPathSegment('segment') - objectUnderTest.variablePathSegment('myVariableSegment','someValue') - objectUnderTest.fixedPathSegment('segment?with:special&characters') - objectUnderTest.queryParameter('param1', 'abc') - objectUnderTest.queryParameter('param2', 'value?with#special:characters') - when: 'the URL template parameters are created' - def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') - then: 'the URL template contains variable names instead of value and un-encoded fixed segment' - assert result.urlTemplate == 'myDmiServer/myBasePath/v1/segment/{myVariableSegment}/segment?with:special&characters?param1={param1}¶m2={param2}' - and: 'URL variables contains name and un-encoded value pairs' - assert result.urlVariables == ['myVariableSegment': 'someValue', 'param1': 'abc', 'param2': 'value?with#special:characters'] - } - - def 'Build URL template parameters with special characters in query parameters.'() { - given: 'the query parameter is given to the builder' - objectUnderTest.queryParameter('my¶m', 'special&characters=are?not\\encoded') - when: 'the URL template parameters are created' - def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') - then: 'Special characters are not encoded' - assert result.urlVariables == ['my¶m': 'special&characters=are?not\\encoded'] - } - - def 'Build URL template parameters with empty query parameters.'() { - when: 'the query parameter is given to the builder' - objectUnderTest.queryParameter('param', value) - and: 'the URL template parameters are create' - def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') - then: 'no parameter gets added' - assert result.urlVariables.isEmpty() - where: 'the following parameter values are used' - value << [ null, '', ' ' ] - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy deleted file mode 100644 index 28f8b02880..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/ConsumerBaseSpec.groovy +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.kafka - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.kafka.config.KafkaListenerEndpointRegistry -import org.springframework.kafka.test.utils.ContainerTestUtils - -@SpringBootTest(classes = KafkaListenerEndpointRegistry.class) -class ConsumerBaseSpec extends MessagingBaseSpec { - - @Autowired - private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry - - def setup() { - activateListeners() - } - - def activateListeners() { - kafkaListenerEndpointRegistry.getListenerContainers().forEach( - messageListenerContainer -> { ContainerTestUtils.waitForAssignment(messageListenerContainer, 1) } - ) - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy deleted file mode 100644 index 0356c3fcdc..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/kafka/MessagingBaseSpec.groovy +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (c) 2023 Nordix Foundation. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an 'AS IS' BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.api.kafka - -import io.cloudevents.CloudEvent -import io.cloudevents.kafka.CloudEventSerializer -import org.apache.kafka.common.serialization.StringDeserializer -import org.apache.kafka.common.serialization.StringSerializer -import org.springframework.kafka.core.DefaultKafkaProducerFactory -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.kafka.support.serializer.JsonSerializer -import org.springframework.test.context.DynamicPropertyRegistry -import org.springframework.test.context.DynamicPropertySource -import org.testcontainers.containers.KafkaContainer -import org.testcontainers.utility.DockerImageName -import spock.lang.Specification - -class MessagingBaseSpec extends Specification { - - def setupSpec() { - kafkaTestContainer.start() - } - - def cleanupSpec() { - kafkaTestContainer.stop() - } - - static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('registry.nordix.org/onaptest/confluentinc/cp-kafka:6.2.1').asCompatibleSubstituteFor('confluentinc/cp-kafka')) - - def legacyEventKafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory(eventProducerConfigProperties(JsonSerializer))) - - def cloudEventKafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory(eventProducerConfigProperties(CloudEventSerializer))) - - @DynamicPropertySource - static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) { - dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers) - } - - def eventProducerConfigProperties(valueSerializer) { - return [('bootstrap.servers'): kafkaTestContainer.getBootstrapServers().split(',')[0], - ('retries') : 0, - ('batch-size') : 16384, - ('linger.ms') : 1, - ('buffer.memory') : 33554432, - ('key.serializer') : StringSerializer, - ('value.serializer') : valueSerializer] - } - - def eventConsumerConfigProperties(consumerGroupId, valueSerializer) { - return [('bootstrap.servers') : kafkaTestContainer.getBootstrapServers().split(',')[0], - ('key.deserializer') : StringDeserializer, - ('value.deserializer'): valueSerializer, - ('auto.offset.reset') : 'earliest', - ('group.id') : consumerGroupId - ] - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy new file mode 100644 index 0000000000..215ea6c219 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/CpsApplicationContextSpec.groovy @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================== + * Copyright (c) 2023-2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration +import spock.lang.Specification; + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +@ContextConfiguration(classes = [CpsApplicationContext.class]) +class CpsApplicationContextSpec extends Specification { + + def 'Verify if cps application context contains a requested bean.'() { + when: 'cps bean is requested from application context' + def jsonObjectMapper = CpsApplicationContext.getCpsBean(JsonObjectMapper.class) + then: 'requested bean of JsonObjectMapper is not null' + assert jsonObjectMapper != null + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/HttpClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/HttpClientConfigurationSpec.groovy new file mode 100644 index 0000000000..91aeb88a54 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/HttpClientConfigurationSpec.groovy @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config + + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import spock.lang.Specification + +@SpringBootTest +@ContextConfiguration(classes = [HttpClientConfiguration]) +@EnableConfigurationProperties(HttpClientConfiguration.class) +@TestPropertySource(properties = ["ncmp.dmi.httpclient.data-services.readTimeoutInSeconds=789", "ncmp.dmi.httpclient.model-services.maximumConnectionsTotal=111"]) +class HttpClientConfigurationSpec extends Specification { + + @Autowired + private HttpClientConfiguration httpClientConfiguration + + def 'Test http client configuration properties of data with custom and default values'() { + expect: 'properties are populated correctly for data' + with(httpClientConfiguration.dataServices) { + assert connectionTimeoutInSeconds == 123 + assert readTimeoutInSeconds == 789 + assert writeTimeoutInSeconds == 30 + assert maximumConnectionsTotal == 100 + assert pendingAcquireMaxCount == 22 + assert maximumInMemorySizeInMegabytes == 7 + } + } + + def 'Test http client configuration properties of model with custom and default values'() { + expect: 'properties are populated correctly for model' + with(httpClientConfiguration.modelServices) { + assert connectionTimeoutInSeconds == 456 + assert readTimeoutInSeconds == 30 + assert writeTimeoutInSeconds == 30 + assert maximumConnectionsTotal == 111 + assert pendingAcquireMaxCount == 44 + assert maximumInMemorySizeInMegabytes == 8 + } + } + + def 'Test http client configuration properties of health with default values'() { + expect: 'properties are populated correctly for health' + with(httpClientConfiguration.healthCheckServices) { + assert connectionTimeoutInSeconds == 30 + assert readTimeoutInSeconds == 30 + assert writeTimeoutInSeconds == 30 + assert maximumConnectionsTotal == 10 + assert pendingAcquireMaxCount == 5 + assert maximumInMemorySizeInMegabytes == 1 + } + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/KafkaConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/KafkaConfigSpec.groovy new file mode 100644 index 0000000000..9e1649ef93 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/KafkaConfigSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config + +import io.cloudevents.CloudEvent +import io.cloudevents.kafka.CloudEventDeserializer +import io.cloudevents.kafka.CloudEventSerializer +import org.spockframework.spring.EnableSharedInjection +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.kafka.KafkaProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.kafka.core.KafkaTemplate +import org.springframework.kafka.support.serializer.JsonDeserializer +import org.springframework.kafka.support.serializer.JsonSerializer +import org.springframework.test.context.TestPropertySource +import spock.lang.Shared +import spock.lang.Specification + +@SpringBootTest(classes = [KafkaProperties, KafkaConfig]) +@EnableSharedInjection +@EnableConfigurationProperties +@TestPropertySource(properties = ["cps.tracing.enabled=true"]) +class KafkaConfigSpec extends Specification { + + @Shared + @Autowired + KafkaTemplate legacyEventKafkaTemplate + + @Shared + @Autowired + KafkaTemplate cloudEventKafkaTemplate + + def 'Verify kafka template serializer and deserializer configuration for #eventType.'() { + expect: 'kafka template is instantiated' + assert kafkaTemplateInstance.properties['beanName'] == beanName + and: 'verify event key and value serializer' + assert kafkaTemplateInstance.properties['producerFactory'].configs['value.serializer'].asType(String.class).contains(valueSerializer.getCanonicalName()) + and: 'verify event key and value deserializer' + assert kafkaTemplateInstance.properties['consumerFactory'].configs['spring.deserializer.value.delegate.class'].asType(String.class).contains(delegateDeserializer.getCanonicalName()) + where: 'the following event type is used' + eventType | kafkaTemplateInstance || beanName | valueSerializer | delegateDeserializer + 'legacy event' | legacyEventKafkaTemplate || 'legacyEventKafkaTemplate' | JsonSerializer | JsonDeserializer + 'cloud event' | cloudEventKafkaTemplate || 'cloudEventKafkaTemplate' | CloudEventSerializer | CloudEventDeserializer + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy new file mode 100644 index 0000000000..0f6906942f --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/OpenTelemetryCmNotificationSubscriptionConfigSpec.groovy @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.config + +import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter +import io.opentelemetry.sdk.extension.trace.jaeger.sampler.JaegerRemoteSampler +import org.spockframework.spring.SpringBean +import org.springframework.boot.actuate.autoconfigure.observation.ObservationRegistryCustomizer +import spock.lang.Shared +import spock.lang.Specification + +class OpenTelemetryConfigSpec extends Specification{ + + @Shared + @SpringBean + OpenTelemetryConfig openTelemetryConfig = new OpenTelemetryConfig() + + def setupSpec() { + openTelemetryConfig.tracingExporterEndpointUrl="http://tracingExporterEndpointUrl" + openTelemetryConfig.jaegerRemoteSamplerUrl="http://jaegerremotesamplerurl" + openTelemetryConfig.serviceId ="cps-application" + } + + def 'OpenTelemetryConfig Construction.'() { + expect: 'the system can create an instance' + new OpenTelemetryConfig() != null + } + + def 'OTLP Exporter creation with Grpc protocol'(){ + when: 'an OTLP exporter is created' + def result = openTelemetryConfig.createOtlpExporterGrpc() + then: 'an OTLP Exporter is created' + assert result instanceof OtlpGrpcSpanExporter + } + + def 'OTLP Exporter creation with HTTP protocol'(){ + when: 'an OTLP exporter is created' + def result = openTelemetryConfig.createOtlpExporterHttp() + then: 'an OTLP Exporter is created' + assert result instanceof OtlpHttpSpanExporter + and: + assert result.builder.endpoint=="http://tracingExporterEndpointUrl" + } + + def 'Jaeger Remote Sampler Creation'(){ + when: 'an OTLP exporter is created' + def result = openTelemetryConfig.createJaegerRemoteSampler() + then: 'an OTLP Exporter is created' + assert result instanceof JaegerRemoteSampler + and: + assert result.delegate.type=="remoteSampling" + and: + assert result.delegate.url.toString().startsWith("http://jaegerremotesamplerurl") + } + + def 'Skipping Acutator endpoints'(){ + when: 'an OTLP exporter is created' + def result = openTelemetryConfig.skipActuatorEndpointsFromObservation() + then: 'an OTLP Exporter is created' + assert result instanceof ObservationRegistryCustomizer + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/DmiOperationsBaseSpec.groovy deleted file mode 100644 index 050932f654..0000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/DmiOperationsBaseSpec.groovy +++ /dev/null @@ -1,76 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.cps.ncmp.impl - -import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.client.DmiRestClient -import org.onap.cps.ncmp.api.inventory.models.CompositeState -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence -import org.onap.cps.ncmp.impl.inventory.models.CmHandleState -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle -import org.spockframework.spring.SpringBean -import spock.lang.Shared -import spock.lang.Specification - -abstract class DmiOperationsBaseSpec extends Specification { - - @Shared - def yangModelCmHandleProperty = new YangModelCmHandle.Property('prop1', 'val1') - - @SpringBean - DmiRestClient mockDmiRestClient = Mock() - - @SpringBean - InventoryPersistence mockInventoryPersistence = Mock() - - @SpringBean - ObjectMapper spyObjectMapper = Spy() - - def yangModelCmHandle = new YangModelCmHandle() - def static dmiServiceName = 'myServiceName' - def static cmHandleId = 'some-cm-handle' - def static resourceIdentifier = 'parent/child' - - def mockYangModelCmHandleRetrieval(dmiProperties) { - populateYangModelCmHandle(dmiProperties, '') - mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle - } - - def mockYangModelCmHandleRetrieval(dmiProperties, moduleSetTag) { - populateYangModelCmHandle(dmiProperties, moduleSetTag) - mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle - } - - def mockYangModelCmHandleCollectionRetrieval(dmiProperties) { - populateYangModelCmHandle(dmiProperties, '') - mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle] - } - - def populateYangModelCmHandle(dmiProperties, moduleSetTag) { - yangModelCmHandle.dmiDataServiceName = dmiServiceName - yangModelCmHandle.dmiServiceName = dmiServiceName - yangModelCmHandle.dmiProperties = dmiProperties - yangModelCmHandle.id = cmHandleId - yangModelCmHandle.compositeState = new CompositeState() - yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY - yangModelCmHandle.moduleSetTag = moduleSetTag - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy index b335843bb3..2d50e770dd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cache/DmiCacheHandlerSpec.groovy @@ -24,7 +24,6 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import io.cloudevents.core.builder.CloudEventBuilder import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.CmSubscriptionStatus import org.onap.cps.ncmp.impl.cmnotificationsubscription.models.DmiCmSubscriptionDetails import org.onap.cps.ncmp.impl.cmnotificationsubscription.utils.CmSubscriptionPersistenceService @@ -32,6 +31,7 @@ import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.Nc import org.onap.cps.ncmp.impl.inventory.InventoryPersistence import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy index 98cc383e7f..a8b5250edf 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/cmavc/CmAvcEventConsumerSpec.groovy @@ -28,9 +28,9 @@ import io.cloudevents.kafka.impl.KafkaHeaders import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.clients.consumer.KafkaConsumer import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.events.avc1_0_0.AvcEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy index 06003fdcb4..6e28d14810 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/dmi/DmiOutEventConsumerSpec.groovy @@ -28,13 +28,13 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import io.cloudevents.core.builder.CloudEventBuilder import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.impl.cmnotificationsubscription.cache.DmiCacheHandler import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventMapper import org.onap.cps.ncmp.impl.cmnotificationsubscription.ncmp.NcmpOutEventProducer import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.Data import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.dmi_to_ncmp.DmiOutEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy index 637e9ebfec..2881737e82 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/NcmpInEventConsumerSpec.groovy @@ -28,9 +28,9 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import io.cloudevents.core.builder.CloudEventBuilder import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.impl.cmnotificationsubscription_1_0_0.client_to_ncmp.NcmpInEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy index 3a199ff417..c2bbfc2edc 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy @@ -25,12 +25,12 @@ import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.data.models.CmResourceAddress import org.onap.cps.ncmp.api.data.models.DataOperationRequest -import org.onap.cps.ncmp.api.impl.config.DmiProperties -import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters +import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException +import org.onap.cps.ncmp.config.CpsApplicationContext import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent -import org.onap.cps.ncmp.impl.DmiOperationsBaseSpec +import org.onap.cps.ncmp.impl.dmi.DmiOperationsBaseSpec +import org.onap.cps.ncmp.impl.dmi.DmiProperties +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.utils.TestUtils import org.onap.cps.utils.JsonObjectMapper diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy index 39701d8e70..d5db24cc33 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpDatastoreRequestHandlerSpec.groovy @@ -26,7 +26,7 @@ import org.onap.cps.ncmp.api.data.exceptions.OperationNotSupportedException import org.onap.cps.ncmp.api.data.models.CmResourceAddress import org.onap.cps.ncmp.api.data.models.DataOperationDefinition import org.onap.cps.ncmp.api.data.models.DataOperationRequest -import org.onap.cps.ncmp.exceptions.PayloadTooLargeException +import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException import org.springframework.http.ResponseEntity import reactor.core.publisher.Mono import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy index ad7d741ae2..4bcafe8c61 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/CpsAsyncRequestResponseEventIntegrationSpec.groovy @@ -25,10 +25,10 @@ import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.serialization.StringDeserializer import org.mapstruct.factory.Mappers import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy index 7e9f5089b7..afb594ab04 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/DataOperationEventConsumerSpec.groovy @@ -30,9 +30,9 @@ import org.apache.kafka.clients.consumer.ConsumerRecord import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.header.internals.RecordHeaders import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy index 0643dbcf17..01d2a3666b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/FilterStrategiesIntegrationSpec.groovy @@ -22,9 +22,9 @@ package org.onap.cps.ncmp.impl.data.async import io.cloudevents.core.builder.CloudEventBuilder import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.config.kafka.KafkaConfig -import org.onap.cps.ncmp.api.kafka.ConsumerBaseSpec +import org.onap.cps.ncmp.config.KafkaConfig import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent +import org.onap.cps.ncmp.utils.events.ConsumerBaseSpec import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Value import org.springframework.boot.autoconfigure.EnableAutoConfiguration diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy index 94ebc38a48..3fe7ec222e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/async/SerializationIntegrationSpec.groovy @@ -23,13 +23,13 @@ package org.onap.cps.ncmp.impl.data.async import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.core.builder.CloudEventBuilder import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.config.kafka.KafkaConfig -import org.onap.cps.ncmp.api.kafka.ConsumerBaseSpec +import org.onap.cps.ncmp.config.KafkaConfig import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent import org.onap.cps.ncmp.events.async1_0_0.Data import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent import org.onap.cps.ncmp.events.async1_0_0.Response +import org.onap.cps.ncmp.utils.events.ConsumerBaseSpec import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy index cdf9eae40b..84eafb0da3 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/utils/DmiDataOperationsHelperSpec.groovy @@ -28,13 +28,13 @@ import org.apache.kafka.clients.consumer.KafkaConsumer import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.data.models.DataOperationRequest import org.onap.cps.ncmp.api.data.models.OperationType -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.config.CpsApplicationContext import org.onap.cps.ncmp.events.async1_0_0.DataOperationEvent import org.onap.cps.ncmp.impl.data.models.DmiDataOperation import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.test.context.ContextConfiguration diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy new file mode 100644 index 0000000000..94c490ab07 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DataJobServiceImplSpec.groovy @@ -0,0 +1,83 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.datajobs + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.spi.ILoggingEvent +import ch.qos.logback.core.read.ListAppender +import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata +import org.onap.cps.ncmp.api.datajobs.models.DataJobReadRequest +import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest +import org.onap.cps.ncmp.api.datajobs.models.ReadOperation +import org.onap.cps.ncmp.api.datajobs.models.WriteOperation +import org.slf4j.LoggerFactory +import spock.lang.Specification + +class DataJobServiceImplSpec extends Specification { + + def mockWriteRequestExaminer = Mock(WriteRequestExaminer) + def mockDmiSubJobRequestHandler = Mock(DmiSubJobRequestHandler) + + def objectUnderTest = new DataJobServiceImpl(mockDmiSubJobRequestHandler, mockWriteRequestExaminer) + + def myDataJobMetadata = new DataJobMetadata('', '', '') + + def logger = Spy(ListAppender) + + def setup() { + setupLogger() + } + + def cleanup() { + ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)).detachAndStopAllAppenders() + } + + def 'Read data job request.'() { + when: 'read data job request is processed' + def readOperation = new ReadOperation('', '', '', [], [], '', '', 1) + objectUnderTest.readDataJob('my-job-id', myDataJobMetadata, new DataJobReadRequest([readOperation])) + then: 'the data job id is correctly logged' + def loggingEvent = logger.list[0] + assert loggingEvent.level == Level.INFO + assert loggingEvent.formattedMessage.contains('data job id for read operation is: my-job-id') + } + + def 'Write data-job request.'() { + given: 'data job metadata and write request' + def dataJobWriteRequest = new DataJobWriteRequest([new WriteOperation('', '', '', null)]) + and: 'a map of producer key and dmi 3gpp write operation' + def dmiWriteOperationsPerProducerKey = [:] + when: 'write data job request is processed' + objectUnderTest.writeDataJob('my-job-id', myDataJobMetadata, dataJobWriteRequest) + then: 'the examiner service is called and a map is returned' + 1 * mockWriteRequestExaminer.splitDmiWriteOperationsFromRequest('my-job-id', dataJobWriteRequest) >> dmiWriteOperationsPerProducerKey + and: 'the dmi request handler is called with the result from the examiner' + 1 * mockDmiSubJobRequestHandler.sendRequestsToDmi('my-job-id', myDataJobMetadata, dmiWriteOperationsPerProducerKey) + } + + def setupLogger() { + def setupLogger = ((Logger) LoggerFactory.getLogger(DataJobServiceImpl.class)) + setupLogger.setLevel(Level.DEBUG) + setupLogger.addAppender(logger) + logger.start() + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy new file mode 100644 index 0000000000..e07b978482 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/DmiSubJobRequestHandlerSpec.groovy @@ -0,0 +1,40 @@ +package org.onap.cps.ncmp.impl.datajobs + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.data.models.OperationType +import org.onap.cps.ncmp.api.datajobs.models.DataJobMetadata +import org.onap.cps.ncmp.api.datajobs.models.DmiWriteOperation +import org.onap.cps.ncmp.api.datajobs.models.ProducerKey +import org.onap.cps.ncmp.api.datajobs.models.SubJobWriteResponse +import org.onap.cps.ncmp.impl.dmi.DmiProperties +import org.onap.cps.ncmp.impl.dmi.DmiRestClient +import org.onap.cps.ncmp.impl.models.RequiredDmiService +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import spock.lang.Specification + +class DmiSubJobRequestHandlerSpec extends Specification { + + def mockDmiRestClient = Mock(DmiRestClient) + def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + def mockDmiProperties = Mock(DmiProperties) + def static NO_AUTH = null + def objectUnderTest = new DmiSubJobRequestHandler(mockDmiRestClient, mockDmiProperties, jsonObjectMapper) + + def 'Send a sub-job request to the DMI Plugin.'() { + given: 'a data job id, metadata and a map of producer keys and write operations to create a request' + def dataJobId = 'some-job-id' + def dataJobMetadata = new DataJobMetadata('', '', '') + def dmiWriteOperation = new DmiWriteOperation('', '', '', null, '', [:]) + def dmiWriteOperationsPerProducerKey = [new ProducerKey('', ''): [dmiWriteOperation]] + def response = new ResponseEntity<>(new SubJobWriteResponse('my-sub-job-id', '', ''), HttpStatus.OK) + when: 'sending request to DMI invoked' + objectUnderTest.sendRequestsToDmi(dataJobId, dataJobMetadata, dmiWriteOperationsPerProducerKey) + then: 'the dmi rest client is called' + 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(RequiredDmiService.DATA, _, _, OperationType.CREATE, NO_AUTH) >> response + and: 'the result contains the expected sub-job write responses' + def result = response.body + assert result.subJobId() == 'my-sub-job-id' + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy new file mode 100644 index 0000000000..84eb78b751 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminerSpec.groovy @@ -0,0 +1,63 @@ + +package org.onap.cps.ncmp.impl.datajobs + +import org.onap.cps.ncmp.api.datajobs.models.DataJobWriteRequest +import org.onap.cps.ncmp.api.datajobs.models.WriteOperation +import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher +import org.onap.cps.spi.model.DataNode +import spock.lang.Specification + +class WriteRequestExaminerSpec extends Specification { + + def mockAlternateIdMatcher = Mock(AlternateIdMatcher) + def objectUnderTest = new WriteRequestExaminer(mockAlternateIdMatcher) + + def setup() { + def ch1 = new DataNode(leaves: [id: 'ch1', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1']) + def ch2 = new DataNode(leaves: [id: 'ch2', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p1']) + def ch3 = new DataNode(leaves: [id: 'ch3', 'dmi-service-name': 'dmiA', 'data-producer-identifier': 'p2']) + def ch4 = new DataNode(leaves: [id: 'ch4', 'dmi-service-name': 'dmiB', 'data-producer-identifier': 'p1']) + mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn1', '/') >> ch1 + mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn2', '/') >> ch2 + mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn3', '/') >> ch3 + mockAlternateIdMatcher.getCmHandleDataNodeByLongestMatchingAlternateId('fdn4', '/') >> ch4 + } + + def 'Create a map of dmi write requests per producer key with #scenario.'() { + given: 'a write request with some write operations' + def writeOperations = writeOperationFdns.collect { + new WriteOperation(it, '', '', null) + } + and: 'operations are wrapped in a write request' + def dataJobWriteRequest = new DataJobWriteRequest(writeOperations) + when: 'the DMI write operations are split from the request' + def dmiWriteOperationsPerProducerKey = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest) + then: 'we get the expected number of keys and values.' + def producerKeysAsStrings = dmiWriteOperationsPerProducerKey.keySet().collect { + it.toString() + } + assert producerKeysAsStrings.size() == expectedKeys.size() + assert expectedKeys.containsAll(producerKeysAsStrings) + where: + scenario | writeOperationFdns || expectedKeys + 'one fdn' | ['fdn1'] || ['dmiA#p1'] + 'a duplicated target' | ['fdn1','fdn1'] || ['dmiA#p1'] + 'two different targets' | ['fdn1','fdn2'] || ['dmiA#p1'] + 'two different targets and different producer keys' | ['fdn1','fdn3'] || ['dmiA#p1', 'dmiA#p2'] + 'two different targets and different DMI services' | ['fdn1','fdn4'] || ['dmiA#p1', 'dmiB#p1'] + 'many targets with different dmi service names and producer keys' | ['fdn1', 'fdn2', 'fdn3', 'fdn4'] || ['dmiA#p1', 'dmiA#p2', 'dmiB#p1'] + } + + def 'Validate the ordering of the created sub jobs.'() { + given: 'a few write operations for the same producer' + def writeOperations = (1..3).collect { + new WriteOperation('fdn1', '', it.toString(), null) + } + and: 'operation is wrapped in a write request' + def dataJobWriteRequest = new DataJobWriteRequest(writeOperations) + when: 'the DMI write operations are split from the request' + def dmiWriteOperations = objectUnderTest.splitDmiWriteOperationsFromRequest('some id', dataJobWriteRequest).values().iterator().next() + then: 'we get the operation ids in the expected order.' + assert dmiWriteOperations.operationId == ['1', '2', '3'] + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy new file mode 100644 index 0000000000..affbf2aa4f --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiOperationsBaseSpec.groovy @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.inventory.models.CompositeState +import org.onap.cps.ncmp.impl.inventory.InventoryPersistence +import org.onap.cps.ncmp.impl.inventory.models.CmHandleState +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.spockframework.spring.SpringBean +import spock.lang.Shared +import spock.lang.Specification + +abstract class DmiOperationsBaseSpec extends Specification { + + @Shared + def yangModelCmHandleProperty = new YangModelCmHandle.Property('prop1', 'val1') + + @SpringBean + DmiRestClient mockDmiRestClient = Mock() + + @SpringBean + InventoryPersistence mockInventoryPersistence = Mock() + + @SpringBean + ObjectMapper spyObjectMapper = Spy() + + def yangModelCmHandle = new YangModelCmHandle() + def static dmiServiceName = 'myServiceName' + def static cmHandleId = 'some-cm-handle' + def static resourceIdentifier = 'parent/child' + + def mockYangModelCmHandleRetrieval(dmiProperties) { + populateYangModelCmHandle(dmiProperties, '') + mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + } + + def mockYangModelCmHandleRetrieval(dmiProperties, moduleSetTag) { + populateYangModelCmHandle(dmiProperties, moduleSetTag) + mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + } + + def mockYangModelCmHandleCollectionRetrieval(dmiProperties) { + populateYangModelCmHandle(dmiProperties, '') + mockInventoryPersistence.getYangModelCmHandles(_) >> [yangModelCmHandle] + } + + def populateYangModelCmHandle(dmiProperties, moduleSetTag) { + yangModelCmHandle.dmiDataServiceName = dmiServiceName + yangModelCmHandle.dmiServiceName = dmiServiceName + yangModelCmHandle.dmiProperties = dmiProperties + yangModelCmHandle.id = cmHandleId + yangModelCmHandle.compositeState = new CompositeState() + yangModelCmHandle.compositeState.cmHandleState = CmHandleState.READY + yangModelCmHandle.moduleSetTag = moduleSetTag + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy new file mode 100644 index 0000000000..418b3bb3c8 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiPropertiesSpec.groovy @@ -0,0 +1,38 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi + + +import spock.lang.Specification + +class DmiPropertiesSpec extends Specification { + + def objectUnderTest = new DmiProperties() + + def 'Geting dmi base path.'() { + given: 'base path of #dmiBasePath' + objectUnderTest.dmiBasePath = dmiBasePath + expect: 'Preceding and trailing slash wil be removed' + assert objectUnderTest.getDmiBasePath() == 'test' + where: 'the following dmi base paths are used' + dmiBasePath << [ 'test' , '/test', 'test/', '/test/' ] + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy new file mode 100644 index 0000000000..3dadf23249 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiRestClientSpec.groovy @@ -0,0 +1,166 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021-2024 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.node.ObjectNode +import org.onap.cps.ncmp.api.exceptions.DmiClientRequestException +import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.http.HttpHeaders +import org.springframework.http.HttpStatus +import org.springframework.http.HttpStatusCode +import org.springframework.http.ResponseEntity +import org.springframework.web.client.HttpServerErrorException +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.reactive.function.client.WebClientRequestException +import org.springframework.web.reactive.function.client.WebClientResponseException +import reactor.core.publisher.Mono +import spock.lang.Specification + +import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR +import static org.onap.cps.ncmp.api.data.models.OperationType.READ +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA +import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL + +class DmiRestClientSpec extends Specification { + + static final NO_AUTH_HEADER = null + static final BASIC_AUTH_HEADER = 'Basic c29tZSB1c2VyOnNvbWUgcGFzc3dvcmQ=' + static final BEARER_AUTH_HEADER = 'Bearer my-bearer-token' + static final urlTemplateParameters = new UrlTemplateParameters('/{pathParam1}/{pathParam2}', ['pathParam1': 'my', 'pathParam2': 'url']) + + def mockDataServicesWebClient = Mock(WebClient) + def mockModelServicesWebClient = Mock(WebClient) + def mockHealthChecksWebClient = Mock(WebClient) + + def mockRequestBody = Mock(WebClient.RequestBodyUriSpec) + def mockResponse = Mock(WebClient.ResponseSpec) + + def mockDmiProperties = Mock(DmiProperties) + + JsonObjectMapper jsonObjectMapper = new JsonObjectMapper(new ObjectMapper()) + + DmiRestClient objectUnderTest = new DmiRestClient(mockDmiProperties, jsonObjectMapper, mockDataServicesWebClient, mockModelServicesWebClient, mockHealthChecksWebClient) + + def setup() { + mockRequestBody.uri(_,_) >> mockRequestBody + mockRequestBody.headers(_) >> mockRequestBody + mockRequestBody.body(_) >> mockRequestBody + mockRequestBody.retrieve() >> mockResponse + } + + def 'DMI POST Operation with JSON for DMI Data Service '() { + given: 'the Data web client returns a valid response entity for the expected parameters' + mockDataServicesWebClient.post() >> mockRequestBody + mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Data service', HttpStatus.I_AM_A_TEAPOT)) + when: 'POST operation is invoked fro Data Service' + def response = objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) + then: 'the output of the method is equal to the output from the test template' + assert response.statusCode == HttpStatus.I_AM_A_TEAPOT + assert response.body == 'from Data service' + } + + def 'DMI POST Operation with JSON for DMI Model Service '() { + given: 'the Model web client returns a valid response entity for the expected parameters' + mockModelServicesWebClient.post() >> mockRequestBody + mockResponse.toEntity(Object.class) >> Mono.just(new ResponseEntity<>('from Model service', HttpStatus.I_AM_A_TEAPOT)) + when: 'POST operation is invoked for Model Service' + def response = objectUnderTest.synchronousPostOperationWithJsonData(MODEL, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) + then: 'the output of the method is equal to the output from the test template' + assert response.statusCode == HttpStatus.I_AM_A_TEAPOT + assert response.body == 'from Model service' + } + + def 'Dmi service sends client error response when #scenario'() { + given: 'the web client unable to return response entity but error' + mockDataServicesWebClient.post() >> mockRequestBody + mockResponse.toEntity(Object.class) >> Mono.error(exceptionType) + when: 'POST operation is invoked' + objectUnderTest.synchronousPostOperationWithJsonData(DATA, urlTemplateParameters, 'some json', READ, NO_AUTH_HEADER) + then: 'a http client exception is thrown' + def thrown = thrown(DmiClientRequestException) + and: 'the exception has the relevant details from the error response' + assert thrown.ncmpResponseStatus == expectedNcmpResponseStatusCode + assert thrown.httpStatusCode == httpStatusCode + where: 'the following errors occur' + scenario | httpStatusCode | exceptionType || expectedNcmpResponseStatusCode + 'dmi service unavailable' | 503 | new WebClientRequestException(new RuntimeException('some-error'), null, null, new HttpHeaders()) || DMI_SERVICE_NOT_RESPONDING + 'dmi request timeout' | 408 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || DMI_SERVICE_NOT_RESPONDING + 'dmi server error' | 500 | new WebClientResponseException('message', httpStatusCode, 'statusText', null, null, null) || UNABLE_TO_READ_RESOURCE_DATA + 'dmi service unavailable' | 503 | new HttpServerErrorException(HttpStatusCode.valueOf(503)) || DMI_SERVICE_NOT_RESPONDING + 'unknown error' | 500 | new Throwable('message') || UNKNOWN_ERROR + } + + def 'Dmi trust level is determined by spring boot health status'() { + given: 'a health check response' + def dmiPluginHealthCheckResponseJsonData = TestUtils.getResourceFileContent('dmiPluginHealthCheckResponse.json') + def jsonNode = jsonObjectMapper.convertJsonString(dmiPluginHealthCheckResponseJsonData, JsonNode.class) + ((ObjectNode) jsonNode).put('status', 'my status') + mockHealthChecksWebClient.get() >> mockRequestBody + mockResponse.onStatus(_,_)>> mockResponse + mockResponse.bodyToMono(JsonNode.class) >> Mono.just(jsonNode) + when: 'get trust level of the dmi plugin' + def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) + def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() + then: 'the status value from the json is returned' + assert result == 'my status' + } + + def 'Failing to get dmi plugin health status #scenario'() { + given: 'web client instance with #scenario' + mockHealthChecksWebClient.get() >> mockRequestBody + mockResponse.onStatus(_, _) >> mockResponse + mockResponse.bodyToMono(_) >> Mono.error(exceptionType) + when: 'attempt to get health status of the dmi plugin' + def urlTemplateParameters = new UrlTemplateParameters('some url', [:]) + def result = objectUnderTest.getDmiHealthStatus(urlTemplateParameters).block() + then: 'result will be empty' + assert result == '' + where: 'the following responses are used' + scenario | exceptionType + 'dmi request timeout' | new WebClientResponseException('some-message', 408, 'some-text', null, null, null) + 'dmi service unavailable' | new HttpServerErrorException(HttpStatus.SERVICE_UNAVAILABLE) + } + + def 'DMI auth header #scenario'() { + when: 'Specific dmi properties are provided' + mockDmiProperties.dmiBasicAuthEnabled >> authEnabled + mockDmiProperties.authUsername >> 'some user' + mockDmiProperties.authPassword >> 'some password' + then: 'http headers to conditionally have Authorization header' + def httpHeaders = new HttpHeaders() + objectUnderTest.configureHttpHeaders(httpHeaders, ncmpAuthHeader) + def outputAuthHeader = (httpHeaders.Authorization == null ? null : httpHeaders.Authorization[0]) + assert outputAuthHeader == expectedAuthHeader + where: 'the following configurations are used' + scenario | authEnabled | ncmpAuthHeader || expectedAuthHeader + 'DMI basic auth enabled, no NCMP bearer token' | true | NO_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth enabled, with NCMP bearer token' | true | BEARER_AUTH_HEADER || BASIC_AUTH_HEADER + 'DMI basic auth disabled, no NCMP bearer token' | false | NO_AUTH_HEADER || NO_AUTH_HEADER + 'DMI basic auth disabled, with NCMP bearer token' | false | BEARER_AUTH_HEADER || BEARER_AUTH_HEADER + 'DMI basic auth disabled, with NCMP basic auth' | false | BASIC_AUTH_HEADER || NO_AUTH_HEADER + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilderSpec.groovy new file mode 100644 index 0000000000..9e1b37023b --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiServiceUrlTemplateBuilderSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2022-2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi + + +import spock.lang.Specification + +class DmiServiceUrlTemplateBuilderSpec extends Specification { + + def objectUnderTest = new DmiServiceUrlTemplateBuilder() + + def 'Build URL template parameters with (variable) path segments and query parameters.'() { + given: 'the URL details are given to the builder' + objectUnderTest.fixedPathSegment('segment') + objectUnderTest.variablePathSegment('myVariableSegment','someValue') + objectUnderTest.fixedPathSegment('segment?with:special&characters') + objectUnderTest.queryParameter('param1', 'abc') + objectUnderTest.queryParameter('param2', 'value?with#special:characters') + when: 'the URL template parameters are created' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'the URL template contains variable names instead of value and un-encoded fixed segment' + assert result.urlTemplate == 'myDmiServer/myBasePath/v1/segment/{myVariableSegment}/segment?with:special&characters?param1={param1}¶m2={param2}' + and: 'URL variables contains name and un-encoded value pairs' + assert result.urlVariables == ['myVariableSegment': 'someValue', 'param1': 'abc', 'param2': 'value?with#special:characters'] + } + + def 'Build URL template parameters with special characters in query parameters.'() { + given: 'the query parameter is given to the builder' + objectUnderTest.queryParameter('my¶m', 'special&characters=are?not\\encoded') + when: 'the URL template parameters are created' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'Special characters are not encoded' + assert result.urlVariables == ['my¶m': 'special&characters=are?not\\encoded'] + } + + def 'Build URL template parameters with empty query parameters.'() { + when: 'the query parameter is given to the builder' + objectUnderTest.queryParameter('param', value) + and: 'the URL template parameters are create' + def result = objectUnderTest.createUrlTemplateParameters('myDmiServer', 'myBasePath') + then: 'no parameter gets added' + assert result.urlVariables.isEmpty() + where: 'the following parameter values are used' + value << [ null, '', ' ' ] + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfigurationSpec.groovy new file mode 100644 index 0000000000..fca47d8c24 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/dmi/DmiWebClientConfigurationSpec.groovy @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.dmi + + +import org.onap.cps.ncmp.config.HttpClientConfiguration +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.TestPropertySource +import org.springframework.web.reactive.function.client.WebClient +import spock.lang.Specification + +@SpringBootTest +@ContextConfiguration(classes = [HttpClientConfiguration]) +@TestPropertySource(properties = ['ncmp.dmi.httpclient.data-services.connectionTimeoutInSeconds=1', 'ncmp.dmi.httpclient.model-services.maximumInMemorySizeInMegabytes=1']) +@EnableConfigurationProperties +class DmiWebClientConfigurationSpec extends Specification { + + def webClientBuilder = Mock(WebClient.Builder) { + defaultHeaders(_) >> it + clientConnector(_) >> it + codecs(_) >> it + build() >> Mock(WebClient) + } + + def httpClientConfiguration = Spy(HttpClientConfiguration.class) + + def objectUnderTest = new DmiWebClientConfiguration(httpClientConfiguration) + + def 'Web Client Configuration construction.'() { + expect: 'the system can create an instance' + new DmiWebClientConfiguration(httpClientConfiguration) != null + } + + def 'Creating a web client instance data service.'() { + given: 'Web client configuration is invoked' + def dataServicesWebClient = objectUnderTest.dataServicesWebClient(webClientBuilder) + expect: 'the system can create an instance for data service' + assert dataServicesWebClient != null + assert dataServicesWebClient instanceof WebClient + } + + def 'Creating a web client instance model service.'() { + given: 'Web client configuration invoked' + def modelServicesWebClient = objectUnderTest.modelServicesWebClient(webClientBuilder) + expect: 'the system can create an instance for model service' + assert modelServicesWebClient != null + assert modelServicesWebClient instanceof WebClient + } + + def 'Creating a web client instance health service.'() { + given: 'Web client configuration invoked' + def healthChecksWebClient = objectUnderTest.healthChecksWebClient(webClientBuilder) + expect: 'the system can create an instance for health service' + assert healthChecksWebClient != null + assert healthChecksWebClient instanceof WebClient + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy index 4ff56312a1..0c702abea6 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy @@ -24,7 +24,7 @@ package org.onap.cps.ncmp.impl.inventory import com.hazelcast.map.IMap import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService -import org.onap.cps.ncmp.api.impl.exception.DmiRequestException +import org.onap.cps.ncmp.api.exceptions.DmiRequestException import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy index 17352977b8..196a1cd360 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy @@ -23,11 +23,11 @@ package org.onap.cps.ncmp.impl.inventory.sync import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.ObjectMapper -import org.onap.cps.ncmp.api.impl.config.DmiProperties -import org.onap.cps.ncmp.impl.DmiOperationsBaseSpec +import org.onap.cps.ncmp.impl.dmi.DmiOperationsBaseSpec +import org.onap.cps.ncmp.impl.dmi.DmiProperties +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters import org.onap.cps.spi.model.ModuleReference import org.onap.cps.utils.JsonObjectMapper -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy index e7674761c8..3e7ed9aff6 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsPublisherSpec.groovy @@ -24,10 +24,10 @@ import com.fasterxml.jackson.databind.ObjectMapper import org.apache.kafka.clients.consumer.KafkaConsumer import org.apache.kafka.common.serialization.StringDeserializer import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec import org.onap.cps.ncmp.events.lcm.v1.Event import org.onap.cps.ncmp.events.lcm.v1.LcmEvent import org.onap.cps.ncmp.utils.TestUtils +import org.onap.cps.ncmp.utils.events.MessagingBaseSpec import org.onap.cps.utils.JsonObjectMapper import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy index f975d23ba2..0a34d267c5 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy @@ -20,9 +20,9 @@ package org.onap.cps.ncmp.impl.inventory.trustlevel -import org.onap.cps.ncmp.api.impl.client.DmiRestClient -import org.onap.cps.ncmp.api.impl.utils.url.builder.UrlTemplateParameters import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.onap.cps.ncmp.impl.dmi.DmiRestClient +import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService import reactor.core.publisher.Mono import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy new file mode 100644 index 0000000000..7f07165df3 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/EventDateTimeFormatterSpec.groovy @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.impl.utils + +import spock.lang.Specification + +import java.time.Year + +class EventDateTimeFormatterSpec extends Specification { + + def 'Get ISO formatted date and time.' () { + expect: 'iso formatted date and time starts with current year' + assert EventDateTimeFormatter.getCurrentIsoFormattedDateTime().startsWith(String.valueOf(Year.now())) + } + + def 'Convert date time from string to OffsetDateTime type.'() { + when: 'date time as a string is converted to OffsetDateTime type' + def result = EventDateTimeFormatter.toIsoOffsetDateTime('2024-05-28T18:28:02.869+0100') + then: 'the result convert back back to a string is the same as the original timestamp (except the format of timezone offset)' + assert result.toString() == '2024-05-28T18:28:02.869+01:00' + } + + def 'Convert blank string.' () { + expect: 'converting a blank string result in null' + assert EventDateTimeFormatter.toIsoOffsetDateTime(' ') == null + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy index 162a9831ce..38eeaa589f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/AbstractModelLoaderSpec.groovy @@ -23,15 +23,15 @@ package org.onap.cps.ncmp.init import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger import ch.qos.logback.core.read.ListAppender -import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService +import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService -import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException +import org.onap.cps.ncmp.exceptions.NcmpStartUpException import org.onap.cps.spi.CascadeDeleteAllowed import org.onap.cps.spi.exceptions.AlreadyDefinedException -import org.springframework.boot.SpringApplication import org.slf4j.LoggerFactory +import org.springframework.boot.SpringApplication import org.springframework.boot.context.event.ApplicationStartedEvent import org.springframework.context.annotation.AnnotationConfigApplicationContext import spock.lang.Specification diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy index dd1fd0b462..caaad8d34d 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/CmDataSubscriptionModelLoaderSpec.groovy @@ -27,7 +27,7 @@ import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService -import org.onap.cps.ncmp.api.impl.exception.NcmpStartUpException +import org.onap.cps.ncmp.exceptions.NcmpStartUpException import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.model.Dataspace import org.slf4j.LoggerFactory diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy index 247f321834..051f5df4cf 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/CmAvcEventPublisherSpec.groovy @@ -23,8 +23,7 @@ package org.onap.cps.ncmp.utils.events import com.fasterxml.jackson.databind.ObjectMapper import io.cloudevents.CloudEvent import org.onap.cps.events.EventsPublisher -import org.onap.cps.ncmp.api.impl.utils.context.CpsApplicationContext -import org.onap.cps.ncmp.api.kafka.MessagingBaseSpec +import org.onap.cps.ncmp.config.CpsApplicationContext import org.onap.cps.ncmp.events.avc.ncmp_to_client.Avc import org.onap.cps.ncmp.events.avc.ncmp_to_client.AvcEvent import org.onap.cps.utils.JsonObjectMapper diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy new file mode 100644 index 0000000000..73dc2a37c5 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/ConsumerBaseSpec.groovy @@ -0,0 +1,44 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.utils.events + + +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.kafka.config.KafkaListenerEndpointRegistry +import org.springframework.kafka.test.utils.ContainerTestUtils + +@SpringBootTest(classes = KafkaListenerEndpointRegistry.class) +class ConsumerBaseSpec extends MessagingBaseSpec { + + @Autowired + private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry + + def setup() { + activateListeners() + } + + def activateListeners() { + kafkaListenerEndpointRegistry.getListenerContainers().forEach( + messageListenerContainer -> { ContainerTestUtils.waitForAssignment(messageListenerContainer, 1) } + ) + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy new file mode 100644 index 0000000000..377a1a6637 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/MessagingBaseSpec.groovy @@ -0,0 +1,75 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (c) 2023 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.utils.events + +import io.cloudevents.CloudEvent +import io.cloudevents.kafka.CloudEventSerializer +import org.apache.kafka.common.serialization.StringDeserializer +import org.apache.kafka.common.serialization.StringSerializer +import org.springframework.kafka.core.DefaultKafkaProducerFactory +import org.springframework.kafka.core.KafkaTemplate +import org.springframework.kafka.support.serializer.JsonSerializer +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource +import org.testcontainers.containers.KafkaContainer +import org.testcontainers.utility.DockerImageName +import spock.lang.Specification + +class MessagingBaseSpec extends Specification { + + def setupSpec() { + kafkaTestContainer.start() + } + + def cleanupSpec() { + kafkaTestContainer.stop() + } + + static kafkaTestContainer = new KafkaContainer(DockerImageName.parse('registry.nordix.org/onaptest/confluentinc/cp-kafka:6.2.1').asCompatibleSubstituteFor('confluentinc/cp-kafka')) + + def legacyEventKafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory(eventProducerConfigProperties(JsonSerializer))) + + def cloudEventKafkaTemplate = new KafkaTemplate<>(new DefaultKafkaProducerFactory(eventProducerConfigProperties(CloudEventSerializer))) + + @DynamicPropertySource + static void registerKafkaProperties(DynamicPropertyRegistry dynamicPropertyRegistry) { + dynamicPropertyRegistry.add('spring.kafka.bootstrap-servers', kafkaTestContainer::getBootstrapServers) + } + + def eventProducerConfigProperties(valueSerializer) { + return [('bootstrap.servers'): kafkaTestContainer.getBootstrapServers().split(',')[0], + ('retries') : 0, + ('batch-size') : 16384, + ('linger.ms') : 1, + ('buffer.memory') : 33554432, + ('key.serializer') : StringSerializer, + ('value.serializer') : valueSerializer] + } + + def eventConsumerConfigProperties(consumerGroupId, valueSerializer) { + return [('bootstrap.servers') : kafkaTestContainer.getBootstrapServers().split(',')[0], + ('key.deserializer') : StringDeserializer, + ('value.deserializer'): valueSerializer, + ('auto.offset.reset') : 'earliest', + ('group.id') : consumerGroupId + ] + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy index 26148f8709..8fc3e18c7f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/utils/events/TopicValidatorSpec.groovy @@ -20,7 +20,7 @@ package org.onap.cps.ncmp.utils.events -import org.onap.cps.ncmp.exceptions.InvalidTopicException +import org.onap.cps.ncmp.api.exceptions.InvalidTopicException import spock.lang.Specification class TopicValidatorSpec extends Specification { -- cgit 1.2.3-korg