Set sub request ID before start callback
[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         oper.generateSubRequestId(2);
170         assertNull(oper.getSubRequestId());
171         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
172         assertTrue(future2.isDone());
173         assertSame(outcome, future2.get());
174         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
175         assertNotNull(oper.getSubRequestId());
176
177         // failed
178         oper.generateSubRequestId(2);
179         assertNull(oper.getSubRequestId());
180         response.getRequest().getRequestStatus().setRequestState(SoOperation.FAILED);
181         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
182         assertTrue(future2.isDone());
183         assertSame(outcome, future2.get());
184         assertEquals(PolicyResult.FAILURE, outcome.getResult());
185         assertNotNull(oper.getSubRequestId());
186
187         // no request id in the response
188         response.getRequestReferences().setRequestId(null);
189         response.getRequest().getRequestStatus().setRequestState("unknown");
190         assertThatIllegalArgumentException()
191                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
192                         .withMessage("missing request ID in response");
193         response.getRequestReferences().setRequestId(REQ_ID.toString());
194
195         // status = 500
196         when(rawResponse.getStatus()).thenReturn(500);
197
198         // null request reference
199         SoRequestReferences ref = response.getRequestReferences();
200         response.setRequestReferences(null);
201         assertThatIllegalArgumentException()
202                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
203                         .withMessage("missing request ID in response");
204         response.setRequestReferences(ref);
205     }
206
207     /**
208      * Tests postProcess() when the "get" is repeated a couple of times.
209      */
210     @Test
211     public void testPostProcessRepeated_testResetGetCount() throws Exception {
212         /*
213          * Two failures and then a success - should result in two "get" calls.
214          *
215          * Note: getStatus() is invoked twice during each call, so have to double up the
216          * return values.
217          */
218         when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200);
219
220         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
221
222         // use a real executor
223         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
224
225         oper = new SoOperation(params, config) {
226             @Override
227             public long getWaitMsGet() {
228                 return 1;
229             }
230         };
231
232         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
233
234         assertSame(outcome, future2.get(500, TimeUnit.SECONDS));
235         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
236         assertEquals(2, oper.getGetCount());
237
238         /*
239          * repeat - this time, the "get" operations will be exhausted, so it should fail
240          */
241         when(rawResponse.getStatus()).thenReturn(500);
242
243         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
244
245         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
246         assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult());
247         assertEquals(MAX_GETS + 1, oper.getGetCount());
248
249         oper.resetGetCount();
250         assertEquals(0, oper.getGetCount());
251     }
252
253     @Test
254     public void testGetRequestState() {
255         SoResponse resp = new SoResponse();
256         assertNull(oper.getRequestState(resp));
257
258         SoRequest req = new SoRequest();
259         resp.setRequest(req);
260         assertNull(oper.getRequestState(resp));
261
262         SoRequestStatus status = new SoRequestStatus();
263         req.setRequestStatus(status);
264         assertNull(oper.getRequestState(resp));
265
266         status.setRequestState("my-state");
267         assertEquals("my-state", oper.getRequestState(resp));
268     }
269
270     @Test
271     public void testIsSuccess() {
272         // always true
273
274         assertTrue(oper.isSuccess(rawResponse, response));
275
276         when(rawResponse.getStatus()).thenReturn(500);
277         assertTrue(oper.isSuccess(rawResponse, response));
278     }
279
280     @Test
281     public void testSetOutcome() {
282         // success case
283         when(rawResponse.getStatus()).thenReturn(200);
284         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response));
285
286         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
287         assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
288
289         // failure case
290         when(rawResponse.getStatus()).thenReturn(500);
291         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response));
292
293         assertEquals(PolicyResult.FAILURE, outcome.getResult());
294         assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage());
295     }
296
297     @Test
298     public void testPrepareSoModelInfo() throws CoderException {
299         verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId);
300         verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId);
301         verifyMissingModelInfo(target::getModelName, target::setModelName);
302         verifyMissingModelInfo(target::getModelVersion, target::setModelVersion);
303         verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId);
304
305         // valid data
306         SoModelInfo info = oper.prepareSoModelInfo();
307         verifyRequest("model.json", info);
308
309         // try with null target
310         params = params.toBuilder().target(null).build();
311         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config) {})
312                         .withMessageContaining("missing Target");
313     }
314
315     private void verifyMissingModelInfo(Supplier<String> getter, Consumer<String> setter) {
316         String original = getter.get();
317
318         setter.accept(null);
319         assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo())
320                         .withMessage("missing VF Module model");
321
322         setter.accept(original);
323     }
324
325     @Test
326     public void testConstructRequestInfo() throws CoderException {
327         SoRequestInfo info = oper.constructRequestInfo();
328         verifyRequest("reqinfo.json", info);
329     }
330
331     @Test
332     public void testBuildRequestParameters() throws CoderException {
333         // valid data
334         verifyRequest("reqparams.json", oper.buildRequestParameters().get());
335
336         // invalid json
337         params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json");
338         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters())
339                         .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM);
340
341         // missing data
342         params.getPayload().remove(SoOperation.REQ_PARAM_NM);
343         assertTrue(oper.buildRequestParameters().isEmpty());
344
345         // null payload
346         params = params.toBuilder().payload(null).build();
347         oper = new SoOperation(params, config) {};
348         assertTrue(oper.buildRequestParameters().isEmpty());
349     }
350
351     @Test
352     public void testBuildConfigurationParameters() {
353         // valid data
354         assertEquals(List.of(Collections.emptyMap()), oper.buildConfigurationParameters().get());
355
356         // invalid json
357         params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json");
358         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters())
359                         .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM);
360
361         // missing data
362         params.getPayload().remove(SoOperation.CONFIG_PARAM_NM);
363         assertTrue(oper.buildConfigurationParameters().isEmpty());
364
365         // null payload
366         params = params.toBuilder().payload(null).build();
367         oper = new SoOperation(params, config) {};
368         assertTrue(oper.buildConfigurationParameters().isEmpty());
369     }
370
371     @Test
372     public void testGetVnfItem() {
373         // missing data
374         AaiCqResponse cq = mock(AaiCqResponse.class);
375         assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo()))
376                         .withMessage("missing generic VNF");
377
378         // valid data
379         GenericVnf vnf = new GenericVnf();
380         when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf);
381         assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo()));
382     }
383
384     @Test
385     public void testGetServiceInstance() {
386         // missing data
387         AaiCqResponse cq = mock(AaiCqResponse.class);
388         assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq))
389                         .withMessage("missing VNF Service Item");
390
391         // valid data
392         ServiceInstance instance = new ServiceInstance();
393         when(cq.getServiceInstance()).thenReturn(instance);
394         assertSame(instance, oper.getServiceInstance(cq));
395     }
396
397     @Test
398     public void testGetDefaultTenant() {
399         // missing data
400         AaiCqResponse cq = mock(AaiCqResponse.class);
401         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq))
402                         .withMessage("missing Tenant Item");
403
404         // valid data
405         Tenant tenant = new Tenant();
406         when(cq.getDefaultTenant()).thenReturn(tenant);
407         assertSame(tenant, oper.getDefaultTenant(cq));
408     }
409
410     @Test
411     public void testGetDefaultCloudRegion() {
412         // missing data
413         AaiCqResponse cq = mock(AaiCqResponse.class);
414         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq))
415                         .withMessage("missing Cloud Region");
416
417         // valid data
418         CloudRegion region = new CloudRegion();
419         when(cq.getDefaultCloudRegion()).thenReturn(region);
420         assertSame(region, oper.getDefaultCloudRegion(cq));
421     }
422 }