summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToine Siebelink <toine.siebelink@est.tech>2022-06-01 14:39:39 +0000
committerGerrit Code Review <gerrit@onap.org>2022-06-01 14:39:39 +0000
commit7bb1a57b47646115c6a33ff9e3b53e3fb0949ea9 (patch)
treecb909182ca7eed63c85e5650c11dd18d903042d1
parent8acaa7d71bca663aeeb7006f90474843b602ffb6 (diff)
parent912c86dec96e675c2635298cea8869d014938042 (diff)
Merge "Module Sync Lock State implementation"
-rw-r--r--cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java21
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy25
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy36
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java3
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java36
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java35
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java (renamed from cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java)71
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/LockReasonCategory.java25
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java27
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java56
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy19
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy5
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy13
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy (renamed from cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy)81
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy46
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy58
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy45
-rw-r--r--cps-ncmp-service/src/test/resources/expectedStateModel.json8
24 files changed, 367 insertions, 285 deletions
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java
index ce3206829..5f4b31118 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapper.java
@@ -25,7 +25,6 @@ import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.mapstruct.NullValueCheckStrategy;
import org.mapstruct.NullValuePropertyMappingStrategy;
-import org.onap.cps.ncmp.api.inventory.CmHandleState;
import org.onap.cps.ncmp.api.inventory.CompositeState;
import org.onap.cps.ncmp.rest.model.DataStores;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleState;
@@ -36,7 +35,7 @@ import org.onap.cps.ncmp.rest.model.SyncState;
public interface RestOutputCmHandleStateMapper {
@Mapping(target = "dataSyncState", source = "dataStores", qualifiedByName = "dataStoreToDataSyncState")
- @Mapping(target = "cmHandleState", source = "cmhandleState", qualifiedByName = "cmHandleStateEnumToString")
+ @Mapping(target = "lockReason.reason", source = "lockReason.lockReasonCategory")
RestOutputCmHandleState toRestOutputCmHandleState(CompositeState compositeState);
/**
@@ -54,13 +53,6 @@ public interface RestOutputCmHandleStateMapper {
final DataStores dataStores = new DataStores();
- if (compositeStateDataStore.getRunningDataStore() != null) {
- final SyncState runningSyncState = new SyncState();
- runningSyncState.setState(compositeStateDataStore.getRunningDataStore().getSyncState());
- runningSyncState.setLastSyncTime(compositeStateDataStore.getRunningDataStore().getLastSyncTime());
- dataStores.setRunning(runningSyncState);
- }
-
if (compositeStateDataStore.getOperationalDataStore() != null) {
final SyncState operationalSyncState = new SyncState();
operationalSyncState.setState(compositeStateDataStore.getOperationalDataStore().getSyncState());
@@ -73,15 +65,4 @@ public interface RestOutputCmHandleStateMapper {
}
- /**
- * Converts cmHandleState enum value to equivalent string.
- *
- * @param cmHandleState cm handle state enum
- * @return cm handle state as string
- */
- @Named("cmHandleStateEnumToString")
- static String toCmHandleState(final CmHandleState cmHandleState) {
- return cmHandleState.name();
- }
-
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 331530425..60ea736d7 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -37,7 +37,6 @@ import java.time.format.DateTimeFormatter
import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH
import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.inventory.CompositeState.LockReason
import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational
import static org.onap.cps.ncmp.api.inventory.CompositeState.Running
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
@@ -256,30 +255,20 @@ class NetworkCmProxyControllerSpec extends Specification {
given: 'an endpoint and a cm handle'
def cmHandleDetailsEndpoint = "$ncmpBasePathV1/ch/some-cm-handle"
and: 'an existing ncmp service cm handle'
- def cmHandleId = 'some-cm-handle'
- def dmiProperties = [ prop:'some DMI property' ]
- def publicProperties = [ "public prop":'some public property' ]
- def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED,
- lockReason: LockReason.builder().reason('LOCKED_OTHER').details("lock-misbehaving-details").build(),
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
lastUpdateTime: formattedDateAndTime.toString(),
- dataSyncEnabled: false,
dataStores: dataStores())
- def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
+ def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle', compositeState: compositeState)
and: 'the service method is invoked with the cm handle id'
1 * mockNetworkCmProxyDataService.getNcmpServiceCmHandle('some-cm-handle') >> ncmpServiceCmHandle
when: 'the cm handle details api is invoked'
def response = mvc.perform(get(cmHandleDetailsEndpoint)).andReturn().response
then: 'the correct response is returned'
response.status == HttpStatus.OK.value()
- and: 'the response returns public properties and the correct cm handle states'
- response.contentAsString.contains('publicCmHandleProperties')
- response.contentAsString.contains('LOCKED_OTHER')
- response.contentAsString.contains('lock-misbehaving-details')
+ and: 'the response returns the correct state and timestamp'
+ response.contentAsString.contains('some-cm-handle')
response.contentAsString.contains('ADVISED')
- response.contentAsString.contains('NONE_REQUESTED')
response.contentAsString.contains('2022-12-31T20:30:40.000+0000')
- and: 'the content does not contain dmi properties'
- !response.contentAsString.contains("some DMI property")
}
def 'Get Cm Handle public properties by Cm Handle id.' () {
@@ -387,11 +376,7 @@ class NetworkCmProxyControllerSpec extends Specification {
DataStores.builder()
.operationalDataStore(Operational.builder()
.syncState('NONE_REQUESTED')
- .lastSyncTime(formattedDateAndTime.toString()).build())
- .runningDataStore(Running.builder()
- .syncState('NONE_REQUESTED')
- .lastSyncTime(formattedDateAndTime.toString()).build())
- .build()
+ .lastSyncTime(formattedDateAndTime.toString()).build()).build()
}
}
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy
index 4560ae481..22c9fe605 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/RestOutputCmHandleStateMapperTest.groovy
@@ -22,7 +22,8 @@ package org.onap.cps.ncmp.rest.mapper
import org.mapstruct.factory.Mappers
import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleState
import spock.lang.Specification
@@ -30,10 +31,6 @@ import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
-import static org.onap.cps.ncmp.api.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.inventory.CompositeState.LockReason
-import static org.onap.cps.ncmp.api.inventory.CompositeState.Operational
-
class RestOutputCmHandleStateMapperTest extends Specification {
def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
@@ -42,11 +39,12 @@ class RestOutputCmHandleStateMapperTest extends Specification {
def 'Composite State to Rest Output CmHandleState'() {
given: 'a composite state model'
- def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED,
- lockReason: LockReason.builder().reason('LOCKED_OTHER').details('locked-other-details').build(),
- lastUpdateTime: formattedDateAndTime.toString(),
- dataSyncEnabled: false,
- dataStores: dataStores())
+ def compositeState = new CompositeStateBuilder()
+ .withCmHandleState(CmHandleState.ADVISED)
+ .withLastUpdatedTime(formattedDateAndTime.toString())
+ .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, 'locked other details')
+ .withOperationalDataStores('SYNCHRONIZED', formattedDateAndTime).build()
+ compositeState.setDataSyncEnabled(false)
when: 'mapper is called'
def result = objectUnderTest.toRestOutputCmHandleState(compositeState)
then: 'result is of the correct type'
@@ -54,22 +52,10 @@ class RestOutputCmHandleStateMapperTest extends Specification {
and: 'mapped result should have correct values'
assert !result.dataSyncEnabled
assert result.lastUpdateTime == formattedDateAndTime
- assert result.lockReason.reason == 'LOCKED_OTHER'
- assert result.lockReason.details == 'locked-other-details'
+ assert result.lockReason.reason == 'LOCKED_MISBEHAVING'
+ assert result.lockReason.details == 'locked other details'
assert result.cmHandleState == CmHandleState.ADVISED.name()
- assert result.dataSyncState.operational != null
- assert result.dataSyncState.running != null
+ assert result.dataSyncState.operational.getState() != null
}
- def dataStores() {
-
- return DataStores.builder()
- .operationalDataStore(Operational.builder()
- .syncState('NONE_REQUESTED')
- .lastSyncTime(formattedDateAndTime.toString()).build())
- .runningDataStore(CompositeState.Running.builder()
- .syncState('NONE_REQUESTED')
- .lastSyncTime(formattedDateAndTime.toString()).build())
- .build()
- }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
index 64942e4bb..717cae565 100755
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
@@ -48,8 +48,8 @@ import org.onap.cps.api.CpsModuleService;
import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
-import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
import org.onap.cps.ncmp.api.inventory.sync.ModuleSyncService;
import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
@@ -84,7 +84,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
private final NetworkCmProxyDataServicePropertyHandler networkCmProxyDataServicePropertyHandler;
- private final YangModelCmHandleRetriever yangModelCmHandleRetriever;
+ private final InventoryPersistence inventoryPersistence;
private final ModuleSyncService moduleSyncService;
@@ -92,7 +92,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
final DmiPluginRegistration dmiPluginRegistration) {
dmiPluginRegistration.validateDmiPluginRegistration();
- final var dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
+ final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
dmiPluginRegistrationResponse.setRemovedCmHandles(
parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles()));
if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
@@ -189,7 +189,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
CpsValidator.validateNameCharacters(cmHandleId);
final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
final YangModelCmHandle yangModelCmHandle =
- yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId);
+ inventoryPersistence.getYangModelCmHandle(cmHandleId);
final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties();
final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
ncmpServiceCmHandle.setCmHandleId(yangModelCmHandle.getId());
@@ -209,7 +209,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
public Map<String, String> getCmHandlePublicProperties(final String cmHandleId) {
CpsValidator.validateNameCharacters(cmHandleId);
final YangModelCmHandle yangModelCmHandle =
- yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId);
+ inventoryPersistence.getYangModelCmHandle(cmHandleId);
final List<YangModelCmHandle.Property> yangModelPublicProperties = yangModelCmHandle.getPublicProperties();
final Map<String, String> cmHandlePublicProperties = new HashMap<>();
asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
index 8e2c0946a..d409a80e5 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
@@ -29,6 +29,7 @@ import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
import org.onap.cps.utils.CpsValidator;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.http.ResponseEntity;
@@ -45,11 +46,11 @@ public class DmiDataOperations extends DmiOperations {
*
* @param dmiRestClient {@code DmiRestClient}
*/
- public DmiDataOperations(final YangModelCmHandleRetriever cmHandlePropertiesRetriever,
+ public DmiDataOperations(final InventoryPersistence inventoryPersistence,
final JsonObjectMapper jsonObjectMapper,
final NcmpConfiguration.DmiProperties dmiProperties,
final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
- super(cmHandlePropertiesRetriever, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
+ super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
}
/**
@@ -72,7 +73,7 @@ public class DmiDataOperations extends DmiOperations {
final String topicParamInQuery) {
CpsValidator.validateNameCharacters(cmHandleId);
final YangModelCmHandle yangModelCmHandle =
- yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId);
+ inventoryPersistence.getYangModelCmHandle(cmHandleId);
final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
.operation(READ)
.requestId(requestId)
@@ -104,7 +105,7 @@ public class DmiDataOperations extends DmiOperations {
final String dataType) {
CpsValidator.validateNameCharacters(cmHandleId);
final YangModelCmHandle yangModelCmHandle =
- yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId);
+ inventoryPersistence.getYangModelCmHandle(cmHandleId);
final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
.operation(operation)
.data(requestData)
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
index 7ab579869..d8d03041f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiModelOperations.java
@@ -34,6 +34,7 @@ import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
import org.onap.cps.ncmp.api.models.YangResource;
import org.onap.cps.spi.model.ModuleReference;
import org.onap.cps.utils.JsonObjectMapper;
@@ -51,11 +52,11 @@ public class DmiModelOperations extends DmiOperations {
*
* @param dmiRestClient {@code DmiRestClient}
*/
- public DmiModelOperations(final YangModelCmHandleRetriever dmiPropertiesRetriever,
+ public DmiModelOperations(final InventoryPersistence inventoryPersistence,
final JsonObjectMapper jsonObjectMapper,
final NcmpConfiguration.DmiProperties dmiProperties,
final DmiRestClient dmiRestClient, final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
- super(dmiPropertiesRetriever, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
+ super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
}
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
index 745007bd4..e26ffef87 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiOperations.java
@@ -26,6 +26,7 @@ import lombok.RequiredArgsConstructor;
import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Service;
@@ -44,7 +45,7 @@ public class DmiOperations {
}
}
- protected final YangModelCmHandleRetriever yangModelCmHandleRetriever;
+ protected final InventoryPersistence inventoryPersistence;
protected final JsonObjectMapper jsonObjectMapper;
protected final NcmpConfiguration.DmiProperties dmiProperties;
protected final DmiRestClient dmiRestClient;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java
index 24fab32a5..0c16adca9 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java
@@ -21,5 +21,5 @@
package org.onap.cps.ncmp.api.inventory;
public enum CmHandleState {
- ADVISED, READY;
+ ADVISED, READY, LOCKED
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java
index 9ac49a6ce..eeaa4cd0b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeState.java
@@ -22,6 +22,8 @@ package org.onap.cps.ncmp.api.inventory;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
@@ -38,7 +40,7 @@ import lombok.Setter;
public class CompositeState {
@JsonProperty("cm-handle-state")
- private CmHandleState cmhandleState;
+ private CmHandleState cmHandleState;
@JsonProperty("lock-reason")
private LockReason lockReason;
@@ -52,13 +54,24 @@ public class CompositeState {
@JsonProperty("datastores")
private DataStores dataStores;
+ /**
+ * Date and Time in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ
+ */
+ public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+
+
+ /**
+ * This will specify the latest lock reason for a specific cm handle. If a cm handle is in a state other than LOCKED
+ * it specifies the last lock reason.
+ * This can be used to track retry attempts as part of the lock details.
+ */
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public static class LockReason {
@JsonProperty("reason")
- private String reason;
+ private LockReasonCategory lockReasonCategory;
@JsonProperty("details")
private String details;
@@ -72,9 +85,6 @@ public class CompositeState {
@JsonProperty("operational")
private Operational operationalDataStore;
-
- @JsonProperty("running")
- private Running runningDataStore;
}
@Data
@@ -101,4 +111,20 @@ public class CompositeState {
private String lastSyncTime;
}
+ /**
+ * The date and time format used for the cm handle sync state.
+ *
+ * @return the date and time in the format of yyyy-MM-dd'T'HH:mm:ss.SSSZ
+ */
+ public static String nowInSyncTimeFormat() {
+ return dateTimeFormatter.format(OffsetDateTime.now());
+ }
+
+ /**
+ * Sets the last updated date and time for the cm handle sync state.
+ */
+ public void setLastUpdateTimeNow() {
+ lastUpdateTime = CompositeState.nowInSyncTimeFormat();
+ }
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
index d8f708031..4ab0cecbf 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2022 Bell Canada
+ * Copyright (C) 2022 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,7 +24,6 @@ package org.onap.cps.ncmp.api.inventory;
import org.onap.cps.ncmp.api.inventory.CompositeState.DataStores;
import org.onap.cps.ncmp.api.inventory.CompositeState.LockReason;
import org.onap.cps.ncmp.api.inventory.CompositeState.Operational;
-import org.onap.cps.ncmp.api.inventory.CompositeState.Running;
import org.onap.cps.spi.model.DataNode;
public class CompositeStateBuilder {
@@ -40,7 +40,7 @@ public class CompositeStateBuilder {
*/
public CompositeState build() {
final CompositeState compositeState = new CompositeState();
- compositeState.setCmhandleState(cmHandleState);
+ compositeState.setCmHandleState(cmHandleState);
compositeState.setLockReason(lockReason);
compositeState.setDataStores(datastores);
compositeState.setLastUpdateTime(lastUpdatedTime);
@@ -65,8 +65,8 @@ public class CompositeStateBuilder {
* @param details for the locked state
* @return CompositeStateBuilder
*/
- public CompositeStateBuilder withLockReason(final String reason, final String details) {
- this.lockReason = LockReason.builder().reason(reason).details(details).build();
+ public CompositeStateBuilder withLockReason(final LockReasonCategory reason, final String details) {
+ this.lockReason = LockReason.builder().lockReasonCategory(reason).details(details).build();
return this;
}
@@ -84,13 +84,10 @@ public class CompositeStateBuilder {
/**
* To use attributes for creating {@link CompositeState}.
*
- * @param syncState for the locked state
- * @param lastSyncTime for the locked state
- * @return CompositeStateBuilder
+ * @return composite state builder
*/
- public CompositeStateBuilder withOperationalDataStores(final String syncState, final String lastSyncTime) {
- this.datastores = DataStores.builder().operationalDataStore(
- Operational.builder().syncState(syncState).lastSyncTime(lastSyncTime).build()).build();
+ public CompositeStateBuilder withLastUpdatedTimeNow() {
+ this.lastUpdatedTime = CompositeState.nowInSyncTimeFormat();
return this;
}
@@ -101,9 +98,9 @@ public class CompositeStateBuilder {
* @param lastSyncTime for the locked state
* @return CompositeStateBuilder
*/
- public CompositeStateBuilder withRunningDataStores(final String syncState, final String lastSyncTime) {
- this.datastores = DataStores.builder().runningDataStore(
- Running.builder().syncState(syncState).lastSyncTime(lastSyncTime).build()).build();
+ public CompositeStateBuilder withOperationalDataStores(final String syncState, final String lastSyncTime) {
+ this.datastores = DataStores.builder().operationalDataStore(
+ Operational.builder().syncState(syncState).lastSyncTime(lastSyncTime).build()).build();
return this;
}
@@ -118,26 +115,20 @@ public class CompositeStateBuilder {
.get("cm-handle-state"));
for (final DataNode stateChildNode : dataNode.getChildDataNodes()) {
if (stateChildNode.getXpath().endsWith("/lock-reason")) {
- this.lockReason = new LockReason((String) stateChildNode.getLeaves().get("reason"),
+ this.lockReason = new LockReason(LockReasonCategory.valueOf(
+ (String) stateChildNode.getLeaves().get("reason")),
(String) stateChildNode.getLeaves().get("details"));
}
if (stateChildNode.getXpath().endsWith("/datastores")) {
for (final DataNode dataStoreNodes : stateChildNode.getChildDataNodes()) {
Operational operationalDataStore = null;
- Running runningDataStore = null;
if (dataStoreNodes.getXpath().contains("/operational")) {
operationalDataStore = Operational.builder()
.syncState((String) dataStoreNodes.getLeaves().get("sync-state"))
.lastSyncTime((String) dataStoreNodes.getLeaves().get("last-sync-time"))
.build();
- } else {
- runningDataStore = Running.builder()
- .syncState((String) dataStoreNodes.getLeaves().get("sync-state"))
- .lastSyncTime((String) dataStoreNodes.getLeaves().get("last-sync-time"))
- .build();
}
- this.datastores = DataStores.builder().operationalDataStore(operationalDataStore)
- .runningDataStore(runningDataStore).build();
+ this.datastores = DataStores.builder().operationalDataStore(operationalDataStore).build();
}
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
index 0edd68c3d..873a44913 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/InventoryPersistence.java
@@ -1,7 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2022 Nordix Foundation
- * Modifications Copyright (C) 2021 Bell Canada
+ * Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,32 +18,78 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations;
+package org.onap.cps.ncmp.api.inventory;
+import java.time.OffsetDateTime;
import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
import org.onap.cps.api.CpsDataService;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.onap.cps.ncmp.api.inventory.CompositeState;
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder;
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
+import org.onap.cps.spi.CpsDataPersistenceService;
import org.onap.cps.spi.FetchDescendantsOption;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.utils.CpsValidator;
+import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
-/**
- * Retrieves YangModelCmHandles & properties.
- */
+@RequiredArgsConstructor
@Component
-@AllArgsConstructor
-public class YangModelCmHandleRetriever {
+public class InventoryPersistence {
private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
+
private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
- private CpsDataService cpsDataService;
+ private final JsonObjectMapper jsonObjectMapper;
+
+ private final CpsDataService cpsDataService;
+
+ private final CpsDataPersistenceService cpsDataPersistenceService;
+
+ private static final CompositeStateBuilder compositeStateBuilder = new CompositeStateBuilder();
+
+ /**
+ * Get the Cm Handle Composite State from the data node.
+ *
+ * @param cmHandleId cm handle id
+ * @return the cm handle composite state
+ */
+ public CompositeState getCmHandleState(final String cmHandleId) {
+ final DataNode stateAsDataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ "/dmi-registry/cm-handles[@id='" + cmHandleId + "']/state",
+ FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+ return compositeStateBuilder.fromDataNode(stateAsDataNode).build();
+ }
+
+ /**
+ * Save the cm handles state.
+ *
+ * @param cmHandleId cm handle id
+ * @param compositeState composite state
+ */
+ public void saveCmHandleState(final String cmHandleId, final CompositeState compositeState) {
+ final String cmHandleJsonData = String.format("{\"state\":%s}",
+ jsonObjectMapper.asJsonString(compositeState));
+ cpsDataService.replaceNodeTree(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
+ "/dmi-registry/cm-handles[@id='" + cmHandleId + "']",
+ cmHandleJsonData, OffsetDateTime.now());
+ }
+
+ /**
+ * Method which returns cm handles by the cm handles state.
+ *
+ * @param cmHandleState cm handle state
+ * @return a list of cm handles
+ */
+ public List<DataNode> getCmHandlesByState(final CmHandleState cmHandleState) {
+ return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME,
+ NCMP_DMI_REGISTRY_ANCHOR, "//state[@cm-handle-state=\""
+ + cmHandleState + "\"]/ancestor::cm-handles",
+ FetchDescendantsOption.OMIT_DESCENDANTS);
+ }
/**
* This method retrieves DMI service name and DMI properties for a given cm handle.
@@ -74,7 +119,7 @@ public class YangModelCmHandleRetriever {
}
private static void populateCmHandleDetails(final DataNode cmHandleDataNode,
- final NcmpServiceCmHandle ncmpServiceCmHandle) {
+ final NcmpServiceCmHandle ncmpServiceCmHandle) {
final Map<String, String> dmiProperties = new LinkedHashMap<>();
final Map<String, String> publicProperties = new LinkedHashMap<>();
final CompositeStateBuilder compositeStateBuilder = new CompositeStateBuilder();
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/LockReasonCategory.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/LockReasonCategory.java
new file mode 100644
index 000000000..596fcb7f9
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/LockReasonCategory.java
@@ -0,0 +1,25 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.inventory;
+
+public enum LockReasonCategory {
+ LOCKED_MISBEHAVING
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
index 353db9d68..2187ec61c 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
@@ -1,5 +1,5 @@
/*
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
* Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,6 +24,9 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.ncmp.api.inventory.CmHandleState;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -32,6 +35,8 @@ import org.springframework.stereotype.Component;
@Component
public class ModuleSyncWatchdog {
+ private final InventoryPersistence inventoryPersistence;
+
private final SyncUtils syncUtils;
private final ModuleSyncService moduleSyncService;
@@ -43,11 +48,21 @@ public class ModuleSyncWatchdog {
public void executeAdvisedCmHandlePoll() {
YangModelCmHandle advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
while (advisedCmHandle != null) {
- moduleSyncService.syncAndCreateSchemaSet(advisedCmHandle);
- // ToDo Lock Cm Handle if module sync fails
- syncUtils.updateCmHandleState(advisedCmHandle, CmHandleState.READY);
- log.info("{} is now in {} state", advisedCmHandle.getId(),
- advisedCmHandle.getCompositeState().getCmhandleState());
+ final String cmHandleId = advisedCmHandle.getId();
+ final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId);
+ try {
+ moduleSyncService.syncAndCreateSchemaSet(advisedCmHandle);
+ compositeState.setCmHandleState(CmHandleState.READY);
+ } catch (final Exception e) {
+ compositeState.setCmHandleState(CmHandleState.LOCKED);
+ syncUtils.updateLockReasonDetailsAndAttempts(compositeState,
+ LockReasonCategory.LOCKED_MISBEHAVING,
+ e.getMessage());
+ }
+ compositeState.setLastUpdateTimeNow();
+ inventoryPersistence.saveCmHandleState(cmHandleId, compositeState);
+ log.info("{} is now in {} state", cmHandleId,
+ advisedCmHandle.getCompositeState().getCmHandleState());
advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
}
log.debug("No Cm-Handles currently found in an ADVISED state");
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
index 3bc43c566..a4f29de3e 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
@@ -1,5 +1,5 @@
/*
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
* Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,23 +20,18 @@
package org.onap.cps.ncmp.api.inventory.sync;
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DATASPACE_NAME;
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_ANCHOR;
-import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_PARENT;
-
import java.security.SecureRandom;
-import java.time.OffsetDateTime;
import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.api.CpsDataService;
-import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever;
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
import org.onap.cps.ncmp.api.inventory.CmHandleState;
-import org.onap.cps.spi.CpsDataPersistenceService;
-import org.onap.cps.spi.FetchDescendantsOption;
+import org.onap.cps.ncmp.api.inventory.CompositeState;
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory;
import org.onap.cps.spi.model.DataNode;
-import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.stereotype.Component;
@Slf4j
@@ -45,13 +40,11 @@ import org.springframework.stereotype.Component;
public class SyncUtils {
private static final SecureRandom secureRandom = new SecureRandom();
- private final CpsDataService cpsDataService;
- private final CpsDataPersistenceService cpsDataPersistenceService;
- private final JsonObjectMapper jsonObjectMapper;
+ private final InventoryPersistence inventoryPersistence;
- private final YangModelCmHandleRetriever yangModelCmHandleRetriever;
+ private static final Pattern retryAttemptPattern = Pattern.compile("^Attempt #(\\d+) failed:");
/**
* Query data nodes for cm handles with an "ADVISED" cm handle state, and select a random entry for processing.
@@ -59,30 +52,37 @@ public class SyncUtils {
* @return a random yang model cm handle with an ADVISED state, return null if not found
*/
public YangModelCmHandle getAnAdvisedCmHandle() {
- final List<DataNode> advisedCmHandles = cpsDataPersistenceService.queryDataNodes("NCMP-Admin",
- "ncmp-dmi-registry", "//cm-handles[@state=\"ADVISED\"]",
- FetchDescendantsOption.OMIT_DESCENDANTS);
+ final List<DataNode> advisedCmHandles = inventoryPersistence.getCmHandlesByState(CmHandleState.ADVISED);
if (advisedCmHandles.isEmpty()) {
return null;
}
final int randomElementIndex = secureRandom.nextInt(advisedCmHandles.size());
final String cmHandleId = advisedCmHandles.get(randomElementIndex).getLeaves()
.get("id").toString();
- return yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId);
+ return inventoryPersistence.getYangModelCmHandle(cmHandleId);
}
+
/**
- * Update the Cm Handle state to "READY".
+ * Update Composite State attempts counter and set new lock reason and details.
*
- * @param yangModelCmHandle yang model cm handle
- * @param cmHandleState cm handle state
+ * @param lockReasonCategory lock reason category
+ * @param errorMessage error message
*/
- public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState cmHandleState) {
- yangModelCmHandle.getCompositeState().setCmhandleState(cmHandleState);
- final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}",
- jsonObjectMapper.asJsonString(yangModelCmHandle));
- cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
- cmHandleJsonData, OffsetDateTime.now());
+ public void updateLockReasonDetailsAndAttempts(final CompositeState compositeState,
+ final LockReasonCategory lockReasonCategory,
+ final String errorMessage) {
+ int attempt = 1;
+ if (compositeState.getLockReason() != null) {
+ final Matcher matcher = retryAttemptPattern.matcher(compositeState.getLockReason().getDetails());
+ if (matcher.find()) {
+ attempt = 1 + Integer.parseInt(matcher.group(1));
+ }
+ }
+ compositeState.setLockReason(CompositeState.LockReason.builder()
+ .details(String.format("Attempt #%d failed: %s", attempt, errorMessage))
+ .lockReasonCategory(lockReasonCategory).build());
}
+
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index 5683d57e5..f56aea7f3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -28,8 +28,7 @@ import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
import org.onap.cps.ncmp.api.impl.exception.DmiRequestException
import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
-import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
-import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence
import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
@@ -61,10 +60,9 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def mockCpsModuleService = Mock(CpsModuleService)
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
def mockCpsAdminService = Mock(CpsAdminService)
- def mockDmiModelOperations = Mock(DmiModelOperations)
def mockDmiDataOperations = Mock(DmiDataOperations)
def mockNetworkCmProxyDataServicePropertyHandler = Mock(NetworkCmProxyDataServicePropertyHandler)
- def mockYangModelCmHandleRetriever = Mock(YangModelCmHandleRetriever)
+ def mockInventoryPersistence = Mock(InventoryPersistence)
def mockModuleSyncService = Mock(ModuleSyncService)
def noTimestamp = null
@@ -389,6 +387,6 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def getObjectUnderTest() {
return Spy(new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations,
- mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockYangModelCmHandleRetriever, mockModuleSyncService))
+ mockCpsModuleService, mockCpsAdminService, mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService))
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index be13344cf..55a1a8d1f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -22,10 +22,11 @@
package org.onap.cps.ncmp.api.impl
-import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever
+import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.inventory.CmHandleState
import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence
import org.onap.cps.ncmp.api.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.exceptions.DataValidationException
@@ -57,7 +58,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
def mockDmiDataOperations = Mock(DmiDataOperations)
def nullNetworkCmProxyDataServicePropertyHandler = null
- def mockYangModelCmHandleRetriever = Mock(YangModelCmHandleRetriever)
+ def mockInventoryPersistence = Mock(InventoryPersistence)
def mockModuleSyncService = Mock(ModuleSyncService)
def mockDmiPluginRegistration = Mock(DmiPluginRegistration)
@@ -69,7 +70,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')
def objectUnderTest = new NetworkCmProxyDataServiceImpl(mockCpsDataService, spiedJsonObjectMapper, mockDmiDataOperations,
- mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockYangModelCmHandleRetriever, mockModuleSyncService)
+ mockCpsModuleService, mockCpsAdminService, nullNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockModuleSyncService)
def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
@@ -171,17 +172,17 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def dmiServiceName = 'some service name'
def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')]
def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')]
- def compositeState = new CompositeState(cmhandleState: 'ADVISED')
+ def compositeState = new CompositeState(cmHandleState: 'ADVISED')
def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName,
dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState)
- 1 * mockYangModelCmHandleRetriever.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
+ 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
when: 'getting cm handle details for a given cm handle id from ncmp service'
def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle')
then: 'the result returns the correct data'
result.cmHandleId == 'some-cm-handle'
result.dmiProperties ==[ Book:'Romance Novel' ]
result.publicProperties == [ "Public Book":'Public Romance Novel' ]
- result.compositeState.cmhandleState == CmHandleState.ADVISED
+ result.compositeState.cmHandleState == CmHandleState.ADVISED
}
def 'Get a cm handle with an invalid id.'() {
@@ -190,7 +191,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
then: 'an exception is thrown'
thrown(DataValidationException)
and: 'the yang model cm handle retriever is not invoked'
- 0 * mockYangModelCmHandleRetriever.getYangModelCmHandle(*_)
+ 0 * mockInventoryPersistence.getYangModelCmHandle(*_)
}
def 'Get cm handle public properties'() {
@@ -199,7 +200,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')]
def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties)
and: 'the system returns this yang modelled cm handle'
- 1 * mockYangModelCmHandleRetriever.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
+ 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle
when: 'getting cm handle public properties for a given cm handle id from ncmp service'
def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle')
then: 'the result returns the correct data'
@@ -212,7 +213,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
then: 'an exception is thrown'
thrown(DataValidationException)
and: 'the yang model cm handle retriever is not invoked'
- 0 * mockYangModelCmHandleRetriever.getYangModelCmHandle(*_)
+ 0 * mockInventoryPersistence.getYangModelCmHandle(*_)
}
def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
index dae2bcc0a..193b94d26 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy
@@ -25,6 +25,7 @@ import org.onap.cps.ncmp.api.impl.client.DmiRestClient
import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence
import org.spockframework.spring.SpringBean
import spock.lang.Shared
import spock.lang.Specification
@@ -38,7 +39,7 @@ abstract class DmiOperationsBaseSpec extends Specification {
DmiRestClient mockDmiRestClient = Mock()
@SpringBean
- YangModelCmHandleRetriever mockCmHandlePropertiesRetriever = Mock()
+ InventoryPersistence mockInventoryPersistence = Mock()
@SpringBean
ObjectMapper spyObjectMapper = Spy()
@@ -56,6 +57,6 @@ abstract class DmiOperationsBaseSpec extends Specification {
yangModelCmHandle.dmiServiceName = dmiServiceName
yangModelCmHandle.dmiProperties = dmiProperties
yangModelCmHandle.id = cmHandleId
- mockCmHandlePropertiesRetriever.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
+ mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy
index 2be523915..d6f4ba6ed 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateBuilderSpec.groovy
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2022 Bell Canada
+ * Copyright (C) 2022 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +37,7 @@ class CompositeStateBuilderSpec extends Specification {
def static cmHandleId = 'myHandle1'
def static cmHandleXpath = "/dmi-registry/cm-handles[@id='${cmHandleId}/state']"
def static stateDataNodes = [new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/lock-reason")
- .withLeaves(['reason': 'lock reason', 'details': 'lock details']).build(),
+ .withLeaves(['reason': 'LOCKED_MISBEHAVING', 'details': 'lock details']).build(),
new DataNodeBuilder().withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/datastores")
.withChildDataNodes(Arrays.asList(new DataNodeBuilder()
.withXpath("/dmi-registry/cm-handles[@id='${cmHandleId}']/state/datastores/operational")
@@ -46,20 +47,20 @@ class CompositeStateBuilderSpec extends Specification {
def "Composite State Specification"() {
when: 'using composite state builder '
def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.ADVISED)
- .withLockReason("lock-reason","").withOperationalDataStores("UNSYNCHRONIZED",
- formattedDateAndTime.toString()).withLastUpdatedTime(formattedDateAndTime).build();
+ .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING,"").withOperationalDataStores("UNSYNCHRONIZED",
+ formattedDateAndTime.toString()).withLastUpdatedTime(formattedDateAndTime).build()
then: 'it matches expected cm handle state and data store sync state'
- assert compositeState.getCmhandleState() == CmHandleState.ADVISED
+ assert compositeState.cmHandleState == CmHandleState.ADVISED
assert compositeState.dataStores.operationalDataStore.syncState == 'UNSYNCHRONIZED'
}
def "Build composite state from DataNode "() {
given: "a Data Node "
- def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
+ new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
when: 'build from data node function is invoked'
def compositeState = new CompositeStateBuilder().fromDataNode(cmHandleDataNode).build()
then: 'it matches expected state model as JSON'
- assert compositeState.cmhandleState == CmHandleState.ADVISED
+ assert compositeState.cmHandleState == CmHandleState.ADVISED
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy
index 59c9951d4..5387fc675 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CompositeStateSpec.groovy
@@ -28,9 +28,7 @@ import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import static CompositeState.DataStores
-import static CompositeState.LockReason
import static CompositeState.Operational
-import static CompositeState.Running
import static org.onap.cps.ncmp.utils.TestUtils.getResourceFileContent
import static org.springframework.util.StringUtils.trimAllWhitespace
@@ -42,8 +40,8 @@ class CompositeStateSpec extends Specification {
def "Composite State Specification"() {
given: "a Composite State"
- def compositeState = new CompositeState(cmhandleState: CmHandleState.ADVISED,
- lockReason: LockReason.builder().reason('lock-reason').details("lock-misbehaving-details").build(),
+ def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED,
+ lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.LOCKED_MISBEHAVING).details("lock misbehaving details").build(),
lastUpdateTime: formattedDateAndTime.toString(),
dataSyncEnabled: false,
dataStores: dataStores())
@@ -57,8 +55,6 @@ class CompositeStateSpec extends Specification {
def dataStores() {
DataStores.builder().operationalDataStore(Operational.builder()
.syncState('NONE_REQUESTED')
- .lastSyncTime(formattedDateAndTime.toString()).build()).runningDataStore(Running.builder()
- .syncState('NONE_REQUESTED')
.lastSyncTime(formattedDateAndTime.toString()).build())
.build()
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
index 7fbfa779d..b638eecd4 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/InventoryPersistenceSpec.groovy
@@ -1,6 +1,6 @@
/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2021-2022 Nordix Foundation
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,33 +18,45 @@
* ============LICENSE_END=========================================================
*/
-package org.onap.cps.ncmp.api.impl.operations
+package org.onap.cps.ncmp.api.inventory
+import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsDataService
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
+import org.onap.cps.spi.CpsDataPersistenceService
+import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.exceptions.DataValidationException
+import org.onap.cps.spi.model.DataNode
+import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
+import spock.lang.Specification
+
+import java.time.OffsetDateTime
+import java.time.ZoneOffset
+import java.time.format.DateTimeFormatter
import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-import org.onap.cps.spi.model.DataNode
-import spock.lang.Specification
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-class YangModelCmHandleRetrieverSpec extends Specification {
+class InventoryPersistenceSpec extends Specification {
+
+ def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
def mockCpsDataService = Mock(CpsDataService)
- def objectUnderTest = new YangModelCmHandleRetriever(mockCpsDataService)
+ def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
+
+
+ def objectUnderTest = new InventoryPersistence(spiedJsonObjectMapper, mockCpsDataService, mockCpsDataPersistenceService)
+
+ def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
+ .format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC))
def cmHandleId = 'some-cm-handle'
def leaves = ["dmi-service-name":"common service name","dmi-data-service-name":"data service name","dmi-model-service-name":"model service name"]
def xpath = "/dmi-registry/cm-handles[@id='some-cm-handle']"
@Shared
- def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.ADVISED).build()
-
- @Shared
def childDataNodesForCmHandleWithAllProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"]),
new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/public-properties[@name='name2']", leaves: ["name":"name2","value":"value2"])]
@@ -72,11 +84,11 @@ class YangModelCmHandleRetrieverSpec extends Specification {
result.dmiProperties == expectedDmiProperties
result.publicProperties == expectedPublicProperties
and: 'the state details are returned'
- result.compositeState.cmhandleState == expectedCompositeState
+ result.compositeState.cmHandleState == expectedCompositeState
where: 'the following parameters are used'
scenario | childDataNodes || expectedDmiProperties || expectedPublicProperties || expectedCompositeState
'no properties' | [] || [] || [] || null
- 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
+ 'DMI and public properties' | childDataNodesForCmHandleWithAllProperties || [new YangModelCmHandle.Property("name1", "value1")] || [new YangModelCmHandle.Property("name2", "value2")] || null
'just DMI properties' | childDataNodesForCmHandleWithDMIProperties || [new YangModelCmHandle.Property("name1", "value1")] || [] || null
'just public properties' | childDataNodesForCmHandleWithPublicProperties || [] || [new YangModelCmHandle.Property("name2", "value2")] || null
'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED
@@ -102,4 +114,45 @@ class YangModelCmHandleRetrieverSpec extends Specification {
result.dmiDataServiceName == null
result.dmiModelServiceName == null
}
+
+ def 'Get a Cm Handle Composite State'() {
+ given: 'a valid cm handle id'
+ def cmHandleId = 'Some-Cm-Handle'
+ def dataNode = new DataNode(leaves: ['cm-handle-state': 'ADVISED'])
+ and: 'cps data service returns a valid data node'
+ mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry',
+ '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']/state', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> dataNode
+ when: 'get cm handle state is invoked'
+ def result = objectUnderTest.getCmHandleState(cmHandleId)
+ then: 'result has returned the correct cm handle state'
+ result.cmHandleState == CmHandleState.ADVISED
+ }
+
+ def 'Update Cm Handle with #scenario State'() {
+ given: 'a cm handle and a composite state'
+ def cmHandleId = 'Some-Cm-Handle'
+ def compositeState = new CompositeState(cmHandleState: cmHandleState, lastUpdateTime: formattedDateAndTime)
+ when: 'update cm handle state is invoked with the #scenario state'
+ objectUnderTest.saveCmHandleState(cmHandleId, compositeState)
+ then: 'update node leaves is invoked with the correct params'
+ 1 * mockCpsDataService.replaceNodeTree('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle\']', expectedJsonData, _ as OffsetDateTime)
+ where: 'the following states are used'
+ scenario | cmHandleState || expectedJsonData
+ 'READY' | CmHandleState.READY || '{"state":{"cm-handle-state":"READY","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
+ 'LOCKED' | CmHandleState.LOCKED || '{"state":{"cm-handle-state":"LOCKED","last-update-time":"2022-12-31T20:30:40.000+0000"}}'
+ }
+
+ def 'Get Cm Handles By State'() {
+ given: 'a cm handle state to query'
+ def cmHandleState = CmHandleState.ADVISED
+ and: 'cps data service returns a list of data nodes'
+ def dataNodes = [new DataNode()]
+ mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', 'ncmp-dmi-registry',
+ '//state[@cm-handle-state="ADVISED"]/ancestor::cm-handles', OMIT_DESCENDANTS) >> dataNodes
+ when: 'get cm handles by state is invoked'
+ def result = objectUnderTest.getCmHandlesByState(cmHandleState)
+ then: 'the returned result is a list of data nodes returned by cps data service'
+ assert result == dataNodes
+ }
+
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy
deleted file mode 100644
index bfc5c6fa3..000000000
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- * ============LICENSE_END=========================================================
- */
-
-package org.onap.cps.ncmp.api.inventory.sync
-
-import org.onap.cps.ncmp.api.inventory.CmHandleState
-import spock.lang.Specification
-
-class CmHandleStateSpec extends Specification{
-
- def 'Transition to READY state from ADVISED state'() {
- given: 'a cm handle with an ADVISED state'
- def cmHandleState = CmHandleState.ADVISED
- when: 'the state transitions to the READY state'
- cmHandleState = CmHandleState.READY
- then: 'the cm handle state changes to READY'
- assert CmHandleState.READY == cmHandleState
- }
-
- def 'Transition to READY state from READY state'() {
- given: 'a cm handle with a READY state'
- def cmHandleState = CmHandleState.READY
- when: 'the state transitions to READY state'
- cmHandleState = CmHandleState.READY
- then: 'the cm handle state remains as READY'
- assert CmHandleState.READY == cmHandleState
- }
-
-}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
index 35de99fef..bcfe47fd5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
@@ -1,5 +1,5 @@
/*
- * ============LICENSE_START=======================================================
+ * ============LICENSE_START=======================================================
* Copyright (C) 2022 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,40 +20,72 @@
package org.onap.cps.ncmp.api.inventory.sync
-
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.inventory.CmHandleState
import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
import spock.lang.Specification
class ModuleSyncSpec extends Specification {
+ def mockInventoryPersistence = Mock(InventoryPersistence)
+
def mockSyncUtils = Mock(SyncUtils)
def mockModuleSyncService = Mock(ModuleSyncService)
def cmHandleState = CmHandleState.ADVISED
- def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils, mockModuleSyncService)
+ def objectUnderTest = new ModuleSyncWatchdog(mockInventoryPersistence, mockSyncUtils, mockModuleSyncService)
def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() {
given: 'cm handles in an advised state'
- def compositeState = new CompositeState()
- compositeState.cmhandleState = cmHandleState
- def yangModelCmHandle1 = new YangModelCmHandle(compositeState: compositeState)
- def yangModelCmHandle2 = new YangModelCmHandle(compositeState: compositeState)
+ def compositeState1 = new CompositeState(cmHandleState: cmHandleState)
+ def compositeState2 = new CompositeState(cmHandleState: cmHandleState)
+ def yangModelCmHandle1 = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState1)
+ def yangModelCmHandle2 = new YangModelCmHandle(id: 'some-cm-handle-2', compositeState: compositeState2)
and: 'sync utilities return a cm handle twice'
mockSyncUtils.getAnAdvisedCmHandle() >>> [yangModelCmHandle1, yangModelCmHandle2, null]
when: 'module sync poll is executed'
objectUnderTest.executeAdvisedCmHandlePoll()
- then: 'module sync service syncs the first cm handle and creates a schema set'
+ then: 'the inventory persistence cm handle returns a composite state for the first cm handle'
+ 1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState1
+ and: 'module sync service syncs the first cm handle and creates a schema set'
1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle1)
- and: 'the first cm handle is updated to state "READY" from "ADVISED"'
- 1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle1, CmHandleState.READY)
- then: 'module sync service syncs the second cm handle and creates a schema set'
+ and: 'the composite state cm handle state is now READY'
+ assert compositeState1.getCmHandleState() == CmHandleState.READY
+ and: 'the first cm handle state is updated'
+ 1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle', compositeState1)
+ then: 'the inventory persistence cm handle returns a composite state for the second cm handle'
+ mockInventoryPersistence.getCmHandleState('some-cm-handle-2') >> compositeState2
+ and: 'module sync service syncs the second cm handle and creates a schema set'
1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle2)
- then: 'the second cm handle is updated to state "READY" from "ADVISED"'
- 1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle2, CmHandleState.READY)
+ and: 'the composite state cm handle state is now READY'
+ assert compositeState2.getCmHandleState() == CmHandleState.READY
+ and: 'the second cm handle state is updated'
+ 1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle-2', compositeState2)
+ }
+
+ def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handle with failure'() {
+ given: 'cm handles in an advised state'
+ def compositeState = new CompositeState(cmHandleState: cmHandleState)
+ def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState)
+ and: 'sync utilities return a cm handle'
+ mockSyncUtils.getAnAdvisedCmHandle() >>> [yangModelCmHandle, null]
+ when: 'module sync poll is executed'
+ objectUnderTest.executeAdvisedCmHandlePoll()
+ then: 'the inventory persistence cm handle returns a composite state for the cm handle'
+ 1 * mockInventoryPersistence.getCmHandleState('some-cm-handle') >> compositeState
+ and: 'module sync service attempts to sync the cm handle and throws an exception'
+ 1 * mockModuleSyncService.syncAndCreateSchemaSet(*_) >> { throw new Exception('some exception') }
+ and: 'the composite state cm handle state is now LOCKED'
+ assert compositeState.getCmHandleState() == CmHandleState.LOCKED
+ and: 'update lock reason, details and attempts is invoked'
+ 1 * mockSyncUtils.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MISBEHAVING ,'some exception')
+ and: 'the cm handle state is updated'
+ 1 * mockInventoryPersistence.saveCmHandleState('some-cm-handle', compositeState)
+
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
index c80263ef0..7d67acccc 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
@@ -20,29 +20,22 @@
package org.onap.cps.ncmp.api.inventory.sync
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.api.CpsDataService
-import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever
-import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
import org.onap.cps.ncmp.api.inventory.CmHandleState
import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.inventory.InventoryPersistence
+import org.onap.cps.ncmp.api.inventory.LockReasonCategory
import org.onap.cps.spi.CpsDataPersistenceService
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.DataNode
-import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Shared
import spock.lang.Specification
-import java.time.OffsetDateTime
-
class SyncUtilsSpec extends Specification{
- def mockCpsDataService = Mock(CpsDataService)
def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService)
- def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
- def mockYangModelCmHandleRetriever = Mock(YangModelCmHandleRetriever)
+ def mockInventoryPersistence = Mock(InventoryPersistence)
- def objectUnderTest = new SyncUtils(mockCpsDataService, mockCpsDataPersistenceService, spiedJsonObjectMapper, mockYangModelCmHandleRetriever)
+ def objectUnderTest = new SyncUtils(mockInventoryPersistence)
@Shared
def dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
@@ -50,16 +43,14 @@ class SyncUtilsSpec extends Specification{
def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() {
- given: 'the cps (persistence service) returns a collection of data nodes'
- mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin',
- 'ncmp-dmi-registry', '//cm-handles[@state=\"ADVISED\"]',
- FetchDescendantsOption.OMIT_DESCENDANTS) >> dataNodeCollection
+ given: 'the inventory persistence service returns a collection of data nodes'
+ mockInventoryPersistence.getCmHandlesByState(CmHandleState.ADVISED) >> dataNodeCollection
when: 'get advised cm handle is called'
objectUnderTest.getAnAdvisedCmHandle()
then: 'the returned data node collection is the correct size'
dataNodeCollection.size() == expectedDataNodeSize
and: 'get yang model cm handles is invoked the correct number of times'
- expectedCallsToGetYangModelCmHandle * mockYangModelCmHandleRetriever.getYangModelCmHandle('cm-handle-123')
+ expectedCallsToGetYangModelCmHandle * mockInventoryPersistence.getYangModelCmHandle('cm-handle-123')
where: 'the following scenarios are used'
scenario | dataNodeCollection || expectedCallsToGetYangModelCmHandle | expectedDataNodeSize
'exists' | [ dataNode ] || 1 | 1
@@ -67,16 +58,18 @@ class SyncUtilsSpec extends Specification{
}
- def 'Update cm handle state from Advised to Ready'() {
- given: 'a yang model cm handle and the expected json data'
- def compositeState = new CompositeState()
- compositeState.cmhandleState = CmHandleState.ADVISED
- def yangModelCmHandle = new YangModelCmHandle(id: 'Some-Cm-Handle', compositeState: compositeState )
- def expectedJsonData = '{"cm-handles":[{"id":"Some-Cm-Handle","state":{"cm-handle-state":"READY"}}]}'
- when: 'update cm handle state is called'
- objectUnderTest.updateCmHandleState(yangModelCmHandle, CmHandleState.READY)
- then: 'update data note leaves is invoked with the correct params'
- 1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, _ as OffsetDateTime)
+ def 'Update Lock Reason, Details and Attempts where lock reason #scenario'() {
+ given: 'A locked state'
+ def compositeState = new CompositeState(lockReason: lockReason)
+ when: 'update cm handle details and attempts is called'
+ objectUnderTest.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.LOCKED_MISBEHAVING, 'new error message')
+ then: 'the composite state lock reason and details are updated'
+ assert compositeState.lockReason.lockReasonCategory == LockReasonCategory.LOCKED_MISBEHAVING
+ assert compositeState.lockReason.details == expectedDetails
+ where:
+ scenario | lockReason || expectedDetails
+ 'does not exist' | null || 'Attempt #1 failed: new error message'
+ 'exists' | CompositeState.LockReason.builder().details("Attempt #2 failed: some error message").build() || 'Attempt #3 failed: new error message'
}
}
diff --git a/cps-ncmp-service/src/test/resources/expectedStateModel.json b/cps-ncmp-service/src/test/resources/expectedStateModel.json
index f68d725ed..5d246d5dd 100644
--- a/cps-ncmp-service/src/test/resources/expectedStateModel.json
+++ b/cps-ncmp-service/src/test/resources/expectedStateModel.json
@@ -1,8 +1,8 @@
{
"cm-handle-state" : "ADVISED",
"lock-reason" : {
- "reason" : "lock-reason",
- "details" : "lock-misbehaving-details"
+ "reason" : "LOCKED_MISBEHAVING",
+ "details" : "lock misbehaving details"
},
"last-update-time" : "2022-12-31T20:30:40.000+0000",
"data-sync-enabled" : false,
@@ -10,10 +10,6 @@
"operational" : {
"sync-state" : "NONE_REQUESTED",
"last-sync-time" : "2022-12-31T20:30:40.000+0000"
- },
- "running" : {
- "sync-state" : "NONE_REQUESTED",
- "last-sync-time" : "2022-12-31T20:30:40.000+0000"
}
}
} \ No newline at end of file