summaryrefslogtreecommitdiffstats
path: root/integration-test/src/test/groovy/org
diff options
context:
space:
mode:
authorsourabh_sourabh <sourabh.sourabh@est.tech>2024-05-02 10:26:16 +0100
committersourabh_sourabh <sourabh.sourabh@est.tech>2024-05-03 12:49:23 +0100
commit7662e814e912e0eecccea583ff18ce9abe84ef9f (patch)
treec8ef0cfbcd5f1ee6d27a65de3fdc0f60c443be0b /integration-test/src/test/groovy/org
parentc5f6c45eb5cd94f76f1f39e5a4593996a9f25474 (diff)
Make NCMP integration tests use MockWebServer
Change from using MockRestServiceServer - which is only compatible with RestTemplate - to MockWebServer, which will allow tests to work using WebClient instead of RestTemplate. Issue-ID: CPS-2183 Change-Id: I7494fe17cba6e92f7df81f0fd0185e1d2b5a5541 Signed-off-by: sourabh_sourabh <sourabh.sourabh@est.tech>
Diffstat (limited to 'integration-test/src/test/groovy/org')
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy51
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy105
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy67
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy35
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy58
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy20
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy29
7 files changed, 218 insertions, 147 deletions
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
index 51b02387ed..44fc258355 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy
@@ -20,8 +20,13 @@
package org.onap.cps.integration.base
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
+import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
+
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
+import okhttp3.mockwebserver.MockWebServer
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsDataspaceService
@@ -48,23 +53,12 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMock
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.ExpectedCount
-import org.springframework.test.web.client.MockRestServiceServer
import org.springframework.test.web.servlet.MockMvc
-import org.springframework.web.client.RestTemplate
import org.testcontainers.spock.Testcontainers
import spock.lang.Shared
import spock.lang.Specification
import spock.util.concurrent.PollingConditions
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
-import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = [CpsDataspaceService])
@Testcontainers
@EnableAutoConfiguration
@@ -111,17 +105,16 @@ abstract class CpsIntegrationSpecBase extends Specification {
NetworkCmProxyQueryService networkCmProxyQueryService
@Autowired
- RestTemplate restTemplate
-
- @Autowired
ModuleSyncWatchdog moduleSyncWatchdog
@Autowired
JsonObjectMapper jsonObjectMapper
- MockRestServiceServer mockDmiServer = null
+ MockWebServer mockDmiServer = null
+ DmiDispatcher dmiDispatcher = new DmiDispatcher()
+
+ def DMI_URL = null
- static DMI_URL = 'http://mock-dmi-server'
static NO_MODULE_SET_TAG = ''
static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
@@ -135,7 +128,14 @@ abstract class CpsIntegrationSpecBase extends Specification {
createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
initialized = true
}
- mockDmiServer = MockRestServiceServer.bindTo(restTemplate).ignoreExpectOrder(true).build()
+ mockDmiServer = new MockWebServer()
+ mockDmiServer.setDispatcher(dmiDispatcher)
+ mockDmiServer.start()
+ DMI_URL = String.format("http://%s:%s", mockDmiServer.getHostName(), mockDmiServer.getPort())
+ }
+
+ def cleanup() {
+ mockDmiServer.shutdown()
}
def static readResourceDataFile(filename) {
@@ -217,23 +217,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
}
- def mockDmiResponsesForModuleSync(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
- }
-
- def mockDmiIsNotAvailableForModuleSync(dmiPlugin, cmHandleId) {
- mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
- .andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
- }
-
- def mockDmiWillRespondToHealthChecks(dmiPlugin) {
- mockDmiServer.expect(ExpectedCount.between(0, Integer.MAX_VALUE), requestTo("${dmiPlugin}/actuator/health"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body('{"status":"UP"}'))
- }
-
def overrideCmHandleLastUpdateTime(cmHandleId, newUpdateTime) {
String ISO_TIMESTAMP_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
DateTimeFormatter ISO_TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(ISO_TIMESTAMP_PATTERN);
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
new file mode 100644
index 0000000000..6676cb74c2
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/DmiDispatcher.groovy
@@ -0,0 +1,105 @@
+/*
+ * ============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.integration.base
+
+import static org.onap.cps.integration.base.CpsIntegrationSpecBase.readResourceDataFile
+
+import org.springframework.http.HttpHeaders
+import java.util.regex.Matcher
+import okhttp3.mockwebserver.Dispatcher
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.RecordedRequest
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+
+/**
+ * This class simulates responses from the DMI server in NCMP integration tests.
+ *
+ * It is to be used with a MockWebServer, using mockWebServer.setDispatcher(new DmiDispatcher()).
+ *
+ * It currently implements the following endpoints:
+ * - /actuator/health: healthcheck endpoint that responds with 200 OK / {"status":"UP"}
+ * - /dmi/v1/ch/{cmHandleId}/modules: returns module references for a CM handle
+ * - /dmi/v1/ch/{cmHandleId}/moduleResources: returns modules resources for a CM handle
+ *
+ * The module resource/reference responses are generated based on the module names in the map moduleNamesPerCmHandleId.
+ * To configure the DMI so that CM handle 'ch-1' will have modules 'M1' and 'M2', you may use:
+ * dmiDispatcher.moduleNamesPerCmHandleId.put('ch-1', ['M1', 'M2']);
+ *
+ * To simulate the DMI not being available, the boolean isAvailable may be set to false, in which case the mock server
+ * will always respond with 503 Service Unavailable.
+ */
+class DmiDispatcher extends Dispatcher {
+
+ static final MODULE_REFERENCES_RESPONSE_TEMPLATE = readResourceDataFile('mock-dmi-responses/moduleReferencesTemplate.json')
+ static final MODULE_RESOURCES_RESPONSE_TEMPLATE = readResourceDataFile('mock-dmi-responses/moduleResourcesTemplate.json')
+
+ def isAvailable = true
+
+ Map<String, List<String>> moduleNamesPerCmHandleId = [:]
+
+ @Override
+ MockResponse dispatch(RecordedRequest request) {
+ if (!isAvailable) {
+ return new MockResponse().setResponseCode(HttpStatus.SERVICE_UNAVAILABLE.value())
+ }
+ switch (request.path) {
+ case ~/^\/dmi\/v1\/ch\/(.*)\/modules$/:
+ def cmHandleId = Matcher.lastMatcher[0][1]
+ return getModuleReferencesResponse(cmHandleId)
+
+ case ~/^\/dmi\/v1\/ch\/(.*)\/moduleResources$/:
+ def cmHandleId = Matcher.lastMatcher[0][1]
+ return getModuleResourcesResponse(cmHandleId)
+
+ default:
+ throw new IllegalArgumentException('Mock DMI does not handle path ' + request.path)
+ }
+ }
+
+ private getModuleReferencesResponse(cmHandleId) {
+ def moduleReferences = '{"schemas":[' + getModuleNamesForCmHandle(cmHandleId).collect {
+ MODULE_REFERENCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
+ }.join(',') + ']}'
+ return mockOkResponseWithBody(moduleReferences)
+ }
+
+ private getModuleResourcesResponse(cmHandleId) {
+ def moduleResources = '[' + getModuleNamesForCmHandle(cmHandleId).collect {
+ MODULE_RESOURCES_RESPONSE_TEMPLATE.replaceAll("<MODULE_NAME>", it)
+ }.join(',') + ']'
+ return mockOkResponseWithBody(moduleResources)
+ }
+
+ private getModuleNamesForCmHandle(cmHandleId) {
+ if (!moduleNamesPerCmHandleId.containsKey(cmHandleId)) {
+ throw new IllegalArgumentException('Mock DMI has no modules configured for ' + cmHandleId)
+ }
+ return moduleNamesPerCmHandleId.get(cmHandleId)
+ }
+
+ private static mockOkResponseWithBody(responseBody) {
+ return new MockResponse()
+ .setResponseCode(HttpStatus.OK.value())
+ .addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
+ .setBody(responseBody)
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
index 28c4280468..4ffe586a99 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpBearerTokenPassthroughSpec.groovy
@@ -20,35 +20,45 @@
package org.onap.cps.integration.functional
-import java.time.Duration
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.springframework.http.HttpHeaders
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.match.MockRestRequestMatchers
-
import static org.springframework.http.HttpMethod.GET
import static org.springframework.http.HttpMethod.DELETE
import static org.springframework.http.HttpMethod.PATCH
import static org.springframework.http.HttpMethod.POST
import static org.springframework.http.HttpMethod.PUT
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.method
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
+import okhttp3.mockwebserver.Dispatcher
+import okhttp3.mockwebserver.MockResponse
+import okhttp3.mockwebserver.RecordedRequest
+import org.jetbrains.annotations.NotNull
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpHeaders
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+import spock.util.concurrent.PollingConditions
+
class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
- static final MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
+ def lastAuthHeaderReceived = null
def setup() {
- mockDmiWillRespondToHealthChecks(DMI_URL)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE, MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
registerCmHandle(DMI_URL, 'ch-1', NO_MODULE_SET_TAG)
- mockDmiServer.reset()
- mockDmiWillRespondToHealthChecks(DMI_URL)
+
+ mockDmiServer.setDispatcher(new Dispatcher() {
+ @Override
+ MockResponse dispatch(@NotNull RecordedRequest request) throws InterruptedException {
+ if (request.path == '/actuator/health') {
+ return new MockResponse()
+ .addHeader("Content-Type", MediaType.APPLICATION_JSON).setBody('{"status":"UP"}')
+ .setResponseCode(HttpStatus.OK.value())
+ } else {
+ lastAuthHeaderReceived = request.getHeader('Authorization')
+ return new MockResponse().setResponseCode(HttpStatus.OK.value())
+ }
+ }
+ })
}
def cleanup() {
@@ -56,12 +66,6 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
}
def 'Bearer token is passed from NCMP to DMI in pass-through data operations.'() {
- given: 'DMI will expect to receive a request with a bearer token'
- def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id"
- mockDmiServer.expect(requestTo(targetDmiUrl))
- .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through data request is sent to NCMP with a bearer token'
mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
.queryParam('resourceIdentifier', 'my-resource-id')
@@ -71,19 +75,13 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with bearer token'
- mockDmiServer.verify()
+ lastAuthHeaderReceived == 'Bearer some-bearer-token'
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
}
def 'Basic auth header is NOT passed from NCMP to DMI in pass-through data operations.'() {
- given: 'DMI will expect to receive a request with no authorization header'
- def targetDmiUrl = "$DMI_URL/dmi/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=my-resource-id"
- mockDmiServer.expect(requestTo(targetDmiUrl))
- .andExpect(MockRestRequestMatchers.headerDoesNotExist(HttpHeaders.AUTHORIZATION))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through data request is sent to NCMP with basic authentication'
mvc.perform(request(httpMethod, '/ncmp/v1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running')
.queryParam('resourceIdentifier', 'my-resource-id')
@@ -93,18 +91,13 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI has received request with no authorization header'
- mockDmiServer.verify()
+ lastAuthHeaderReceived == null
where: 'all HTTP operations are applied'
httpMethod << [GET, POST, PUT, PATCH, DELETE]
}
def 'Bearer token is passed from NCMP to DMI in async batch pass-through data operation.'() {
- given: 'DMI will expect to receive a request with a bearer token'
- mockDmiServer.expect(method(POST))
- .andExpect(MockRestRequestMatchers.header(HttpHeaders.AUTHORIZATION, 'Bearer some-bearer-token'))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON))
-
when: 'a pass-through async data request is sent to NCMP with a bearer token'
def requestBody = """{"operations": [{
"operation": "read",
@@ -121,7 +114,9 @@ class NcmpBearerTokenPassthroughSpec extends CpsIntegrationSpecBase {
.andExpect(status().is2xxSuccessful())
then: 'DMI will receive the async request with bearer token'
- mockDmiServer.verify(Duration.ofSeconds(1))
+ new PollingConditions().within(3, () -> {
+ assert lastAuthHeaderReceived == 'Bearer some-bearer-token'
+ })
}
}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
index a6b516cd74..5c337f179b 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
@@ -41,19 +41,13 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
def kafkaConsumer = KafkaTestContainer.getConsumer('ncmp-group', StringDeserializer.class)
- static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
-
def setup() {
objectUnderTest = networkCmProxyDataService
- mockDmiWillRespondToHealthChecks(DMI_URL)
}
def 'CM Handle registration is successful.'() {
given: 'DMI will return modules when requested'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+ dmiDispatcher.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
and: 'consumer subscribed to topic'
kafkaConsumer.subscribe(['ncmp-events'])
@@ -88,16 +82,13 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
and: 'the CM-handle has expected modules'
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
- and: 'DMI received expected requests'
- mockDmiServer.verify()
-
cleanup: 'deregister CM handle'
deregisterCmHandle(DMI_URL, 'ch-1')
}
def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
given: 'DMI is not available to handle requests'
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
+ dmiDispatcher.isAvailable = false
when: 'a CM-handle is registered for creation'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
@@ -122,13 +113,11 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
}
def 'Create a CM-handle with existing moduleSetTag.'() {
- given: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ given: 'DMI will return modules when requested'
+ dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
+ and: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
registerCmHandle(DMI_URL, 'ch-1', 'A')
registerCmHandle(DMI_URL, 'ch-2', 'B')
- assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences('ch-1').moduleName.sort()
- assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-2').moduleName.sort()
when: 'a CM-handle is registered for creation with moduleSetTag "B"'
def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-3', moduleSetTag: 'B')
@@ -152,11 +141,7 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
def 'CM Handle retry after failed module sync.'() {
given: 'DMI is not initially available to handle requests'
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-1')
- mockDmiIsNotAvailableForModuleSync(DMI_URL, 'ch-2')
- and: 'DMI will be available for retry'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ dmiDispatcher.isAvailable = false
when: 'CM-handles are registered for creation'
def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'ch-1'), new NcmpServiceCmHandle(cmHandleId: 'ch-2')]
@@ -179,7 +164,11 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
assert objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState == CmHandleState.ADVISED
assert objectUnderTest.getCmHandleCompositeState('ch-2').cmHandleState == CmHandleState.ADVISED
- when: 'module sync runs'
+ when: 'DMI is available for retry'
+ dmiDispatcher.isAvailable = true
+ and: 'DMI will return expected modules'
+ dmiDispatcher.moduleNamesPerCmHandleId = ['ch-1': ['M1', 'M2'], 'ch-2': ['M1', 'M3']]
+ and: 'module sync runs'
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handles go to READY state'
new PollingConditions().within(3, () -> {
@@ -192,8 +181,6 @@ class NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
and: 'CM-handles have expected module set tags (blank)'
assert objectUnderTest.getNcmpServiceCmHandle('ch-1').moduleSetTag == ''
assert objectUnderTest.getNcmpServiceCmHandle('ch-2').moduleSetTag == ''
- and: 'DMI received expected requests'
- mockDmiServer.verify()
cleanup: 'deregister CM handle'
deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2'])
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
index 5421ad3237..4d1d77e694 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
@@ -27,38 +27,26 @@ import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.models.UpgradedCmHandles
-import org.springframework.http.HttpStatus
import spock.util.concurrent.PollingConditions
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
-
class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
NetworkCmProxyDataService objectUnderTest
- static final INITIAL_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final INITIAL_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final UPDATED_MODULE_REFERENCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final UPDATED_MODULE_RESOURCES_RESPONSE = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
static final CM_HANDLE_ID = 'ch-1'
static final CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG = 'ch-2'
def setup() {
objectUnderTest = networkCmProxyDataService
- mockDmiWillRespondToHealthChecks(DMI_URL)
}
def 'Upgrade CM-handle with new moduleSetTag or no moduleSetTag.'() {
- given: 'DMI will return modules for initial registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- and: 'DMI returns different modules for upgrade'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
-
- when: 'a CM-handle is created with expected initial modules: M1 and M2'
+ given: 'a CM-handle is created with expected initial modules: M1 and M2'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag)
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
- and: "the CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
+
+ when: "the CM-handle is upgraded with given moduleSetTag '${updatedModuleSetTag}'"
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
@@ -72,14 +60,16 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE
assert cmHandleCompositeState.lockReason.details == "Upgrade to ModuleSetTag: ${updatedModuleSetTag}"
- when: 'module sync runs'
+ when: 'DMI will return different modules for upgrade: M1 and M3'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M3']
+ and: 'module sync runs'
moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().eventually {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- })
+ }
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -87,9 +77,6 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
and: 'CM-handle has expected updated modules: M1 and M3'
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
- and: 'DMI received expected requests'
- mockDmiServer.verify()
-
cleanup: 'deregister CM-handle'
deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
@@ -103,8 +90,8 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Upgrade CM-handle with existing moduleSetTag.'() {
given: 'DMI will return modules for registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG] = ['M1', 'M3']
and: "an existing CM-handle handle with moduleSetTag '${updatedModuleSetTag}'"
registerCmHandle(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag)
assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG).moduleName.sort()
@@ -125,9 +112,9 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
+ new PollingConditions().eventually {
assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
- })
+ }
and: 'the CM-handle has expected moduleSetTag'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == updatedModuleSetTag
@@ -146,7 +133,7 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
def 'Skip upgrade of CM-handle with same moduleSetTag as before.'() {
given: 'an existing CM-handle with expected initial modules: M1 and M2'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, 'same')
assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
@@ -169,14 +156,13 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
}
def 'Upgrade of CM-handle fails due to DMI error.'() {
- given: 'DMI will return modules for initial registration'
- mockDmiResponsesForModuleSync(DMI_URL, CM_HANDLE_ID, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
- and: 'DMI returns error code for upgrade'
- mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
-
- when: 'a CM-handle is created'
+ given: 'a CM-handle exists'
+ dmiDispatcher.moduleNamesPerCmHandleId[CM_HANDLE_ID] = ['M1', 'M2']
registerCmHandle(DMI_URL, CM_HANDLE_ID, 'oldTag')
- and: 'the CM-handle is upgraded'
+ and: 'DMI is not available for upgrade'
+ dmiDispatcher.isAvailable = false
+
+ when: 'the CM-handle is upgraded'
def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'newTag')
networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
@@ -186,11 +172,11 @@ class NcmpCmHandleUpgradeSpec extends CpsIntegrationSpecBase {
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED'
- new PollingConditions().within(3, () -> {
+ new PollingConditions(timeout: 3).eventually {
def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED
- })
+ }
and: 'the CM-handle has same moduleSetTag as before'
assert objectUnderTest.getNcmpServiceCmHandle(CM_HANDLE_ID).moduleSetTag == 'oldTag'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
index 9129f09fb5..302c7e512c 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmNotificationSubscriptionSpec.groovy
@@ -1,3 +1,23 @@
+/*
+ * ============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.integration.functional
import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING;
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
index d7f8771e18..950cd65e72 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpRestApiSpec.groovy
@@ -32,20 +32,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
class NcmpRestApiSpec extends CpsIntegrationSpecBase {
- static final MODULE_REFERENCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_Response.json')
- static final MODULE_RESOURCES_RESPONSE_A = readResourceDataFile('mock-dmi-responses/bookStoreAWithModules_M1_M2_ResourcesResponse.json')
- static final MODULE_REFERENCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_Response.json')
- static final MODULE_RESOURCES_RESPONSE_B = readResourceDataFile('mock-dmi-responses/bookStoreBWithModules_M1_M3_ResourcesResponse.json')
-
- def setup() {
- mockDmiWillRespondToHealthChecks(DMI_URL)
- }
-
def 'Register CM Handles using REST API.'() {
given: 'DMI will return modules'
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-2', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
- mockDmiResponsesForModuleSync(DMI_URL, 'ch-3', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_B)
+ dmiDispatcher.moduleNamesPerCmHandleId = [
+ 'ch-1': ['M1', 'M2'],
+ 'ch-2': ['M1', 'M2'],
+ 'ch-3': ['M1', 'M3']
+ ]
and: 'a POST request is made to register the CM Handles'
def requestBody = '{"dmiPlugin":"'+DMI_URL+'","createdCmHandles":[{"cmHandle":"ch-1"},{"cmHandle":"ch-2"},{"cmHandle":"ch-3"}]}'
mvc.perform(post('/ncmpInventory/v1/ch').contentType(MediaType.APPLICATION_JSON).content(requestBody))
@@ -53,10 +46,12 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase {
when: 'module sync runs'
moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
then: 'CM-handles go to READY state'
- new PollingConditions(timeout: 3, delay: 0.5).eventually {
- mvc.perform(get('/ncmp/v1/ch/ch-1'))
- .andExpect(status().isOk())
- .andExpect(jsonPath('$.state.cmHandleState').value('READY'))
+ new PollingConditions().eventually {
+ (1..3).each {
+ mvc.perform(get('/ncmp/v1/ch/ch-'+it))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath('$.state.cmHandleState').value('READY'))
+ }
}
}
@@ -71,7 +66,7 @@ class NcmpRestApiSpec extends CpsIntegrationSpecBase {
]
}""".formatted(moduleName)
expect: "a search for module ${moduleName} returns expected CM handles"
- mvc.perform(post(DMI_URL+'/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithModuleCondition))
+ mvc.perform(post('/ncmp/v1/ch/id-searches').contentType(MediaType.APPLICATION_JSON).content(requestBodyWithModuleCondition))
.andExpect(status().is2xxSuccessful())
.andExpect(jsonPath('$[*]', containsInAnyOrder(expectedCmHandles.toArray())))
.andExpect(jsonPath('$', hasSize(expectedCmHandles.size())));