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