aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIttay Stern <ittay.stern@att.com>2019-11-03 19:43:20 +0200
committerIttay Stern <ittay.stern@att.com>2019-11-04 10:24:34 +0200
commit6de0af739f85377cf07f6f0ad8118d63e9e8578c (patch)
tree001ca1879be969855e1945f371d1605951d063da
parent46d7ba49211c86e9208d6634461afc6ebac70f8d (diff)
vfModule upgrade: don't fallback on mismatching newest model
Issue-ID: VID-603 Change-Id: I96a0d4ed3a6717a4f1ee7c285dc71e2d7d695302 Signed-off-by: Ittay Stern <ittay.stern@att.com>
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt5
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/NetworkCommand.kt8
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt4
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt84
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VnfCommand.kt14
-rw-r--r--vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupCommand.kt6
-rw-r--r--vid-app-common/src/test/java/org/onap/vid/job/command/VfmoduleCommandTest.kt85
7 files changed, 150 insertions, 56 deletions
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt
index 26fb9aa09..886251a0c 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/InstanceGroupCommand.kt
@@ -67,14 +67,13 @@ class InstanceGroupCommand @Autowired constructor(
}
override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val instantiatePath = asyncInstantiationBL.getInstanceGroupInstantiationPath()
val requestDetailsWrapper = msoRequestBuilder.generateInstanceGroupInstantiationRequest(
request as InstanceGroup,
- serviceModelInfo, serviceInstanceId,
+ serviceModelInfoFromRequest(), serviceInstanceId,
userId,
testApi
)
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkCommand.kt
index bc4de7ccd..6c9af14ea 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/NetworkCommand.kt
@@ -34,13 +34,11 @@ class NetworkCommand @Autowired constructor(
}
override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
-
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val instantiatePath = asyncInstantiationBL.getNetworkInstantiationPath(serviceInstanceId)
val requestDetailsWrapper = msoRequestBuilder.generateNetworkInstantiationRequest(
request as Network,
- serviceModelInfo,
+ serviceModelInfoFromRequest(),
serviceInstanceId,
userId,
testApi
@@ -52,7 +50,7 @@ class NetworkCommand @Autowired constructor(
}
override fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val path = asyncInstantiationBL.getNetworkDeletePath(serviceInstanceId, getRequest().instanceId)
val requestDetailsWrapper = msoRequestBuilder.generateDeleteNetworkRequest(getRequest() as Network, userId)
return MsoRestCallPlan(HttpMethod.DELETE, path, Optional.of(requestDetailsWrapper), Optional.of(userId),
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt
index 60a579e30..a266dd002 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/ResourceCommand.kt
@@ -35,6 +35,7 @@ import org.onap.vid.model.Action
import org.onap.vid.model.RequestReferencesContainer
import org.onap.vid.model.serviceInstantiation.BaseResource
import org.onap.vid.mso.RestMsoImplementation
+import org.onap.vid.mso.model.ModelInfo
import org.onap.vid.utils.JACKSON_OBJECT_MAPPER
import org.onap.vid.utils.getEnumFromMapOfStrings
import org.slf4j.MDC
@@ -408,6 +409,9 @@ abstract class ResourceCommand(
return commandParentData.parentData
}
+ protected fun serviceModelInfoFromRequest(): ModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+ protected fun serviceInstanceIdFromRequest(): String = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+
protected open fun addMyselfToChildrenData(commandParentData: CommandParentData, request: BaseResource) {
// Nothing by default
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt
index 25373d4ac..bee42fbd4 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VfmoduleCommand.kt
@@ -1,6 +1,7 @@
package org.onap.vid.job.command
import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate
+import org.onap.vid.exceptions.GenericUncheckedException
import org.onap.vid.job.Job
import org.onap.vid.job.JobAdapter
import org.onap.vid.job.JobCommand
@@ -42,8 +43,8 @@ class VfmoduleCommand @Autowired constructor(
}
override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
+ val serviceModelInfo = serviceModelInfoFromRequest()
val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO)
val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID)
val vgInstaceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VG_INSTANCE_ID)
@@ -61,7 +62,7 @@ class VfmoduleCommand @Autowired constructor(
}
override fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID)
val path = asyncInstantiationBL.getVfModuleDeletePath(serviceInstanceId, vnfInstanceId, getRequest().instanceId)
@@ -82,7 +83,7 @@ class VfmoduleCommand @Autowired constructor(
val newestModel = fetchNewestServiceModel()
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID)
val (serviceModelInfo, vnfModelInfo, vfmModelInfo) = newestSelector(newestModel, commandParentData);
@@ -103,44 +104,52 @@ class VfmoduleCommand @Autowired constructor(
data class ModelsInfoTriplet(val serviceModelInfo: ModelInfo, val vnfModelInfo: ModelInfo, val vfmModelInfo: ModelInfo)
private fun newestSelector(newestModel: ServiceModel, commandParentData: CommandParentData): ModelsInfoTriplet {
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
- val vfmModelInfo = getRequest().modelInfo
- val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO)
-
- val newestServiceModelInfo = newestServiceModelInfo(newestModel)
- val newestVfmModelInfo = newestVfmModelInfo(newestModel)
- val newestVnfModelInfo = newestVnfModelInfo(newestModel, commandParentData)
-
- return if (newestServiceModelInfo == null || newestVfmModelInfo == null || newestVnfModelInfo == null) {
- ModelsInfoTriplet(serviceModelInfo, vnfModelInfo, vfmModelInfo)
- } else {
- ModelsInfoTriplet(newestServiceModelInfo, newestVnfModelInfo, newestVfmModelInfo)
+ try {
+ return ModelsInfoTriplet(
+ newestServiceModelInfo(newestModel),
+ newestVnfModelInfo(newestModel, commandParentData),
+ newestVfmModelInfo(newestModel)
+ )
+ } catch (e: Exception) {
+ throw GenericUncheckedException("Cannot upgrade ${serviceModelInfoFromRequest()} to ${newestModel.service}", e)
}
}
private fun newestServiceModelInfo(newestModel: ServiceModel) = toModelInfo(newestModel.service)
- private fun newestVfmModelInfo(newestModel: ServiceModel): ModelInfo? {
+ private fun newestVfmModelInfo(newestModel: ServiceModel): ModelInfo {
val vfmModelInfo = getRequest().modelInfo
- val matchingVfms = selectVfms(newestModel, vfmModelInfo)
- return toModelInfo(matchingVfms.getOrNull(0))
+ val matchingVfm = selectVfm(newestModel, vfmModelInfo)
+ return toModelInfo(matchingVfm)
}
- private fun newestVnfModelInfo(newestModel: ServiceModel, commandParentData: CommandParentData): ModelInfo? {
+ private fun newestVnfModelInfo(newestModel: ServiceModel, commandParentData: CommandParentData): ModelInfo {
val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO)
- val matchingVnfs = selectVnfs(newestModel, vnfModelInfo)
- return toModelInfo(matchingVnfs.getOrNull(0))
+ val matchingVnf = selectVnf(newestModel, vnfModelInfo)
+ return toModelInfo(matchingVnf)
}
- private fun selectVfms(newestModel: ServiceModel, modelInfo: ModelInfo) =
- newestModel.vfModules.values.filter { it.modelCustomizationName == modelInfo.modelCustomizationName }
-
- private fun selectVnfs(newestModel: ServiceModel, modelInfo: ModelInfo) =
- newestModel.vnfs.values.filter { it.modelCustomizationName == modelInfo.modelCustomizationName }
+ internal fun selectVfm(serviceModel: ServiceModel, modelInfo: ModelInfo): ToscaVfm =
+ exactlyOne("vfModule for modelCustomizationName \"${modelInfo.modelCustomizationName}\"") {
+ serviceModel.vfModules.values.single { it.modelCustomizationName == modelInfo.modelCustomizationName }
+ }
+
+ internal fun selectVnf(serviceModel: ServiceModel, modelInfo: ModelInfo): VNF =
+ exactlyOne("VNF for modelCustomizationName \"${modelInfo.modelCustomizationName}\"") {
+ serviceModel.vnfs.values.single { it.modelCustomizationName == modelInfo.modelCustomizationName }
+ }
+
+ private fun <T: Any> exactlyOne(predicateDescription: String, itemSupplier: () -> T): T {
+ return try {
+ itemSupplier.invoke()
+ } catch (cause: Exception) {
+ throw IllegalStateException("Cannot match ${predicateDescription}: ${cause.localizedMessage}", cause)
+ }
+ }
- private fun toModelInfo(toBeConverted: VNF?): ModelInfo? = toBeConverted?.let { toModelInfo(it, "vnf") }
+ private fun toModelInfo(toBeConverted: VNF): ModelInfo = toModelInfo(toBeConverted, "vnf")
- private fun toModelInfo(toBeConverted: ToscaVfm?): ModelInfo? = toBeConverted?.let { toModelInfo(it, "vfModule") }
+ private fun toModelInfo(toBeConverted: ToscaVfm): ModelInfo = toModelInfo(toBeConverted, "vfModule")
private fun toModelInfo(toBeConverted: MinimalNode, modelType: String): ModelInfo {
val targetModelInfo = ModelInfo()
@@ -167,11 +176,7 @@ class VfmoduleCommand @Autowired constructor(
return targetModelInfo
}
- private fun toModelInfo(toBeConverted: Service?): ModelInfo? {
-
- if (toBeConverted == null)
- return null
-
+ internal fun toModelInfo(toBeConverted: Service): ModelInfo {
val targetModelInfo = ModelInfo()
targetModelInfo.modelVersionId = toBeConverted.uuid
@@ -197,10 +202,15 @@ class VfmoduleCommand @Autowired constructor(
return getActionType() == Action.Upgrade
}
+ @Throws(IllegalStateException::class)
private fun fetchNewestServiceModel(): ServiceModel {
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
- var modelNewestUuid = commandUtils.getNewestModelUuid(serviceModelInfo.modelInvariantId);
- var serviceNewestModel = commandUtils.getServiceModel(modelNewestUuid);
+ val serviceModelInfo = serviceModelInfoFromRequest()
+ val modelNewestUuid = commandUtils.getNewestModelUuid(serviceModelInfo.modelInvariantId);
+
+ check(!modelNewestUuid.equals(serviceModelInfo.modelVersionId, true)) {
+ "Model version id ${serviceModelInfo.modelVersionId} is already the latest version of model's invariant id ${serviceModelInfo.modelInvariantId}" }
+
+ val serviceNewestModel = commandUtils.getServiceModel(modelNewestUuid);
return serviceNewestModel;
}
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VnfCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfCommand.kt
index a89e196de..6f00f9ae6 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/VnfCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VnfCommand.kt
@@ -62,7 +62,8 @@ class VnfCommand @Autowired constructor(
childJobs = pushChildrenJobsToBroker(vfModules.filter { filterModuleByNeedToCreateBase(it) }, dataForChild, JobType.VolumeGroupInstantiation)
} catch (e: AsdcCatalogException) {
LOGGER.error("Failed to retrieve service definitions from SDC, for VfModule is BaseModule.. Error: " + e.message , e)
- return Job.JobStatus.FAILED
+ //return Job.JobStatus.FAILED
+ throw e;
}
}
@@ -72,19 +73,18 @@ class VnfCommand @Autowired constructor(
private fun filterModuleByNeedToCreateBase(it: VfModule):Boolean {
return needToCreateBaseModule ==
commandUtils.isVfModuleBaseModule(
- commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO).getModelVersionId(),
- it.modelInfo.modelVersionId)
+ serviceModelInfoFromRequest().modelVersionId,
+ it.modelInfo.modelVersionId)
}
override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val instantiatePath = asyncInstantiationBL.getVnfInstantiationPath(serviceInstanceId)
val requestDetailsWrapper = msoRequestBuilder.generateVnfInstantiationRequest(
request as Vnf,
- serviceModelInfo, serviceInstanceId,
+ serviceModelInfoFromRequest(), serviceInstanceId,
userId,
testApi
)
@@ -110,7 +110,7 @@ class VnfCommand @Autowired constructor(
}
override fun planDeleteMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String): MsoRestCallPlan {
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val path = asyncInstantiationBL.getVnfDeletionPath(serviceInstanceId, getRequest().instanceId)
val requestDetailsWrapper = msoRequestBuilder.generateDeleteVnfRequest(getRequest(), userId)
return MsoRestCallPlan(HttpMethod.DELETE, path, Optional.of(requestDetailsWrapper), Optional.of(userId),
diff --git a/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupCommand.kt b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupCommand.kt
index 4da1dad15..9794933ce 100644
--- a/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupCommand.kt
+++ b/vid-app-common/src/main/java/org/onap/vid/job/command/VolumeGroupCommand.kt
@@ -43,9 +43,7 @@ class VolumeGroupCommand @Autowired constructor(
}
override fun planCreateMyselfRestCall(commandParentData: CommandParentData, request: JobAdapter.AsyncJobRequest, userId: String, testApi: String?): MsoRestCallPlan {
-
- val serviceInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.SERVICE_INSTANCE_ID)
- val serviceModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.SERVICE_MODEL_INFO)
+ val serviceInstanceId = serviceInstanceIdFromRequest()
val vnfInstanceId = commandParentData.getInstanceId(CommandParentData.CommandDataKey.VNF_INSTANCE_ID)
val vnfModelInfo = commandParentData.getModelInfo(CommandParentData.CommandDataKey.VNF_MODEL_INFO)
@@ -53,7 +51,7 @@ class VolumeGroupCommand @Autowired constructor(
val requestDetailsWrapper = msoRequestBuilder.generateVolumeGroupInstantiationRequest(
request as VfModule,
- serviceModelInfo, serviceInstanceId,
+ serviceModelInfoFromRequest(), serviceInstanceId,
vnfModelInfo,vnfInstanceId,
userId,
testApi
diff --git a/vid-app-common/src/test/java/org/onap/vid/job/command/VfmoduleCommandTest.kt b/vid-app-common/src/test/java/org/onap/vid/job/command/VfmoduleCommandTest.kt
new file mode 100644
index 000000000..ea67f2372
--- /dev/null
+++ b/vid-app-common/src/test/java/org/onap/vid/job/command/VfmoduleCommandTest.kt
@@ -0,0 +1,85 @@
+package org.onap.vid.job.command
+
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.beans.SamePropertyValuesAs.samePropertyValuesAs
+import org.mockito.InjectMocks
+import org.mockito.Mock
+import org.onap.vid.job.JobAdapter
+import org.onap.vid.job.JobsBrokerService
+import org.onap.vid.model.ServiceModel
+import org.onap.vid.model.VfModule
+import org.onap.vid.mso.RestMsoImplementation
+import org.onap.vid.mso.model.ModelInfo
+import org.onap.vid.services.AsyncInstantiationBusinessLogic
+import org.onap.vid.testUtils.TestUtils.initMockitoMocks
+import org.testng.annotations.BeforeMethod
+import org.testng.annotations.Test
+
+class VfmoduleCommandTest {
+
+ @Mock lateinit var asyncInstantiationBL: AsyncInstantiationBusinessLogic;
+ @Mock lateinit var restMso: RestMsoImplementation;
+ @Mock lateinit var msoRequestBuilder: MsoRequestBuilder;
+ @Mock lateinit var msoResultHandlerService: MsoResultHandlerService;
+ @Mock lateinit var inProgressStatusService: InProgressStatusService;
+ @Mock lateinit var watchChildrenJobsBL: WatchChildrenJobsBL;
+ @Mock lateinit var jobsBrokerService: JobsBrokerService;
+ @Mock lateinit var jobAdapter: JobAdapter;
+
+ @InjectMocks lateinit var vfModuleCommand: VfmoduleCommand;
+
+ private val uniqueCustomizationName = "my unique customization name"
+
+ @BeforeMethod
+ fun initMocks() {
+ initMockitoMocks(this)
+ }
+
+ @Test
+ fun `given correlated modelCustomizationName, selectVfms returns the vfm`() {
+ val newestModel = ServiceModel()
+ newestModel.vfModules = someVfModules()
+ .plus("my vfm" to vfModuleWithCustomizationName())
+
+ val selectedVfm = vfModuleCommand.selectVfm(newestModel, modelInfoWithCustomizationName())
+
+ assertThat(selectedVfm, samePropertyValuesAs(vfModuleWithCustomizationName()))
+ }
+
+ @Test(
+ expectedExceptions = [IllegalStateException::class],
+ expectedExceptionsMessageRegExp =
+ """Cannot match vfModule for modelCustomizationName "my unique customization name": Collection contains no element matching the predicate.""")
+ fun `given no matching modelCustomizationName, selectVfms throws`() {
+ val newestModel = ServiceModel()
+ newestModel.vfModules = someVfModules()
+
+ vfModuleCommand.selectVfm(newestModel, modelInfoWithCustomizationName())
+ }
+
+ @Test(
+ expectedExceptions = [IllegalStateException::class],
+ expectedExceptionsMessageRegExp =
+ """Cannot match vfModule for modelCustomizationName "my unique customization name": Collection contains more than one matching element.""")
+ fun `given a few matching modelCustomizationName, selectVfms throws`() {
+
+ val newestModel = ServiceModel()
+ newestModel.vfModules = someVfModules()
+ .plus("my vfm" to vfModuleWithCustomizationName())
+ .plus("my vfm2" to vfModuleWithCustomizationName())
+
+ vfModuleCommand.selectVfm(newestModel, modelInfoWithCustomizationName())
+ }
+
+ private fun modelInfoWithCustomizationName(customizationName: String = uniqueCustomizationName) =
+ ModelInfo().also { it.modelCustomizationName = customizationName }
+
+ private fun someVfModules(): Map<String, VfModule> = mapOf(
+ "any vfm 1" to vfModuleWithCustomizationName("any customization name 1"),
+ "any vfm 2" to vfModuleWithCustomizationName("any customization name 2")
+ )
+
+ private fun vfModuleWithCustomizationName(customizationName: String = uniqueCustomizationName) =
+ VfModule().also { it.modelCustomizationName = customizationName }
+
+} \ No newline at end of file