aboutsummaryrefslogtreecommitdiffstats
path: root/cps-ncmp-service/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ncmp-service/src/test')
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy7
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfigSpec.groovy76
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy69
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy2
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy3
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy11
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy85
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy83
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy5
-rw-r--r--cps-ncmp-service/src/test/resources/application.yml1
12 files changed, 214 insertions, 132 deletions
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy
index ca71c345c1..b988f9e171 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/config/PolicyExecutorHttpClientConfigSpec.groovy
@@ -41,8 +41,13 @@ class PolicyExecutorHttpClientConfigSpec extends Specification {
assert maximumConnectionsTotal == 32
assert pendingAcquireMaxCount == 33
assert connectionTimeoutInSeconds == 34
- assert readTimeoutInSeconds == 35
assert writeTimeoutInSeconds == 36
}
}
+
+ def 'Increased read timeout.'() {
+ expect: 'Read timeout is 10 seconds more then configured to enable a separate timeout method in policy executor with the required timeout'
+ assert policyExecutorHttpClientConfig.allServices.readTimeoutInSeconds == 35 + 10
+
+ }
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfigSpec.groovy
new file mode 100644
index 0000000000..e7eb893b03
--- /dev/null
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfigSpec.groovy
@@ -0,0 +1,76 @@
+/*
+ * ============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.cache
+
+import com.hazelcast.config.Config
+import com.hazelcast.config.RestEndpointGroup
+import spock.lang.Specification
+
+class HazelcastCacheConfigSpec extends Specification {
+
+ def objectUnderTest = new HazelcastCacheConfig()
+
+ def 'Create Hazelcast instance with a #scenario'() {
+ given: 'a cluster name'
+ objectUnderTest.clusterName = 'my cluster'
+ when: 'an hazelcast instance is created (name has to be unique)'
+ def result = objectUnderTest.createHazelcastInstance(scenario, config)
+ then: 'the instance is created and has the correct name'
+ assert result.name == scenario
+ and: 'if applicable it has a map config with the expected name'
+ if (expectMapConfig) {
+ assert result.config.mapConfigs.values()[0].name == 'my map config'
+ } else {
+ assert result.config.mapConfigs.isEmpty()
+ }
+ and: 'if applicable it has a queue config with the expected name'
+ if (expectQueueConfig) {
+ assert result.config.queueConfigs.values()[0].name == 'my queue config'
+ } else {
+ assert result.config.queueConfigs.isEmpty()
+ }
+ and: 'if applicable it has a set config with the expected name'
+ if (expectSetConfig) {
+ assert result.config.setConfigs.values()[0].name == 'my set config'
+ } else {
+ assert result.config.setConfigs.isEmpty()
+ }
+ where: 'the following configs are used'
+ scenario | config || expectMapConfig | expectQueueConfig | expectSetConfig
+ 'Map Config' | HazelcastCacheConfig.createMapConfig('my map config') || true | false | false
+ 'Queue Config' | HazelcastCacheConfig.createQueueConfig('my queue config') || false | true | false
+ 'Set Config' | HazelcastCacheConfig.createSetConfig('my set config') || false | false | true
+ }
+
+ def 'Verify Hazelcast Cluster Information'() {
+ given: 'a test configuration'
+ def testConfig = new Config()
+ when: 'cluster information is exposed'
+ objectUnderTest.exposeClusterInformation(testConfig)
+ then: 'REST api configs are enabled'
+ assert testConfig.networkConfig.restApiConfig.enabled
+ and: 'only health check and cluster read are enabled'
+ def enabledGroups = testConfig.networkConfig.restApiConfig.enabledGroups
+ assert enabledGroups.size() == 2
+ assert enabledGroups.containsAll([RestEndpointGroup.CLUSTER_READ, RestEndpointGroup.HEALTH_CHECK])
+ }
+
+}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy
index c859bb0a09..960e6b32f3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy
@@ -39,7 +39,9 @@ class PolicyExecutorConfigurationSpec extends Specification {
def 'Policy executor configuration properties.'() {
expect: 'properties used from application.yml'
assert objectUnderTest.enabled
+ assert objectUnderTest.defaultDecision == 'some default decision'
assert objectUnderTest.serverAddress == 'http://localhost'
assert objectUnderTest.serverPort == '8785'
+ assert objectUnderTest.readTimeoutInSeconds == 35
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
index 63a915ab64..46c0ddeb93 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
@@ -28,7 +28,6 @@ import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.ncmp.api.exceptions.NcmpException
import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException
-import org.onap.cps.ncmp.api.exceptions.ServerNcmpException
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
@@ -37,6 +36,8 @@ import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
import spock.lang.Specification
+import java.util.concurrent.TimeoutException
+
import static org.onap.cps.ncmp.api.data.models.OperationType.CREATE
import static org.onap.cps.ncmp.api.data.models.OperationType.DELETE
import static org.onap.cps.ncmp.api.data.models.OperationType.PATCH
@@ -69,52 +70,90 @@ class PolicyExecutorSpec extends Specification {
((Logger) LoggerFactory.getLogger(PolicyExecutor)).detachAndStopAllAppenders()
}
- def 'Permission check with allow response.'() {
+ def 'Permission check with "allow" decision.'() {
given: 'allow response'
mockResponse([decision:'allow'], HttpStatus.OK)
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), operationType, 'my credentials','my resource',someValidJson)
then: 'system logs the operation is allowed'
- assert getLogEntry(2) == 'Policy Executor allows the operation'
+ assert getLogEntry(2) == 'Operation allowed.'
and: 'no exception occurs'
noExceptionThrown()
where: 'all write operations are tested'
operationType << [ CREATE, DELETE, PATCH, UPDATE ]
}
- def 'Permission check with other response (not allowed).'() {
+ def 'Permission check with "other" decision (not allowed).'() {
given: 'other response'
mockResponse([decision:'other', decisionId:123, message:'I dont like Mondays' ], HttpStatus.OK)
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
then: 'Policy Executor exception is thrown'
def thrownException = thrown(PolicyExecutorException)
- assert thrownException.message == 'Policy Executor did not allow request. Decision #123 : other'
+ assert thrownException.message == 'Operation not allowed. Decision id 123 : other'
assert thrownException.details == 'I dont like Mondays'
}
- def 'Permission check with non 2xx response.'() {
- given: 'other response'
+ def 'Permission check with non-2xx response and "allow" default decision.'() {
+ given: 'other http response'
mockResponse([], HttpStatus.I_AM_A_TEAPOT)
+ and: 'the configured default decision is "allow"'
+ objectUnderTest.defaultDecision = 'allow'
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
- then: 'Server Ncmp exception is thrown'
- def thrownException = thrown(ServerNcmpException)
- assert thrownException.message == 'Policy Executor invocation failed'
- assert thrownException.details == 'HTTP status code: 418'
+ then: 'No exception is thrown'
+ noExceptionThrown()
+ }
+
+ def 'Permission check with non-2xx response and "other" default decision.'() {
+ given: 'other http response'
+ mockResponse([], HttpStatus.I_AM_A_TEAPOT)
+ and: 'the configured default decision is NOT "allow"'
+ objectUnderTest.defaultDecision = 'deny by default'
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials', 'my resource', someValidJson)
+ then: 'Policy Executor exception is thrown'
+ def thrownException = thrown(PolicyExecutorException)
+ assert thrownException.message == 'Operation not allowed. Decision id N/A : deny by default'
+ assert thrownException.details == 'Policy Executor returned HTTP Status code 418. Falling back to configured default decision: deny by default'
}
def 'Permission check with invalid response from Policy Executor.'() {
given: 'invalid response from Policy executor'
mockResponseSpec.toEntity(*_) >> invalidResponse
when: 'permission is checked for an operation'
- objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials','my resource',someValidJson)
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
then: 'system logs the expected message'
assert getLogEntry(1) == expectedMessage
where: 'following invalid responses are received'
- invalidResponse || expectedMessage
- Mono.empty() || 'No valid response from policy, ignored'
- Mono.just(new ResponseEntity<>(null, HttpStatus.OK)) || 'No valid response body from policy, ignored'
+ invalidResponse || expectedMessage
+ Mono.empty() || 'No valid response from Policy Executor, ignored'
+ Mono.just(new ResponseEntity<>(null, HttpStatus.OK)) || 'No valid response body from Policy Executor, ignored'
+ }
+
+ def 'Permission check with timeout exception.'() {
+ given: 'a timeout during the request'
+ def cause = new TimeoutException()
+ mockResponseSpec.toEntity(*_) >> { throw new RuntimeException(cause) }
+ and: 'the configured default decision is NOT "allow"'
+ objectUnderTest.defaultDecision = 'deny by default'
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
+ then: 'Policy Executor exception is thrown'
+ def thrownException = thrown(PolicyExecutorException)
+ assert thrownException.message == 'Operation not allowed. Decision id N/A : deny by default'
+ assert thrownException.details == 'Policy Executor request timed out. Falling back to configured default decision: deny by default'
+ }
+
+ def 'Permission check with other runtime exception.'() {
+ given: 'some other runtime exception'
+ def originalException = new RuntimeException()
+ mockResponseSpec.toEntity(*_) >> { throw originalException}
+ when: 'permission is checked for an operation'
+ objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', someValidJson)
+ then: 'The original exception is thrown'
+ def thrownException = thrown(RuntimeException)
+ assert thrownException == originalException
}
def 'Permission check with an invalid change request json.'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
index cb3c4ffec1..7e34fe2822 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy
@@ -23,10 +23,10 @@ package org.onap.cps.ncmp.impl.inventory
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsQueryService
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.spi.model.DataNode
-import org.onap.cps.spi.utils.CpsValidator
import spock.lang.Shared
import spock.lang.Specification
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
index fdf12a880d..1830f1331d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
+import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.ncmp.api.inventory.models.CompositeState
import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
@@ -35,7 +36,6 @@ import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.model.DataNode
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
-import org.onap.cps.spi.utils.CpsValidator
import org.onap.cps.utils.ContentType
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
index 9e07de48bf..fec07556eb 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
@@ -244,8 +244,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification {
and: 'query cm handle method returns two cm handles'
mockParameterizedCmHandleQueryService.queryCmHandles(
spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class))
- >> [new YangModelCmHandle(id: 'ch-0', dmiProperties: [], publicProperties: []),
- new YangModelCmHandle(id: 'ch-1', dmiProperties: [], publicProperties: [])]
+ >> [new NcmpServiceCmHandle(cmHandleId: 'ch-0'), new NcmpServiceCmHandle(cmHandleId: 'ch-1')]
and: 'a trust level for cm handles'
mockTrustLevelManager.getEffectiveTrustLevel(*_) >> TrustLevel.COMPLETE
when: 'execute cm handle search is called'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
index 08644202c6..013bace04d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2024 Nordix Foundation
+ * 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.
@@ -22,6 +22,7 @@ package org.onap.cps.ncmp.impl.inventory
import org.onap.cps.cpspath.parser.PathParsingException
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.DataInUseException
@@ -138,10 +139,10 @@ class ParameterizedCmHandleQueryServiceSpec extends Specification {
and: 'the inventory service is called with teh correct if and returns a yang model cm handle'
1 * mockInventoryPersistence.getYangModelCmHandles(['ch1']) >>
[new YangModelCmHandle(id: 'abc', dmiProperties: [new YangModelCmHandle.Property('name','value')], publicProperties: [])]
- and: 'the expected cm handle(s) are returned as Yang Model cm handles'
- assert result[0] instanceof YangModelCmHandle
+ and: 'the expected cm handle(s) are returned as NCMP Service cm handles'
+ assert result[0] instanceof NcmpServiceCmHandle
assert result.size() == 1
- assert result[0].dmiProperties.size() == 1
+ assert result[0].dmiProperties == [name:'value']
}
def 'Query cm handle ids when the query is empty.'() {
@@ -164,7 +165,7 @@ class ParameterizedCmHandleQueryServiceSpec extends Specification {
def result = objectUnderTest.queryCmHandles(cmHandleQueryParameters)
then: 'the correct cm handles are returned'
assert result.size() == 4
- assert result.id.containsAll('PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4')
+ assert result.cmHandleId.containsAll('PNFDemo1', 'PNFDemo2', 'PNFDemo3', 'PNFDemo4')
}
def 'Query CMHandleId with #scenario.' () {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
index babe8101dd..65b7ff6d6f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
@@ -40,12 +40,8 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import spock.lang.Specification
-
-import java.time.OffsetDateTime
-import java.time.format.DateTimeFormatter
import java.util.stream.Collectors
-import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.LOCKED_MISBEHAVING
import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE
import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE_FAILED
@@ -60,17 +56,12 @@ class ModuleOperationsUtilsSpec extends Specification{
def objectUnderTest = new ModuleOperationsUtils(mockCmHandleQueries, mockDmiDataOperations, jsonObjectMapper)
- def static neverUpdatedBefore = '1900-01-01T00:00:00.000+0100'
-
- def static now = OffsetDateTime.now()
-
- def static nowAsString = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(now)
-
def static dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
def applicationContext = new AnnotationConfigApplicationContext()
def logger = (Logger) LoggerFactory.getLogger(ModuleOperationsUtils)
+
def loggingListAppender
void setup() {
@@ -103,7 +94,7 @@ class ModuleOperationsUtilsSpec extends Specification{
given: 'A locked state'
def compositeState = new CompositeState(lockReason: lockReason)
when: 'update cm handle details and attempts is called'
- objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, MODULE_SYNC_FAILED, 'new error message')
+ objectUnderTest.updateLockReasonWithAttempts(compositeState, MODULE_SYNC_FAILED, 'new error message')
then: 'the composite state lock reason and details are updated'
assert compositeState.lockReason.lockReasonCategory == MODULE_SYNC_FAILED
assert compositeState.lockReason.details.contains(expectedDetails)
@@ -118,14 +109,14 @@ class ModuleOperationsUtilsSpec extends Specification{
def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
.withLockReason(MODULE_UPGRADE, "Upgrade to ModuleSetTag: " + moduleSetTag).build()
when: 'update cm handle details'
- objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, MODULE_UPGRADE_FAILED, 'new error message')
+ objectUnderTest.updateLockReasonWithAttempts(compositeState, MODULE_UPGRADE_FAILED, 'new error message')
then: 'the composite state lock reason and details are updated'
assert compositeState.lockReason.lockReasonCategory == MODULE_UPGRADE_FAILED
- assert compositeState.lockReason.details.contains("Upgrade to ModuleSetTag: " + expectedDetails)
+ assert compositeState.lockReason.details.contains(expectedDetails)
where:
scenario | moduleSetTag || expectedDetails
- 'a module set tag' | 'someModuleSetTag' || 'someModuleSetTag'
- 'empty module set tag' | '' || ''
+ 'a module set tag' | 'someModuleSetTag' || 'Upgrade to ModuleSetTag: someModuleSetTag'
+ 'empty module set tag' | '' || 'Attempt'
}
def 'Get all locked cm-Handles where lock reasons are model sync failed or upgrade'() {
@@ -135,49 +126,9 @@ class ModuleOperationsUtilsSpec extends Specification{
when: 'get locked Misbehaving cm handle is called'
def result = objectUnderTest.getCmHandlesThatFailedModelSyncOrUpgrade()
then: 'the returned cm handle collection is the correct size'
- result.size() == 1
+ assert result.size() == 1
and: 'the correct cm handle is returned'
- result[0].id == 'cm-handle-123'
- }
-
- def 'Retry Locked Cm-Handle where the last update time is #scenario'() {
- given: 'Last update was #lastUpdateMinutesAgo minutes ago (-1 means never)'
- def lastUpdatedTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(now.minusMinutes(lastUpdateMinutesAgo))
- if (lastUpdateMinutesAgo < 0 ) {
- lastUpdatedTime = neverUpdatedBefore
- }
- when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
- .withLockReason(MODULE_SYNC_FAILED, lockDetails)
- .withLastUpdatedTime(lastUpdatedTime).build())
- then: 'retry is only attempted when expected'
- assert result == retryExpected
- and: 'logs contain related information'
- def logs = loggingListAppender.list.toString()
- assert logs.contains(logReason)
- where: 'the following parameters are used'
- scenario | lastUpdateMinutesAgo | lockDetails | logReason || retryExpected
- 'never attempted before' | -1 | 'Fist attempt:' | 'First Attempt:' || true
- '1st attempt, last attempt > 2 minute ago' | 3 | 'Attempt #1 failed: some error' | 'Retry due now' || true
- '2nd attempt, last attempt < 4 minutes ago' | 1 | 'Attempt #2 failed: some error' | 'Time until next attempt is 3 minutes:' || false
- '2nd attempt, last attempt > 4 minutes ago' | 5 | 'Attempt #2 failed: some error' | 'Retry due now' || true
- }
-
- def 'Retry Locked Cm-Handle with lock reasons (category) #lockReasonCategory'() {
- when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
- .withLockReason(lockReasonCategory, 'some details')
- .withLastUpdatedTime(nowAsString).build())
- then: 'verify retry attempts'
- assert !result
- and: 'logs contain related information'
- def logs = loggingListAppender.list.toString()
- assert logs.contains(logReason)
- where: 'the following lock reasons occurred'
- scenario | lockReasonCategory || logReason
- 'module upgrade' | MODULE_UPGRADE_FAILED || 'First Attempt:'
- 'module sync failed' | MODULE_SYNC_FAILED || 'First Attempt:'
- 'lock misbehaving' | LOCKED_MISBEHAVING || 'Locked for other reason'
+ assert result[0].id == 'cm-handle-123'
}
def 'Get a Cm-Handle where #scenario'() {
@@ -197,19 +148,25 @@ class ModuleOperationsUtilsSpec extends Specification{
'all Cm-Handle synchronized' | [] | false || 0 | [] as Set
}
- def 'Get resource data through DMI Operations #scenario'() {
- given: 'the inventory persistence service returns a collection of data nodes'
+ def 'Retrieve resource data from DMI operations for #scenario'() {
+ given: 'a JSON string representing the resource data'
def jsonString = '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
- JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonString);
- def responseEntity = new ResponseEntity<>(jsonNode, HttpStatus.OK)
+ JsonNode jsonNode = jsonObjectMapper.convertToJsonNode(jsonString)
+ and: 'DMI operations are mocked to return a response based on the scenario'
+ def responseEntity = new ResponseEntity<>(statusCode == HttpStatus.OK ? jsonNode : null, statusCode)
mockDmiDataOperations.getAllResourceDataFromDmi('cm-handle-123', _) >> responseEntity
when: 'get resource data is called'
def result = objectUnderTest.getResourceData('cm-handle-123')
- then: 'the returned data is correct'
- result == jsonString
+ then: 'the returned data matches the expected result'
+ assert result == expectedResult
+ where:
+ scenario | statusCode | expectedResult
+ 'successful response' | HttpStatus.OK | '{"stores:bookstore":{"categories":[{"code":"01"}]}}'
+ 'response with not found status' | HttpStatus.NOT_FOUND | null
+ 'response with internal server error' | HttpStatus.INTERNAL_SERVER_ERROR | null
}
- def 'Extract module set tag and number of attempt when lock reason contains #scenario'() {
+ def 'Extract module set tag and number of attempt when lock reason contains #scenario'() {
expect: 'lock reason details are extracted correctly'
def result = objectUnderTest.getLockedCompositeStateDetails(new CompositeStateBuilder().withLockReason(MODULE_UPGRADE, lockReasonDetails).build().lockReason)
and: 'the result contains the correct moduleSetTag'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
index ee49f2f901..160744a7d7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
@@ -32,16 +32,15 @@ import org.onap.cps.ncmp.api.inventory.models.CompositeState
import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder
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.LockReasonCategory
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandler
import org.onap.cps.spi.model.DataNode
import org.slf4j.LoggerFactory
import spock.lang.Specification
-
import java.util.concurrent.atomic.AtomicInteger
import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_SYNC_FAILED
+import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE
import static org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory.MODULE_UPGRADE_FAILED
class ModuleSyncTasksSpec extends Specification {
@@ -96,70 +95,52 @@ class ModuleSyncTasksSpec extends Specification {
assert batchCount.get() == 4
}
- def 'Module Sync ADVISED cm handle with failure during sync.'() {
- given: 'a cm handle in an ADVISED state'
- def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.ADVISED)
- and: 'the inventory persistence cm handle returns a ADVISED state for the cm handle'
- def cmHandleState = new CompositeState(cmHandleState: CmHandleState.ADVISED)
- 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> cmHandleState
- and: 'module sync service attempts to sync the cm handle and throws an exception'
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
+ def 'Handle CM handle failure during #scenario and log MODULE_UPGRADE lock reason'() {
+ given: 'a CM handle in LOCKED state with a specific lock reason'
+ def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
+ def expectedCmHandleState = new CompositeState(cmHandleState: CmHandleState.LOCKED, lockReason: CompositeState
+ .LockReason.builder().lockReasonCategory(lockReasonCategory).details(lockReasonDetails).build())
+ 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> expectedCmHandleState
+ and: 'module sync service attempts to sync/upgrade the CM handle and throws an exception'
+ mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { throw new Exception('some exception') }
+ mockModuleSyncService.syncAndUpgradeSchemaSet(_) >> { throw new Exception('some exception') }
when: 'module sync is executed'
objectUnderTest.performModuleSync([cmHandle], batchCount)
- then: 'update lock reason, details and attempts is invoked'
- 1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(cmHandleState, MODULE_SYNC_FAILED, 'some exception')
+ then: 'lock reason is updated with number of attempts'
+ 1 * mockSyncUtils.updateLockReasonWithAttempts(expectedCmHandleState, expectedLockReasonCategory, 'some exception')
and: 'the state handler is called to update the state to LOCKED'
1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> { args ->
assertBatch(args, ['cm-handle'], CmHandleState.LOCKED)
}
and: 'batch count is decremented by one'
assert batchCount.get() == 4
- }
-
- def 'Failed cm handle during #scenario.'() {
- given: 'a cm handle in LOCKED state'
- def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
- and: 'the inventory persistence cm handle returns a LOCKED state with reason for the cm handle'
- def expectedCmHandleState = new CompositeState(cmHandleState: cmHandleState, lockReason: CompositeState
- .LockReason.builder().lockReasonCategory(lockReasonCategory).details(lockReasonDetails).build())
- 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> expectedCmHandleState
- and: 'module sync service attempts to sync/upgrade the cm handle and throws an exception'
- mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
- mockModuleSyncService.syncAndUpgradeSchemaSet(*_) >> { throw new Exception('some exception') }
- when: 'module sync is executed'
- objectUnderTest.performModuleSync([cmHandle], batchCount)
- then: 'update lock reason, details and attempts is invoked'
- 1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(expectedCmHandleState, expectedLockReasonCategory, 'some exception')
where:
- scenario | cmHandleState | lockReasonCategory | lockReasonDetails || expectedLockReasonCategory
- 'module upgrade' | CmHandleState.LOCKED | MODULE_UPGRADE_FAILED | 'Upgrade to ModuleSetTag: some-module-set-tag' || MODULE_UPGRADE_FAILED
- 'module sync' | CmHandleState.LOCKED | MODULE_SYNC_FAILED | 'some lock details' || MODULE_SYNC_FAILED
+ scenario | lockReasonCategory | lockReasonDetails || expectedLockReasonCategory
+ 'module sync' | MODULE_SYNC_FAILED | 'some lock details' || MODULE_SYNC_FAILED
+ 'module upgrade' | MODULE_UPGRADE_FAILED | 'Upgrade to ModuleSetTag: some-module-set-tag' || MODULE_UPGRADE_FAILED
+ 'module upgrade' | MODULE_UPGRADE | 'Upgrade in progress' || MODULE_UPGRADE_FAILED
}
+
def 'Reset failed CM Handles #scenario.'() {
given: 'cm handles in an locked state'
def lockedState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
- .withLockReason(LockReasonCategory.MODULE_SYNC_FAILED, '').withLastUpdatedTimeNow().build()
+ .withLockReason(MODULE_SYNC_FAILED, '').withLastUpdatedTimeNow().build()
def yangModelCmHandle1 = new YangModelCmHandle(id: 'cm-handle-1', compositeState: lockedState)
def yangModelCmHandle2 = new YangModelCmHandle(id: 'cm-handle-2', compositeState: lockedState)
- def expectedCmHandleStatePerCmHandle = [(yangModelCmHandle1): CmHandleState.ADVISED]
+ def expectedCmHandleStatePerCmHandle
+ = [(yangModelCmHandle1): CmHandleState.ADVISED, (yangModelCmHandle2): CmHandleState.ADVISED]
and: 'clear in progress map'
resetModuleSyncStartedOnCmHandles(moduleSyncStartedOnCmHandles)
and: 'add cm handle entry into progress map'
moduleSyncStartedOnCmHandles.put('cm-handle-1', 'started')
moduleSyncStartedOnCmHandles.put('cm-handle-2', 'started')
- and: 'sync utils retry locked cm handle returns #isReadyForRetry'
- mockSyncUtils.needsModuleSyncRetryOrUpgrade(lockedState) >>> isReadyForRetry
when: 'resetting failed cm handles'
objectUnderTest.resetFailedCmHandles([yangModelCmHandle1, yangModelCmHandle2])
then: 'updated to state "ADVISED" from "READY" is called as often as there are cm handles ready for retry'
- expectedNumberOfInvocationsToUpdateCmHandleState * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(expectedCmHandleStatePerCmHandle)
- and: 'after reset performed size of in progress map'
- assert moduleSyncStartedOnCmHandles.size() == inProgressMapSize
- where:
- scenario | isReadyForRetry | inProgressMapSize || expectedNumberOfInvocationsToUpdateCmHandleState
- 'retry locked cm handle' | [true, false] | 1 || 1
- 'do not retry locked cm handle' | [false, false] | 2 || 0
+ 1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(expectedCmHandleStatePerCmHandle)
+ and: 'after reset performed progress map is empty'
+ assert moduleSyncStartedOnCmHandles.size() == 0
}
def 'Module Sync ADVISED cm handle without entry in progress map.'() {
@@ -189,6 +170,24 @@ class ModuleSyncTasksSpec extends Specification {
assert loggingEvent.formattedMessage == 'ch-1 removed from in progress map'
}
+ def 'Sync and upgrade CM handle if in upgrade state for #scenario'() {
+ given: 'a CM handle in an upgrade state'
+ def cmHandle = cmHandleAsDataNodeByIdAndState('cm-handle', CmHandleState.LOCKED)
+ def compositeState = new CompositeState(lockReason: CompositeState.LockReason.builder().lockReasonCategory(lockReasonCategory).build())
+ 1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> compositeState
+ when: 'module sync is executed'
+ objectUnderTest.performModuleSync([cmHandle], batchCount)
+ then: 'the module sync service should attempt to sync and upgrade the CM handle'
+ 1 * mockModuleSyncService.syncAndUpgradeSchemaSet(_) >> { args ->
+ assert args[0].id == 'cm-handle'
+ }
+ where: 'the following lock reasons are used'
+ scenario | lockReasonCategory
+ 'module upgrade' | MODULE_UPGRADE
+ 'module upgrade failed' | MODULE_UPGRADE_FAILED
+ }
+
+
def 'Remove non-existing cm handle id from hazelcast map'() {
given: 'hazelcast map does not contains cm handle id'
def result = moduleSyncStartedOnCmHandles.get('non-existing-cm-handle')
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
index 7dc9602e46..fe762f891a 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
@@ -25,6 +25,7 @@ import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.ncmp.utils.events.CmAvcEventPublisher
+import spock.lang.Ignore
import spock.lang.Specification
class TrustLevelManagerSpec extends Specification {
@@ -135,13 +136,15 @@ class TrustLevelManagerSpec extends Specification {
0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
}
+ @Ignore
+ // TODO: CPS-2375
def 'Select effective trust level among CmHandle and dmi plugin'() {
given: 'a non trusted dmi'
trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE)
and: 'a trusted CmHandle'
trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE)
when: 'effective trust level selected'
- def effectiveTrustLevel = objectUnderTest.getEffectiveTrustLevel('my-dmi', 'ch-1')
+ def effectiveTrustLevel = objectUnderTest.getEffectiveTrustLevel('ch-1')
then: 'effective trust level is trusted'
assert effectiveTrustLevel == TrustLevel.NONE
}
diff --git a/cps-ncmp-service/src/test/resources/application.yml b/cps-ncmp-service/src/test/resources/application.yml
index c76831da74..df3375d5d0 100644
--- a/cps-ncmp-service/src/test/resources/application.yml
+++ b/cps-ncmp-service/src/test/resources/application.yml
@@ -83,6 +83,7 @@ ncmp:
policy-executor:
enabled: true
+ defaultDecision: "some default decision"
server:
address: http://localhost
port: 8785