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