Merge "Modify Actors to use properties when provided"
[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.Mockito.mock;
32 import static org.mockito.Mockito.when;
33
34 import java.time.LocalDateTime;
35 import java.time.Month;
36 import java.util.Collections;
37 import java.util.List;
38 import java.util.concurrent.CompletableFuture;
39 import java.util.function.BiConsumer;
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.ModelVer;
47 import org.onap.aai.domain.yang.ServiceInstance;
48 import org.onap.aai.domain.yang.Tenant;
49 import org.onap.policy.aai.AaiCqResponse;
50 import org.onap.policy.common.utils.coder.Coder;
51 import org.onap.policy.common.utils.coder.CoderException;
52 import org.onap.policy.controlloop.ControlLoopOperation;
53 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
54 import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
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.SoRequestStatus;
60 import org.onap.policy.so.SoResponse;
61
62 public class SoOperationTest extends BasicSoOperation {
63
64     private static final String VF_COUNT_KEY = SoConstants.VF_COUNT_PREFIX
65                     + "[my-model-customization-id][my-model-invariant-id][my-model-version-id]";
66
67     private static final List<String> PROP_NAMES = Collections.emptyList();
68
69     private static final String VERSION_ID = "1.2.3";
70
71     private SoOperation oper;
72
73     /**
74      * Sets up.
75      */
76     @Before
77     public void setUp() throws Exception {
78         super.setUp();
79
80         initConfig();
81
82         oper = new SoOperation(params, config, PROP_NAMES) {};
83     }
84
85     @Test
86     public void testConstructor() {
87         assertEquals(DEFAULT_ACTOR, oper.getActorName());
88         assertEquals(DEFAULT_OPERATION, oper.getName());
89         assertSame(config, oper.getConfig());
90         assertTrue(oper.isUsePolling());
91
92         // check when Target is null
93         params = params.toBuilder().target(null).build();
94         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config, PROP_NAMES) {})
95                         .withMessageContaining("Target information");
96     }
97
98     @Test
99     public void testValidateTarget() {
100         // check when various fields are null
101         verifyNotNull("modelCustomizationId", target::getModelCustomizationId, target::setModelCustomizationId);
102         verifyNotNull("modelInvariantId", target::getModelInvariantId, target::setModelInvariantId);
103         verifyNotNull("modelVersionId", target::getModelVersionId, target::setModelVersionId);
104
105         // verify it's still valid
106         assertThatCode(() -> new VfModuleCreate(params, config)).doesNotThrowAnyException();
107     }
108
109     private void verifyNotNull(String expectedText, Supplier<String> getter, Consumer<String> setter) {
110         String originalValue = getter.get();
111
112         // try with null
113         setter.accept(null);
114         assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config))
115                         .withMessageContaining(expectedText);
116
117         setter.accept(originalValue);
118     }
119
120     @Test
121     public void testStartPreprocessorAsync() {
122         assertNotNull(oper.startPreprocessorAsync());
123     }
124
125     @Test
126     public void testObtainVfCount_testGetVfCount_testSetVfCount() throws Exception {
127         // insert CQ data so it's there for the check
128         context.setProperty(AaiCqResponse.CONTEXT_KEY, makeCqResponse());
129
130         // shouldn't actually need to do anything
131         assertNull(oper.obtainVfCount());
132
133         // verify that the count was stored
134         Integer vfcount = context.getProperty(VF_COUNT_KEY);
135         assertEquals(VF_COUNT, vfcount);
136         assertEquals(VF_COUNT.intValue(), oper.getVfCount());
137
138         // change the count and then verify that it isn't overwritten by another call
139         oper.setVfCount(VF_COUNT + 1);
140
141         assertNull(oper.obtainVfCount());
142         vfcount = context.getProperty(VF_COUNT_KEY);
143         assertEquals(VF_COUNT + 1, vfcount.intValue());
144         assertEquals(VF_COUNT + 1, oper.getVfCount());
145     }
146
147     /**
148      * Tests the VF Count methods when properties are being used.
149      * @throws Exception if an error occurs
150      */
151     @Test
152     public void testGetVfCount_testSetVfCount_ViaProperties() throws Exception {
153         oper.setProperty(OperationProperties.DATA_VF_COUNT, VF_COUNT);
154
155         // verify that the count was stored
156         assertEquals(VF_COUNT.intValue(), oper.getVfCount());
157
158         oper.setVfCount(VF_COUNT + 1);
159
160         int count = oper.getProperty(OperationProperties.DATA_VF_COUNT);
161         assertEquals(VF_COUNT + 1, count);
162         assertEquals(VF_COUNT + 1, oper.getVfCount());
163     }
164
165     /**
166      * Tests obtainVfCount() when it actually has to query.
167      */
168     @Test
169     public void testObtainVfCountQuery() throws Exception {
170         CompletableFuture<OperationOutcome> future2 = oper.obtainVfCount();
171         assertNotNull(future2);
172         assertTrue(executor.runAll(100));
173
174         // not done yet
175         assertFalse(future2.isDone());
176
177         provideCqResponse(makeCqResponse());
178
179         assertTrue(executor.runAll(100));
180         assertTrue(future2.isDone());
181         assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
182
183         // verify that the count was stored
184         Integer vfcount = context.getProperty(VF_COUNT_KEY);
185         assertEquals(VF_COUNT, vfcount);
186
187         // repeat - shouldn't need to do anything now
188         assertNull(oper.obtainVfCount());
189     }
190
191     @Test
192     public void testGetRequestState() {
193         SoResponse resp = new SoResponse();
194         assertNull(oper.getRequestState(resp));
195
196         SoRequest req = new SoRequest();
197         resp.setRequest(req);
198         assertNull(oper.getRequestState(resp));
199
200         SoRequestStatus status = new SoRequestStatus();
201         req.setRequestStatus(status);
202         assertNull(oper.getRequestState(resp));
203
204         status.setRequestState("my-state");
205         assertEquals("my-state", oper.getRequestState(resp));
206     }
207
208     @Test
209     public void testIsSuccess() {
210         // always true
211
212         assertTrue(oper.isSuccess(rawResponse, response));
213
214         when(rawResponse.getStatus()).thenReturn(500);
215         assertTrue(oper.isSuccess(rawResponse, response));
216     }
217
218     @Test
219     public void testSetOutcome() {
220         // success case
221         when(rawResponse.getStatus()).thenReturn(200);
222         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response));
223
224         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
225         assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
226         assertSame(response, outcome.getResponse());
227
228         // failure case
229         when(rawResponse.getStatus()).thenReturn(500);
230         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response));
231
232         assertEquals(PolicyResult.FAILURE, outcome.getResult());
233         assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage());
234         assertSame(response, outcome.getResponse());
235     }
236
237     @Test
238     public void testPrepareSoModelInfo() throws CoderException {
239         verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId);
240         verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId);
241         verifyMissingModelInfo(target::getModelName, target::setModelName);
242         verifyMissingModelInfo(target::getModelVersion, target::setModelVersion);
243         verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId);
244
245         // valid data
246         SoModelInfo info = oper.prepareSoModelInfo();
247         verifyRequest("model.json", info);
248
249         // try with null target
250         params = params.toBuilder().target(null).build();
251         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config, PROP_NAMES) {})
252                         .withMessageContaining("missing Target");
253     }
254
255     private void verifyMissingModelInfo(Supplier<String> getter, Consumer<String> setter) {
256         String original = getter.get();
257
258         setter.accept(null);
259         assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo())
260                         .withMessage("missing VF Module model");
261
262         setter.accept(original);
263     }
264
265     @Test
266     public void testConstructRequestInfo() throws CoderException {
267         SoRequestInfo info = oper.constructRequestInfo();
268         verifyRequest("reqinfo.json", info);
269     }
270
271     @Test
272     public void testBuildRequestParameters() throws CoderException {
273         // valid data
274         verifyRequest("reqparams.json", oper.buildRequestParameters().get());
275
276         // invalid json
277         params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json");
278         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters())
279                         .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM);
280
281         // missing data
282         params.getPayload().remove(SoOperation.REQ_PARAM_NM);
283         assertTrue(oper.buildRequestParameters().isEmpty());
284
285         // null payload
286         params = params.toBuilder().payload(null).build();
287         oper = new SoOperation(params, config, PROP_NAMES) {};
288         assertTrue(oper.buildRequestParameters().isEmpty());
289     }
290
291     @Test
292     public void testBuildConfigurationParameters() {
293         // valid data
294         assertEquals(List.of(Collections.emptyMap()), oper.buildConfigurationParameters().get());
295
296         // invalid json
297         params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json");
298         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters())
299                         .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM);
300
301         // missing data
302         params.getPayload().remove(SoOperation.CONFIG_PARAM_NM);
303         assertTrue(oper.buildConfigurationParameters().isEmpty());
304
305         // null payload
306         params = params.toBuilder().payload(null).build();
307         oper = new SoOperation(params, config, PROP_NAMES) {};
308         assertTrue(oper.buildConfigurationParameters().isEmpty());
309     }
310
311     @Test
312     public void testGetItem() {
313         AaiCqResponse cq = mock(AaiCqResponse.class);
314         params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
315
316         // in neither property nor custom query
317         assertThatIllegalArgumentException().isThrownBy(() -> oper.getItem("propA", cq2 -> null, "not found"))
318                         .withMessage("not found");
319
320         // only in custom query
321         assertEquals("valueB", oper.getItem("propB", cq2 -> "valueB", "failureB"));
322
323         // both - should choose the property
324         oper.setProperty("propC", "valueC");
325         assertEquals("valueC", oper.getItem("propC", cq2 -> "valueC2", "failureC"));
326
327         // both - should choose the property, even if it's null
328         oper.setProperty("propD", null);
329         assertNull(oper.getItem("propD", cq2 -> "valueD2", "failureD"));
330     }
331
332     @Test
333     public void testGetVnfItem() {
334         // @formatter:off
335         verifyItems(OperationProperties.AAI_VNF, GenericVnf::new,
336             (cq, instance) -> when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(instance),
337             () -> oper.getVnfItem(oper.prepareSoModelInfo()),
338             "missing generic VNF");
339         // @formatter:on
340     }
341
342     @Test
343     public void testGetServiceInstance() {
344         // @formatter:off
345         verifyItems(OperationProperties.AAI_SERVICE, ServiceInstance::new,
346             (cq, instance) -> when(cq.getServiceInstance()).thenReturn(instance),
347             () -> oper.getServiceInstance(),
348             "missing VNF Service Item");
349         // @formatter:on
350     }
351
352     @Test
353     public void testGetDefaultTenant() {
354         // @formatter:off
355         verifyItems(OperationProperties.AAI_DEFAULT_TENANT, Tenant::new,
356             (cq, tenant) -> when(cq.getDefaultTenant()).thenReturn(tenant),
357             () -> oper.getDefaultTenant(),
358             "missing Default Tenant Item");
359         // @formatter:on
360     }
361
362     @Test
363     public void testGetVnfModel() {
364         GenericVnf vnf = new GenericVnf();
365         vnf.setModelVersionId(VERSION_ID);
366
367         // @formatter:off
368         verifyItems(OperationProperties.AAI_VNF_MODEL, ModelVer::new,
369             (cq, model) -> when(cq.getModelVerByVersionId(VERSION_ID)).thenReturn(model),
370             () -> oper.getVnfModel(vnf),
371             "missing generic VNF Model");
372         // @formatter:on
373     }
374
375     @Test
376     public void testGetServiceModel() {
377         ServiceInstance service = new ServiceInstance();
378         service.setModelVersionId(VERSION_ID);
379
380         // @formatter:off
381         verifyItems(OperationProperties.AAI_SERVICE_MODEL, ModelVer::new,
382             (cq, model) -> when(cq.getModelVerByVersionId(VERSION_ID)).thenReturn(model),
383             () -> oper.getServiceModel(service),
384             "missing Service Model");
385         // @formatter:on
386     }
387
388     @Test
389     public void testGetDefaultCloudRegion() {
390         // @formatter:off
391         verifyItems(OperationProperties.AAI_DEFAULT_CLOUD_REGION, CloudRegion::new,
392             (cq, region) -> when(cq.getDefaultCloudRegion()).thenReturn(region),
393             () -> oper.getDefaultCloudRegion(),
394             "missing Default Cloud Region");
395         // @formatter:on
396     }
397
398     private <T> void verifyItems(String propName, Supplier<T> maker, BiConsumer<AaiCqResponse, T> setter,
399                     Supplier<T> getter, String errmsg) {
400
401         AaiCqResponse cq = mock(AaiCqResponse.class);
402         params.getContext().setProperty(AaiCqResponse.CONTEXT_KEY, cq);
403
404         // in neither property nor custom query
405         assertThatIllegalArgumentException().isThrownBy(getter::get).withMessage(errmsg);
406
407         // only in custom query
408         final T item1 = maker.get();
409         setter.accept(cq, item1);
410         assertSame(item1, getter.get());
411
412         // both - should choose the property
413         final T item2 = maker.get();
414         oper.setProperty(propName, item2);
415         assertSame(item2, getter.get());
416
417         // both - should choose the property, even if it's null
418         oper.setProperty(propName, null);
419         assertNull(getter.get());
420     }
421
422     @Test
423     public void testGetCoder() throws CoderException {
424         Coder opcoder = oper.getCoder();
425
426         // ensure we can decode an SO timestamp
427         String json = "{'request':{'finishTime':'Fri, 15 May 2020 12:14:21 GMT'}}";
428         SoResponse resp = opcoder.decode(json.replace('\'', '"'), SoResponse.class);
429
430         LocalDateTime tfinish = resp.getRequest().getFinishTime();
431         assertNotNull(tfinish);
432         assertEquals(2020, tfinish.getYear());
433         assertEquals(Month.MAY, tfinish.getMonth());
434     }
435 }