Add initial version of code
[nonrtric/plt/rappmanager.git] / rapp-manager-application / src / test / java / com / oransc / rappmanager / service / AcmDeployerTest.java
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2023 Nordix Foundation. All rights reserved.
4  * ===============================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END========================================================================
17  */
18
19 package com.oransc.rappmanager.service;
20
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.times;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
31 import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
32 import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
33 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
34
35 import com.fasterxml.jackson.core.JsonProcessingException;
36 import com.fasterxml.jackson.databind.ObjectMapper;
37 import com.oransc.rappmanager.acm.configuration.ACMConfiguration;
38 import com.oransc.rappmanager.acm.service.AcmDeployer;
39 import com.oransc.rappmanager.configuration.RappManagerConfiguration;
40 import com.oransc.rappmanager.models.Rapp;
41 import com.oransc.rappmanager.models.RappEvent;
42 import com.oransc.rappmanager.models.RappState;
43 import com.oransc.rappmanager.models.cache.RappCacheService;
44 import com.oransc.rappmanager.models.statemachine.RappStateMachine;
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.IOException;
48 import java.nio.file.Files;
49 import java.nio.file.Path;
50 import java.util.UUID;
51 import org.apache.http.entity.ContentType;
52 import org.junit.jupiter.api.BeforeAll;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.junit.jupiter.api.TestInstance;
56 import org.onap.policy.clamp.models.acm.concepts.AutomationComposition;
57 import org.onap.policy.clamp.models.acm.concepts.DeployState;
58 import org.onap.policy.clamp.models.acm.concepts.LockState;
59 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
60 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.PrimeOrder;
61 import org.onap.policy.clamp.models.acm.messages.rest.instantiation.InstantiationResponse;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
64 import org.springframework.boot.test.context.SpringBootTest;
65 import org.springframework.boot.test.mock.mockito.SpyBean;
66 import org.springframework.http.HttpMethod;
67 import org.springframework.http.HttpStatus;
68 import org.springframework.http.MediaType;
69 import org.springframework.mock.web.MockMultipartFile;
70 import org.springframework.test.context.TestPropertySource;
71 import org.springframework.test.web.client.ExpectedCount;
72 import org.springframework.test.web.client.MockRestServiceServer;
73 import org.springframework.test.web.servlet.MockMvc;
74 import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
75 import org.springframework.web.client.RestTemplate;
76
77 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
78 @TestPropertySource(properties = "rappmanager.csarlocation=src/test/resources")
79 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
80 @AutoConfigureMockMvc
81 public class AcmDeployerTest {
82
83     MockRestServiceServer mockServer;
84     @SpyBean
85     AcmDeployer acmDeployer;
86     @Autowired
87     RestTemplate restTemplate;
88     @Autowired
89     ACMConfiguration acmConfiguration;
90     @Autowired
91     RappManagerConfiguration rappManagerConfiguration;
92     @Autowired
93     private MockMvc mockMvc;
94     @Autowired
95     RappCacheService rappCacheService;
96     @SpyBean
97     RappStateMachine rappStateMachine;
98     private final String validRappFile = "valid-rapp-package.csar";
99     ObjectMapper objectMapper = new ObjectMapper();
100     String URI_ACM_COMPOSITIONS, URI_ACM_COMPOSITION, URI_ACM_INSTANCES, URI_ACM_INSTANCE;
101
102     @BeforeAll
103     void initACMURI() {
104         URI_ACM_COMPOSITIONS = acmConfiguration.getBaseUrl() + "compositions";
105         URI_ACM_COMPOSITION = acmConfiguration.getBaseUrl() + "compositions/%s";
106         URI_ACM_INSTANCES = acmConfiguration.getBaseUrl() + "compositions/%s/instances";
107         URI_ACM_INSTANCE = acmConfiguration.getBaseUrl() + "compositions/%s/instances/%s";
108     }
109
110
111     @BeforeEach
112     public void init() {
113         mockServer = MockRestServiceServer.createServer(restTemplate);
114     }
115
116     @Test
117     void testCreateComposition() throws IOException {
118         String compositionPayload = Files.readString(Path.of(acmConfiguration.getCompositionDefinitionLocation()));
119         CommissioningResponse commissioningResponseExpected = new CommissioningResponse();
120         commissioningResponseExpected.setCompositionId(UUID.randomUUID());
121         mockServer.expect(ExpectedCount.once(), requestTo(URI_ACM_COMPOSITIONS)).andExpect(method(HttpMethod.POST))
122                 .andRespond(withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
123                                     .body(objectMapper.writeValueAsString(commissioningResponseExpected)));
124         CommissioningResponse commissioningResponseActual = acmDeployer.createComposition(compositionPayload);
125         mockServer.verify();
126         assertEquals(commissioningResponseActual.getCompositionId(), commissioningResponseExpected.getCompositionId());
127     }
128
129     @Test
130     void testCreateCompositionFailure() throws IOException {
131         String compositionPayload = Files.readString(Path.of(acmConfiguration.getCompositionDefinitionLocation()));
132         mockServer.expect(ExpectedCount.once(), requestTo(URI_ACM_COMPOSITIONS)).andExpect(method(HttpMethod.POST))
133                 .andRespond(withStatus(HttpStatus.BAD_GATEWAY));
134         CommissioningResponse commissioningResponseActual = acmDeployer.createComposition(compositionPayload);
135         mockServer.verify();
136         assertNull(commissioningResponseActual);
137     }
138
139     @Test
140     void testCompositionPriming() {
141         UUID compositionId = UUID.randomUUID();
142         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_COMPOSITION, compositionId)))
143                 .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
144
145         acmDeployer.primeACMComposition(compositionId, PrimeOrder.PRIME);
146         mockServer.verify();
147     }
148
149     @Test
150     void testDeployRapp() throws Exception {
151
152         UUID compositionId = UUID.randomUUID();
153         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
154         UUID rappId = UUID.randomUUID();
155         UUID instanceId = UUID.randomUUID();
156         Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
157                             .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
158                             .build();
159         onBoardRappCsar(rappId);
160         InstantiationResponse instantiationResponse = new InstantiationResponse();
161         instantiationResponse.setInstanceId(instanceId);
162         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCES, compositionId)))
163                 .andExpect(method(HttpMethod.POST)).andRespond(
164                         withStatus(HttpStatus.ACCEPTED).contentType(MediaType.APPLICATION_JSON)
165                                 .body(objectMapper.writeValueAsString(instantiationResponse)));
166
167         mockServer.expect(ExpectedCount.once(),
168                         requestTo(acmConfiguration.getBaseUrl() + "compositions/" + compositionId + "/instances/" + instanceId))
169                 .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
170
171
172         boolean rappDeployStateActual = acmDeployer.deployRapp(rapp);
173         assertTrue(rappDeployStateActual);
174         mockServer.verify();
175     }
176
177     @Test
178     void testDeployRappFailure() throws Exception {
179         UUID compositionId = UUID.randomUUID();
180         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
181         UUID rappId = UUID.randomUUID();
182         UUID instanceId = UUID.randomUUID();
183         Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
184                             .packageLocation(rappManagerConfiguration.getCsarLocation()).state(RappState.ONBOARDED)
185                             .build();
186         onBoardRappCsar(rappId);
187         InstantiationResponse instantiationResponse = new InstantiationResponse();
188         instantiationResponse.setInstanceId(instanceId);
189         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCES, compositionId)))
190                 .andExpect(method(HttpMethod.POST)).andRespond(withStatus(HttpStatus.BAD_GATEWAY));
191
192         boolean rappDeployStateActual = acmDeployer.deployRapp(rapp);
193         mockServer.verify();
194         assertFalse(rappDeployStateActual);
195     }
196
197     @Test
198     void testUndeployRapp() throws JsonProcessingException {
199         UUID compositionId = UUID.randomUUID();
200         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
201         UUID rappId = UUID.randomUUID();
202         UUID instanceId = UUID.randomUUID();
203         Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
204                             .compositionId(compositionId).compositionInstanceId(instanceId).state(RappState.DEPLOYED)
205                             .build();
206         rappCacheService.putRapp(rapp);
207         rappStateMachine.onboardRapp(rappId);
208
209         expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.DEPLOYED, LockState.LOCKED,
210                 ExpectedCount.once());
211
212         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
213                 .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
214
215         expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYED, LockState.UNLOCKED,
216                 ExpectedCount.once());
217
218         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
219                 .andExpect(method(HttpMethod.DELETE)).andRespond(withStatus(HttpStatus.NO_CONTENT));
220
221
222         boolean rappUndeployStateActual = acmDeployer.undeployRapp(rapp);
223         mockServer.verify();
224         assertTrue(rappUndeployStateActual);
225     }
226
227     @Test
228     void testUndeployRappFailure() throws JsonProcessingException {
229         UUID compositionId = UUID.randomUUID();
230         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
231         UUID rappId = UUID.randomUUID();
232         UUID instanceId = UUID.randomUUID();
233         Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
234                             .compositionInstanceId(instanceId).state(RappState.DEPLOYED).build();
235         rappCacheService.putRapp(rapp);
236
237         expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.DEPLOYED, LockState.LOCKED,
238                 ExpectedCount.once());
239
240         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
241                 .andExpect(method(HttpMethod.PUT)).andRespond(withStatus(HttpStatus.ACCEPTED));
242
243         expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYING,
244                 LockState.UNLOCKING, ExpectedCount.manyTimes());
245
246         boolean rappUndeployStateActual = acmDeployer.undeployRapp(rapp);
247         mockServer.verify();
248         assertFalse(rappUndeployStateActual);
249     }
250
251     @Test
252     void testSyncRappStatus() throws JsonProcessingException {
253         UUID compositionId = UUID.randomUUID();
254         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
255         UUID rappId = UUID.randomUUID();
256         UUID instanceId = UUID.randomUUID();
257         Rapp rapp = Rapp.builder().rappId(rappId).name(rappId.toString()).packageName(validRappFile)
258                             .compositionId(compositionId).compositionInstanceId(instanceId).state(RappState.DEPLOYED)
259                             .build();
260         rappCacheService.putRapp(rapp);
261         rappStateMachine.onboardRapp(rappId);
262
263         expectAcmGetInstanceToReturnDeployedState(compositionId, instanceId, DeployState.UNDEPLOYING,
264                 LockState.UNLOCKING, ExpectedCount.once());
265
266         acmDeployer.syncRappStatus(rapp);
267         mockServer.verify();
268         verify(rappStateMachine, times(1)).sendRappEvent(rapp, RappEvent.UNDEPLOYING);
269     }
270
271     @Test
272     void testSyncRappStatusFailure() {
273         UUID compositionId = UUID.randomUUID();
274         when(acmDeployer.getCompositionId()).thenReturn(compositionId);
275         UUID rappId = UUID.randomUUID();
276         UUID instanceId = UUID.randomUUID();
277         Rapp rapp = Rapp.builder().name(rappId.toString()).packageName(validRappFile).compositionId(compositionId)
278                             .compositionInstanceId(instanceId).state(RappState.DEPLOYED).build();
279         rappCacheService.putRapp(rapp);
280
281         mockServer.expect(ExpectedCount.once(), requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
282                 .andExpect(method(HttpMethod.GET)).andRespond(withStatus(HttpStatus.BAD_GATEWAY));
283
284         acmDeployer.syncRappStatus(rapp);
285         mockServer.verify();
286         verify(rappStateMachine, never()).sendRappEvent(any(), any());
287     }
288
289     void expectAcmGetInstanceToReturnDeployedState(UUID compositionId, UUID instanceId, DeployState deployState,
290             LockState lockState, ExpectedCount expectedCount) throws JsonProcessingException {
291         AutomationComposition automationCompositionDeployed = new AutomationComposition();
292         automationCompositionDeployed.setCompositionId(compositionId);
293         automationCompositionDeployed.setInstanceId(instanceId);
294         automationCompositionDeployed.setDeployState(deployState);
295         automationCompositionDeployed.setLockState(lockState);
296
297         mockServer.expect(expectedCount, requestTo(String.format(URI_ACM_INSTANCE, compositionId, instanceId)))
298                 .andExpect(method(HttpMethod.GET)).andRespond(
299                         withStatus(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON)
300                                 .body(objectMapper.writeValueAsString(automationCompositionDeployed)));
301     }
302
303     void onBoardRappCsar(UUID rappId) throws Exception {
304         String rappCsarPath = rappManagerConfiguration.getCsarLocation() + File.separator + validRappFile;
305         MockMultipartFile multipartFile =
306                 new MockMultipartFile("file", validRappFile, ContentType.MULTIPART_FORM_DATA.getMimeType(),
307                         new FileInputStream(rappCsarPath));
308         mockMvc.perform(MockMvcRequestBuilders.multipart("/rapps/{rapp_id}/onboard", rappId).file(multipartFile))
309                 .andExpect(status().isAccepted());
310     }
311
312
313 }