2  * ============LICENSE_START=======================================================
 
   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
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  21 package org.onap.policy.controlloop.actor.so;
 
  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;
 
  35 import java.time.LocalDateTime;
 
  36 import java.time.Month;
 
  37 import java.util.Collections;
 
  38 import java.util.List;
 
  39 import java.util.concurrent.CompletableFuture;
 
  40 import java.util.concurrent.ForkJoinPool;
 
  41 import java.util.concurrent.TimeUnit;
 
  42 import java.util.function.Consumer;
 
  43 import java.util.function.Supplier;
 
  44 import org.junit.Before;
 
  45 import org.junit.Test;
 
  46 import org.onap.aai.domain.yang.CloudRegion;
 
  47 import org.onap.aai.domain.yang.GenericVnf;
 
  48 import org.onap.aai.domain.yang.ServiceInstance;
 
  49 import org.onap.aai.domain.yang.Tenant;
 
  50 import org.onap.policy.aai.AaiCqResponse;
 
  51 import org.onap.policy.common.utils.coder.Coder;
 
  52 import org.onap.policy.common.utils.coder.CoderException;
 
  53 import org.onap.policy.controlloop.ControlLoopOperation;
 
  54 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 
  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.SoRequestReferences;
 
  60 import org.onap.policy.so.SoRequestStatus;
 
  61 import org.onap.policy.so.SoResponse;
 
  63 public class SoOperationTest extends BasicSoOperation {
 
  65     private static final String VF_COUNT_KEY = SoConstants.VF_COUNT_PREFIX
 
  66                     + "[my-model-customization-id][my-model-invariant-id][my-model-version-id]";
 
  67     private SoOperation oper;
 
  73     public void setUp() throws Exception {
 
  78         oper = new SoOperation(params, config) {};
 
  82     public void testConstructor_testGetWaitMsGet() {
 
  83         assertEquals(DEFAULT_ACTOR, oper.getActorName());
 
  84         assertEquals(DEFAULT_OPERATION, oper.getName());
 
  85         assertSame(config, oper.getConfig());
 
  86         assertEquals(1000 * WAIT_SEC_GETS, oper.getWaitMsGet());
 
  88         // check when Target is null
 
  89         params = params.toBuilder().target(null).build();
 
  90         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config) {})
 
  91                         .withMessageContaining("Target information");
 
  95     public void testValidateTarget() {
 
  96         // check when various fields are null
 
  97         verifyNotNull("modelCustomizationId", target::getModelCustomizationId, target::setModelCustomizationId);
 
  98         verifyNotNull("modelInvariantId", target::getModelInvariantId, target::setModelInvariantId);
 
  99         verifyNotNull("modelVersionId", target::getModelVersionId, target::setModelVersionId);
 
 101         // verify it's still valid
 
 102         assertThatCode(() -> new VfModuleCreate(params, config)).doesNotThrowAnyException();
 
 105     private void verifyNotNull(String expectedText, Supplier<String> getter, Consumer<String> setter) {
 
 106         String originalValue = getter.get();
 
 110         assertThatIllegalArgumentException().isThrownBy(() -> new VfModuleCreate(params, config))
 
 111                         .withMessageContaining(expectedText);
 
 113         setter.accept(originalValue);
 
 117     public void testStartPreprocessorAsync() {
 
 118         assertNotNull(oper.startPreprocessorAsync());
 
 122     public void testObtainVfCount_testGetVfCount_testSetVfCount() throws Exception {
 
 123         // insert CQ data so it's there for the check
 
 124         context.setProperty(AaiCqResponse.CONTEXT_KEY, makeCqResponse());
 
 126         // shouldn't actually need to do anything
 
 127         assertNull(oper.obtainVfCount());
 
 129         // verify that the count was stored
 
 130         Integer vfcount = context.getProperty(VF_COUNT_KEY);
 
 131         assertEquals(VF_COUNT, vfcount);
 
 132         assertEquals(VF_COUNT.intValue(), oper.getVfCount());
 
 134         // change the count and then verify that it isn't overwritten by another call
 
 135         oper.setVfCount(VF_COUNT + 1);
 
 137         assertNull(oper.obtainVfCount());
 
 138         vfcount = context.getProperty(VF_COUNT_KEY);
 
 139         assertEquals(VF_COUNT + 1, vfcount.intValue());
 
 140         assertEquals(VF_COUNT + 1, oper.getVfCount());
 
 144      * Tests obtainVfCount() when it actually has to query.
 
 147     public void testObtainVfCountQuery() throws Exception {
 
 148         CompletableFuture<OperationOutcome> future2 = oper.obtainVfCount();
 
 149         assertNotNull(future2);
 
 150         assertTrue(executor.runAll(100));
 
 153         assertFalse(future2.isDone());
 
 155         provideCqResponse(makeCqResponse());
 
 157         assertTrue(executor.runAll(100));
 
 158         assertTrue(future2.isDone());
 
 159         assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
 
 161         // verify that the count was stored
 
 162         Integer vfcount = context.getProperty(VF_COUNT_KEY);
 
 163         assertEquals(VF_COUNT, vfcount);
 
 165         // repeat - shouldn't need to do anything now
 
 166         assertNull(oper.obtainVfCount());
 
 170     public void testPostProcess() throws Exception {
 
 172         oper.generateSubRequestId(2);
 
 173         assertNull(oper.getSubRequestId());
 
 174         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
 
 175         assertTrue(future2.isDone());
 
 176         assertSame(outcome, future2.get());
 
 177         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
 
 178         assertNotNull(oper.getSubRequestId());
 
 179         assertSame(response, outcome.getResponse());
 
 182         oper.generateSubRequestId(2);
 
 183         assertNull(oper.getSubRequestId());
 
 184         response.getRequest().getRequestStatus().setRequestState(SoOperation.FAILED);
 
 185         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
 
 186         assertTrue(future2.isDone());
 
 187         assertSame(outcome, future2.get());
 
 188         assertEquals(PolicyResult.FAILURE, outcome.getResult());
 
 189         assertNotNull(oper.getSubRequestId());
 
 190         assertSame(response, outcome.getResponse());
 
 192         // no request id in the response
 
 193         oper.generateSubRequestId(2);
 
 194         assertNull(oper.getSubRequestId());
 
 195         response.getRequestReferences().setRequestId(null);
 
 196         response.getRequest().getRequestStatus().setRequestState("unknown");
 
 197         assertThatIllegalArgumentException()
 
 198                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
 
 199                         .withMessage("missing request ID in response");
 
 200         response.getRequestReferences().setRequestId(REQ_ID.toString());
 
 203         when(rawResponse.getStatus()).thenReturn(500);
 
 205         // null request reference
 
 206         SoRequestReferences ref = response.getRequestReferences();
 
 207         response.setRequestReferences(null);
 
 208         assertThatIllegalArgumentException()
 
 209                         .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response))
 
 210                         .withMessage("missing request ID in response");
 
 211         response.setRequestReferences(ref);
 
 215      * Tests postProcess() when the "get" is repeated a couple of times.
 
 218     public void testPostProcessRepeated_testResetGetCount() throws Exception {
 
 220          * Two failures and then a success - should result in two "get" calls.
 
 222          * Note: getStatus() is invoked twice during each call, so have to double up the
 
 225         when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200);
 
 227         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
 
 229         // use a real executor
 
 230         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
 
 232         oper = new SoOperation(params, config) {
 
 234             public long getWaitMsGet() {
 
 239         CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
 
 241         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
 
 242         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
 
 243         assertEquals(2, oper.getGetCount());
 
 246          * repeat - this time, the "get" operations will be exhausted, so it should fail
 
 248         when(rawResponse.getStatus()).thenReturn(500);
 
 250         future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response);
 
 252         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
 
 253         assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult());
 
 254         assertEquals(MAX_GETS + 1, oper.getGetCount());
 
 256         oper.resetGetCount();
 
 257         assertEquals(0, oper.getGetCount());
 
 258         assertNull(oper.getSubRequestId());
 
 262     public void testGetRequestState() {
 
 263         SoResponse resp = new SoResponse();
 
 264         assertNull(oper.getRequestState(resp));
 
 266         SoRequest req = new SoRequest();
 
 267         resp.setRequest(req);
 
 268         assertNull(oper.getRequestState(resp));
 
 270         SoRequestStatus status = new SoRequestStatus();
 
 271         req.setRequestStatus(status);
 
 272         assertNull(oper.getRequestState(resp));
 
 274         status.setRequestState("my-state");
 
 275         assertEquals("my-state", oper.getRequestState(resp));
 
 279     public void testIsSuccess() {
 
 282         assertTrue(oper.isSuccess(rawResponse, response));
 
 284         when(rawResponse.getStatus()).thenReturn(500);
 
 285         assertTrue(oper.isSuccess(rawResponse, response));
 
 289     public void testSetOutcome() {
 
 291         when(rawResponse.getStatus()).thenReturn(200);
 
 292         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response));
 
 294         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
 
 295         assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
 
 296         assertSame(response, outcome.getResponse());
 
 299         when(rawResponse.getStatus()).thenReturn(500);
 
 300         assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response));
 
 302         assertEquals(PolicyResult.FAILURE, outcome.getResult());
 
 303         assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage());
 
 304         assertSame(response, outcome.getResponse());
 
 308     public void testPrepareSoModelInfo() throws CoderException {
 
 309         verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId);
 
 310         verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId);
 
 311         verifyMissingModelInfo(target::getModelName, target::setModelName);
 
 312         verifyMissingModelInfo(target::getModelVersion, target::setModelVersion);
 
 313         verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId);
 
 316         SoModelInfo info = oper.prepareSoModelInfo();
 
 317         verifyRequest("model.json", info);
 
 319         // try with null target
 
 320         params = params.toBuilder().target(null).build();
 
 321         assertThatIllegalArgumentException().isThrownBy(() -> new SoOperation(params, config) {})
 
 322                         .withMessageContaining("missing Target");
 
 325     private void verifyMissingModelInfo(Supplier<String> getter, Consumer<String> setter) {
 
 326         String original = getter.get();
 
 329         assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo())
 
 330                         .withMessage("missing VF Module model");
 
 332         setter.accept(original);
 
 336     public void testConstructRequestInfo() throws CoderException {
 
 337         SoRequestInfo info = oper.constructRequestInfo();
 
 338         verifyRequest("reqinfo.json", info);
 
 342     public void testBuildRequestParameters() throws CoderException {
 
 344         verifyRequest("reqparams.json", oper.buildRequestParameters().get());
 
 347         params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json");
 
 348         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters())
 
 349                         .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM);
 
 352         params.getPayload().remove(SoOperation.REQ_PARAM_NM);
 
 353         assertTrue(oper.buildRequestParameters().isEmpty());
 
 356         params = params.toBuilder().payload(null).build();
 
 357         oper = new SoOperation(params, config) {};
 
 358         assertTrue(oper.buildRequestParameters().isEmpty());
 
 362     public void testBuildConfigurationParameters() {
 
 364         assertEquals(List.of(Collections.emptyMap()), oper.buildConfigurationParameters().get());
 
 367         params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json");
 
 368         assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters())
 
 369                         .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM);
 
 372         params.getPayload().remove(SoOperation.CONFIG_PARAM_NM);
 
 373         assertTrue(oper.buildConfigurationParameters().isEmpty());
 
 376         params = params.toBuilder().payload(null).build();
 
 377         oper = new SoOperation(params, config) {};
 
 378         assertTrue(oper.buildConfigurationParameters().isEmpty());
 
 382     public void testGetVnfItem() {
 
 384         AaiCqResponse cq = mock(AaiCqResponse.class);
 
 385         assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo()))
 
 386                         .withMessage("missing generic VNF");
 
 389         GenericVnf vnf = new GenericVnf();
 
 390         when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf);
 
 391         assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo()));
 
 395     public void testGetServiceInstance() {
 
 397         AaiCqResponse cq = mock(AaiCqResponse.class);
 
 398         assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq))
 
 399                         .withMessage("missing VNF Service Item");
 
 402         ServiceInstance instance = new ServiceInstance();
 
 403         when(cq.getServiceInstance()).thenReturn(instance);
 
 404         assertSame(instance, oper.getServiceInstance(cq));
 
 408     public void testGetDefaultTenant() {
 
 410         AaiCqResponse cq = mock(AaiCqResponse.class);
 
 411         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq))
 
 412                         .withMessage("missing Tenant Item");
 
 415         Tenant tenant = new Tenant();
 
 416         when(cq.getDefaultTenant()).thenReturn(tenant);
 
 417         assertSame(tenant, oper.getDefaultTenant(cq));
 
 421     public void testGetDefaultCloudRegion() {
 
 423         AaiCqResponse cq = mock(AaiCqResponse.class);
 
 424         assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq))
 
 425                         .withMessage("missing Cloud Region");
 
 428         CloudRegion region = new CloudRegion();
 
 429         when(cq.getDefaultCloudRegion()).thenReturn(region);
 
 430         assertSame(region, oper.getDefaultCloudRegion(cq));
 
 434     public void testGetCoder() throws CoderException {
 
 435         Coder opcoder = oper.getCoder();
 
 437         // ensure we can decode an SO timestamp
 
 438         String json = "{'request':{'finishTime':'Fri, 15 May 2020 12:14:21 GMT'}}";
 
 439         SoResponse resp = opcoder.decode(json.replace('\'', '"'), SoResponse.class);
 
 441         LocalDateTime tfinish = resp.getRequest().getFinishTime();
 
 442         assertNotNull(tfinish);
 
 443         assertEquals(2020, tfinish.getYear());
 
 444         assertEquals(Month.MAY, tfinish.getMonth());