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