/*- * ============LICENSE_START======================================================= * ONAP * ================================================================================ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.onap.policy.controlloop.actor.so; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Supplier; import org.junit.Before; import org.junit.Test; import org.onap.aai.domain.yang.CloudRegion; import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.ServiceInstance; import org.onap.aai.domain.yang.Tenant; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.common.utils.coder.CoderException; import org.onap.policy.controlloop.ControlLoopOperation; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.policy.PolicyResult; import org.onap.policy.so.SoModelInfo; import org.onap.policy.so.SoRequest; import org.onap.policy.so.SoRequestInfo; import org.onap.policy.so.SoRequestParameters; import org.onap.policy.so.SoRequestReferences; import org.onap.policy.so.SoRequestStatus; import org.onap.policy.so.SoResponse; public class SoOperationTest extends BasicSoOperation { private SoOperation oper; /** * Sets up. */ @Before public void setUp() throws Exception { super.setUp(); initConfig(); oper = new SoOperation(params, config) {}; } @Test public void testConstructor_testGetWaitMsGet() { assertEquals(DEFAULT_ACTOR, oper.getActorName()); assertEquals(DEFAULT_OPERATION, oper.getName()); assertSame(config, oper.getConfig()); assertEquals(1000 * WAIT_SEC_GETS, oper.getWaitMsGet()); } @Test public void testStartPreprocessorAsync() { AtomicBoolean guardStarted = new AtomicBoolean(); oper = new SoOperation(params, config) { @Override protected CompletableFuture startGuardAsync() { guardStarted.set(true); return super.startGuardAsync(); } }; assertNull(oper.startPreprocessorAsync()); assertTrue(guardStarted.get()); } @Test public void testPostProcess() throws Exception { // completed CompletableFuture future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); assertTrue(future2.isDone()); assertSame(outcome, future2.get()); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); // failed response.getRequest().getRequestStatus().setRequestState(SoOperation.FAILED); future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); assertTrue(future2.isDone()); assertSame(outcome, future2.get()); assertEquals(PolicyResult.FAILURE, outcome.getResult()); // no request id in the response response.getRequestReferences().setRequestId(null); response.getRequest().getRequestStatus().setRequestState("unknown"); assertThatIllegalArgumentException() .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response)) .withMessage("missing request ID in response"); response.getRequestReferences().setRequestId(REQ_ID.toString()); // status = 500 when(rawResponse.getStatus()).thenReturn(500); // null request reference SoRequestReferences ref = response.getRequestReferences(); response.setRequestReferences(null); assertThatIllegalArgumentException() .isThrownBy(() -> oper.postProcessResponse(outcome, PATH, rawResponse, response)) .withMessage("missing request ID in response"); response.setRequestReferences(ref); } /** * Tests postProcess() when the "get" is repeated a couple of times. */ @Test public void testPostProcessRepeated_testResetGetCount() throws Exception { /* * Two failures and then a success - should result in two "get" calls. * * Note: getStatus() is invoked twice during each call, so have to double up the * return values. */ when(rawResponse.getStatus()).thenReturn(500, 500, 500, 500, 200, 200); when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse)); // use a real executor params = params.toBuilder().executor(ForkJoinPool.commonPool()).build(); oper = new SoOperation(params, config) { @Override public long getWaitMsGet() { return 1; } }; CompletableFuture future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); assertSame(outcome, future2.get(500, TimeUnit.SECONDS)); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); assertEquals(2, oper.getGetCount()); /* * repeat - this time, the "get" operations will be exhausted, so it should fail */ when(rawResponse.getStatus()).thenReturn(500); future2 = oper.postProcessResponse(outcome, PATH, rawResponse, response); assertSame(outcome, future2.get(5, TimeUnit.SECONDS)); assertEquals(PolicyResult.FAILURE_TIMEOUT, outcome.getResult()); assertEquals(MAX_GETS + 1, oper.getGetCount()); oper.resetGetCount(); assertEquals(0, oper.getGetCount()); } @Test public void testGetRequestState() { SoResponse resp = new SoResponse(); assertNull(oper.getRequestState(resp)); SoRequest req = new SoRequest(); resp.setRequest(req); assertNull(oper.getRequestState(resp)); SoRequestStatus status = new SoRequestStatus(); req.setRequestStatus(status); assertNull(oper.getRequestState(resp)); status.setRequestState("my-state"); assertEquals("my-state", oper.getRequestState(resp)); } @Test public void testIsSuccess() { // always true assertTrue(oper.isSuccess(rawResponse, response)); when(rawResponse.getStatus()).thenReturn(500); assertTrue(oper.isSuccess(rawResponse, response)); } @Test public void testSetOutcome() { // success case when(rawResponse.getStatus()).thenReturn(200); assertSame(outcome, oper.setOutcome(outcome, PolicyResult.SUCCESS, rawResponse, response)); assertEquals(PolicyResult.SUCCESS, outcome.getResult()); assertEquals("200 " + ControlLoopOperation.SUCCESS_MSG, outcome.getMessage()); // failure case when(rawResponse.getStatus()).thenReturn(500); assertSame(outcome, oper.setOutcome(outcome, PolicyResult.FAILURE, rawResponse, response)); assertEquals(PolicyResult.FAILURE, outcome.getResult()); assertEquals("500 " + ControlLoopOperation.FAILED_MSG, outcome.getMessage()); } @Test public void testPrepareSoModelInfo() throws CoderException { verifyMissingModelInfo(target::getModelCustomizationId, target::setModelCustomizationId); verifyMissingModelInfo(target::getModelInvariantId, target::setModelInvariantId); verifyMissingModelInfo(target::getModelName, target::setModelName); verifyMissingModelInfo(target::getModelVersion, target::setModelVersion); verifyMissingModelInfo(target::getModelVersionId, target::setModelVersionId); // valid data SoModelInfo info = oper.prepareSoModelInfo(); verifyRequest("model.json", info); // try with null target params = params.toBuilder().target(null).build(); oper = new SoOperation(params, config) {}; assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo()).withMessage("missing Target"); } private void verifyMissingModelInfo(Supplier getter, Consumer setter) { String original = getter.get(); setter.accept(null); assertThatIllegalArgumentException().isThrownBy(() -> oper.prepareSoModelInfo()) .withMessage("missing VF Module model"); setter.accept(original); } @Test public void testConstructRequestInfo() throws CoderException { SoRequestInfo info = oper.constructRequestInfo(); verifyRequest("reqinfo.json", info); } @Test public void testBuildRequestParameters() throws CoderException { // valid data SoRequestParameters reqParams = oper.buildRequestParameters(); verifyRequest("reqparams.json", reqParams); // invalid json params.getPayload().put(SoOperation.REQ_PARAM_NM, "{invalid json"); assertThatIllegalArgumentException().isThrownBy(() -> oper.buildRequestParameters()) .withMessage("invalid payload value: " + SoOperation.REQ_PARAM_NM); // missing data params.getPayload().remove(SoOperation.REQ_PARAM_NM); assertNull(oper.buildRequestParameters()); // null payload params = params.toBuilder().payload(null).build(); oper = new SoOperation(params, config) {}; assertNull(oper.buildRequestParameters()); } @Test public void testBuildConfigurationParameters() { // valid data List> result = oper.buildConfigurationParameters(); assertEquals(List.of(Collections.emptyMap()), result); // invalid json params.getPayload().put(SoOperation.CONFIG_PARAM_NM, "{invalid json"); assertThatIllegalArgumentException().isThrownBy(() -> oper.buildConfigurationParameters()) .withMessage("invalid payload value: " + SoOperation.CONFIG_PARAM_NM); // missing data params.getPayload().remove(SoOperation.CONFIG_PARAM_NM); assertNull(oper.buildConfigurationParameters()); // null payload params = params.toBuilder().payload(null).build(); oper = new SoOperation(params, config) {}; assertNull(oper.buildConfigurationParameters()); } @Test public void testGetVnfItem() { // missing data AaiCqResponse cq = mock(AaiCqResponse.class); assertThatIllegalArgumentException().isThrownBy(() -> oper.getVnfItem(cq, oper.prepareSoModelInfo())) .withMessage("missing generic VNF"); // valid data GenericVnf vnf = new GenericVnf(); when(cq.getGenericVnfByVfModuleModelInvariantId(MODEL_INVAR_ID)).thenReturn(vnf); assertSame(vnf, oper.getVnfItem(cq, oper.prepareSoModelInfo())); } @Test public void testGetServiceInstance() { // missing data AaiCqResponse cq = mock(AaiCqResponse.class); assertThatIllegalArgumentException().isThrownBy(() -> oper.getServiceInstance(cq)) .withMessage("missing VNF Service Item"); // valid data ServiceInstance instance = new ServiceInstance(); when(cq.getServiceInstance()).thenReturn(instance); assertSame(instance, oper.getServiceInstance(cq)); } @Test public void testGetDefaultTenant() { // missing data AaiCqResponse cq = mock(AaiCqResponse.class); assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultTenant(cq)) .withMessage("missing Tenant Item"); // valid data Tenant tenant = new Tenant(); when(cq.getDefaultTenant()).thenReturn(tenant); assertSame(tenant, oper.getDefaultTenant(cq)); } @Test public void testGetDefaultCloudRegion() { // missing data AaiCqResponse cq = mock(AaiCqResponse.class); assertThatIllegalArgumentException().isThrownBy(() -> oper.getDefaultCloudRegion(cq)) .withMessage("missing Cloud Region"); // valid data CloudRegion region = new CloudRegion(); when(cq.getDefaultCloudRegion()).thenReturn(region); assertSame(region, oper.getDefaultCloudRegion(cq)); } }