public class DataMigration {
public final InventoryPersistence inventoryPersistence;
- protected int batchSize = 300;
private final CmHandleQueryService cmHandleQueryService;
private final NetworkCmProxyInventoryFacade networkCmProxyInventoryFacade;
* Migration of CompositeState CmHandleState into a new top level attribute.
* One off migration job.
*/
- public void migrateInventoryToModelRelease20250722() {
+ public void migrateInventoryToModelRelease20250722(final int batchSize) {
log.info("Inventory data migration started");
final List<String> cmHandleIds = new ArrayList<>(cmHandleQueryService.getAllCmHandleReferences(false));
log.info("Number of cm handles to process {}", cmHandleIds.size());
private static final String PREVIOUS_SCHEMA_SET_NAME = "dmi-registry-2024-02-23";
private static final String NEW_INVENTORY_SCHEMA_SET_NAME = "dmi-registry-2025-07-22";
private static final String INVENTORY_YANG_MODULE_NAME = "dmi-registry";
+ private static final int MIGRATION_BATCH_SIZE = 300;
@Value("${ncmp.inventory.model.upgrade.r20250722.enabled:false}")
private boolean newRevisionEnabled;
private void upgradeAndMigrateInventoryModel() {
upgradeInventoryModel();
- dataMigration.migrateInventoryToModelRelease20250722();
+ dataMigration.migrateInventoryToModelRelease20250722(MIGRATION_BATCH_SIZE);
}
}
def cmHandleIds = ['ch-1', 'ch-2', 'ch-3']
mockCmHandleQueryService.getAllCmHandleReferences(false) >> cmHandleIds
when: 'migration is performed'
- objectUnderTest.migrateInventoryToModelRelease20250722()
+ objectUnderTest.migrateInventoryToModelRelease20250722(3)
then: 'handles are processed in bulk'
1 * mockInventoryPersistence.bulkUpdateCmHandleStates({ cmHandleStateUpdates ->
def actualData = cmHandleStateUpdates.collect { [id: it.cmHandleId, state: it.state] }
and: 'an exception is thrown when getting cm handle'
mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('faultyCmHandle') >> { throw new RuntimeException('Simulated failure') }
when: 'migration is performed'
- objectUnderTest.migrateInventoryToModelRelease20250722()
+ objectUnderTest.migrateInventoryToModelRelease20250722(2)
then: 'migration processes no batches'
1 * mockInventoryPersistence.bulkUpdateCmHandleStates([])
}
throw new RuntimeException('Simulated failure')
}
when: 'migration is performed'
- objectUnderTest.migrateInventoryToModelRelease20250722()
+ objectUnderTest.migrateInventoryToModelRelease20250722(2)
then: 'exception is caught and logged'
def loggingEvent = logger.list[0]
assert loggingEvent.level == Level.ERROR
applicationContext.close()
}
- def callPrivatePerformInventoryDataMigration() {
- def method = objectUnderTest.class.getDeclaredMethod('upgradeAndMigrateInventoryModel')
- method.accessible = true
- method.invoke(objectUnderTest)
- }
-
-
def 'Onboard subscription model via application ready event.'() {
given: 'dataspace is ready for use with default newRevisionEnabled flag'
objectUnderTest.newRevisionEnabled = false
def "Perform inventory data migration to Release20250722"() {
when: 'the migration is performed'
- callPrivatePerformInventoryDataMigration()
+ objectUnderTest.upgradeAndMigrateInventoryModel()
then: 'the call is delegated to the Data Migration service'
- 1 * mockDataMigration.migrateInventoryToModelRelease20250722()
+ 1 * mockDataMigration.migrateInventoryToModelRelease20250722(_)
}
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.integration.functional.ncmp.inventory
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
+import org.onap.cps.ncmp.init.DataMigration
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.test.context.TestPropertySource
+
+@TestPropertySource(properties = ["ncmp.inventory.model.upgrade.r20250722.enabled=true"])
+class DataMigrationIntegrationSpec extends CpsIntegrationSpecBase {
+
+ @Autowired
+ DataMigration objectUnderTest
+
+ def 'Migrate inventory with batch processing.'() {
+ given: 'DMI will return modules when requested'
+ dmiDispatcher1.moduleNamesPerCmHandleId = (1..2).collectEntries{ ['ch-'+it, ['M1']] }
+ and: 'multiple CM handles registered, (top level) status is null'
+ (1..2).each {
+ registerCmHandle(DMI1_URL, 'ch-'+it, NO_MODULE_SET_TAG)
+ def someCmHandle = networkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-'+it)
+ assert someCmHandle.getCmHandleStatus() == null
+ assert someCmHandle.getCompositeState().getCmHandleState().name() == 'READY'
+ }
+ when: 'migration is executed'
+ objectUnderTest.migrateInventoryToModelRelease20250722(1)
+ then: 'all CM handles are processed successfully,' +
+ 'the (top level) status is set to the same value as the name of the complex state value'
+ (1..2).each {
+ def someCmHandle = networkCmProxyInventoryFacade.getNcmpServiceCmHandle('ch-'+it)
+ assert someCmHandle.getCmHandleStatus() == 'READY'
+ assert someCmHandle.getCompositeState().getCmHandleState().name() == 'READY'
+ }
+ cleanup: 'deregister CM handles'
+ deregisterCmHandles(DMI1_URL, (1..2).collect{ 'ch-'+it })
+ }
+}
\ No newline at end of file
when: 'A new version of the dmi-registry module (upgrade) is available'
def newYangContent = readResourceDataFile('inventory/dmi-registry@2025-07-22.yang')
def newYangResourceContentPerName = ["dmi-registry@2025-07-22.yang": newYangContent]
- then: 'The schema set is upgraded with the new module revision'
- cpsModulePersistenceService.createSchemaSet('NCMP-Admin', 'dmi-registry-2025-07-22', newYangResourceContentPerName)
+ then: 'Install the latest version of inventory model dmi-registry-2025-07-22'
+ if (!cpsModulePersistenceService.schemaSetExists('NCMP-Admin', 'dmi-registry-2025-07-22')) {
+ cpsModulePersistenceService.createSchemaSet('NCMP-Admin', 'dmi-registry-2025-07-22', newYangResourceContentPerName)
+ }
cpsAnchorService.updateAnchorSchemaSet('NCMP-Admin','ncmp-dmi-registry','dmi-registry-2025-07-22')
when: 'that state gets updated to a different value'
final Collection<DataNode> cmHandleDataNodes = inventoryPersistence.getCmHandleDataNodeByCmHandleId('ch-1', FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS)