summaryrefslogtreecommitdiffstats
path: root/participant/participant-impl/participant-impl-kubernetes/src
diff options
context:
space:
mode:
Diffstat (limited to 'participant/participant-impl/participant-impl-kubernetes/src')
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java3
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java (renamed from participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java)2
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java3
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java3
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java62
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java4
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java2
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java3
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java7
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java130
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java122
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/CommonTestData.java152
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/ParticipantK8sParametersTest.java88
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java230
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java147
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java170
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/utils/TestUtils.java43
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json15
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties26
-rw-r--r--participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml (renamed from participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml)0
20 files changed, 1180 insertions, 32 deletions
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java
index 37ecf4e6f..5d9d203fe 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/Application.java
@@ -23,12 +23,15 @@ package org.onap.policy.clamp.controlloop.participant.kubernetes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
+import org.springframework.context.annotation.ComponentScan;
/**
* Starter.
*
*/
@SpringBootApplication
+@ComponentScan({"org.onap.policy.clamp.controlloop.participant.kubernetes",
+ "org.onap.policy.clamp.controlloop.participant.intermediary"})
@ConfigurationPropertiesScan("org.onap.policy.clamp.controlloop.participant.kubernetes.parameters")
public class Application {
/**
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java
index 3199d0cd9..94789a74f 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/BeanFactory.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/configurations/ParticipantConfig.java
@@ -31,7 +31,7 @@ import org.springframework.web.multipart.commons.CommonsMultipartResolver;
* Bean Factory class for helm client.
*/
@Configuration
-public class BeanFactory {
+public class ParticipantConfig {
@Value("${server.http-port}")
private int httpPort = 0;
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java
index 5560e47a8..23605e641 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/controller/ChartController.java
@@ -149,13 +149,12 @@ public class ChartController {
* @param name name of the chart
* @param version version of the chart
* @return Status of operation
- * @throws ServiceException in case of error.
*/
@DeleteMapping(path = "/charts/{name}/{version}")
@ApiOperation(value = "Delete the chart")
@ApiResponses(value = {@ApiResponse(code = 204, message = "Chart Deleted")})
public ResponseEntity<Object> deleteChart(@PathVariable("name") String name,
- @PathVariable("version") String version) throws ServiceException {
+ @PathVariable("version") String version) {
ChartInfo chart = chartService.getChart(name, version);
if (chart == null) {
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java
index 6257c3d19..4f654832d 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/handler/ControlLoopElementHandler.java
@@ -26,6 +26,8 @@ import java.lang.invoke.MethodHandles;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import lombok.AccessLevel;
+import lombok.Getter;
import lombok.Setter;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
@@ -57,6 +59,7 @@ public class ControlLoopElementHandler implements ControlLoopElementListener {
private ParticipantIntermediaryApi intermediaryApi;
// Map of CLElement Id and installed Helm charts
+ @Getter(AccessLevel.PACKAGE)
private final Map<UUID, ChartInfo> chartMap = new HashMap<>();
/**
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java
index 343a44617..90d7218da 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/helm/HelmClient.java
@@ -75,12 +75,33 @@ public class HelmClient {
*/
public String findChartRepository(ChartInfo chart) throws ServiceException, IOException {
updateHelmRepo();
- logger.info("Looking for helm chart {} in all the configured helm repositories", chart.getChartName());
- String repository = null;
+ String repository = verifyConfiguredRepo(chart);
+ if (repository != null) {
+ return repository;
+ }
+ var localHelmChartDir = chartStore.getAppPath(chart.getChartName(), chart.getVersion()).toString();
+ logger.info("Chart not found in helm repositories, verifying local repo {} ", localHelmChartDir);
+ if (verifyLocalHelmRepo(localHelmChartDir + "/" + chart.getChartName())) {
+ repository = localHelmChartDir;
+ }
- var process = helmRepoVerifyCommand(chart.getChartName()).start();
+ return repository;
+ }
- try (var reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+ /**
+ * Verify helm chart in configured repositories.
+ * @param chart chartInfo
+ * @return repo name
+ * @throws IOException incase of error
+ * @throws ServiceException incase of error
+ */
+ public String verifyConfiguredRepo(ChartInfo chart) throws IOException, ServiceException {
+ logger.info("Looking for helm chart {} in all the configured helm repositories", chart.getChartName());
+ String repository = null;
+ var builder = helmRepoVerifyCommand(chart.getChartName());
+ String output = executeCommand(builder);
+ try (var reader = new BufferedReader(new InputStreamReader(IOUtils.toInputStream(output,
+ StandardCharsets.UTF_8)))) {
String line = reader.readLine();
while (line != null) {
if (line.contains(chart.getChartName())) {
@@ -91,13 +112,6 @@ public class HelmClient {
line = reader.readLine();
}
}
-
- var localHelmChartDir = chartStore.getAppPath(chart.getChartName(), chart.getVersion()).toString();
- logger.info("Chart not found in helm repositories, verifying local repo {} ", localHelmChartDir);
- if (verifyLocalHelmRepo(localHelmChartDir + "/" + chart.getChartName())) {
- repository = localHelmChartDir;
- }
-
return repository;
}
@@ -111,7 +125,13 @@ public class HelmClient {
executeCommand(prepareUnInstallCommand(chart));
}
- static String executeCommand(ProcessBuilder processBuilder) throws ServiceException {
+ /**
+ * Execute helm cli bash commands .
+ * @param processBuilder processbuilder
+ * @return string output
+ * @throws ServiceException incase of error.
+ */
+ public static String executeCommand(ProcessBuilder processBuilder) throws ServiceException {
var commandStr = toString(processBuilder);
try {
@@ -123,13 +143,15 @@ public class HelmClient {
var error = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);
throw new ServiceException("Command execution failed: " + commandStr + " " + error);
}
+
var output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);
logger.debug("Command <{}> execution, output: {}", commandStr, output);
return output;
+
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new ServiceException("Failed to execute the Command: " + commandStr + ", the command was interrupted",
- ie);
+ ie);
} catch (Exception exc) {
throw new ServiceException("Failed to execute the Command: " + commandStr, exc);
}
@@ -140,12 +162,12 @@ public class HelmClient {
// @formatter:off
List<String> helmArguments = new ArrayList<>(
Arrays.asList(
- "helm",
- "install", chart.getReleaseName(), chart.getRepository() + "/" + chart.getChartName(),
- "--version", chart.getVersion(),
- "--namespace", chart.getNamespace()
+ "helm",
+ "install", chart.getReleaseName(), chart.getRepository() + "/" + chart.getChartName(),
+ "--version", chart.getVersion(),
+ "--namespace", chart.getNamespace()
)
- );
+ );
// @formatter:on
// Verify if values.yaml available for the chart
@@ -176,9 +198,7 @@ public class HelmClient {
private void updateHelmRepo() throws ServiceException {
logger.info("Updating local helm repositories before verifying the chart");
- List<String> helmArguments = Arrays.asList("helm", "repo", "update");
-
- executeCommand(new ProcessBuilder().command(helmArguments));
+ executeCommand(new ProcessBuilder().command("helm", "repo", "update"));
logger.debug("Helm repositories updated successfully");
}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java
index c86bff58a..7f46bbde5 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/models/ChartList.java
@@ -18,7 +18,7 @@
package org.onap.policy.clamp.controlloop.participant.kubernetes.models;
-import java.util.Collection;
+import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@@ -27,5 +27,5 @@ import lombok.Setter;
@Setter
@Builder
public class ChartList {
- private Collection<ChartInfo> charts;
+ private List<ChartInfo> charts;
}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java
index a5731da74..3b2b3732b 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/parameters/ParticipantK8sParameters.java
@@ -20,13 +20,13 @@
package org.onap.policy.clamp.controlloop.participant.kubernetes.parameters;
+import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantIntermediaryParameters;
import org.onap.policy.clamp.controlloop.participant.intermediary.parameters.ParticipantParameters;
-import org.onap.policy.common.parameters.annotations.Valid;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java
index 29a49a9ff..adb6cf0d1 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartService.java
@@ -53,9 +53,8 @@ public class ChartService {
* @param name name of the app
* @param version version of the app
* @return chart
- * @throws ServiceException in case of error.
*/
- public ChartInfo getChart(String name, String version) throws ServiceException {
+ public ChartInfo getChart(String name, String version) {
return chartStore.getChart(name, version);
}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java
index dcdff62f5..03b35161d 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java
+++ b/participant/participant-impl/participant-impl-kubernetes/src/main/java/org/onap/policy/clamp/controlloop/participant/kubernetes/service/ChartStore.java
@@ -33,6 +33,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import lombok.AccessLevel;
+import lombok.Getter;
import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters;
@@ -52,9 +54,8 @@ public class ChartStore {
private final ParticipantK8sParameters participantK8sParameters;
- /**
- * The chartStore map contains chart name as key & ChartInfo as value.
- */
+ // ChartStore map contains chart name as key & ChartInfo as value.
+ @Getter(AccessLevel.PACKAGE)
private Map<String, ChartInfo> localChartMap = new ConcurrentHashMap<>();
/**
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java
new file mode 100644
index 000000000..f3d27a63c
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/handler/ControlLoopElementHandlerTest.java
@@ -0,0 +1,130 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.handler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopOrderedState;
+import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopState;
+import org.onap.policy.clamp.controlloop.participant.intermediary.api.ParticipantIntermediaryApi;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartService;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.utils.TestUtils;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+
+@ExtendWith(SpringExtension.class)
+class ControlLoopElementHandlerTest {
+
+ private static final Coder CODER = new StandardCoder();
+ private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
+ private static final String KEY_NAME = "org.onap.domain.database.HelloWorld_K8SMicroserviceControlLoopElement";
+ private static List<ChartInfo> charts;
+ private static ToscaServiceTemplate toscaServiceTemplate;
+
+
+ @InjectMocks
+ private ControlLoopElementHandler controlLoopElementHandler = new ControlLoopElementHandler();
+
+ @Mock
+ private ChartService chartService;
+
+ @Mock
+ private ParticipantIntermediaryApi participantIntermediaryApi;
+
+ @BeforeAll
+ static void init() throws CoderException {
+ charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
+ toscaServiceTemplate = TestUtils.testControlLoopRead();
+ }
+
+
+ @Test
+ void test_ControlLoopElementStateChange() throws ServiceException {
+ UUID controlLoopElementId1 = UUID.randomUUID();
+ UUID controlLoopElementId2 = UUID.randomUUID();
+
+ controlLoopElementHandler.getChartMap().put(controlLoopElementId1, charts.get(0));
+ controlLoopElementHandler.getChartMap().put(controlLoopElementId2, charts.get(1));
+
+ doNothing().when(chartService).uninstallChart(charts.get(0));
+
+ controlLoopElementHandler.controlLoopElementStateChange(controlLoopElementId1, ControlLoopState.PASSIVE,
+ ControlLoopOrderedState.UNINITIALISED);
+
+ doThrow(new ServiceException("Error uninstalling the chart")).when(chartService)
+ .uninstallChart(charts.get(0));
+
+ assertDoesNotThrow(() -> controlLoopElementHandler
+ .controlLoopElementStateChange(controlLoopElementId1, ControlLoopState.PASSIVE,
+ ControlLoopOrderedState.UNINITIALISED));
+
+ assertDoesNotThrow(() -> controlLoopElementHandler
+ .controlLoopElementStateChange(controlLoopElementId1, ControlLoopState.PASSIVE,
+ ControlLoopOrderedState.RUNNING));
+
+ }
+
+ @Test
+ void test_ControlLoopElementUpdate() throws PfModelException, IOException, ServiceException {
+
+ UUID elementId1 = UUID.randomUUID();
+ ControlLoopElement element = new ControlLoopElement();
+ element.setId(elementId1);
+ element.setDefinition(new ToscaConceptIdentifier(KEY_NAME, "1.0.1"));
+ element.setOrderedState(ControlLoopOrderedState.PASSIVE);
+
+ controlLoopElementHandler.controlLoopElementUpdate(element, toscaServiceTemplate);
+
+ assertThat(controlLoopElementHandler.getChartMap()).hasSize(1).containsKey(elementId1);
+
+ doThrow(new ServiceException("Error installing the chart")).when(chartService)
+ .installChart(Mockito.any());
+
+ UUID elementId2 = UUID.randomUUID();
+ element.setId(elementId2);
+ controlLoopElementHandler.controlLoopElementUpdate(element, toscaServiceTemplate);
+
+ assertThat(controlLoopElementHandler.getChartMap().containsKey(elementId2)).isFalse();
+ }
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java
new file mode 100644
index 000000000..5f8b7dc78
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/helm/HelmClientTest.java
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.helm;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mockStatic;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartStore;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+
+@ExtendWith(SpringExtension.class)
+class HelmClientTest {
+
+ private static final Coder CODER = new StandardCoder();
+ private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
+ private static List<ChartInfo> charts;
+
+ @InjectMocks
+ @Spy
+ private HelmClient helmClient = new HelmClient();
+
+ @Mock
+ ChartStore chartStore;
+
+ private static MockedStatic<HelmClient> mockedClient;
+
+ @BeforeAll
+ static void init() throws CoderException {
+ charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
+ //Mock static method for bash command execution
+ mockedClient = mockStatic(HelmClient.class);
+ }
+
+ @Test
+ void test_installChart() throws IOException {
+ mockedClient.when(() -> HelmClient.executeCommand(any()))
+ .thenReturn("success");
+ doReturn(new File("/target/tmp/override.yaml")).when(chartStore)
+ .getOverrideFile(any());
+ assertDoesNotThrow(() -> helmClient.installChart(charts.get(0)));
+ }
+
+ @Test
+ void test_findChartRepository() throws IOException, ServiceException {
+ mockedClient.when(() -> HelmClient.executeCommand(Mockito.any()))
+ .thenReturn("nginx-stable/nginx-ingress\t0.9.3\t1.11.3"
+ + " \tNGINX Ingress Controller");
+ String configuredRepo = helmClient.findChartRepository(charts.get(1));
+
+ assertThat(configuredRepo).isEqualTo("nginx-stable");
+
+ doReturn(Path.of("/target/tmp/dummyChart/1.0")).when(chartStore).getAppPath(charts.get(1).getChartName(),
+ charts.get(1).getVersion());
+
+ doReturn(null).when(helmClient).verifyConfiguredRepo(charts.get(1));
+
+ String localRepoName = helmClient.findChartRepository(charts.get(1));
+ assertNotNull(localRepoName);
+ assertThat(localRepoName).endsWith(charts.get(0).getVersion());
+ }
+
+ @Test
+ void test_uninstallChart() throws ServiceException {
+ helmClient.uninstallChart(charts.get(0));
+ mockedClient.when(() -> HelmClient.executeCommand(any())).thenThrow(new ServiceException("error in execution"));
+
+ assertThatThrownBy(() -> helmClient.uninstallChart(charts.get(0)))
+ .isInstanceOf(ServiceException.class);
+ }
+
+ @Test
+ void test_verifyConfiguredRepoForInvalidChart() throws IOException, ServiceException {
+ mockedClient.when(() -> HelmClient.executeCommand(Mockito.any()))
+ .thenReturn("");
+ String configuredRepo = helmClient.verifyConfiguredRepo(charts.get(1));
+ assertNull(configuredRepo);
+ }
+
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/CommonTestData.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/CommonTestData.java
new file mode 100644
index 000000000..d8d477d1b
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/CommonTestData.java
@@ -0,0 +1,152 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.parameters;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import org.onap.policy.common.endpoints.parameters.TopicParameters;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
+
+public class CommonTestData {
+
+ public static final String PARTICIPANT_GROUP_NAME = "ControlLoopParticipantGroup";
+ public static final String DESCRIPTION = "Participant description";
+ public static final long TIME_INTERVAL = 2000;
+ public static final List<TopicParameters> TOPIC_PARAMS = Arrays.asList(getTopicParams());
+ public static final Coder CODER = new StandardCoder();
+
+
+ /**
+ * Get ParticipantK8sParameters.
+ *
+ * @return ParticipantK8sParameters
+ */
+ public ParticipantK8sParameters getParticipantK8sParameters() {
+ try {
+ return CODER.convert(getParticipantK8sParametersMap(PARTICIPANT_GROUP_NAME),
+ ParticipantK8sParameters.class);
+ } catch (final CoderException e) {
+ throw new RuntimeException("cannot create ParticipantK8sParameters from map", e);
+ }
+ }
+
+ /**
+ * Returns a property map for a ParticipantK8sParameters map for test cases.
+ *
+ * @param name name of the parameters
+ *
+ * @return a property map suitable for constructing an object
+ */
+ public Map<String, Object> getParticipantK8sParametersMap(final String name) {
+ final Map<String, Object> map = new TreeMap<>();
+
+ map.put("name", name);
+ map.put("intermediaryParameters", getIntermediaryParametersMap(false));
+ map.put("localChartDirectory", getLocalChartDir());
+ map.put("infoFileName", getInfoFileName());
+ return map;
+ }
+
+
+ /**
+ * Returns string value of local chart Directory.
+ * @return a string value
+ */
+ public String getLocalChartDir() {
+ return "/var/helm-manager/local-charts";
+ }
+
+ /**
+ * Returns string value of Info file name.
+ * @return string value
+ */
+ public String getInfoFileName() {
+ return "CHART-INFO.json";
+ }
+
+
+
+ /**
+ * Returns a property map for a intermediaryParameters map for test cases.
+ *
+ * @param isEmpty boolean value to represent that object created should be empty or not
+ * @return a property map suitable for constructing an object
+ */
+ public Map<String, Object> getIntermediaryParametersMap(final boolean isEmpty) {
+ final Map<String, Object> map = new TreeMap<>();
+ if (!isEmpty) {
+ map.put("name", "Participant parameters");
+ map.put("reportingTimeInterval", TIME_INTERVAL);
+ map.put("description", DESCRIPTION);
+ map.put("participantId", getParticipantId());
+ map.put("participantType", getParticipantId());
+ map.put("clampControlLoopTopics", getTopicParametersMap(false));
+ }
+
+ return map;
+ }
+
+ /**
+ * Returns participantId for test cases.
+ *
+ * @return participant Id
+ */
+ public static ToscaConceptIdentifier getParticipantId() {
+ final ToscaConceptIdentifier participantId = new ToscaConceptIdentifier();
+ participantId.setName("K8sParticipant0");
+ participantId.setVersion("1.0.0");
+ return participantId;
+ }
+
+
+ /**
+ * Returns a property map for a TopicParameters map for test cases.
+ *
+ * @param isEmpty boolean value to represent that object created should be empty or not
+ * @return a property map suitable for constructing an object
+ */
+ public Map<String, Object> getTopicParametersMap(final boolean isEmpty) {
+ final Map<String, Object> map = new TreeMap<>();
+ if (!isEmpty) {
+ map.put("topicSources", TOPIC_PARAMS);
+ map.put("topicSinks", TOPIC_PARAMS);
+ }
+ return map;
+ }
+
+ /**
+ * Returns topic parameters for test cases.
+ *
+ * @return topic parameters
+ */
+ public static TopicParameters getTopicParams() {
+ final TopicParameters topicParams = new TopicParameters();
+ topicParams.setTopic("POLICY-CLRUNTIME-PARTICIPANT");
+ topicParams.setTopicCommInfrastructure("dmaap");
+ topicParams.setServers(Arrays.asList("localhost"));
+ return topicParams;
+ }
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/ParticipantK8sParametersTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/ParticipantK8sParametersTest.java
new file mode 100644
index 000000000..177d7bc23
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/parameters/ParticipantK8sParametersTest.java
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.parameters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Set;
+import javax.validation.ConstraintViolation;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+import org.junit.jupiter.api.Test;
+
+class ParticipantK8sParametersTest {
+
+ private CommonTestData commonTestData = new CommonTestData();
+ private ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
+
+ @Test
+ void testParticipantPolicyParameters() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ assertThat(validatorFactory.getValidator().validate(participantParameters)).isNullOrEmpty();
+ }
+
+ @Test
+ void testParticipantK8sParameters_NullTopicSinks() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.getIntermediaryParameters().getClampControlLoopTopics().setTopicSinks(null);
+ assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty();
+ }
+
+ @Test
+ void testParticipantK8sParameters_NullTopicSources() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.getIntermediaryParameters().getClampControlLoopTopics().setTopicSources(null);
+ assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty();
+ }
+
+ @Test
+ void testParticipantK8sParameters_BlankLocalChartDirParameter() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.setLocalChartDirectory(" ");
+ Set<ConstraintViolation<ParticipantK8sParameters>> violations = validatorFactory.getValidator()
+ .validate(participantParameters);
+ assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void testParticipantK8sParameters_BlankInfoFileParameter() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.setInfoFileName("");
+ Set<ConstraintViolation<ParticipantK8sParameters>> violations = validatorFactory.getValidator()
+ .validate(participantParameters);
+ assertThat(violations.size()).isEqualTo(1);
+ }
+
+ @Test
+ void testNoIntermediaryParameters() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.setIntermediaryParameters(null);
+ assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty();
+ }
+
+ @Test
+ void testNoParticipantId() {
+ final ParticipantK8sParameters participantParameters = commonTestData.getParticipantK8sParameters();
+ participantParameters.getIntermediaryParameters().setParticipantId(null);
+ assertThat(validatorFactory.getValidator().validate(participantParameters)).isNotEmpty();
+ }
+
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java
new file mode 100644
index 000000000..1a1bdae5b
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/rest/ChartControllerTest.java
@@ -0,0 +1,230 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.rest;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.when;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.io.File;
+import java.util.List;
+import org.json.JSONObject;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.controller.ChartController;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.service.ChartService;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.http.MediaType;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.RequestBuilder;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+
+@ExtendWith(SpringExtension.class)
+@WebMvcTest(value = ChartController.class)
+@EnableConfigurationProperties(value = ParticipantK8sParameters.class)
+class ChartControllerTest {
+
+ private static final Coder CODER = new StandardCoder();
+ private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
+ private static List<ChartInfo> charts;
+ private static String DEFAULT_CHART_URL = "/helm/charts";
+ private static String INSTALL_CHART_URL = "/helm/install";
+ private static String UNINSTALL_CHART_URL = "/helm/uninstall/";
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @MockBean
+ private ChartService chartService;
+
+ @Autowired
+ private WebApplicationContext context;
+
+ /**
+ * Read input chart info json.
+ * @throws Exception incase of error.
+ */
+ @BeforeAll
+ static void setupParams() throws CoderException {
+ charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
+ }
+
+ /**
+ * Mock service layer in Controller.
+ * @throws Exception incase of error.
+ */
+ @BeforeEach
+ void mockServiceClass() {
+ when(chartService.getAllCharts()).thenReturn(charts);
+ when(chartService.getChart(charts.get(0).getChartName(), charts.get(0).getVersion()))
+ .thenReturn(charts.get(0));
+
+ this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
+ }
+
+ /**
+ * Test endpoint for retrieving all charts.
+ * @throws Exception incase of error.
+ */
+ @Test
+ void retrieveAllCharts() throws Exception {
+ RequestBuilder requestBuilder;
+ requestBuilder = MockMvcRequestBuilders.get(DEFAULT_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
+ .andExpect(jsonPath("$.charts.[0].chartName", is("HelloWorld")));
+ }
+
+ /**
+ * Test endpoint for installing a chart.
+ * @throws Exception incase of error.
+ */
+ @Test
+ void installChart() throws Exception {
+ RequestBuilder requestBuilder;
+
+ //Mocking successful installation for void install method
+ doNothing().when(chartService).installChart(charts.get(0));
+
+ requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE)
+ .content(getInstallationJson(charts.get(0).getChartName(), charts.get(0).getVersion()))
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isCreated());
+
+ //Install Invalid chart, expects HTTP status NOT_FOUND
+ requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE)
+ .content(getInstallationJson("invalidName", "invalidVersion"))
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
+ }
+
+ /**
+ * Test endpoint for uninstalling a chart.
+ * @throws Exception incase of error.
+ */
+ @Test
+ void uninstallChart() throws Exception {
+ RequestBuilder requestBuilder;
+
+ //Mocking successful scenario for void uninstall method
+ doNothing().when(chartService).uninstallChart(charts.get(0));
+
+ requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0).getChartName()
+ + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isNoContent());
+
+ //Invalid chart
+ requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + "invalidName"
+ + "/" + "invalidVersion").accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
+ }
+
+ /**
+ * Test endpoint for chart onboarding.
+ * @throws Exception incase of error.
+ */
+ @Test
+ void onboardChart() throws Exception {
+ RequestBuilder requestBuilder;
+ MockMultipartFile chartFile = new MockMultipartFile("chart", "hello.tgz",
+ MediaType.TEXT_PLAIN_VALUE, "Dummy data".getBytes());
+
+ MockMultipartFile overrideFile = new MockMultipartFile("values", "values.yaml",
+ MediaType.TEXT_PLAIN_VALUE, "Dummy data".getBytes());
+
+ //Mocking successful scenario for void uninstall method
+ when(chartService.saveChart(charts.get(0), chartFile, null)).thenReturn(charts.get(0));
+
+ requestBuilder = MockMvcRequestBuilders.multipart(DEFAULT_CHART_URL)
+ .file(chartFile).file(overrideFile).param("info", getChartInfoJson());
+
+ mockMvc.perform(requestBuilder).andExpect(status().isOk());
+ }
+
+ /**
+ * Test endpoint for deleting a chart.
+ * @throws Exception incase of error.
+ */
+ @Test
+ void deleteChart() throws Exception {
+ RequestBuilder requestBuilder;
+
+ //Mocking successful scenario for void uninstall method
+ doNothing().when(chartService).deleteChart(charts.get(0));
+
+ requestBuilder = MockMvcRequestBuilders.delete(DEFAULT_CHART_URL + "/" + charts.get(0).getChartName()
+ + "/" + charts.get(0).getVersion()).accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isNoContent());
+ //Invalid chart
+ requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + "invalidName"
+ + "/" + "invalidVersion").accept(MediaType.APPLICATION_JSON_VALUE)
+ .contentType(MediaType.APPLICATION_JSON_VALUE);
+
+ mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
+
+ }
+
+ private String getInstallationJson(String name, String version) {
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("name", name);
+ jsonObj.put("version", version);
+ return jsonObj.toString();
+ }
+
+ private String getChartInfoJson() {
+ JSONObject jsonObj = new JSONObject();
+ jsonObj.put("chartName", charts.get(0).getChartName());
+ jsonObj.put("version", charts.get(0).getVersion());
+ jsonObj.put("namespace", charts.get(0).getNamespace());
+ jsonObj.put("repository", charts.get(0).getRepository());
+ jsonObj.put("releaseName", charts.get(0).getReleaseName());
+ return jsonObj.toString();
+ }
+
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java
new file mode 100644
index 000000000..957a69a08
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartServiceTest.java
@@ -0,0 +1,147 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.helm.HelmClient;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+class ChartServiceTest {
+
+ private static final Coder CODER = new StandardCoder();
+ private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
+ private static List<ChartInfo> charts;
+
+ @InjectMocks
+ @Spy
+ private ChartService chartService = new ChartService();
+
+ @Mock
+ private ChartStore chartStore;
+
+ @Mock
+ private HelmClient helmClient;
+
+ @BeforeAll
+ static void init() throws CoderException {
+ charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
+ }
+
+ @Test
+ void test_getAllCharts() {
+ assertThat(chartService.getAllCharts()).isEmpty();
+
+ doReturn(charts).when(chartStore).getAllCharts();
+ Collection<ChartInfo> result = chartService.getAllCharts();
+ assertNotNull(result);
+ assertThat(result).containsAll(charts);
+ }
+
+ @Test
+ void test_getChart() {
+ assertNull(chartService.getChart("dummyName", "dummyversion"));
+
+ doReturn(charts.get(0)).when(chartStore).getChart(any(), any());
+ ChartInfo chart = chartService.getChart(charts.get(0).getChartName(),
+ charts.get(0).getVersion());
+ assertNotNull(chart);
+ assertThat(chart.getNamespace()).isEqualTo(charts.get(0).getNamespace());
+ }
+
+ @Test
+ void test_saveChart() throws IOException, ServiceException {
+ doThrow(IOException.class).when(chartStore).saveChart(charts.get(0), null, null);
+ assertThatThrownBy(() -> chartService.saveChart(charts.get(0), null, null))
+ .isInstanceOf(IOException.class);
+
+ MockMultipartFile mockChartFile = new MockMultipartFile("chart", "dummy".getBytes());
+ MockMultipartFile mockOverrideFile = new MockMultipartFile("override", "dummy".getBytes());
+
+ doReturn(charts.get(0)).when(chartStore).saveChart(any(), any(), any());
+
+ ChartInfo chart = chartService.saveChart(charts.get(0), mockChartFile, mockOverrideFile);
+ assertNotNull(chart);
+ assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName());
+
+ }
+
+ @Test
+ void test_installChart() throws IOException, ServiceException {
+ assertDoesNotThrow(() -> chartService.installChart(charts.get(0)));
+ doThrow(ServiceException.class).when(helmClient).installChart(any());
+ assertThatThrownBy(() -> chartService.installChart(charts.get(0))).isInstanceOf(ServiceException.class);
+
+ doReturn("dummyRepoName").when(chartService).findChartRepo(any());
+ doNothing().when(helmClient).installChart(any());
+ chartService.installChart(charts.get(1));
+ assertEquals("dummyRepoName", charts.get(1).getRepository());
+
+ ChartInfo testChart = charts.get(1);
+ testChart.setRepository(null);
+ doReturn(null).when(chartService).findChartRepo(any());
+ chartService.installChart(charts.get(1));
+ }
+
+ @Test
+ void test_UninstallChart() throws ServiceException {
+ assertDoesNotThrow(() -> chartService.uninstallChart(charts.get(0)));
+ doThrow(ServiceException.class).when(helmClient).uninstallChart(any());
+ assertThatThrownBy(() -> chartService.uninstallChart(charts.get(0))).isInstanceOf(ServiceException.class);
+ }
+
+ @Test
+ void test_findChartRepo() throws IOException, ServiceException {
+ assertDoesNotThrow(() -> chartService.findChartRepo(charts.get(0)));
+ doReturn("dummyRepoName").when(helmClient).findChartRepository(any());
+ assertEquals("dummyRepoName", chartService.findChartRepo(charts.get(1)));
+
+ doThrow(ServiceException.class).when(helmClient).findChartRepository(any());
+ assertThatThrownBy(() -> chartService.findChartRepo(charts.get(0))).isInstanceOf(ServiceException.class);
+ }
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java
new file mode 100644
index 000000000..2d05a7a0e
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/service/ChartStoreTest.java
@@ -0,0 +1,170 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assert.assertNull;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.exception.ServiceException;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartInfo;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.models.ChartList;
+import org.onap.policy.clamp.controlloop.participant.kubernetes.parameters.ParticipantK8sParameters;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.util.FileSystemUtils;
+
+
+@ExtendWith(MockitoExtension.class)
+@MockitoSettings(strictness = Strictness.LENIENT)
+class ChartStoreTest {
+
+ private static final Coder CODER = new StandardCoder();
+ private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
+ private static List<ChartInfo> charts;
+
+ @Mock
+ private ParticipantK8sParameters parameters;
+
+ private ChartStore chartStore;
+
+
+ @BeforeAll
+ static void init() throws CoderException {
+ charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
+ }
+
+ //Overriding the local chart dir parameter to a temp folder under target for testing java FILE IO operations.
+ @BeforeEach
+ void setup() {
+ Mockito.doReturn("target/tmp/").when(parameters).getLocalChartDirectory();
+ Mockito.doReturn("info.json").when(parameters).getInfoFileName();
+ chartStore = new ChartStore(parameters);
+ }
+
+ //Clean up the 'tmp' dir after each test case.
+ @AfterEach
+ void cleanUp() throws IOException {
+ FileSystemUtils.deleteRecursively(Path.of(parameters.getLocalChartDirectory()));
+ chartStore.getLocalChartMap().clear();
+ }
+
+ @Test
+ void test_getHelmChartFile() {
+ File file = chartStore.getHelmChartFile(charts.get(0));
+ assertNotNull(file);
+ assertThat(file.getPath()).endsWith(charts.get(0).getChartName());
+ }
+
+ @Test
+ void test_getOverrideFile() {
+ File file = chartStore.getOverrideFile(charts.get(0));
+ assertNotNull(file);
+ assertThat(file.getPath()).endsWith("values.yaml");
+ }
+
+ @Test
+ void test_saveChart() throws IOException, ServiceException {
+ MockMultipartFile mockChartFile = new MockMultipartFile("chart", "dummy".getBytes());
+ MockMultipartFile mockOverrideFile = new MockMultipartFile("override", "dummy".getBytes());
+ ChartInfo testChart = charts.get(0);
+ testChart.setChartName("testChart");
+ ChartInfo result = chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile);
+
+ assertThat(result.getChartName()).isEqualTo("testChart");
+ assertThat(chartStore.getLocalChartMap()).hasSize(1);
+
+ assertThatThrownBy(() -> chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile))
+ .isInstanceOf(ServiceException.class);
+ }
+
+
+ @Test
+ void test_getChart() {
+ assertNull(chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion()));
+ chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(),
+ charts.get(0));
+ ChartInfo chart = chartStore.getChart(charts.get(0).getChartName(), charts.get(0).getVersion());
+ assertThat(chart.getChartName()).isEqualTo(charts.get(0).getChartName());
+ }
+
+ @Test
+ void test_getAllChart() {
+ // When the chart store is empty before adding any charts
+ assertThat(chartStore.getAllCharts()).isEmpty();
+
+ for (ChartInfo chart : charts) {
+ chartStore.getLocalChartMap().put(chart.getChartName() + "_" + chart.getVersion(), chart);
+ }
+ List<ChartInfo> retrievedChartList = chartStore.getAllCharts();
+ assertThat(retrievedChartList).isNotEmpty();
+ assertThat(retrievedChartList.size()).isEqualTo(charts.size());
+ }
+
+ @Test
+ void test_deleteChart() {
+ chartStore.getLocalChartMap().put(charts.get(0).getChartName() + "_" + charts.get(0).getVersion(),
+ charts.get(0));
+ assertThat(chartStore.getLocalChartMap()).hasSize(1);
+ chartStore.deleteChart(charts.get(0));
+ assertThat(chartStore.getLocalChartMap()).isEmpty();
+ }
+
+ @Test
+ void test_getAppPath() {
+ Path path = chartStore.getAppPath(charts.get(0).getChartName(), charts.get(0).getVersion());
+ assertNotNull(path);
+ assertThat(path.toString()).endsWith(charts.get(0).getVersion());
+ assertThat(path.toString()).startsWith("target");
+ }
+
+ @Test
+ void test_chartSoreInstantiationWithExistingChartFiles() throws IOException, ServiceException {
+ MockMultipartFile mockChartFile = new MockMultipartFile("HelmChartFile", "dummyData".getBytes());
+ MockMultipartFile mockOverrideFile = new MockMultipartFile("overrideFile.yaml", "dummyData".getBytes());
+ ChartInfo testChart = charts.get(0);
+ testChart.setChartName("dummyChart");
+
+ //Creating a dummy chart in local dir.
+ chartStore.saveChart(charts.get(0), mockChartFile, mockOverrideFile);
+
+ //Instantiating a new chartStore object with pre available chart in local.
+ ChartStore chartStore2 = new ChartStore(parameters);
+ assertThat(chartStore2.getLocalChartMap()).hasSize(1).containsKey("dummyChart_" + charts.get(0).getVersion());
+ }
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/utils/TestUtils.java b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/utils/TestUtils.java
new file mode 100644
index 000000000..8585e9d11
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/java/org.onap.policy.clamp.controlloop.participant.kubernetes/utils/TestUtils.java
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.clamp.controlloop.participant.kubernetes.utils;
+
+import org.onap.policy.common.utils.coder.YamlJsonTranslator;
+import org.onap.policy.common.utils.resources.ResourceUtils;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
+
+public class TestUtils {
+
+ private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator();
+ private static final String TOSCA_TEMPLATE_YAML = "src/test/resources/servicetemplates/KubernetesHelm.yaml";
+
+
+ public static ToscaServiceTemplate testControlLoopRead() {
+ return testControlLoopYamlSerialization(TOSCA_TEMPLATE_YAML);
+ }
+
+
+ private static ToscaServiceTemplate testControlLoopYamlSerialization(String controlLoopFilePath) {
+ String controlLoopString = ResourceUtils.getResourceAsString(controlLoopFilePath);
+ ToscaServiceTemplate serviceTemplate = yamlTranslator.fromYaml(controlLoopString, ToscaServiceTemplate.class);
+ return serviceTemplate;
+ }
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json
new file mode 100644
index 000000000..4e355c38e
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/ChartList.json
@@ -0,0 +1,15 @@
+{
+ "charts" : [
+ {
+ "chartName" : "HelloWorld",
+ "version" : "1.0",
+ "namespace" : "onap",
+ "repository" : "chartMuseum"
+ },
+ {
+ "chartName" : "nginx",
+ "version" : "1.1",
+ "namespace" : "onap"
+ }
+ ]
+}
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties
new file mode 100644
index 000000000..188623af0
--- /dev/null
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/application_test.properties
@@ -0,0 +1,26 @@
+spring.security.user.name=healthcheck
+spring.security.user.password=zb!XztG34
+
+server.servlet.context-path=/onap/participantsim
+server.error.path=/error
+server.http-port=8083
+
+participant.name=ControlLoopParticipant Kubernetes Test
+participant.intermediaryParameters.name=Participant parameters
+participant.intermediaryParameters.reportingTimeInterval=120000
+participant.intermediaryParameters.description=Participant Description
+participant.intermediaryParameters.participantId.name=K8sParticipant0
+participant.intermediaryParameters.participantId.version=1.0.0
+participant.intermediaryParameters.participantType.name=org.onap.k8s.controlloop.K8SControlLoopParticipant
+participant.intermediaryParameters.participantType.version=2.3.4
+participant.intermediaryParameters.clampControlLoopTopics.name=ControlLoop Topics
+participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].topic=POLICY-CLRUNTIME-PARTICIPANT
+participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].servers[0]=localhost
+participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].topicCommInfrastructure=dmaap
+participant.intermediaryParameters.clampControlLoopTopics.topicSources[0].fetchTimeout=15000
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topic=POLICY-CLRUNTIME-PARTICIPANT
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].servers[0]=localhost
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[0].topicCommInfrastructure=dmaap
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topic=POLICY-NOTIFICATION
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].servers[0]=localhost
+participant.intermediaryParameters.clampControlLoopTopics.topicSinks[1].topicCommInfrastructure=dmaap
diff --git a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml
index 3212b5ad2..3212b5ad2 100644
--- a/participant/participant-impl/participant-impl-kubernetes/src/test/resources/KubernetesHelm.yaml
+++ b/participant/participant-impl/participant-impl-kubernetes/src/test/resources/servicetemplates/KubernetesHelm.yaml