# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+# Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2022 Bell Canada
# ================================================================================
type: string
example: my-dmi-model-plugin
default: ""
+ dmiDatajobsReadPlugin:
+ type: string
+ example: my-dmi-datajobs-read-plugin
+ default: ""
+ dmiDatajobsWritePlugin:
+ type: string
+ example: my-dmi-datajobs-write-plugin
+ default: ""
createdCmHandles:
type: array
items:
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
+ * Copyright (C) 2021-2026 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.
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.google.common.base.Strings;
import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
-import org.onap.cps.ncmp.api.exceptions.DmiRequestException;
-import org.onap.cps.ncmp.api.exceptions.NcmpException;
/**
* Dmi Registry request object.
private String dmiModelPlugin;
+ private String dmiDatajobsReadPlugin;
+
+ private String dmiDatajobsWritePlugin;
+
private List<NcmpServiceCmHandle> createdCmHandles = Collections.emptyList();
private List<NcmpServiceCmHandle> updatedCmHandles = Collections.emptyList();
private UpgradedCmHandles upgradedCmHandles = new UpgradedCmHandles();
- /**
- * Validates plugin service names.
- * @throws NcmpException if validation fails.
- */
- public void validateDmiPluginRegistration() throws NcmpException {
- final String combinedServiceName = dmiPlugin;
- final String dataServiceName = dmiDataPlugin;
- final String modelsServiceName = dmiModelPlugin;
-
- String errorMessage = null;
-
- if (isNullEmptyOrBlank(combinedServiceName)) {
- if ((isNullEmptyOrBlank(dataServiceName) && isNullEmptyOrBlank(modelsServiceName))) {
- errorMessage = "No DMI plugin service names";
- } else {
- if (isNullEmptyOrBlank(dataServiceName) || isNullEmptyOrBlank(modelsServiceName)) {
- errorMessage = "Cannot register just a Data or Model plugin service name";
- }
- }
- } else {
- if (!isNullEmptyOrBlank(dataServiceName) || !isNullEmptyOrBlank(modelsServiceName)) {
- errorMessage = "Cannot register combined plugin service name and other service names";
- }
- }
-
- if (errorMessage != null) {
- throw new DmiRequestException(errorMessage, "Please supply correct plugin information.");
- }
- }
-
- public static boolean isNullEmptyOrBlank(final String serviceName) {
- return Strings.isNullOrEmpty(serviceName) || serviceName.isBlank();
- }
-
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2024 Nordix Foundation
+ * Copyright (C) 2021-2026 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@JsonSetter(nulls = Nulls.AS_EMPTY)
private String dmiModelServiceName;
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
+ private String dmiDatajobsReadServiceName;
+
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
+ private String dmiDatajobsWriteServiceName;
+
@JsonSetter(nulls = Nulls.AS_EMPTY)
private Map<String, String> additionalProperties = Collections.emptyMap();
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2024-2026 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.
final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(dataJobMetadata.destination(),
producerKey);
final ResponseEntity<Object> responseEntity = dmiRestClient.synchronousPostOperation(
- RequiredDmiService.DATA,
+ RequiredDmiService.DATAJOBS_WRITE,
urlTemplateParameters,
jsonObjectMapper.asJsonString(subJobWriteRequest),
OperationType.CREATE,
private ProducerKey createProducerKey(final YangModelCmHandle yangModelCmHandle) {
final String dmiDataServiceName =
- DmiServiceNameResolver.resolveDmiServiceName(RequiredDmiService.DATA, yangModelCmHandle);
+ DmiServiceNameResolver.resolveDmiServiceName(RequiredDmiService.DATAJOBS_WRITE, yangModelCmHandle);
return new ProducerKey(dmiDataServiceName, yangModelCmHandle.getDataProducerIdentifier());
}
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA;
import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR;
import static org.onap.cps.ncmp.api.data.models.OperationType.READ;
-import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.REQUEST_TIMEOUT;
}
private WebClient getWebClient(final RequiredDmiService requiredDmiService) {
- return DATA.equals(requiredDmiService) ? dataServicesWebClient : modelServicesWebClient;
+ return requiredDmiService == MODEL ? modelServicesWebClient : dataServicesWebClient;
}
private void configureHttpHeaders(final HttpHeaders httpHeaders, final String authorization) {
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024 Nordix Foundation
+ * Copyright (C) 2024-2026 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.
package org.onap.cps.ncmp.impl.dmi;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATAJOBS_READ;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATAJOBS_WRITE;
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL;
+
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
import org.onap.cps.ncmp.impl.models.RequiredDmiService;
+/**
+ * Resolves DMI service names based on the required service type.
+ * Resolution follows a priority order: specific service name first, then falls back to the combined service name.
+ * For example, if DATA service is required and dmiDataServiceName is set, it will be used;
+ * otherwise, the combined dmiServiceName will be returned.
+ */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DmiServiceNameResolver {
return resolveDmiServiceName(requiredService,
yangModelCmHandle.getDmiServiceName(),
yangModelCmHandle.getDmiDataServiceName(),
- yangModelCmHandle.getDmiModelServiceName());
+ yangModelCmHandle.getDmiModelServiceName(),
+ yangModelCmHandle.getDmiDatajobsReadServiceName(),
+ yangModelCmHandle.getDmiDatajobsWriteServiceName());
}
/**
return resolveDmiServiceName(requiredService,
ncmpServiceCmHandle.getDmiServiceName(),
ncmpServiceCmHandle.getDmiDataServiceName(),
- ncmpServiceCmHandle.getDmiModelServiceName());
+ ncmpServiceCmHandle.getDmiModelServiceName(),
+ ncmpServiceCmHandle.getDmiDatajobsReadServiceName(),
+ ncmpServiceCmHandle.getDmiDatajobsWriteServiceName());
}
/**
return resolveDmiServiceName(requiredService,
dmiPluginRegistration.getDmiPlugin(),
dmiPluginRegistration.getDmiDataPlugin(),
- dmiPluginRegistration.getDmiModelPlugin());
+ dmiPluginRegistration.getDmiModelPlugin(),
+ dmiPluginRegistration.getDmiDatajobsReadPlugin(),
+ dmiPluginRegistration.getDmiDatajobsWritePlugin());
}
private static String resolveDmiServiceName(final RequiredDmiService requiredService,
final String dmiServiceName,
final String dmiDataServiceName,
- final String dmiModelServiceName) {
- if (StringUtils.isBlank(dmiServiceName)) {
- if (RequiredDmiService.DATA.equals(requiredService)) {
- return dmiDataServiceName;
- }
+ final String dmiModelServiceName,
+ final String dmiDatajobsReadServiceName,
+ final String dmiDatajobsWriteServiceName) {
+ if (DATA.equals(requiredService) && StringUtils.isNotBlank(dmiDataServiceName)) {
+ return dmiDataServiceName;
+ }
+ if (MODEL.equals(requiredService) && StringUtils.isNotBlank(dmiModelServiceName)) {
return dmiModelServiceName;
}
+ if (DATAJOBS_READ.equals(requiredService) && StringUtils.isNotBlank(dmiDatajobsReadServiceName)) {
+ return dmiDatajobsReadServiceName;
+ }
+ if (DATAJOBS_WRITE.equals(requiredService) && StringUtils.isNotBlank(dmiDatajobsWriteServiceName)) {
+ return dmiDatajobsWriteServiceName;
+ }
return dmiServiceName;
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021-2022 Bell Canada
* Modifications Copyright (C) 2023 Deutsche Telekom AG
*/
public DmiPluginRegistrationResponse updateDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
- dmiPluginRegistration.validateDmiPluginRegistration();
final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
trustLevelManager.registerDmiPlugin(dmiPluginRegistration);
copy.dmiServiceName = original.getDmiServiceName();
copy.dmiDataServiceName = original.getDmiDataServiceName();
copy.dmiModelServiceName = original.getDmiModelServiceName();
+ copy.dmiDatajobsReadServiceName = original.getDmiDatajobsReadServiceName();
+ copy.dmiDatajobsWriteServiceName = original.getDmiDatajobsWriteServiceName();
copy.compositeState =
original.getCompositeState() == null ? null : new CompositeState(original.getCompositeState());
copy.additionalProperties = original.getAdditionalProperties()
yangModelCmHandle.setDmiServiceName(dmiPluginRegistration.getDmiPlugin());
yangModelCmHandle.setDmiDataServiceName(dmiPluginRegistration.getDmiDataPlugin());
yangModelCmHandle.setDmiModelServiceName(dmiPluginRegistration.getDmiModelPlugin());
+ yangModelCmHandle.setDmiDatajobsReadServiceName(dmiPluginRegistration.getDmiDatajobsReadPlugin());
+ yangModelCmHandle.setDmiDatajobsWriteServiceName(dmiPluginRegistration.getDmiDatajobsWritePlugin());
yangModelCmHandle.setModuleSetTag(StringUtils.trimToEmpty(moduleSetTag));
yangModelCmHandle.setAlternateId(StringUtils.trimToEmpty(alternateId));
yangModelCmHandle.setDataProducerIdentifier(StringUtils.trimToEmpty(dataProducerIdentifier));
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 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.
package org.onap.cps.ncmp.impl.models;
/**
- * Enum to determine if the required service is for a data or model operation.
+ * Enum to determine if the required service is for a data, model, or data job operation.
*/
public enum RequiredDmiService {
- DATA, MODEL
+ DATA, MODEL, DATAJOBS_READ, DATAJOBS_WRITE
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2022-2026 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.
ncmpServiceCmHandle.setDmiServiceName(yangModelCmHandle.getDmiServiceName());
ncmpServiceCmHandle.setDmiDataServiceName(yangModelCmHandle.getDmiDataServiceName());
ncmpServiceCmHandle.setDmiModelServiceName(yangModelCmHandle.getDmiModelServiceName());
+ ncmpServiceCmHandle.setDmiDatajobsReadServiceName(yangModelCmHandle.getDmiDatajobsReadServiceName());
+ ncmpServiceCmHandle.setDmiDatajobsWriteServiceName(yangModelCmHandle.getDmiDatajobsWriteServiceName());
ncmpServiceCmHandle.setCompositeState(yangModelCmHandle.getCompositeState());
ncmpServiceCmHandle.setModuleSetTag(yangModelCmHandle.getModuleSetTag());
ncmpServiceCmHandle.setAlternateId(yangModelCmHandle.getAlternateId());
dmiPluginRegistration.setDmiPlugin(safeGetLeafValue(cmHandleDataNode, "dmi-service-name"));
dmiPluginRegistration.setDmiDataPlugin(safeGetLeafValue(cmHandleDataNode, "dmi-data-service-name"));
dmiPluginRegistration.setDmiModelPlugin(safeGetLeafValue(cmHandleDataNode, "dmi-model-service-name"));
+ dmiPluginRegistration.setDmiDatajobsReadPlugin(safeGetLeafValue(
+ cmHandleDataNode, "dmi-datajobs-read-service"));
+ dmiPluginRegistration.setDmiDatajobsWritePlugin(safeGetLeafValue(
+ cmHandleDataNode, "dmi-datajobs-write-service"));
return YangModelCmHandle.toYangModelCmHandle(
dmiPluginRegistration,
ncmpServiceCmHandle,
--- /dev/null
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2025-2026 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.ncmp.api.exceptions
+
+import spock.lang.Specification
+
+class DmiRequestExceptionSpec extends Specification {
+
+ def objectUnderTest = new DmiRequestException('my message', 'my details')
+
+ def 'A DMI request exception.'() {
+ expect: 'the exception has the correct message'
+ objectUnderTest.message == 'my message'
+ and: 'the exception has the correct details'
+ objectUnderTest.details == 'my details'
+ }
+
+}
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2024-2026 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.ncmp.impl.datajobs
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.ncmp.impl.dmi.DmiServiceAuthenticationProperties
import org.onap.cps.ncmp.impl.dmi.DmiRestClient
import org.onap.cps.ncmp.impl.models.RequiredDmiService
+import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters
import org.onap.cps.utils.JsonObjectMapper
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
def responseAsKeyValuePairs = [subJobId:'my-sub-job-id']
def responseEntity = new ResponseEntity<>(responseAsKeyValuePairs, HttpStatus.OK)
def expectedJson = '{"destination":"d1","dataAcceptType":"t1","dataContentType":"t2","dataProducerId":"prod1","dataJobId":"some-job-id","data":[{"path":"p","op":"operation","moduleSetTag":"tag","value":null,"operationId":"o1"}]}'
- mockDmiRestClient.synchronousPostOperation(RequiredDmiService.DATA, _, expectedJson, OperationType.CREATE, authorization) >> responseEntity
+ mockDmiRestClient.synchronousPostOperation(RequiredDmiService.DATAJOBS_WRITE, _ as UrlTemplateParameters, expectedJson, OperationType.CREATE, authorization) >> responseEntity
when: 'sending request to DMI invoked'
objectUnderTest.sendRequestsToDmi(authorization, dataJobId, dataJobMetadata, dmiWriteOperationsPerProducerKey)
then: 'the result contains the expected sub-job id'
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2024-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2024-2026 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.
}
def 'Validate the creation of a ProducerKey with correct dmiservicename.'() {
- given: 'yangModelCmHandles with service name: "#dmiServiceName" and data service name: "#dataServiceName"'
- def yangModelCmHandle = new YangModelCmHandle(dmiServiceName: dmiServiceName, dmiDataServiceName: dataServiceName, dataProducerIdentifier: 'dpi1')
+ given: 'a yang model cm handle'
+ def yangModelCmHandle = new YangModelCmHandle(dmiServiceName: dmiServiceName, dmiDatajobsWriteServiceName: datajobsWriteServiceName, dataProducerIdentifier: 'dpi1')
when: 'the ProducerKey is created'
def result = objectUnderTest.createProducerKey(yangModelCmHandle).toString()
- then: 'we get the ProducerKey with the correct service name'
+ then: 'the ProducerKey has the correct service name'
assert result == expectedProducerKey
- where: 'the following services are registered'
- dmiServiceName | dataServiceName || expectedProducerKey
- 'dmi-service-name' | '' || 'dmi-service-name#dpi1'
- '' | 'dmi-data-service-name' || 'dmi-data-service-name#dpi1'
- 'dmi-service-name' | 'dmi-data-service-name' || 'dmi-service-name#dpi1'
+ where:
+ scenario | dmiServiceName | datajobsWriteServiceName || expectedProducerKey
+ 'fallback to common service' | 'dmi-service-name' | '' || 'dmi-service-name#dpi1'
+ 'specific datajobs write service' | '' | 'dmi-datajobs-write-service' || 'dmi-datajobs-write-service#dpi1'
+ 'datajobs write takes precedence' | 'dmi-service-name' | 'dmi-datajobs-write-service' || 'dmi-datajobs-write-service#dpi1'
}
}
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 OpenInfra Foundation Europe. All rights reserved.
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
import org.onap.cps.api.exceptions.CpsException
import org.onap.cps.api.exceptions.DataNodeNotFoundException
import org.onap.cps.api.exceptions.DataValidationException
-import org.onap.cps.ncmp.api.exceptions.DmiRequestException
import org.onap.cps.ncmp.api.inventory.DataStoreSyncState
import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.inventory.models.CompositeState
assert result.upgradedCmHandles[0].ncmpResponseStatus == UNKNOWN_ERROR
}
- def 'Create CM-handle Validation: Registration with valid Service names: #scenario'() {
- given: 'a registration '
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: dmiPlugin, dmiModelPlugin: dmiModelPlugin,
- dmiDataPlugin: dmiDataPlugin)
- dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
- when: 'update registration and sync module is called with correct DMI plugin information'
- objectUnderTest.updateDmiRegistration(dmiPluginRegistration)
- then: 'create cm handles registration and sync modules is called with the correct plugin information'
- 1 * objectUnderTest.processCreatedCmHandles(dmiPluginRegistration, _)
- where:
- scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedDmiPluginRegisteredName
- 'combined DMI plugin' | 'service1' | '' | '' || 'service1'
- 'data & model DMI plugins' | '' | 'service1' | 'service2' || 'service2'
- 'data & model using same service' | '' | 'service1' | 'service1' || 'service1'
- }
-
- def 'Create CM-handle Validation: Invalid DMI plugin service name with #scenario'() {
- given: 'a registration '
- def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: dmiPlugin, dmiModelPlugin: dmiModelPlugin,
- dmiDataPlugin: dmiDataPlugin)
- dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
- when: 'registration is called with incorrect DMI plugin information'
- objectUnderTest.updateDmiRegistration(dmiPluginRegistration)
- then: 'a DMI Request Exception is thrown with correct message details'
- def exceptionThrown = thrown(DmiRequestException.class)
- assert exceptionThrown.getMessage().contains(expectedMessageDetails)
- and: 'registration is not called'
- 0 * objectUnderTest.processCreatedCmHandles(*_)
- where:
- scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
- 'empty DMI plugins' | '' | '' | '' || 'No DMI plugin service names'
- 'blank DMI plugins' | ' ' | ' ' | ' ' || 'No DMI plugin service names'
- 'null DMI plugins' | null | null | null || 'No DMI plugin service names'
- 'all DMI plugins' | 'service1' | 'service2' | 'service3' || 'Cannot register combined plugin service name and other service names'
- '(combined)DMI and Data Plugin' | 'service1' | '' | 'service2' || 'Cannot register combined plugin service name and other service names'
- '(combined)DMI and model Plugin' | 'service1' | 'service2' | '' || 'Cannot register combined plugin service name and other service names'
- 'only model DMI plugin' | '' | 'service1' | '' || 'Cannot register just a Data or Model plugin service name'
- 'only data DMI plugin' | '' | '' | 'service1' || 'Cannot register just a Data or Model plugin service name'
- }
-
def 'Create CM-Handle Successfully: #scenario.'() {
given: 'a registration without cm-handle properties'
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server')
'without additional & public properties' | [:] | [:] || [:] | [:]
}
+ def 'Create CM-handle with data jobs plugins: #scenario'() {
+ given: 'a registration with data jobs plugins'
+ def dmiPluginRegistration = new DmiPluginRegistration(
+ dmiPlugin: dmiPlugin,
+ dmiDataPlugin: dmiDataPlugin,
+ dmiModelPlugin: dmiModelPlugin,
+ dmiDatajobsReadPlugin: dmiDatajobsReadPlugin,
+ dmiDatajobsWritePlugin: dmiDatajobsWritePlugin
+ )
+ dmiPluginRegistration.createdCmHandles = [new NcmpServiceCmHandle(cmHandleId: 'cmhandle')]
+ when: 'registration is updated'
+ def response = objectUnderTest.updateDmiRegistration(dmiPluginRegistration)
+ then: 'a successful response is received'
+ response.createdCmHandles.size() == 1
+ response.createdCmHandles[0].status == Status.SUCCESS
+ where:
+ scenario | dmiPlugin | dmiDataPlugin | dmiModelPlugin | dmiDatajobsReadPlugin | dmiDatajobsWritePlugin
+ 'only data jobs write plugin' | '' | '' | '' | '' | 'datajobs-write-service'
+ 'only data jobs read plugin' | '' | '' | '' | 'datajobs-read-service' | ''
+ 'both data jobs plugins' | '' | '' | '' | 'datajobs-read-service' | 'datajobs-write-service'
+ 'combined with data jobs plugins' | 'combined' | '' | '' | 'datajobs-read-service' | 'datajobs-write-service'
+ 'all plugins including data jobs' | '' | 'data-svc' | 'model-svc' | 'datajobs-read-service' | 'datajobs-write-service'
+ }
+
def 'Add CM-Handle #scenario.'() {
given: ' registration details for one cm handles'
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server',
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2021-2026 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.
import spock.lang.Specification
import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATA
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATAJOBS_READ
+import static org.onap.cps.ncmp.impl.models.RequiredDmiService.DATAJOBS_WRITE
import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL
class YangModelCmHandleSpec extends Specification {
def 'Resolve DMI service name: #scenario and #requiredService service require.'() {
given: 'a yang model cm handle'
- def dmiPluginRegistration = new DmiPluginRegistration(
- dmiPlugin: dmiServiceName,
- dmiDataPlugin: dmiDataServiceName,
- dmiModelPlugin: dmiModelServiceName
+ def yangModelCmHandle = new YangModelCmHandle(
+ dmiServiceName: dmiServiceName,
+ dmiDataServiceName: dmiDataServiceName,
+ dmiModelServiceName: dmiModelServiceName,
+ dmiDatajobsReadServiceName: dmiDatajobsReadServiceName,
+ dmiDatajobsWriteServiceName: dmiDatajobsWriteServiceName
)
- def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiPluginRegistration, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'),'', '', '', '', '')
expect:
- assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
+ assert yangModelCmHandle.resolveDmiServiceName(requiredService) == expectedService
where:
- scenario | dmiServiceName | dmiDataServiceName | dmiModelServiceName | requiredService || expectedService
- 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | DATA || 'common service'
- 'common service registered' | 'common service' | 'does not matter' | 'does not matter' | MODEL || 'common service'
- 'common service empty' | '' | 'data service' | 'does not matter' | DATA || 'data service'
- 'common service empty' | '' | 'does not matter' | 'model service' | MODEL || 'model service'
- 'common service blank' | ' ' | 'data service' | 'does not matter' | DATA || 'data service'
- 'common service blank' | ' ' | 'does not matter' | 'model service' | MODEL || 'model service'
- 'common service null ' | null | 'data service' | 'does not matter' | DATA || 'data service'
- 'common service null' | null | 'does not matter' | 'model service' | MODEL || 'model service'
- 'only model service registered' | null | null | 'does not matter' | DATA || null
- 'only data service registered' | null | 'does not matter' | null | MODEL || null
+ scenario | dmiServiceName | dmiDataServiceName | dmiModelServiceName | dmiDatajobsReadServiceName | dmiDatajobsWriteServiceName | requiredService || expectedService
+ 'specific data service registered' | 'common service' | 'data service' | 'does not matter' | null | null | DATA || 'data service'
+ 'specific model service registered' | 'common service' | 'does not matter' | 'model service' | null | null | MODEL || 'model service'
+ 'specific datajobs read service' | 'common service' | 'does not matter' | 'does not matter' | 'datajobs-read' | null | DATAJOBS_READ || 'datajobs-read'
+ 'specific datajobs write service' | 'common service' | 'does not matter' | 'does not matter' | null | 'datajobs-write' | DATAJOBS_WRITE || 'datajobs-write'
+ 'fallback to common for data' | 'common service' | null | 'does not matter' | null | null | DATA || 'common service'
+ 'fallback to common for model' | 'common service' | 'does not matter' | null | null | null | MODEL || 'common service'
+ 'fallback to common for datajobs read' | 'common service' | 'does not matter' | 'does not matter' | null | null | DATAJOBS_READ || 'common service'
+ 'fallback to common for datajobs write' | 'common service' | 'does not matter' | 'does not matter' | null | null | DATAJOBS_WRITE || 'common service'
+ 'blank specific ignored, uses fallback' | 'common service' | ' ' | 'does not matter' | null | null | DATA || 'common service'
+ 'no services available returns null' | null | null | null | null | null | DATA || null
}
def 'Yang Model Cm Handle Deep Copy.'() {
/*
* ============LICENSE_START========================================================
- * Copyright (C) 2022-2025 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2022-2026 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.
package org.onap.cps.ncmp.impl.utils
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
+
import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.ADVISED
import org.onap.cps.api.model.DataNode
assert yangModelCmHandle.compositeState.cmHandleState == ADVISED
}
+ def 'Convert a cm handle data node with data jobs service names.'() {
+ given: 'a datanode with data jobs service names'
+ def dataNodeCmHandle = new DataNode(leaves:['id':'ch-1', 'dmi-service-name': 'dmi1',
+ 'dmi-datajobs-read-service': 'dmi-read', 'dmi-datajobs-write-service': 'dmi-write'])
+ when: 'the dataNode is converted'
+ def yangModelCmHandle = YangDataConverter.toYangModelCmHandle(dataNodeCmHandle)
+ then: 'the data jobs service names are set'
+ assert yangModelCmHandle.dmiDatajobsReadServiceName == 'dmi-read'
+ assert yangModelCmHandle.dmiDatajobsWriteServiceName == 'dmi-write'
+ }
+
+ def 'Convert yang model cm handle to ncmp service cm handle with data jobs service names.'() {
+ given: 'a yang model cm handle with data jobs service names'
+ def yangModelCmHandle = new YangModelCmHandle(id: 'ch-1', dmiServiceName: 'dmi1',
+ dmiDatajobsReadServiceName: 'dmi-read', dmiDatajobsWriteServiceName: 'dmi-write',
+ additionalProperties: [], publicProperties: [])
+ when: 'converted to ncmp service cm handle'
+ def ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle)
+ then: 'the data jobs service names are preserved'
+ assert ncmpServiceCmHandle.dmiDatajobsReadServiceName == 'dmi-read'
+ assert ncmpServiceCmHandle.dmiDatajobsWriteServiceName == 'dmi-write'
+ }
+
def 'Convert multiple cm handle data nodes'(){
given: 'two data nodes in a collection'
def dataNodes = [new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'some-cm-handle\']', leaves: ['id':'some-cm-handle']),
default: false
example: true
type: boolean
+ - description: Content type in header
+ in: header
+ name: Content-Type
+ required: false
+ schema:
+ default: application/json
+ enum:
+ - application/json
+ - application/xml
+ type: string
responses:
"200":
content:
$ref: '#/components/examples/deltaReportSample'
schema:
type: object
+ application/xml:
+ examples:
+ dataSample:
+ $ref: '#/components/examples/deltaReportSampleXml'
+ schema:
+ type: object
description: OK
"400":
content:
name: Funny
target-data:
name: Comic
+ deltaReportSampleXml:
+ value: "<deltaReports> <deltaReport> <action>replace</action> <xpath>/bookstore/categories[@code='1']</xpath>\
+ \ <source-data> <name>SciFi</name> </source-data> <target-data> <name>Comic</name>\
+ \ </target-data> </deltaReport> <deltaReport> <action>remove</action> <xpath>/bookstore/categories[@code='2']</xpath>\
+ \ <source-data> <code>2</code> <name>kids</name> </source-data> </deltaReport>\
+ \ <deltaReport> <action>create</action> <xpath>/bookstore/categories[@code='3']</xpath>\
+ \ <target-data> <code>3</code> <name>Fiction</name> </target-data> </deltaReport>\
+ \ </deltaReports>"
dataSampleAcrossAnchors:
value:
- anchorName: bookstore1
schemas:
RestDmiPluginRegistration:
example:
+ dmiDatajobsReadPlugin: my-dmi-datajobs-read-plugin
updatedCmHandles:
- cmHandle: my-cm-handle
alternateId: "Subnetwork=Europe,ManagedElement=X123"
trustLevel: COMPLETE
dmiProperties: my-dmi-property
dmiPlugin: my-dmi-plugin
+ dmiDatajobsWritePlugin: my-dmi-datajobs-write-plugin
dmiModelPlugin: my-dmi-model-plugin
upgradedCmHandles:
cmHandles:
default: ""
example: my-dmi-model-plugin
type: string
+ dmiDatajobsReadPlugin:
+ default: ""
+ example: my-dmi-datajobs-read-plugin
+ type: string
+ dmiDatajobsWritePlugin:
+ default: ""
+ example: my-dmi-datajobs-write-plugin
+ type: string
createdCmHandles:
items:
$ref: '#/components/schemas/RestInputCmHandle'