Merge "Point to parent SNAPSHOT"
[policy/models.git] / models-interactions / model-actors / actor.so / src / test / java / org / onap / policy / controlloop / actor / so / SoOperationTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.controlloop.actor.so;
22
23 import static org.assertj.core.api.Assertions.assertThatCode;
24 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assert.assertNull;
29 import static org.junit.Assert.assertSame;
30 import static org.junit.Assert.assertTrue;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.when;
34
35 import java.time.LocalDateTime;
36 import java.time.Month;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.concurrent.CompletableFuture;
40 import java.util.concurrent.ForkJoinPool;
41 import java.util.concurrent.TimeUnit;
42 import java.util.function.Consumer;
43 import java.util.function.Supplier;
44 import org.junit.Before;
45 import org.junit.Test;
46 import org.onap.aai.domain.yang.CloudRegion;
47 import org.onap.aai.domain.yang.GenericVnf;
48 import org.onap.aai.domain.yang.ServiceInstance;
49 import org.onap.aai.domain.yang.Tenant;
50 import org.onap.policy.aai.AaiCqResponse;
51 import org.onap.policy.common.utils.coder.Coder;
52 import org.onap.policy.common.utils.coder.CoderException;
53 import org.onap.policy.controlloop.ControlLoopOperation;
54 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
55 import org.onap.policy.controlloop.policy.PolicyResult;
56 import org.onap.policy.so.SoModelInfo;
57 import org.onap.policy.so.SoRequest;
58 import org.onap.policy.so.SoRequestInfo;
59 import org.onap.policy.so.SoRequestReferences;
60 import org.onap.policy.so.SoRequestStatus;
61 import org.onap.policy.so.SoResponse;
62
63 public class SoOperationTest extends BasicSoOperation {
64
65     private static final String VF_COUNT_KEY = SoConstants.VF_COUNT_PREFIX
66                     + "[my-model-customization-id][my-model-invariant-id][my-model-version-id]";
67     private SoOperation oper;
68
69     /**
70      * Sets up.
71      */
72     @Before
73     public void setUp() throws Exception {
74         super.setUp();
75
76         initConfig();
77
78         oper = new SoOperation(params, config) {};
79     }
80
81     @Test
82     public void testConstructor_testGetWaitMsGet() {
83         assertEquals(DEFAULT_ACTOR, oper.getActorName());
84         assertEquals(DEFAULT_OPERATION, oper.getName());
85         assertSame(config, oper.getConfig());
86         assertEquals(1000 * WAIT_SEC_GETS, oper.getWaitMsGet());
87
88         // check when Target is null
89         params = params.toBuilder().target(null).build();
90         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config) {})
91                         .withMessageContaining("Target information");
92     }
93
94     @Test
95     public void testValidateTarget() {
96         // check when various fields are null
97         verifyNotNull("modelCustomizationId", target::getModelCustomizationId, target::setModelCustomizationId);
98         verifyNotNull("modelInvariantId", target::getModelInvariantId, target::setModelInvariantId);
99         verifyNotNull("modelVersionId", target::getModelVersionId, target::setModelVersionId);
100
101         // verify it's still valid
102         assertThatCode(() -> new VfModuleCreate(params, config)).doesNotThrowAnyException();
103     }
104
105     private void verifyNotNull(String expectedText, Supplier<String> getter, Consumer<String> setter) {
106         String originalValue = getter.get();
107
108         // try with null
109         setter.accept(null);
110         assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config))
111                         .withMessageContaining(expectedText);
112
113         setter.accept(originalValue);
114     }
115
116     @Test
117     public void testStartPreprocessorAsync() {
118         assertNotNull(oper.startPreprocessorAsync());
119     }
120
121     @Test
122     public void testObtainVfCount_testGetVfCount_testSetVfCount() throws Exception {
123         // insert CQ data so it's there for the check
124         context.setProperty(AaiCqResponse.CONTEXT_KEY, makeCqResponse());
125
126         // shouldn't actually need to do anything
127         assertNull(oper.obtainVfCount());
128
129         // verify that the count was stored
130         Integer vfcount = context.getProperty(VF_COUNT_KEY);
131         assertEquals(VF_COUNT, vfcount);
132         assertEquals(VF_COUNT.intValue(), oper.getVfCount());
133
134         // change the count and then verify that it isn't overwritten by another call
135         oper.setVfCount(VF_COUNT + 1);
136
137         assertNull(oper.obtainVfCount());
138         vfcount = context.getProperty(VF_COUNT_KEY);
139         assertEquals(VF_COUNT + 1, vfcount.intValue());
140         assertEquals(VF_COUNT + 1, oper.getVfCount());
141     }
142
143     /**
144      * Tests obtainVfCount() when it actually has to query.
145      */
146     @Test
147     public void testObtainVfCountQuery() throws Exception {
148         CompletableFuture<OperationOutcome> future2 = oper.obtainVfCount();
149         assertNotNull(future2);
150         assertTrue(executor.runAll(100));
151
152         // not done yet
153         assertFalse(future2.isDone());
154
155         provideCqResponse(makeCqResponse());
156
157         assertTrue(executor.runAll(100));
158         assertTrue(future2.isDone());
159         assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
160
161         // verify that the count was stored
162         Integer vfcount = context.getProperty(VF_COUNT_KEY);
163         assertEquals(VF_COUNT, vfcount);
164
165         // repeat - shouldn't need to do anything now
166         assertNull(oper.obtainVfCount());
167     }
168
169     @Test
170     public void testPostProcess() throws Exception {
171         // completed
172         oper.generateSubRequestId(2);
173         assertNull(oper.getSubRequestId());
174         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
175         assertTrue(future2.isDone());
176         assertSame(outcome, future2.get());
177         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
178         assertNotNull(oper.getSubRequestId());
179         assertSame(response, outcome.getResponse());
180
181         // failed
182         oper.generateSubRequestId(2);
183         assertNull(oper.getSubRequestId());
184         response.getRequest().getRequestStatus().setRequestState(SoOperation.FAILED);
185         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
186         assertTrue(future2.isDone());
187         assertSame(outcome, future2.get());
188         assertEquals(PolicyResult.FAILURE, outcome.getResult());
189         assertNotNull(oper.getSubRequestId());
190         assertSame(response, outcome.getResponse());
191
192         // no request id in the response
193         oper.generateSubRequestId(2);
194         assertNull(oper.getSubRequestId());
195         response.getRequestReferences().setRequestId(null);
196         response.getRequest().getRequestStatus().setRequestState("unknown");
197         assertThatIllegalArgumentException()
198                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
199                         .withMessage("missing request ID in response");
200         response.getRequestReferences().setRequestId(REQ_ID.toString());
201
202         // status = 500
203         when(rawResponse.getStatus()).thenReturn(500);
204
205         // null request reference
206         SoRequestReferences ref = response.getRequestReferences();
207         response.setRequestReferences(null);
208         assertThatIllegalArgumentException()
209                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
210                         .withMessage("missing request ID in response");
211         response.setRequestReferences(ref);
212     }
213
214     /**
215      * Tests postProcess() when the "get" is repeated a couple of times.
216      */
217     @Test
218     public void testPostProcessRepeated_testResetGetCount() throws Exception {
219         /*
220          * Two failures and then a success - should result in two "get" calls.
221          *
222          * Note: getStatus() is invoked twice during each call, so have to double up the
223          * return values.
224          */
225         when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200);
226
227         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
228
229         // use a real executor
230         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
231
232         oper = new SoOperation(params, config) {
233             @Override
234             public long getWaitMsGet() {
235                 return 1;
236             }
237         };
238
239         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
240
241         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
242         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
243         assertEquals(2, oper.getGetCount());
244
245         /*
246          * repeat - this time, the "get" operations will be exhausted, so it should fail
247          */
248         when(rawResponse.getStatus()).thenReturn(500);
249
250         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
251
252         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
253         assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult());
254         assertEquals(MAX_GETS + 1, oper.getGetCount());
255
256         oper.resetGetCount();
257         assertEquals(0, oper.getGetCount());
258         assertNull(oper.getSubRequestId());
259     }
260
261     @Test
262     public void testGetRequestState() {
263         SoResponse resp = new SoResponse();
264         assertNull(oper.getRequestState(resp));
265
266         SoRequest req = new SoRequest();
267         resp.setRequest(req);
268         assertNull(oper.getRequestState(resp));
269
270         SoRequestStatus status = new SoRequestStatus();
271         req.setRequestStatus(status);
272         assertNull(oper.getRequestState(resp));
273
274         status.setRequestState("my-state");
275         assertEquals("my-state", oper.getRequestState(resp));
276     }
277
278     @Test
279     public void testIsSuccess() {
280         // always true
281
282         assertTrue(oper.isSuccess(rawResponse, response));
283
284         when(rawResponse.getStatus()).thenReturn(500);
285         assertTrue(oper.isSuccess(rawResponse, response));
286     }
287
288     @Test
289     public void testSetOutcome() {
290         // success case
291         when(rawResponse.getStatus()).thenReturn(200);
292         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response));
293
294         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
295         assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
296         assertSame(response, outcome.getResponse());
297
298         // failure case
299         when(rawResponse.getStatus()).thenReturn(500);
300         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response));
301
302         assertEquals(PolicyResult.FAILURE, outcome.getResult());
303         assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage());
304         assertSame(response, outcome.getResponse());
305     }
306
307     @Test
308     public void testPrepareSoModelInfo() throws CoderException {
309         verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId);
310         verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId);
311         verifyMissingModelInfo(target::getModelName, target::setModelName);
312         verifyMissingModelInfo(target::getModelVersion, target::setModelVersion);
313         verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId);
314
315         // valid data
316         SoModelInfo info = oper.prepareSoModelInfo();
317         verifyRequest("model.json", info);
318
319         // try with null target
320         params = params.toBuilder().target(null).build();
321         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config) {})
322                         .withMessageContaining("missing Target");
323     }
324
325     private void verifyMissingModelInfo(Supplier<String> getter, Consumer<String> setter) {
326         String original = getter.get();
327
328         setter.accept(null);
329         assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo())
330                         .withMessage("missing VF Module model");
331
332         setter.accept(original);
333     }
334
335     @Test
336     public void testConstructRequestInfo() throws CoderException {
337         SoRequestInfo info = oper.constructRequestInfo();
338         verifyRequest("reqinfo.json", info);
339     }
340
341     @Test
342     public void testBuildRequestParameters() throws CoderException {
343         // valid data
344         verifyRequest("reqparams.json", oper.buildRequestParameters().get());
345
346         // invalid json
347         params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json");
348         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters())
349                         .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM);
350
351         // missing data
352         params.getPayload().remove(SoOperation.REQ_PARAM_NM);
353         assertTrue(oper.buildRequestParameters().isEmpty());
354
355         // null payload
356         params = params.toBuilder().payload(null).build();
357         oper = new SoOperation(params, config) {};
358         assertTrue(oper.buildRequestParameters().isEmpty());
359     }
360
361     @Test
362     public void testBuildConfigurationParameters() {
363         // valid data
364         assertEquals(List.of(Collections.emptyMap()), oper.buildConfigurationParameters().get());
365
366         // invalid json
367         params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json");
368         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters())
369                         .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM);
370
371         // missing data
372         params.getPayload().remove(SoOperation.CONFIG_PARAM_NM);
373         assertTrue(oper.buildConfigurationParameters().isEmpty());
374
375         // null payload
376         params = params.toBuilder().payload(null).build();
377         oper = new SoOperation(params, config) {};
378         assertTrue(oper.buildConfigurationParameters().isEmpty());
379     }
380
381     @Test
382     public void testGetVnfItem() {
383         // missing data
384         AaiCqResponse cq = mock(AaiCqResponse.class);
385         assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo()))
386                         .withMessage("missing generic VNF");
387
388         // valid data
389         GenericVnf vnf = new GenericVnf();
390         when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf);
391         assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo()));
392     }
393
394     @Test
395     public void testGetServiceInstance() {
396         // missing data
397         AaiCqResponse cq = mock(AaiCqResponse.class);
398         assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq))
399                         .withMessage("missing VNF Service Item");
400
401         // valid data
402         ServiceInstance instance = new ServiceInstance();
403         when(cq.getServiceInstance()).thenReturn(instance);
404         assertSame(instance, oper.getServiceInstance(cq));
405     }
406
407     @Test
408     public void testGetDefaultTenant() {
409         // missing data
410         AaiCqResponse cq = mock(AaiCqResponse.class);
411         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq))
412                         .withMessage("missing Tenant Item");
413
414         // valid data
415         Tenant tenant = new Tenant();
416         when(cq.getDefaultTenant()).thenReturn(tenant);
417         assertSame(tenant, oper.getDefaultTenant(cq));
418     }
419
420     @Test
421     public void testGetDefaultCloudRegion() {
422         // missing data
423         AaiCqResponse cq = mock(AaiCqResponse.class);
424         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq))
425                         .withMessage("missing Cloud Region");
426
427         // valid data
428         CloudRegion region = new CloudRegion();
429         when(cq.getDefaultCloudRegion()).thenReturn(region);
430         assertSame(region, oper.getDefaultCloudRegion(cq));
431     }
432
433     @Test
434     public void testMakeCoder() throws CoderException {
435         Coder opcoder = oper.makeCoder();
436
437         // ensure we can decode an SO timestamp
438         String json = "{'request':{'finishTime':'Fri, 15 May 2020 12:14:21 GMT'}}";
439         SoResponse resp = opcoder.decode(json.replace('\'', '"'), SoResponse.class);
440
441         LocalDateTime tfinish = resp.getRequest().getFinishTime();
442         assertNotNull(tfinish);
443         assertEquals(2020, tfinish.getYear());
444         assertEquals(Month.MAY, tfinish.getMonth());
445     }
446 }