aboutsummaryrefslogtreecommitdiffstats
path: root/integration-test/src/test/groovy/org
diff options
context:
space:
mode:
Diffstat (limited to 'integration-test/src/test/groovy/org')
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy70
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy131
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy141
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy187
4 files changed, 381 insertions, 148 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 ecf7d67d2d..23504e49cd 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
@@ -30,6 +30,10 @@ import org.onap.cps.integration.DatabaseTestContainer
import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
+import org.onap.cps.ncmp.api.models.DmiPluginRegistration
+import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.exceptions.DataspaceNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.repository.DataspaceRepository
@@ -40,10 +44,17 @@ import org.springframework.boot.autoconfigure.domain.EntityScan
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.MockRestServiceServer
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.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
+import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
@SpringBootTest(classes = [CpsDataspaceService])
@Testcontainers
@@ -75,9 +86,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
SessionManager sessionManager
@Autowired
- RestTemplate restTemplate
-
- @Autowired
NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService
@Autowired
@@ -86,6 +94,16 @@ abstract class CpsIntegrationSpecBase extends Specification {
@Autowired
NetworkCmProxyQueryService networkCmProxyQueryService
+ @Autowired
+ RestTemplate restTemplate
+
+ @Autowired
+ ModuleSyncWatchdog moduleSyncWatchdog
+
+ MockRestServiceServer mockDmiServer = null
+
+ static final DMI_URL = 'http://mock-dmi-server'
+
def static GENERAL_TEST_DATASPACE = 'generalTestDataspace'
def static BOOKSTORE_SCHEMA_SET = 'bookstoreSchemaSet'
@@ -98,8 +116,19 @@ abstract class CpsIntegrationSpecBase extends Specification {
createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE)
initialized = true
}
+ mockDmiServer = MockRestServiceServer.createServer(restTemplate)
+ }
+
+ def cleanup() {
+ mockDmiServer.reset()
}
+ def static readResourceDataFile(filename) {
+ return new File('src/test/resources/data/' + filename).text
+ }
+
+ // *** CPS Integration Test Utilities ***
+
def static countDataNodesInTree(DataNode dataNode) {
return 1 + countDataNodesInTree(dataNode.getChildDataNodes())
}
@@ -112,10 +141,6 @@ abstract class CpsIntegrationSpecBase extends Specification {
return nodeCount
}
- def static readResourceDataFile(filename) {
- return new File('src/test/resources/data/' + filename).text
- }
-
def getBookstoreYangResourcesNameToContentMap() {
def bookstoreModelFileContent = readResourceDataFile('bookstore/bookstore.yang')
def bookstoreTypesFileContent = readResourceDataFile('bookstore/bookstore-types.yang')
@@ -158,4 +183,35 @@ abstract class CpsIntegrationSpecBase extends Specification {
return '"' + name + '":[' + innerJson + ']'
}
+ // *** NCMP Integration Test Utilities ***
+
+ def registerCmHandle(dmiPlugin, cmHandleId, moduleSetTag, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: cmHandleId, moduleSetTag: moduleSetTag)
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, createdCmHandles: [cmHandleToCreate]))
+ mockDmiResponsesForRegistration(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse)
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ new PollingConditions().within(3, () -> {
+ CmHandleState.READY == networkCmProxyDataService.getCmHandleCompositeState(cmHandleId).cmHandleState
+ })
+ mockDmiServer.reset()
+ }
+
+ def deregisterCmHandle(dmiPlugin, cmHandleId) {
+ deregisterCmHandles(dmiPlugin, [cmHandleId])
+ }
+
+ def deregisterCmHandles(dmiPlugin, cmHandleIds) {
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: dmiPlugin, removedCmHandles: cmHandleIds))
+ }
+
+ def mockDmiResponsesForRegistration(dmiPlugin, cmHandleId, dmiModuleReferencesResponse, dmiModuleResourcesResponse) {
+ if (dmiModuleReferencesResponse != null) {
+ mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/modules"))
+ .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleReferencesResponse))
+ }
+ if (dmiModuleResourcesResponse != null) {
+ mockDmiServer.expect(requestTo("${dmiPlugin}/dmi/v1/ch/${cmHandleId}/moduleResources"))
+ .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(dmiModuleResourcesResponse))
+ }
+ }
}
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
new file mode 100644
index 0000000000..6707753257
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleCreateSpec.groovy
@@ -0,0 +1,131 @@
+/*
+ * ============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 org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+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.NcmpServiceCmHandle
+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 NcmpCmHandleCreateSpec extends CpsIntegrationSpecBase {
+
+ NetworkCmProxyDataService objectUnderTest
+
+ 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
+ }
+
+ def 'CM Handle registration is successful.'() {
+ given: 'DMI will return modules when requested'
+ mockDmiResponsesForRegistration(DMI_URL, 'ch-1', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+
+ when: 'a CM-handle is registered for creation'
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
+ def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.createdCmHandles == [CmHandleRegistrationResponse.createSuccessResponse('ch-1')]
+
+ and: 'CM-handle is initially in ADVISED state'
+ assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-1').cmHandleState
+ })
+
+ 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'
+ mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
+
+ when: 'a CM-handle is registered for creation'
+ def cmHandleToCreate = new NcmpServiceCmHandle(cmHandleId: 'ch-1')
+ def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate])
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
+
+ and: 'module sync runs'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to LOCKED state with reason MODULE_SYNC_FAILED'
+ new PollingConditions().within(3, () -> {
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState('ch-1')
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_SYNC_FAILED
+ })
+
+ and: 'CM-handle has no modules'
+ assert objectUnderTest.getYangResourcesModuleReferences('ch-1').empty
+
+ cleanup: 'deregister CM handle'
+ deregisterCmHandle(DMI_URL, 'ch-1')
+ }
+
+ def 'Create a CM-handle with existing moduleSetTag.'() {
+ given: 'existing CM-handles cm-1 with moduleSetTag "A", and cm-2 with moduleSetTag "B"'
+ registerCmHandle(DMI_URL, 'ch-1', 'A', MODULE_REFERENCES_RESPONSE_A, MODULE_RESOURCES_RESPONSE_A)
+ registerCmHandle(DMI_URL, 'ch-2', 'B', MODULE_REFERENCES_RESPONSE_B, MODULE_RESOURCES_RESPONSE_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')
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: [cmHandleToCreate]))
+
+ then: 'the CM-handle goes to READY state after module sync'
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('ch-3').cmHandleState
+ })
+
+ and: 'the CM-handle has expected modules from module set "B": M1 and M3'
+ ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences('ch-3').moduleName.sort()
+
+ cleanup: 'deregister CM handles'
+ deregisterCmHandles(DMI_URL, ['ch-1', 'ch-2', 'ch-3'])
+ }
+}
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy
deleted file mode 100644
index 9cd4d7cbf9..0000000000
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleRegistrationSpec.groovy
+++ /dev/null
@@ -1,141 +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.integration.functional
-
-import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.api.NetworkCmProxyDataService
-import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
-import org.onap.cps.ncmp.api.impl.inventory.sync.ModuleSyncWatchdog
-import org.onap.cps.ncmp.api.models.DmiPluginRegistration
-import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
-import org.onap.cps.spi.exceptions.DataNodeNotFoundException
-import org.springframework.beans.factory.annotation.Autowired
-import org.springframework.http.HttpStatus
-import org.springframework.http.MediaType
-import org.springframework.test.web.client.MockRestServiceServer
-import spock.util.concurrent.PollingConditions
-
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything
-import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo
-import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
-
-class NcmpCmHandleRegistrationSpec extends CpsIntegrationSpecBase {
-
- NetworkCmProxyDataService objectUnderTest
-
- @Autowired
- ModuleSyncWatchdog moduleSyncWatchdog
-
- static final DMI_URL = 'http://mock-dmi-server'
- def mockDmiServer
- def moduleReferencesResponse
- def moduleResourcesResponse
-
- def setup() {
- objectUnderTest = networkCmProxyDataService
- mockDmiServer = MockRestServiceServer.createServer(restTemplate)
- moduleReferencesResponse = readResourceDataFile('mock-dmi-responses/ietfYangModuleResponse.json')
- moduleResourcesResponse = readResourceDataFile('mock-dmi-responses/ietfYangModuleResourcesResponse.json')
- }
-
- def 'CM Handle is READY when Registration is successful.'() {
- given: 'a CM handle to create'
- def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'cm-1')]
-
- and: 'DMI registration params'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- and: 'DMI returns modules'
- mockDmiServer.expect(requestTo("${DMI_URL}/dmi/v1/ch/cm-1/modules"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(moduleReferencesResponse))
- mockDmiServer.expect(requestTo("${DMI_URL}/dmi/v1/ch/cm-1/moduleResources"))
- .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(moduleResourcesResponse))
-
- when: 'a CM-handle is registered'
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'registration gives expected response'
- assert dmiPluginRegistrationResponse.createdCmHandles.size() == 1
-
- and: 'CM-handle is initially in ADVISED state'
- assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('cm-1').cmHandleState
-
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to READY state'
- new PollingConditions().within(3, () -> {
- assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState('cm-1').cmHandleState
- })
-
- and: 'DMI received expected requests'
- mockDmiServer.verify()
- }
-
- def 'CM Handle goes to LOCKED state when DMI gives error during module sync.'() {
- given: 'a CM handle to create'
- def cmHandlesToCreate = [new NcmpServiceCmHandle(cmHandleId: 'cm-2')]
-
- and: 'DMI registration params'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, createdCmHandles: cmHandlesToCreate)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- and: 'DMI returns error code'
- mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
-
- when: 'a CM-handle is registered'
- def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'registration gives expected response'
- assert dmiPluginRegistrationResponse.createdCmHandles.size() == 1
-
- and: 'CM-handle is initially in ADVISED state'
- assert CmHandleState.ADVISED == objectUnderTest.getCmHandleCompositeState('cm-2').cmHandleState
-
- when: 'module sync runs'
- moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
-
- then: 'CM-handle goes to LOCKED state'
- new PollingConditions().within(3, () -> {
- assert CmHandleState.LOCKED == objectUnderTest.getCmHandleCompositeState('cm-2').cmHandleState
- })
-
- and: 'DMI received expected requests'
- mockDmiServer.verify()
- }
-
- def 'Deregister CM-handles.'() {
- given: 'a list of CM handles to remove'
- def cmHandlesToRemove = ['cm-1', 'cm-2']
-
- and: 'DMI registration parameters are set'
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: DMI_URL, removedCmHandles: cmHandlesToRemove)
- dmiPluginRegistration.validateDmiPluginRegistration()
-
- when: 'the CM-handles are deregistered'
- networkCmProxyDataService.updateDmiRegistrationAndSyncModule(dmiPluginRegistration);
-
- then: 'the CM-handles no longer exists'
- assert !objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier(DMI_URL).contains('cm-1')
- assert !objectUnderTest.getAllCmHandleIdsByDmiPluginIdentifier(DMI_URL).contains('cm-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
new file mode 100644
index 0000000000..6b550a76bc
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/NcmpCmHandleUpgradeSpec.groovy
@@ -0,0 +1,187 @@
+/*
+ * ============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 org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.NetworkCmProxyDataService
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
+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.lang.Ignore
+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 NO_MODULE_SET_TAG = ''
+ static final CM_HANDLE_ID = 'ch-1'
+ static final CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG = 'ch-2'
+
+ def setup() {
+ objectUnderTest = networkCmProxyDataService
+ }
+
+ @Ignore
+ def 'Upgrade CM-handle with new moduleSetTag or no moduleSetTag.'() {
+ given: 'an existing CM-handle with expected initial modules: M1 and M2'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ and: 'DMI returns different modules for upgrade'
+ mockDmiResponsesForRegistration(DMI_URL, CM_HANDLE_ID, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+
+ when: "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))
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
+
+ and: 'CM-handle is in LOCKED state due to MODULE_UPGRADE'
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE
+ assert cmHandleCompositeState.lockReason.details == "Upgrade to ModuleSetTag: ${updatedModuleSetTag}"
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+ })
+
+ 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)
+
+ where:
+ initialModuleSetTag | updatedModuleSetTag
+ NO_MODULE_SET_TAG | NO_MODULE_SET_TAG
+ NO_MODULE_SET_TAG | 'new'
+ 'initial' | NO_MODULE_SET_TAG
+ 'initial' | 'new'
+ }
+
+ def 'Upgrade CM-handle with existing moduleSetTag.'() {
+ given: "an existing CM-handle handle with moduleSetTag '${updatedModuleSetTag}'"
+ registerCmHandle(DMI_URL, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG, updatedModuleSetTag, UPDATED_MODULE_REFERENCES_RESPONSE, UPDATED_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG).moduleName.sort()
+ and: "a CM-handle with moduleSetTag '${initialModuleSetTag}' which will be upgraded"
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, initialModuleSetTag, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ when: "CM-handle is upgraded to moduleSetTag '${updatedModuleSetTag}'"
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: updatedModuleSetTag)
+ def dmiPluginRegistrationResponse = networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ then: 'registration gives successful response'
+ assert dmiPluginRegistrationResponse.upgradedCmHandles == [CmHandleRegistrationResponse.createSuccessResponse(CM_HANDLE_ID)]
+
+ when: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to READY state'
+ new PollingConditions().within(3, () -> {
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+ })
+
+ and: 'CM-handle has expected updated modules: M1 and M3'
+ assert ['M1', 'M3'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandles(DMI_URL, [CM_HANDLE_ID, CM_HANDLE_ID_WITH_EXISTING_MODULE_SET_TAG])
+
+ where:
+ initialModuleSetTag | updatedModuleSetTag
+ NO_MODULE_SET_TAG | 'moduleSet2'
+ 'moduleSet1' | 'moduleSet2'
+ }
+
+ @Ignore
+ def 'Skip upgrade of CM-handle with same moduleSetTag as before.'() {
+ given: 'an existing CM-handle with expected initial modules: M1 and M2'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, 'same', INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ when: 'CM-handle is upgraded with the same moduleSetTag'
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: 'same')
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ then: 'CM-handle remains in READY state'
+ assert CmHandleState.READY == objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID).cmHandleState
+
+ and: 'CM-handle has same modules as before: M1 and M2'
+ assert ['M1', 'M2'] == objectUnderTest.getYangResourcesModuleReferences(CM_HANDLE_ID).moduleName.sort()
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ }
+
+ def 'Upgrade of CM-handle fails due to DMI error.'() {
+ given: 'an existing CM-handle'
+ registerCmHandle(DMI_URL, CM_HANDLE_ID, NO_MODULE_SET_TAG, INITIAL_MODULE_REFERENCES_RESPONSE, INITIAL_MODULE_RESOURCES_RESPONSE)
+
+ and: 'DMI returns error code'
+ mockDmiServer.expect(anything()).andRespond(withStatus(HttpStatus.SERVICE_UNAVAILABLE))
+
+ when: "CM-handle is upgraded"
+ def cmHandlesToUpgrade = new UpgradedCmHandles(cmHandles: [CM_HANDLE_ID], moduleSetTag: NO_MODULE_SET_TAG)
+ networkCmProxyDataService.updateDmiRegistrationAndSyncModule(
+ new DmiPluginRegistration(dmiPlugin: DMI_URL, upgradedCmHandles: cmHandlesToUpgrade))
+
+ and: 'module sync runs'
+ moduleSyncWatchdog.resetPreviouslyFailedCmHandles()
+ moduleSyncWatchdog.moduleSyncAdvisedCmHandles()
+
+ then: 'CM-handle goes to LOCKED state with reason MODULE_UPGRADE_FAILED'
+ new PollingConditions().within(3, () -> {
+ def cmHandleCompositeState = objectUnderTest.getCmHandleCompositeState(CM_HANDLE_ID)
+ assert cmHandleCompositeState.cmHandleState == CmHandleState.LOCKED
+ assert cmHandleCompositeState.lockReason.lockReasonCategory == LockReasonCategory.MODULE_UPGRADE_FAILED
+ })
+
+ cleanup: 'deregister CM-handle'
+ deregisterCmHandle(DMI_URL, CM_HANDLE_ID)
+ }
+
+}