222b0f5fbc930022e54a76cc4208720df30ef7ba
[vid.git] / vid-automation / src / test / java / org / onap / vid / api / OperationalEnvironmentControllerApiTest.java
1 package org.onap.vid.api;
2
3 import com.google.common.collect.ImmutableList;
4 import com.google.common.collect.ImmutableMap;
5 import org.apache.commons.text.StringEscapeUtils;
6 import org.springframework.http.HttpEntity;
7 import org.springframework.http.HttpMethod;
8 import org.springframework.http.HttpStatus;
9 import org.springframework.http.ResponseEntity;
10 import org.springframework.web.client.HttpClientErrorException;
11 import org.testng.annotations.BeforeClass;
12 import org.testng.annotations.DataProvider;
13 import org.testng.annotations.Test;
14 import vid.automation.test.services.SimulatorApi;
15 import vid.automation.test.services.SimulatorApi.RegistrationStrategy;
16
17 import java.io.IOException;
18 import java.lang.reflect.Method;
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.LinkedList;
22 import java.util.stream.Collectors;
23
24 import static org.hamcrest.CoreMatchers.containsString;
25 import static org.hamcrest.core.Is.is;
26 import static org.junit.Assert.assertThat;
27 import static org.springframework.http.HttpStatus.BAD_REQUEST;
28 import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED;
29
30 public class OperationalEnvironmentControllerApiTest extends BaseMsoApiTest {
31     private static final String UUID = "927befca-e32c-4f7d-be8d-b4107e0ac31e";
32     public static final String GET_STATUS_REQUEST_UUID = "3212b08c-0dcd-4d20-8c84-51e4f325c14a";
33     private static final String BASIC_DEACTIVATE_REQUEST_BODY = "{}";
34     private static final String BASIC_ACTIVATE_REQUEST_BODY = getResourceAsString("operationalEnvironmentController/activateOperationalEnvironment.json");
35     private static final String BASIC_CREATE_REQUEST_BODY = getResourceAsString("operationalEnvironmentController/createOperationalEnvironment.json");
36     private final String MSO_OK_RESPONSE_FOR_DEACTIVATE = "mso_ok_response_for_deactivate.json";
37     public static final String GET_CLOUD_RESOURCES_REQUEST_STATUS = "get_cloud_resources_request_status.json";
38     private final String MSO_ERROR_RESPONSE_FOR_DEACTIVATE = "mso_error_response_for_deactivate.json";
39     private final String MSO_ERROR_RESPONSE_FOR_STATUS = "mso_error_response_for_status.json";
40     private final String MSO_OK_RESPONSE_FOR_POST_OPERATIONAL_ENVIRONMENT = "mso_ok_response_for_post_operational_environmnet.json";
41     private final String MSO_ERROR_RESPONSE_FOR_POST_OPERATIONAL_ENVIRONMENT = "mso_error_response_for_post_operational_environmnet.json";
42     private final String missingParamErrorText = "Required String parameter 'operationalEnvironment' is not present";
43
44     /*
45     # DEACTIVATION
46
47     ## Tests
48     [x]  -  Try all methods: only POST is working
49     [x]  -  Send wrong requests; all are responded with 400 and nice description
50     [x]      -  missing param
51     [x]      -  missing body
52     [x]      -  operationalEnvironment value is empty
53          -  Simulate MSO responses (status and body); verify all are propagated inside a VID's 200 OK
54     [x]      -  [ 200, 202, 400, 404, 500 ]
55
56          -  Positive cases
57     [x]      - Request body is just '{}'
58     [x]      - Request body is with some fields
59     [x]      - URI with more query params
60
61     ### Always verify
62     [x]  -  Payload to MSO is the valid schema and values
63     [ ]  -  RequestorId is ok
64
65      */
66
67     @Override
68     @BeforeClass
69     public void login() {
70         super.login();
71     }
72
73
74     @Test(dataProvider = "wrongHttpMethodsForAllUris")
75     public void tryAllWrongMethods(HttpMethod httpMethod, String uri) throws IOException {
76         try {
77             ResponseEntity<String> responseEntity = restTemplate.exchange(uri, httpMethod, new HttpEntity<ImmutableMap>(ImmutableMap.of()), String.class);
78             assertThat("Response should be method not allowed => " + responseEntity, responseEntity.getBody(), containsString("Request method '" + httpMethod + "' not supported"));
79         } catch (HttpClientErrorException e) {
80             assertThat("Response should be method not allowed (by error code)", e.getStatusCode(), is(METHOD_NOT_ALLOWED));
81         }
82
83     }
84
85
86     @Test
87     public void activateWithAdditionalQueryParam() throws IOException {
88         doWithFineRequest(BASIC_ACTIVATE_REQUEST_BODY, getActivationTargetUri(ACTIVATION_URI_UUID_MODE.EXTENDED), "/activate\"");
89     }
90
91     @Test(expectedExceptions = { HttpClientErrorException.class })
92     public void activateWithMissingOperationalEnvironmentParam() throws IOException {
93         doWithBadRequest(BASIC_ACTIVATE_REQUEST_BODY, missingParamErrorText, getActivationTargetUri(ACTIVATION_URI_UUID_MODE.MISSING));
94     }
95
96     @Test(expectedExceptions = { HttpClientErrorException.class })
97     public void activateWithNoValueForOperationalEnvironmentParam() throws IOException {
98         doWithBadRequest(BASIC_ACTIVATE_REQUEST_BODY, missingParamErrorText, getActivationTargetUri(ACTIVATION_URI_UUID_MODE.NO_VALUE));
99     }
100
101     @Test
102     public void deactivateWithAdditionalQueryParam() throws IOException {
103         doWithFineRequest(BASIC_DEACTIVATE_REQUEST_BODY, getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.EXTENDED), "/deactivate\"");
104     }
105
106     @Test(expectedExceptions = { HttpClientErrorException.class })
107     public void deactivateWithMissingOperationalEnvironmentParam() throws IOException {
108         doWithBadRequest(BASIC_DEACTIVATE_REQUEST_BODY, missingParamErrorText, getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.MISSING));
109     }
110
111     @Test(expectedExceptions = { HttpClientErrorException.class })
112     public void deactivateWithNoValueForOperationalEnvironmentParam() throws IOException {
113         doWithBadRequest(BASIC_DEACTIVATE_REQUEST_BODY, missingParamErrorText, getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.NO_VALUE));
114     }
115
116     @Test(dataProvider = "requestPayloads")
117     public void activateWithBody(String requestBody) throws IOException {
118         doWithFineRequest(requestBody, getActivationTargetUri(ACTIVATION_URI_UUID_MODE.OK), "/activate\"");
119     }
120
121     @Test(dataProvider = "requestPayloads")
122     public void deactivateWithBody(String requestBody) throws IOException {
123         doWithFineRequest(requestBody, getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.OK), "/deactivate\"");
124     }
125
126
127     private void doWithFineRequest(String requestBody, String targetUri, String v1) throws IOException {
128         final String expectedResult = "" +
129                 "{" +
130                 "  \"requestReferences\": {" +
131                 "     \"requestId\": \"dbe54591-c8ed-46d3-abc7-d3a24873dfbd\"," +
132                 "     \"instanceId\": \"" + UUID + "\"" +
133                 "  }" +
134                 "}";
135         callMsoWithFineRequest(MSO_OK_RESPONSE_FOR_DEACTIVATE, ImmutableMap.of(
136                     "/deactivate\"", v1,
137                     "UUID", UUID)
138                 ,targetUri,requestBody,HttpStatus.ACCEPTED.value(),expectedResult, HttpMethod.POST);
139        }
140
141     @Test(dataProvider = "errorCodes")
142     public void deactivateWithErrorResponse(int errorCode) throws IOException {
143         doWithSimulatedErrorResponse(errorCode, getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.OK), BASIC_DEACTIVATE_REQUEST_BODY, "/deactivate\"", MSO_ERROR_RESPONSE_FOR_DEACTIVATE, HttpMethod.POST);
144     }
145
146     @Test(dataProvider = "errorCodes")
147     public void activateWithErrorResponse(int errorCode) throws IOException {
148         doWithSimulatedErrorResponse(errorCode, getActivationTargetUri(ACTIVATION_URI_UUID_MODE.OK), BASIC_ACTIVATE_REQUEST_BODY, "/activate\"", MSO_ERROR_RESPONSE_FOR_DEACTIVATE, HttpMethod.POST);
149     }
150
151     @Test(dataProvider = "errorCodes")
152     public void testStatusWithErrorResponse(int errorCode) throws IOException {
153         doWithSimulatedErrorResponse(errorCode, getStatusTargetUri(STATUS_URI_UUID_MODE.OK), "", "", MSO_ERROR_RESPONSE_FOR_STATUS, HttpMethod.GET);
154     }
155
156     private void doWithSimulatedErrorResponse(int errorCode, String targetUri, String basicRequestBody, String msoPathSuffix, String expectationTemplateFilename, HttpMethod method) throws IOException {
157         final String expectedResult = "" +
158                 "<head>Huston, you have a problem<head>";
159         callMsoWithSimulatedErrorResponse(expectationTemplateFilename, ImmutableMap.of(
160                     "/deactivate\"", msoPathSuffix,
161                     "UUID", UUID,
162                     "500", errorCode,
163                     "ERROR_PAYLOAD", StringEscapeUtils.escapeJson(expectedResult)
164                     ),targetUri,basicRequestBody,errorCode, expectedResult, method);
165     }
166
167     @Test(
168             dataProvider = "requestPayloads",
169             expectedExceptions = { HttpClientErrorException.class }
170     )
171     public void activateWithBadRequest(String requestBody) throws IOException {
172         doWithBadRequest(requestBody, "HttpMessageNotReadableException", getActivationTargetUri(ACTIVATION_URI_UUID_MODE.OK));
173     }
174
175     @Test(
176             dataProvider = "activateBadHalfBakedPayloads",
177             expectedExceptions = { HttpClientErrorException.class }
178     )
179     public void activateWithBadHalfBakedPayload(String requestBody) throws IOException {
180         doWithBadRequest(requestBody, "HttpMessageNotReadableException", getActivationTargetUri(ACTIVATION_URI_UUID_MODE.OK));
181     }
182
183     @Test(
184             dataProvider = "requestPayloads",
185             expectedExceptions = { HttpClientErrorException.class }
186     )
187     public void deactivateWithBadRequest(String requestBody) throws IOException {
188         doWithBadRequest(requestBody, "HttpMessageNotReadableException", getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.OK));
189     }
190
191     private void doWithBadRequest(String requestBody, String httpMessageNotReadableException, String targetUri) throws IOException {
192         SimulatorApi.registerExpectation(MSO_OK_RESPONSE_FOR_DEACTIVATE, ImmutableMap.of("UUID", UUID), RegistrationStrategy.CLEAR_THEN_SET);
193
194         try {
195             ResponseEntity<String> responseEntity = restTemplate.postForEntity(targetUri, requestBody, String.class);
196         } catch (HttpClientErrorException e) {
197             assertThat("Response should be Bad Request (by error code)", e.getStatusCode(), is(BAD_REQUEST));
198             assertThat("Response should be Bad Request (by body)", e.getResponseBodyAsString(), containsString(httpMessageNotReadableException));
199             throw e;
200         }
201
202     }
203
204
205     @DataProvider
206     public Object[][] wrongHttpMethodsForAllUris() {
207         ImmutableList<String> uris = ImmutableList.of(
208                 getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE.OK),
209                 getActivationTargetUri(ACTIVATION_URI_UUID_MODE.OK)
210         );
211         
212         return Arrays.stream(HttpMethod.values())
213                 .filter(Streams.not(ImmutableList.of(
214                         HttpMethod.POST,    // because POST *should* work
215                         HttpMethod.PATCH,   // because PATCH is invalid method for Java.net
216                         HttpMethod.OPTIONS, // because OPTIONS is somehow valid...  :-(  => Allow=[GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH]
217                         HttpMethod.HEAD     // because HEAD is like POST/GET but without body, so error is hidden
218                 )::contains))
219                 .flatMap(httpMethod -> uris.stream()
220                         .map(uri -> new Object[]{ httpMethod, uri})  // pair given method for each of the URIs
221                 ) 
222                 .collect(Collectors.toList())
223                 .toArray(new Object[][] {});
224     }
225
226     @DataProvider
227     public static Object[][] requestPayloads(Method test) {
228         switch (test.getName()) {
229             case "deactivateWithBody":
230                 return new Object[][]{
231                         {BASIC_DEACTIVATE_REQUEST_BODY}
232                         , {"{ \"a\": \"b\" }"}
233                         , {"{ \"a\": [ 55 ] }"}
234                 };
235             case "activateWithBody":
236                 return new Object[][]{
237                         {BASIC_ACTIVATE_REQUEST_BODY}
238                 };
239             default: // bad payloads
240                 return new Object[][]{
241                         {null}
242                         , {""}
243                         , {"{"}
244                         , {"foo"}
245                 };
246         }
247     }
248
249     @DataProvider
250     public static Object[][] activateBadHalfBakedPayloads(Method test) {
251         final ImmutableList<String> strings = ImmutableList.of(
252                 "\"relatedInstanceId\": \"1117887f-068f-46d7-9e43-9b73bef17af8\"",
253                 "\"relatedInstanceName\": \"managing ECOMP Operational Environment\"",
254                 "\"workloadContext\": \"VNF_E2E-IST\"",
255                 "\"manifest\": {" +
256                         "  \"serviceModelList\": [" +
257                         "    {" +
258                         "      \"serviceModelVersionId\": \"uuid2\"," +
259                         "      \"recoveryAction\": \"retry\"" +
260                         "    }" +
261                         "  ]" +
262                         "}"
263         );
264
265         final LinkedList<String> tests = new LinkedList<>();
266         for (int i = 0; i < strings.size(); i++) {
267             final ArrayList<String> aCase = new ArrayList<>(strings);
268             aCase.remove(i);
269             tests.add("{" + String.join(", ", aCase) + "}");
270         }
271
272         return tests.stream().map(o -> new Object[] { o }).collect(Collectors.toList()).toArray(new Object[][]{});
273     }
274
275     @DataProvider
276     public static Object[][] errorCodes(Method test) {
277         return new Object[][]{
278                 {500}, {505}, {400}, {401}, {405}
279         };
280     }
281
282     @DataProvider
283     public static Object[][] statusLegitUri(Method test) {
284         return new Object[][]{
285                 {STATUS_URI_UUID_MODE.OK}, {STATUS_URI_UUID_MODE.EXTENDED}
286         };
287     }
288
289     @DataProvider
290     public static Object[][] statusNotLegitUri(Method test) {
291         return new Object[][]{
292                 {STATUS_URI_UUID_MODE.MISSING}, {STATUS_URI_UUID_MODE.NO_VALUE}
293         };
294     }
295
296     private enum ACTIVATION_URI_UUID_MODE {
297         MISSING(""),
298         NO_VALUE("?operationalEnvironment="),
299         OK(NO_VALUE.val + UUID),
300         EXTENDED(OK.val + "&anotherParam=6");
301
302         final String val;
303
304         ACTIVATION_URI_UUID_MODE(String val) {
305             this.val = val;
306         }
307     }
308
309     private enum STATUS_URI_UUID_MODE {
310         MISSING(""),
311         NO_VALUE("?requestId="),
312         OK(NO_VALUE.val + GET_STATUS_REQUEST_UUID),
313         EXTENDED(OK.val + "&anotherParam=6");
314
315         final String val;
316
317         STATUS_URI_UUID_MODE(String val) {
318             this.val = val;
319         }
320     }
321
322     private String getDeactivationTargetUri(ACTIVATION_URI_UUID_MODE uriUuidMode) {
323         return uri.toASCIIString() + "/operationalEnvironment/deactivate" + uriUuidMode.val;
324     }
325
326     private String getActivationTargetUri(ACTIVATION_URI_UUID_MODE uriUuidMode) {
327         return uri.toASCIIString() + "/operationalEnvironment/activate" + uriUuidMode.val;
328     }
329
330     private String getStatusTargetUri(STATUS_URI_UUID_MODE uriUuidMode) {
331         return uri.toASCIIString() + "/operationalEnvironment/requestStatus" + uriUuidMode.val;
332     }
333
334     private String getCreateOperationEnvironmentUri() {
335         return uri.toASCIIString() + "/operationalEnvironment/create";
336     }
337
338     @Test
339     public void createWithSimplestBody()throws IOException {
340
341         final String expectedResult = "" +
342                 "{" +
343                 "  \"requestReferences\": {" +
344                 "     \"requestId\": \"dbe54591-c8ed-46d3-abc7-d3a24873dfbd\","+
345                 "     \"instanceId\": \"" + UUID + "\"" +
346                 "  }" +
347                 "}";
348         callMsoWithFineRequest(MSO_OK_RESPONSE_FOR_POST_OPERATIONAL_ENVIRONMENT, ImmutableMap.of(
349                 "UUID", UUID), getCreateOperationEnvironmentUri(), BASIC_CREATE_REQUEST_BODY, HttpStatus.ACCEPTED.value(), expectedResult, HttpMethod.POST);
350    }
351
352     @Test(dataProvider = "errorCodes")
353     public void createWithErrorResponse(int errorCode) throws IOException {
354         final String expectedResult = "" +
355                 "<head>Huston, you have a problem<head>";
356         callMsoWithSimulatedErrorResponse(MSO_ERROR_RESPONSE_FOR_POST_OPERATIONAL_ENVIRONMENT,ImmutableMap.of(
357                 "500", errorCode,
358                 "ERROR_PAYLOAD", StringEscapeUtils.escapeJson(expectedResult)
359         ),  getCreateOperationEnvironmentUri(), BASIC_CREATE_REQUEST_BODY, errorCode,expectedResult, HttpMethod.POST);
360     }
361
362
363
364
365     @Test(dataProvider = "statusLegitUri")
366     public void testStatusWithLegitUri(STATUS_URI_UUID_MODE statusUriMode) throws IOException {
367
368         String uri = getStatusTargetUri(statusUriMode);
369
370         final String expectedResult = "" +
371                 "{" +
372                 "  \"request\": {" +
373                 "    \"requestId\": \"3212b08c-0dcd-4d20-8c84-51e4f325c14a\"," +
374                 "    \"startTime\": \"Thu, 02 Jun 2017 02:51:59 GMT\"," +
375                 "    \"instanceReferences\": {" +
376                 "      \"operationalEnvironmentInstanceId\": \"bc305d54-75b4-431b-adb2-eb6b9e546014\"" +
377                 "    }," +
378                 "    \"requestScope\": \"operationalEnvironment\"," +
379                 "    \"requestType\": \"deactivate\"," +
380                 "    \"requestDetails\": {" +
381                 "      \"requestInfo\": {" +
382                 "        \"resourceType\": \"operationalEnvironment\"," +
383                 "        \"source\": \"VID\"," +
384                 "        \"requestorId\": \"az2017\"" +
385                 "      }," +
386                 "      \"requestParameters\": {" +
387                 "        \"operationalEnvironmentType\": \"VNF\"" +
388                 "      }" +
389                 "    }," +
390                 "    \"requestStatus\": {" +
391                 "      \"timestamp\": \"Thu, 02 Jun 2017 02:53:39 GMT\"," +
392                 "      \"requestState\": \"COMPLETE\"," +
393                 "      \"statusMessage\": \"Operational Environment successfully deactivated\"," +
394                 "      \"percentProgress\": \"100\"" +
395                 "    }" +
396                 "  }" +
397                 "}";
398
399         callMsoWithFineRequest(GET_CLOUD_RESOURCES_REQUEST_STATUS, ImmutableMap.of()
400                 ,uri,"",HttpStatus.OK.value(),expectedResult, HttpMethod.GET);
401
402     }
403
404     @Test(
405             expectedExceptions = {HttpClientErrorException.class},
406             dataProvider = "statusNotLegitUri"
407     )
408     public void testStatusWithBadRequest(STATUS_URI_UUID_MODE statusUriMode) throws IOException {
409         SimulatorApi.registerExpectation(GET_CLOUD_RESOURCES_REQUEST_STATUS, RegistrationStrategy.CLEAR_THEN_SET);
410
411         String uri = getStatusTargetUri(statusUriMode);
412
413         try {
414             ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
415         } catch (HttpClientErrorException e) {
416             assertThat("Response should be Bad Request (by error code)", e.getStatusCode(), is(BAD_REQUEST));
417             assertThat("Response should be Bad Request (by body)", e.getResponseBodyAsString(), containsString("'requestId' is not present"));
418             throw e;
419         }
420     }
421
422     @Test
423     public void testStatusWithWrongMethodPost() throws IOException {
424         SimulatorApi.registerExpectation(GET_CLOUD_RESOURCES_REQUEST_STATUS, RegistrationStrategy.CLEAR_THEN_SET);
425
426         String myUri = getStatusTargetUri(STATUS_URI_UUID_MODE.OK);
427
428         String response = restTemplate.postForObject(myUri, "", String.class);
429         assertThat("Response should be method not allowed => " + response, response, containsString("Request method '" + HttpMethod.POST + "' not supported"));
430     }
431 }