Instance creation validation added 19/14719/1
authoraravind.est <aravindhan.a@est.tech>
Mon, 14 Jul 2025 17:43:11 +0000 (18:43 +0100)
committeraravind.est <aravindhan.a@est.tech>
Mon, 14 Jul 2025 17:43:11 +0000 (18:43 +0100)
rApp instance creation payload values compared with the rApp package for validation

Issue-ID: NONRTRIC-1080
Change-Id: Ic4cde14eddf4b3ad0294e1adb2a944b204027f89
Signed-off-by: aravind.est <aravindhan.a@est.tech>
13 files changed:
rapp-manager-application/src/main/java/org/oransc/rappmanager/rest/RappInstanceController.java
rapp-manager-application/src/test/java/org/oransc/rappmanager/rest/RappInstanceControllerTest.java
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidator.java [new file with mode: 0644]
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidator.java [new file with mode: 0644]
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandler.java [new file with mode: 0644]
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidator.java [new file with mode: 0644]
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidator.java [new file with mode: 0644]
rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidator.java [new file with mode: 0644]
rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidatorTest.java [new file with mode: 0644]
rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidatorTest.java [new file with mode: 0644]
rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandlerTest.java [new file with mode: 0644]
rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidatorTest.java [new file with mode: 0644]
rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidatorTest.java [new file with mode: 0644]

index 4d2d33a..c2fc36f 100644 (file)
@@ -31,6 +31,7 @@ import org.oransc.rappmanager.models.rapp.Rapp;
 import org.oransc.rappmanager.models.rappinstance.DeployOrder;
 import org.oransc.rappmanager.models.rappinstance.RappInstance;
 import org.oransc.rappmanager.models.rappinstance.RappInstanceDeployOrder;
+import org.oransc.rappmanager.models.rappinstance.validator.RappInstanceValidationHandler;
 import org.oransc.rappmanager.models.statemachine.RappInstanceStateMachine;
 import org.oransc.rappmanager.service.RappService;
 import org.springframework.http.HttpStatus;
@@ -51,6 +52,7 @@ public class RappInstanceController {
 
     private final RappCacheService rappCacheService;
     private final RappInstanceStateMachine rappInstanceStateMachine;
+    private final RappInstanceValidationHandler rappInstanceValidationHandler;
     private final RappService rappService;
     private static final String RAPP_INSTANCE_NOT_FOUND = "rApp instance %s not found.";
 
@@ -64,6 +66,7 @@ public class RappInstanceController {
     public ResponseEntity<RappInstance> createRappInstance(@PathVariable("rapp_id") String rappId,
             @Valid @RequestBody RappInstance rappInstance) {
         return rappCacheService.getRapp(rappId).map(rapp -> {
+            rappInstanceValidationHandler.validateRappInstance(rapp, rappInstance);
             rappInstanceStateMachine.onboardRappInstance(rappInstance.getRappInstanceId());
             rapp.getRappInstances().put(rappInstance.getRappInstanceId(), rappInstance);
             return ResponseEntity.ok(rappInstance);
index 46d06c5..0ef098f 100644 (file)
@@ -27,6 +27,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -35,6 +36,7 @@ import org.oransc.rappmanager.acm.service.AcmDeployer;
 import org.oransc.rappmanager.dme.service.DmeDeployer;
 import org.oransc.rappmanager.models.cache.RappCacheService;
 import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappResources;
 import org.oransc.rappmanager.models.rapp.RappState;
 import org.oransc.rappmanager.models.rappinstance.DeployOrder;
 import org.oransc.rappmanager.models.rappinstance.RappACMInstance;
@@ -112,8 +114,10 @@ class RappInstanceControllerTest {
         rappACMInstance.setInstance("test-instance");
         rappInstance.setAcm(rappACMInstance);
         rappInstance.setState(RappInstanceState.UNDEPLOYED);
+        RappResources rappResources = new RappResources();
+        rappResources.setAcm(RappResources.ACMResources.builder().compositionInstances(Set.of("test-instance")).build());
         Rapp rapp = Rapp.builder().rappId(rappId).name(String.valueOf(rappId)).packageName(validRappFile)
-                            .packageLocation(validCsarFileLocation).state(RappState.PRIMED).build();
+                            .packageLocation(validCsarFileLocation).rappResources(rappResources).state(RappState.PRIMED).build();
         rappCacheService.putRapp(rapp);
         mockMvc.perform(
                 MockMvcRequestBuilders.post("/rapps/{rapp_id}/instance", rappId).contentType(MediaType.APPLICATION_JSON)
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidator.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidator.java
new file mode 100644 (file)
index 0000000..1ad6ca2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import org.jetbrains.annotations.NotNull;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AcmPayloadValidator implements RappInstanceValidator {
+
+    private static final int VALIDATION_ORDER = 5;
+
+    @Override
+    public int getOrder() {
+        return VALIDATION_ORDER;
+    }
+
+    @Override
+    public void validate(@NotNull Rapp rApp, @NotNull RappInstance rAppInstance) {
+        if (rAppInstance.getAcm() != null) {
+            comparePayloadValue(rAppInstance.getAcm().getInstance(),
+                    rApp.getRappResources().getAcm().getCompositionInstances(),
+                    "Invalid ACM instance in the rApp instance payload.");
+        }
+    }
+}
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidator.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidator.java
new file mode 100644 (file)
index 0000000..144efbe
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import org.jetbrains.annotations.NotNull;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DmePayloadValidator implements RappInstanceValidator {
+
+    private static final int VALIDATION_ORDER = 15;
+
+    @Override
+    public int getOrder() {
+        return VALIDATION_ORDER;
+    }
+
+    @Override
+    public void validate(@NotNull Rapp rApp, @NotNull RappInstance rAppInstance) {
+        if (rAppInstance.isDMEEnabled()) {
+            if (rAppInstance.getDme().getInfoTypesProducer() != null && !rApp.getRappResources().getDme()
+                                                                                 .getProducerInfoTypes().containsAll(
+                            rAppInstance.getDme().getInfoTypesProducer())) {
+                throw new RappValidationException("Invalid DME info types producer in the rApp instance payload.");
+            }
+
+            comparePayloadValue(rAppInstance.getDme().getInfoProducer(),
+                    rApp.getRappResources().getDme().getInfoProducers(),
+                    "Invalid DME info producer in the rApp instance payload.");
+
+            comparePayloadValue(rAppInstance.getDme().getInfoTypeConsumer(),
+                    rApp.getRappResources().getDme().getConsumerInfoTypes(),
+                    "Invalid DME info type consumer in the rApp instance payload.");
+
+            comparePayloadValue(rAppInstance.getDme().getInfoConsumer(),
+                    rApp.getRappResources().getDme().getInfoConsumers(),
+                    "Invalid DME info consumer in the rApp instance payload.");
+        }
+    }
+}
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandler.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandler.java
new file mode 100644 (file)
index 0000000..0f3c7f7
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import java.util.Comparator;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.stereotype.Component;
+
+@Component
+@RequiredArgsConstructor
+public class RappInstanceValidationHandler {
+
+    private final List<RappInstanceValidator> rappInstanceValidators;
+
+    public void validateRappInstance(Rapp rApp, RappInstance rAppInstance) {
+        List<RappInstanceValidator> validatorList =
+                rappInstanceValidators.stream().sorted(Comparator.comparing(RappInstanceValidator::getOrder)).toList();
+        validatorList.forEach(rAppValidator -> rAppValidator.validate(rApp, rAppInstance));
+    }
+}
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidator.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidator.java
new file mode 100644 (file)
index 0000000..777846f
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import java.util.Set;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+
+public interface RappInstanceValidator {
+
+    int getOrder();
+
+    void validate(Rapp rApp, RappInstance rAppInstance);
+
+    default void comparePayloadValue(String rAppInstancePayloadValue, Set<String> allowedValues, String errorMessage) {
+        if (rAppInstancePayloadValue != null && !allowedValues.contains(rAppInstancePayloadValue)) {
+            throw new RappValidationException(errorMessage);
+        }
+    }
+}
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidator.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidator.java
new file mode 100644 (file)
index 0000000..cdff2ee
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import org.jetbrains.annotations.NotNull;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappState;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RappStatusValidator implements RappInstanceValidator {
+
+    private static final int VALIDATION_ORDER = 1;
+
+    @Override
+    public int getOrder() {
+        return VALIDATION_ORDER;
+    }
+
+    @Override
+    public void validate(@NotNull Rapp rApp, @NotNull RappInstance rAppInstance) {
+        if (!rApp.getState().equals(RappState.PRIMED)) {
+            throw new RappValidationException("Unable to create rApp instance as rApp is not in PRIMED state");
+        }
+    }
+}
diff --git a/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidator.java b/rapp-manager-models/src/main/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidator.java
new file mode 100644 (file)
index 0000000..75d89ce
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import org.jetbrains.annotations.NotNull;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SmePayloadValidator implements RappInstanceValidator {
+
+    private static final int VALIDATION_ORDER = 10;
+
+    @Override
+    public int getOrder() {
+        return VALIDATION_ORDER;
+    }
+
+    @Override
+    public void validate(@NotNull Rapp rApp, @NotNull RappInstance rAppInstance) {
+        if (rAppInstance.isSMEEnabled()) {
+            comparePayloadValue(rAppInstance.getSme().getProviderFunction(),
+                    rApp.getRappResources().getSme().getProviderFunctions(),
+                    "Invalid SME provider function in the rApp instance payload.");
+
+            comparePayloadValue(rAppInstance.getSme().getServiceApis(),
+                    rApp.getRappResources().getSme().getServiceApis(),
+                    "Invalid SME service APIs in the rApp instance payload.");
+
+            comparePayloadValue(rAppInstance.getSme().getInvokers(), rApp.getRappResources().getSme().getInvokers(),
+                    "Invalid SME invokers in the rApp instance payload.");
+        }
+    }
+}
diff --git a/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidatorTest.java b/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/AcmPayloadValidatorTest.java
new file mode 100644 (file)
index 0000000..3e27fa6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappResources;
+import org.oransc.rappmanager.models.rappinstance.RappACMInstance;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = {AcmPayloadValidator.class})
+class AcmPayloadValidatorTest {
+
+    public static final String K8S_INSTANCE = "k8s-instance";
+    @Autowired
+    AcmPayloadValidator acmPayloadValidator;
+
+    @Test
+    void testAcmPayloadValidationSuccess() {
+        RappResources rappResources = new RappResources();
+        RappResources.ACMResources rappACMResources =
+                RappResources.ACMResources.builder().compositionInstances(Set.of(K8S_INSTANCE)).build();
+        rappResources.setAcm(rappACMResources);
+        Rapp rapp = Rapp.builder().rappResources(rappResources).build();
+        RappInstance rappInstance = new RappInstance();
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance(K8S_INSTANCE);
+        rappInstance.setAcm(rappACMInstance);
+        assertDoesNotThrow(() -> acmPayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testAcmPayloadValidationWithNull() {
+        RappResources rappResources = new RappResources();
+        RappResources.ACMResources rappACMResources =
+                RappResources.ACMResources.builder().compositionInstances(Set.of(K8S_INSTANCE)).build();
+        rappResources.setAcm(rappACMResources);
+        Rapp rapp = Rapp.builder().rappResources(rappResources).build();
+        RappInstance rappInstance = new RappInstance();
+        rappInstance.setAcm(null);
+        assertDoesNotThrow(() -> acmPayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testAcmPayloadValidationSuccessNoAcm() {
+        Rapp rapp = Rapp.builder().build();
+        RappInstance rappInstance = new RappInstance();
+        assertDoesNotThrow(() -> acmPayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testAcmPayloadValidationFailure() {
+        RappResources rappResources = new RappResources();
+        RappResources.ACMResources rappACMResources =
+                RappResources.ACMResources.builder().compositionInstances(Set.of(K8S_INSTANCE)).build();
+        rappResources.setAcm(rappACMResources);
+        Rapp rapp = Rapp.builder().rappResources(rappResources).build();
+        RappInstance rappInstance = new RappInstance();
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance("invalid-instance");
+        rappInstance.setAcm(rappACMInstance);
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> acmPayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid ACM instance in the rApp instance payload.", rappValidationException.getMessage());
+    }
+}
diff --git a/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidatorTest.java b/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/DmePayloadValidatorTest.java
new file mode 100644 (file)
index 0000000..7a19a7f
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappResources;
+import org.oransc.rappmanager.models.rappinstance.RappDMEInstance;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = {DmePayloadValidator.class})
+class DmePayloadValidatorTest {
+
+    private static final String PRODUCER_INFOTYPE_1 = "producer-infotype-1";
+    private static final String PRODUCER_INFOTYPE_2 = "producer-infotype-2";
+    private static final String CONSUMER_INFOTYPE_1 = "consumer-infotype-1";
+    private static final String CONSUMER_INFOTYPE_2 = "consumer-infotype-2";
+    private static final String INFO_CONSUMER_1 = "info-consumer-1";
+    private static final String INFO_CONSUMER_2 = "info-consumer-2";
+    private static final String INFO_PRODUCER_1 = "info-producer-1";
+    private static final String INFO_PRODUCER_2 = "info-producer-2";
+
+    @Autowired
+    private DmePayloadValidator dmePayloadValidator;
+
+    @Test
+    void testDmePayloadValidatorSuccess() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PRODUCER_INFOTYPE_1));
+        rappDMEInstance.setInfoTypeConsumer(CONSUMER_INFOTYPE_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+        assertDoesNotThrow(() -> dmePayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testDmePayloadValidatorSuccessWithNull() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(null);
+        rappDMEInstance.setInfoTypeConsumer(null);
+        rappDMEInstance.setInfoConsumer(null);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+        assertDoesNotThrow(() -> dmePayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testDmePayloadValidatorFailureInvalidProducerInfoType() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of("invalid-infotype"));
+        rappDMEInstance.setInfoTypeConsumer(CONSUMER_INFOTYPE_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> dmePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid DME info types producer in the rApp instance payload.",
+                rappValidationException.getMessage());
+    }
+
+    @Test
+    void testDmePayloadValidatorFailureInvalidConsumerInfoType() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PRODUCER_INFOTYPE_1));
+        rappDMEInstance.setInfoTypeConsumer("invalid-infotype");
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> dmePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid DME info type consumer in the rApp instance payload.",
+                rappValidationException.getMessage());
+    }
+
+    @Test
+    void testDmePayloadValidatorFailureInvalidInfoConsumer() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PRODUCER_INFOTYPE_1));
+        rappDMEInstance.setInfoTypeConsumer(CONSUMER_INFOTYPE_1);
+        rappDMEInstance.setInfoConsumer("invalid-consumer");
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> dmePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid DME info consumer in the rApp instance payload.", rappValidationException.getMessage());
+    }
+
+    @Test
+    void testDmePayloadValidatorFailureInvalidInfoProducer() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PRODUCER_INFOTYPE_1));
+        rappDMEInstance.setInfoTypeConsumer(CONSUMER_INFOTYPE_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer("invalid-producer");
+        rappInstance.setDme(rappDMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> dmePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid DME info producer in the rApp instance payload.", rappValidationException.getMessage());
+    }
+
+
+    private Rapp getRapp() {
+        RappResources rappResources = new RappResources();
+        RappResources.DMEResources rappDMEResources =
+                RappResources.DMEResources.builder().producerInfoTypes(Set.of(PRODUCER_INFOTYPE_1, PRODUCER_INFOTYPE_2))
+                        .consumerInfoTypes(Set.of(CONSUMER_INFOTYPE_1, CONSUMER_INFOTYPE_2))
+                        .infoConsumers(Set.of(INFO_CONSUMER_1, INFO_CONSUMER_2))
+                        .infoProducers(Set.of(INFO_PRODUCER_1, INFO_PRODUCER_2)).build();
+
+        rappResources.setDme(rappDMEResources);
+        return Rapp.builder().rappResources(rappResources).build();
+    }
+}
diff --git a/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandlerTest.java b/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappInstanceValidationHandlerTest.java
new file mode 100644 (file)
index 0000000..4aad66d
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappResources;
+import org.oransc.rappmanager.models.rapp.RappState;
+import org.oransc.rappmanager.models.rappinstance.RappACMInstance;
+import org.oransc.rappmanager.models.rappinstance.RappDMEInstance;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.oransc.rappmanager.models.rappinstance.RappSMEInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(
+        classes = {RappInstanceValidationHandler.class, RappStatusValidator.class, AcmPayloadValidator.class,
+                SmePayloadValidator.class, DmePayloadValidator.class})
+class RappInstanceValidationHandlerTest {
+
+    public static final String K8S_INSTANCE = "k8s-instance";
+    public static final String A1PMS_INSTANCE = "a1pms-instance";
+    public static final String PROVIDER_1 = "provider-1";
+    public static final String PROVIDER_2 = "provider-2";
+    public static final String INV_1 = "inv-1";
+    public static final String INV_2 = "inv-2";
+    public static final String SVC_API_1 = "svc-api-1";
+    public static final String SVC_API_2 = "svc-api-2";
+    public static final String PROD_INFO_1 = "prod-info-1";
+    public static final String PROD_INFO_2 = "prod-info-2";
+    public static final String CONS_INFO_1 = "cons-info-1";
+    public static final String CONS_INFO_2 = "cons-info-2";
+    public static final String INFO_CONSUMER_1 = "info-consumer-1";
+    public static final String INFO_CONSUMER_2 = "info-consumer-2";
+    public static final String INFO_PRODUCER_1 = "info-producer-1";
+    public static final String INFO_PRODUCER_2 = "info-producer-2";
+    @Autowired
+    RappInstanceValidationHandler rappValidationHandler;
+
+    @Test
+    void testrAppInstanceValidationSuccessAcmInstance() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance(K8S_INSTANCE);
+        rappInstance.setAcm(rappACMInstance);
+        assertDoesNotThrow(() -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+    }
+
+    @Test
+    void testrAppInstanceValidationSuccessSmeInstance() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(PROVIDER_1);
+        rappSMEInstance.setServiceApis(SVC_API_1);
+        rappSMEInstance.setInvokers(INV_1);
+        rappInstance.setSme(rappSMEInstance);
+        assertDoesNotThrow(() -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+    }
+
+    @Test
+    void testrAppInstanceValidationSuccessDmeInstance() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PROD_INFO_1));
+        rappDMEInstance.setInfoTypeConsumer(CONS_INFO_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+        assertDoesNotThrow(() -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+    }
+
+    @Test
+    void testAppInstanceValidationSuccessAllInstances() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance(K8S_INSTANCE);
+        rappInstance.setAcm(rappACMInstance);
+
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(PROVIDER_1);
+        rappSMEInstance.setServiceApis(SVC_API_1);
+        rappSMEInstance.setInvokers(INV_1);
+        rappInstance.setSme(rappSMEInstance);
+
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of(PROD_INFO_1));
+        rappDMEInstance.setInfoTypeConsumer(CONS_INFO_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+
+        assertDoesNotThrow(() -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+    }
+
+    @Test
+    void testrAppInstanceValidationFailureOnRappState() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance(K8S_INSTANCE);
+        rappInstance.setAcm(rappACMInstance);
+        rapp.setState(RappState.COMMISSIONED);
+
+        RappValidationException rappValidationException = assertThrows(RappValidationException.class,
+                () -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+        assertEquals("Unable to create rApp instance as rApp is not in PRIMED state",
+                rappValidationException.getMessage());
+    }
+
+    @Test
+    void testrAppInstanceValidationFailureOnAcmPayload() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappACMInstance rappACMInstance = new RappACMInstance();
+        rappACMInstance.setInstance("invalid-instance");
+        rappInstance.setAcm(rappACMInstance);
+
+        RappValidationException rappValidationException = assertThrows(RappValidationException.class,
+                () -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+        assertEquals("Invalid ACM instance in the rApp instance payload.", rappValidationException.getMessage());
+    }
+
+    @Test
+    void testrAppInstanceValidationFailureOnSmePayload() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction("invalid-provider");
+        rappSMEInstance.setServiceApis(SVC_API_1);
+        rappSMEInstance.setInvokers(INV_1);
+        rappInstance.setSme(rappSMEInstance);
+
+        RappValidationException rappValidationException = assertThrows(RappValidationException.class,
+                () -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+        assertEquals("Invalid SME provider function in the rApp instance payload.",
+                rappValidationException.getMessage());
+    }
+
+    @Test
+    void testrAppInstanceValidationFailureOnDmePayload() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappDMEInstance rappDMEInstance = new RappDMEInstance();
+        rappDMEInstance.setInfoTypesProducer(Set.of("invalid-prod-info"));
+        rappDMEInstance.setInfoTypeConsumer(CONS_INFO_1);
+        rappDMEInstance.setInfoConsumer(INFO_CONSUMER_1);
+        rappDMEInstance.setInfoProducer(INFO_PRODUCER_1);
+        rappInstance.setDme(rappDMEInstance);
+
+        RappValidationException rappValidationException = assertThrows(RappValidationException.class,
+                () -> rappValidationHandler.validateRappInstance(rapp, rappInstance));
+        assertEquals("Invalid DME info types producer in the rApp instance payload.",
+                rappValidationException.getMessage());
+    }
+
+    Rapp getRapp() {
+        RappResources rappResources = new RappResources();
+        RappResources.ACMResources acmResources =
+                RappResources.ACMResources.builder().compositionInstances(Set.of(K8S_INSTANCE, A1PMS_INSTANCE)).build();
+        rappResources.setAcm(acmResources);
+        RappResources.SMEResources smeResources =
+                RappResources.SMEResources.builder().providerFunctions(Set.of(PROVIDER_1, PROVIDER_2))
+                        .serviceApis(Set.of(SVC_API_1, SVC_API_2)).invokers(Set.of(INV_1, INV_2)).build();
+        rappResources.setSme(smeResources);
+        RappResources.DMEResources dmeResources =
+                RappResources.DMEResources.builder().producerInfoTypes(Set.of(PROD_INFO_1, PROD_INFO_2))
+                        .consumerInfoTypes(Set.of(CONS_INFO_1, CONS_INFO_2))
+                        .infoConsumers(Set.of(INFO_CONSUMER_1, INFO_CONSUMER_2))
+                        .infoProducers(Set.of(INFO_PRODUCER_1, INFO_PRODUCER_2)).build();
+        rappResources.setDme(dmeResources);
+
+        return Rapp.builder().name("").state(RappState.PRIMED).rappResources(rappResources).build();
+    }
+}
diff --git a/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidatorTest.java b/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/RappStatusValidatorTest.java
new file mode 100644 (file)
index 0000000..2a63a35
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappState;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = {RappStatusValidator.class})
+class RappStatusValidatorTest {
+
+    @Autowired
+    private RappStatusValidator rappStatusValidator;
+
+    @Test
+    void testRappStatusValidatorSuccess() {
+        Rapp rapp = Rapp.builder().state(RappState.PRIMED).build();
+        RappInstance rAppInstance = new RappInstance();
+        assertDoesNotThrow(() -> rappStatusValidator.validate(rapp, rAppInstance));
+    }
+
+    @Test
+    void testRappStatusValidatorFailure() {
+        Rapp rapp = Rapp.builder().state(RappState.COMMISSIONED).build();
+        RappInstance rAppInstance = new RappInstance();
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> rappStatusValidator.validate(rapp, rAppInstance));
+        assertEquals("Unable to create rApp instance as rApp is not in PRIMED state",
+                rappValidationException.getMessage());
+    }
+
+}
diff --git a/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidatorTest.java b/rapp-manager-models/src/test/java/org/oransc/rappmanager/models/rappinstance/validator/SmePayloadValidatorTest.java
new file mode 100644 (file)
index 0000000..2af5047
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * ============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.
+ * ============LICENSE_END========================================================================
+ *
+ */
+
+package org.oransc.rappmanager.models.rappinstance.validator;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.Set;
+import org.junit.jupiter.api.Test;
+import org.oransc.rappmanager.models.exception.RappValidationException;
+import org.oransc.rappmanager.models.rapp.Rapp;
+import org.oransc.rappmanager.models.rapp.RappResources;
+import org.oransc.rappmanager.models.rappinstance.RappInstance;
+import org.oransc.rappmanager.models.rappinstance.RappSMEInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest
+@ContextConfiguration(classes = {SmePayloadValidator.class})
+class SmePayloadValidatorTest {
+
+    public static final String PROVIDER_FUNCTION_1 = "provider-function-1";
+    public static final String SERVICE_API_1 = "service-api-1";
+    public static final String INVOKER_1 = "invoker-1";
+    @Autowired
+    private SmePayloadValidator smePayloadValidator;
+
+    @Test
+    void testSmePayloadValidatorSuccess() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(PROVIDER_FUNCTION_1);
+        rappSMEInstance.setServiceApis(SERVICE_API_1);
+        rappSMEInstance.setInvokers(INVOKER_1);
+        rappInstance.setSme(rappSMEInstance);
+        assertDoesNotThrow(() -> smePayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testSmePayloadValidatorSuccessWithNull() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(null);
+        rappSMEInstance.setServiceApis(null);
+        rappSMEInstance.setInvokers(INVOKER_1);
+        rappInstance.setSme(rappSMEInstance);
+        assertDoesNotThrow(() -> smePayloadValidator.validate(rapp, rappInstance));
+    }
+
+    @Test
+    void testSmePayloadValidatorFailureInvalidProviderFunction() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction("invalid-provider-function");
+        rappSMEInstance.setServiceApis(SERVICE_API_1);
+        rappSMEInstance.setInvokers(INVOKER_1);
+        rappInstance.setSme(rappSMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> smePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid SME provider function in the rApp instance payload.",
+                rappValidationException.getMessage());
+    }
+
+    @Test
+    void testSmePayloadValidatorFailureInvalidServiceApis() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(PROVIDER_FUNCTION_1);
+        rappSMEInstance.setServiceApis("invalid-service-api");
+        rappSMEInstance.setInvokers(INVOKER_1);
+        rappInstance.setSme(rappSMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> smePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid SME service APIs in the rApp instance payload.", rappValidationException.getMessage());
+    }
+
+    @Test
+    void testSmePayloadValidatorFailureInvalidInvokers() {
+        Rapp rapp = getRapp();
+        RappInstance rappInstance = new RappInstance();
+        RappSMEInstance rappSMEInstance = new RappSMEInstance();
+        rappSMEInstance.setProviderFunction(PROVIDER_FUNCTION_1);
+        rappSMEInstance.setServiceApis(SERVICE_API_1);
+        rappSMEInstance.setInvokers("invalid-invoker");
+        rappInstance.setSme(rappSMEInstance);
+
+        RappValidationException rappValidationException =
+                assertThrows(RappValidationException.class, () -> smePayloadValidator.validate(rapp, rappInstance));
+        assertEquals("Invalid SME invokers in the rApp instance payload.", rappValidationException.getMessage());
+    }
+
+
+    private Rapp getRapp() {
+        RappResources rappResources = new RappResources();
+        RappResources.SMEResources rappSMEResources = RappResources.SMEResources.builder().providerFunctions(
+                        Set.of(PROVIDER_FUNCTION_1, "provider-function-2")).serviceApis(Set.of(SERVICE_API_1, "service-api-2"))
+                                                              .invokers(Set.of(INVOKER_1, "invoker-2")).build();
+
+        rappResources.setSme(rappSMEResources);
+        return Rapp.builder().rappResources(rappResources).build();
+    }
+}