73c5c98a17ac185012149fd0c7ba342dd8c4c967
[policy/clamp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2022 Nordix Foundation.
4  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.clamp.acm.participant.kubernetes.rest;
23
24 import static org.hamcrest.CoreMatchers.is;
25 import static org.mockito.Mockito.doNothing;
26 import static org.mockito.Mockito.when;
27 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
28 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
29 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
30
31 import java.io.File;
32 import java.io.IOException;
33 import java.nio.charset.StandardCharsets;
34 import java.util.List;
35 import org.apache.commons.io.FileUtils;
36 import org.json.JSONObject;
37 import org.junit.jupiter.api.BeforeAll;
38 import org.junit.jupiter.api.BeforeEach;
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.api.extension.ExtendWith;
41 import org.onap.policy.clamp.acm.participant.kubernetes.controller.ChartController;
42 import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartInfo;
43 import org.onap.policy.clamp.acm.participant.kubernetes.models.ChartList;
44 import org.onap.policy.clamp.acm.participant.kubernetes.parameters.ParticipantK8sParameters;
45 import org.onap.policy.clamp.acm.participant.kubernetes.service.ChartService;
46 import org.onap.policy.common.utils.coder.Coder;
47 import org.onap.policy.common.utils.coder.CoderException;
48 import org.onap.policy.common.utils.coder.StandardCoder;
49 import org.springframework.beans.factory.annotation.Autowired;
50 import org.springframework.boot.context.properties.EnableConfigurationProperties;
51 import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
52 import org.springframework.boot.test.mock.mockito.MockBean;
53 import org.springframework.http.MediaType;
54 import org.springframework.mock.web.MockMultipartFile;
55 import org.springframework.test.context.junit.jupiter.SpringExtension;
56 import org.springframework.test.web.servlet.MockMvc;
57 import org.springframework.test.web.servlet.RequestBuilder;
58 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
59 import org.springframework.test.web.servlet.setup.MockMvcBuilders;
60 import org.springframework.web.context.WebApplicationContext;
61
62
63 @ExtendWith(SpringExtension.class)
64 @WebMvcTest(value = ChartController.class, properties = "chart.api.enabled=true")
65 @EnableConfigurationProperties(value = ParticipantK8sParameters.class)
66 class ChartControllerTest {
67
68     private static final Coder CODER = new StandardCoder();
69     private static final String CHART_INFO_YAML = "src/test/resources/ChartList.json";
70     private static List<ChartInfo> charts;
71     private static String RETRIEVE_CHART_URL = "/helm/charts";
72     private static String INSTALL_CHART_URL = "/helm/install";
73     private static String UNINSTALL_CHART_URL = "/helm/uninstall/";
74     private static String ONBOARD_CHART_URL = "/helm/onboard/chart";
75     private static String DELETE_CHART_URL = "/helm/chart";
76     private static String CONFIGURE_REPO_URL = "/helm/repo";
77
78     @Autowired
79     private MockMvc mockMvc;
80
81     @MockBean
82     private ChartService chartService;
83
84     @Autowired
85     private WebApplicationContext context;
86
87     /**
88      * Read input chart info json.
89      * @throws Exception incase of error.
90      */
91     @BeforeAll
92     static void setupParams() throws CoderException {
93         charts = CODER.decode(new File(CHART_INFO_YAML), ChartList.class).getCharts();
94     }
95
96     /**
97      * Mock service layer in Controller.
98      * @throws Exception incase of error.
99      */
100     @BeforeEach
101     void mockServiceClass() {
102         when(chartService.getAllCharts()).thenReturn(charts);
103         when(chartService.getChart(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion()))
104             .thenReturn(charts.get(0));
105
106         this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
107     }
108
109     /**
110      * Test endpoint for retrieving all charts.
111      * @throws Exception incase of error.
112      */
113     @Test
114     void retrieveAllCharts() throws Exception {
115         RequestBuilder requestBuilder;
116         requestBuilder = MockMvcRequestBuilders.get(RETRIEVE_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE);
117
118         mockMvc.perform(requestBuilder).andExpect(status().isOk())
119             .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))
120             .andExpect(jsonPath("$.charts.[0].chartId.name", is("HelloWorld")));
121     }
122
123     /**
124      * Test endpoint for installing a chart.
125      * @throws Exception incase of error.
126      */
127     @Test
128     void installChart() throws Exception {
129         RequestBuilder requestBuilder;
130
131         //Mocking successful installation for void install method
132         doNothing().when(chartService).installChart(charts.get(0));
133
134         requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE)
135             .content(getInstallationJson(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion()))
136             .contentType(MediaType.APPLICATION_JSON_VALUE);
137
138         mockMvc.perform(requestBuilder).andExpect(status().isCreated());
139
140         //Install Invalid chart, expects HTTP status NOT_FOUND
141         requestBuilder = MockMvcRequestBuilders.post(INSTALL_CHART_URL).accept(MediaType.APPLICATION_JSON_VALUE)
142             .content(getInstallationJson("invalidName", "invalidVersion"))
143             .contentType(MediaType.APPLICATION_JSON_VALUE);
144
145         mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
146     }
147
148     /**
149      * Test endpoint for uninstalling a chart.
150      * @throws Exception incase of error.
151      */
152     @Test
153     void uninstallChart() throws Exception {
154         RequestBuilder requestBuilder;
155
156         //Mocking successful scenario for void uninstall method
157         doNothing().when(chartService).uninstallChart(charts.get(0));
158
159         requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + charts.get(0)
160             .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion())
161             .accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE);
162
163         mockMvc.perform(requestBuilder).andExpect(status().isNoContent());
164
165         //Invalid chart
166         requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + "invalidName"
167             + "/" + "invalidVersion").accept(MediaType.APPLICATION_JSON_VALUE)
168             .contentType(MediaType.APPLICATION_JSON_VALUE);
169
170         mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
171     }
172
173     /**
174      * Test endpoint for chart onboarding.
175      * @throws Exception incase of error.
176      */
177     @Test
178     void onboardChart() throws Exception {
179         RequestBuilder requestBuilder;
180         MockMultipartFile chartFile = new MockMultipartFile("chart", "hello.tgz",
181             MediaType.TEXT_PLAIN_VALUE, "Dummy data".getBytes());
182
183         MockMultipartFile overrideFile = new MockMultipartFile("values", "values.yaml",
184             MediaType.TEXT_PLAIN_VALUE, "Dummy data".getBytes());
185
186         //Mocking successful scenario for void uninstall method
187         when(chartService.saveChart(charts.get(0), chartFile, null)).thenReturn(charts.get(0));
188
189         requestBuilder = MockMvcRequestBuilders.multipart(ONBOARD_CHART_URL)
190             .file(chartFile).file(overrideFile).param("info", getChartInfoJson());
191
192         mockMvc.perform(requestBuilder).andExpect(status().isOk());
193     }
194
195     /**
196      * Test endpoint for deleting a chart.
197      * @throws Exception incase of error.
198      */
199     @Test
200     void deleteChart() throws Exception {
201         RequestBuilder requestBuilder;
202
203         //Mocking successful scenario for void uninstall method
204         doNothing().when(chartService).deleteChart(charts.get(0));
205
206         requestBuilder = MockMvcRequestBuilders.delete(DELETE_CHART_URL + "/" + charts.get(0)
207             .getChartId().getName() + "/" + charts.get(0).getChartId().getVersion())
208             .accept(MediaType.APPLICATION_JSON_VALUE)
209             .contentType(MediaType.APPLICATION_JSON_VALUE);
210
211         mockMvc.perform(requestBuilder).andExpect(status().isNoContent());
212         //Invalid chart
213         requestBuilder = MockMvcRequestBuilders.delete(UNINSTALL_CHART_URL + "invalidName"
214             + "/" + "invalidVersion").accept(MediaType.APPLICATION_JSON_VALUE)
215             .contentType(MediaType.APPLICATION_JSON_VALUE);
216
217         mockMvc.perform(requestBuilder).andExpect(status().isNotFound());
218
219     }
220
221     /**
222      * Test endpoint for configuring a helm repository.
223      * @throws Exception in case of error.
224      */
225     @Test
226     void testConfigureRepo() throws Exception {
227         RequestBuilder requestBuilder;
228
229         requestBuilder = MockMvcRequestBuilders.post(CONFIGURE_REPO_URL).accept(MediaType.APPLICATION_JSON_VALUE)
230             .content(getInstallationJson(charts.get(0).getChartId().getName(), charts.get(0).getChartId().getVersion()))
231             .contentType(MediaType.APPLICATION_JSON_VALUE);
232
233         mockMvc.perform(requestBuilder).andExpect(status().isCreated());
234
235     }
236
237
238     private String getInstallationJson(String name, String version) {
239         JSONObject jsonObj = new JSONObject();
240         jsonObj.put("name", name);
241         jsonObj.put("version", version);
242         return jsonObj.toString();
243     }
244
245     private String getChartInfoJson() throws IOException {
246         return FileUtils.readFileToString(new File(CHART_INFO_YAML), StandardCharsets.UTF_8);
247     }
248
249 }