/*-
* ============LICENSE_START=======================================================
- * AppcLcmOperation
+ * ONAP
* ================================================================================
- * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
+ * Modifications Copyright (C) 2023 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package org.onap.policy.controlloop.actor.appclcm;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeast;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
-import java.util.UUID;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.After;
+import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.Ignore;
+import org.junit.BeforeClass;
import org.junit.Test;
-import org.mockito.Mockito;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
import org.onap.policy.appclcm.AppcLcmBody;
import org.onap.policy.appclcm.AppcLcmCommonHeader;
import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
-import org.onap.policy.appclcm.AppcLcmInput;
import org.onap.policy.appclcm.AppcLcmOutput;
import org.onap.policy.appclcm.AppcLcmResponseStatus;
-import org.onap.policy.controlloop.VirtualControlLoopEvent;
-import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
-import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
+import org.onap.policy.common.endpoints.event.comm.TopicSink;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.common.utils.coder.Coder;
+import org.onap.policy.common.utils.coder.CoderException;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.controlloop.ControlLoopOperation;
+import org.onap.policy.controlloop.actor.test.BasicBidirectionalTopicOperation;
+import org.onap.policy.controlloop.actorserviceprovider.OperationProperties;
+import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
import org.onap.policy.controlloop.actorserviceprovider.impl.BidirectionalTopicOperation.Status;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicConfig;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicParams;
import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
-import org.onap.policy.controlloop.policy.PolicyResult;
-import org.powermock.reflect.Whitebox;
-
-public class AppcLcmOperationTest {
- private AppcLcmInput mockInput;
- private AppcLcmOutput mockOutput;
- private AppcLcmBody mockBody;
- private AppcLcmDmaapWrapper mockInputWrapper;
- private AppcLcmDmaapWrapper mockOutputWrapper;
- private OperationOutcome mockOperationOutcome;
- private AppcLcmOperation operation;
- private AppcLcmResponseStatus mockResponseStatus;
- private AppcLcmCommonHeader mockCommonHeader;
- private ControlLoopOperationParams mockParams;
- private ControlLoopEventContext mockContext;
- private VirtualControlLoopEvent mockEvent;
+import org.onap.policy.simulators.AppcLcmTopicServer;
+import org.onap.policy.simulators.TopicServer;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AppcLcmOperationTest extends BasicBidirectionalTopicOperation<AppcLcmDmaapWrapper> {
+
+ private static final String EXPECTED_EXCEPTION = "expected exception";
+ private static final String PAYLOAD_KEY1 = "key-A";
+ private static final String PAYLOAD_VALUE1 = "value-A";
+ private static final String MY_MESSAGE = "my-message";
+ protected static final String MY_VNF = "my-vnf";
+ protected static final String RESOURCE_ID = "my-resource";
+ private static final int SUCCESS_CODE = 400;
+
+ private AppcLcmDmaapWrapper response;
+ private AppcLcmOperation oper;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ initBeforeClass(MY_SINK, MY_SOURCE);
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() {
+ destroyAfterClass();
+ }
/**
- * Setup mocks for testing.
+ * Sets up.
*/
@Before
- public void setup() {
- mockInput = Mockito.mock(AppcLcmInput.class);
- mockOutput = Mockito.mock(AppcLcmOutput.class);
- mockBody = Mockito.mock(AppcLcmBody.class);
- mockContext = Mockito.mock(ControlLoopEventContext.class);
- mockEvent = Mockito.mock(VirtualControlLoopEvent.class);
- mockInputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class);
- mockOutputWrapper = Mockito.mock(AppcLcmDmaapWrapper.class);
- mockOperationOutcome = Mockito.mock(OperationOutcome.class);
- mockResponseStatus = Mockito.mock(AppcLcmResponseStatus.class);
- mockCommonHeader = Mockito.mock(AppcLcmCommonHeader.class);
- mockParams = Mockito.mock(ControlLoopOperationParams.class);
- operation = Mockito.mock(AppcLcmOperation.class);
+ public void setUp() {
+ super.setUpBasic();
+
+ response = makeResponse();
+
+ oper = new AppcLcmOperation(params, config);
+ oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, TARGET_ENTITY);
}
+ @After
+ public void tearDown() {
+ super.tearDownBasic();
+ }
+
+ @Override
+ protected TopicServer<AppcLcmDmaapWrapper> makeServer(TopicSink sink, TopicSource source) {
+ return new AppcLcmTopicServer(sink, source);
+ }
+
+ /**
+ * Tests "success" case with simulator.
+ */
@Test
- public void testStartPreprocessorAsync() {
- Mockito.doCallRealMethod().when(operation).startPreprocessorAsync();
- assertNull(operation.startPreprocessorAsync());
+ public void testSuccess() throws Exception {
+ BidirectionalTopicParams opParams =
+ BidirectionalTopicParams.builder().sinkTopic(MY_SINK).sourceTopic(MY_SOURCE).build();
+ config = new BidirectionalTopicConfig(blockingExecutor, opParams, topicMgr, AppcLcmOperation.SELECTOR_KEYS);
+
+ params = params.toBuilder().retry(0).timeoutSec(5).executor(blockingExecutor).build();
+
+ oper = new AppcLcmOperation(params, config);
+ oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, TARGET_ENTITY);
+
+ outcome = oper.start().get();
+ assertEquals(OperationResult.SUCCESS, outcome.getResult());
+ assertTrue(outcome.getResponse() instanceof AppcLcmDmaapWrapper);
+ }
+
+ @Test
+ public void testConstructor() {
+ assertEquals(DEFAULT_ACTOR, oper.getActorName());
+ assertEquals(DEFAULT_OPERATION, oper.getName());
+ }
+
+ @Test
+ public void testGetPropertyNames() {
+ assertThat(oper.getPropertyNames()).isEqualTo(List.of(OperationProperties.AAI_TARGET_ENTITY));
}
- @Ignore
@Test
public void testMakeRequest() {
- UUID randomId = UUID.randomUUID();
- Mockito.doCallRealMethod().when(operation).makeRequest(1, "sampleTargetVnf");
- Mockito.when(mockParams.getRequestId()).thenReturn(randomId);
- Mockito.when(mockParams.getPayload()).thenReturn(null);
- Mockito.when(mockParams.getContext()).thenReturn(mockContext);
- Mockito.when(mockParams.getOperation()).thenReturn("Config-Modify");
- Mockito.when(mockContext.getEvent()).thenReturn(mockEvent);
- Mockito.when(mockEvent.getRequestId()).thenReturn(randomId);
- Whitebox.setInternalState(operation, "params", mockParams);
- assertNotNull(operation.makeRequest(1, "sampleTargetVnf"));
- Mockito.verify(mockParams, atLeast(1)).getRequestId();
- Mockito.verify(mockParams, atLeast(1)).getPayload();
- Mockito.verify(mockParams, atLeast(1)).getContext();
- Mockito.verify(mockContext, atLeast(1)).getEvent();
- Mockito.verify(mockEvent, atLeast(1)).getRequestId();
+ oper.generateSubRequestId(2);
+ String subreq = oper.getSubRequestId();
+ assertNotNull(subreq);
+
+ AppcLcmDmaapWrapper request = oper.makeRequest(2);
+ assertEquals("DefaultOperation", request.getBody().getInput().getAction());
+
+ AppcLcmCommonHeader header = request.getBody().getInput().getCommonHeader();
+ assertNotNull(header);
+ assertEquals(params.getRequestId(), header.getRequestId());
+
+ assertEquals(subreq, header.getSubRequestId());
+
+ assertEquals("{vnf-id=my-target}", request.getBody().getInput().getActionIdentifiers().toString());
+
+ request = oper.makeRequest(2);
+ assertEquals(subreq, request.getBody().getInput().getCommonHeader().getSubRequestId());
}
+ /**
+ * Tests makeRequest() when a property is missing.
+ */
@Test
- public void testGetExpectedKeyValues() {
- Mockito.doCallRealMethod().when(operation).getExpectedKeyValues(1, mockInputWrapper);
- Mockito.when(mockInputWrapper.getBody()).thenReturn(mockBody);
- Mockito.when(mockBody.getInput()).thenReturn(mockInput);
- Mockito.when(mockInput.getCommonHeader()).thenReturn(mockCommonHeader);
- Mockito.when(mockCommonHeader.getSubRequestId()).thenReturn("sampleSubRequestId");
+ public void testMakeRequestMissingProperty() throws Exception {
+ oper = new AppcLcmOperation(params, config);
+ oper.generateSubRequestId(1);
+
+ assertThatIllegalStateException().isThrownBy(() -> oper.makeRequest(1))
+ .withMessageContaining("missing target entity");
+ }
+
+ @Test
+ public void testConvertPayload() {
+ // only builds a payload for ConfigModify
+ params = params.toBuilder().operation(AppcLcmConstants.OPERATION_CONFIG_MODIFY).build();
+ oper = new AppcLcmOperation(params, config);
+ oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, TARGET_ENTITY);
+
+ oper.generateSubRequestId(2);
+ AppcLcmDmaapWrapper req = oper.makeRequest(2);
+ assertEquals("{\"key-A\":\"value-A\"}", req.getBody().getInput().getPayload());
- List<String> retList = operation.getExpectedKeyValues(1, mockInputWrapper);
- assertNotNull(retList);
- assertEquals(1, retList.size());
+ // coder exception
+ oper = new AppcLcmOperation(params, config) {
+ @Override
+ protected Coder getCoder() {
+ return new StandardCoder() {
+ @Override
+ public String encode(Object object) throws CoderException {
+ throw new CoderException(EXPECTED_EXCEPTION);
+ }
+ };
+ }
+ };
- Mockito.verify(mockInputWrapper, atLeast(1)).getBody();
- Mockito.verify(mockBody, atLeast(1)).getInput();
- Mockito.verify(mockInput, atLeast(1)).getCommonHeader();
- Mockito.verify(mockCommonHeader, atLeast(1)).getSubRequestId();
+ oper.setProperty(OperationProperties.AAI_TARGET_ENTITY, TARGET_ENTITY);
+ oper.generateSubRequestId(2);
+
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.makeRequest(2))
+ .withMessageContaining("Cannot convert payload");
+ }
+
+ @Test
+ public void testGetExpectedKeyValues() {
+ oper.generateSubRequestId(2);
+ AppcLcmDmaapWrapper request = oper.makeRequest(2);
+ assertEquals(Arrays.asList(request.getBody().getInput().getCommonHeader().getSubRequestId()),
+ oper.getExpectedKeyValues(50, request));
}
@Test
public void testDetmStatus() {
- Mockito.doCallRealMethod().when(operation).detmStatus("testResponse", mockOutputWrapper);
- Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody);
- Mockito.when(mockBody.getOutput()).thenReturn(mockOutput);
- Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus);
- Mockito.when(mockResponseStatus.getCode()).thenReturn(100);
- Status retStatus = operation.detmStatus("testResponse", mockOutputWrapper);
- assertEquals(Status.STILL_WAITING, retStatus);
+ assertEquals(Status.SUCCESS, oper.detmStatus(null, response));
- Mockito.when(mockResponseStatus.getCode()).thenReturn(400);
- retStatus = operation.detmStatus("testResponse", mockOutputWrapper);
- assertEquals(Status.SUCCESS, retStatus);
+ // failure
+ response.getBody().getOutput().getStatus().setCode(405);
+ assertEquals(Status.FAILURE, oper.detmStatus(null, response));
- Mockito.when(mockResponseStatus.getCode()).thenReturn(450);
- retStatus = operation.detmStatus("testResponse", mockOutputWrapper);
- assertEquals(Status.FAILURE, retStatus);
+ // error
+ response.getBody().getOutput().getStatus().setCode(200);
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response));
- Mockito.when(mockOutput.getStatus()).thenReturn(null);
- assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper));
+ // reject
+ response.getBody().getOutput().getStatus().setCode(305);
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response));
- Mockito.when(mockResponseStatus.getCode()).thenReturn(200);
- assertThatIllegalArgumentException().isThrownBy(() -> operation.detmStatus("testResponse", mockOutputWrapper));
+ // accepted
+ response.getBody().getOutput().getStatus().setCode(100);
+ assertEquals(Status.STILL_WAITING, oper.detmStatus(null, response));
- Mockito.verify(mockOutputWrapper, atLeast(1)).getBody();
- Mockito.verify(mockBody, atLeast(1)).getOutput();
- Mockito.verify(mockOutput, atLeast(1)).getStatus();
- Mockito.verify(mockResponseStatus, atLeast(1)).getCode();
+ // other
+ response.getBody().getOutput().getStatus().setCode(-1);
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response));
+
+ // null status
+ response.getBody().getOutput().setStatus(null);
+ assertThatIllegalArgumentException().isThrownBy(() -> oper.detmStatus(null, response));
}
@Test
public void testSetOutcome() {
- Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS,
- mockOutputWrapper);
- Mockito.doCallRealMethod().when(operation).setOutcome(mockOperationOutcome, PolicyResult.FAILURE,
- mockOutputWrapper);
-
- Mockito.doCallRealMethod().when(mockOperationOutcome).setResult(any(PolicyResult.class));
- Mockito.doCallRealMethod().when(mockOperationOutcome).setMessage(any(String.class));
- Mockito.doCallRealMethod().when(mockOperationOutcome).getResult();
- Mockito.doCallRealMethod().when(mockOperationOutcome).getMessage();
-
- Mockito.when(mockOutputWrapper.getBody()).thenReturn(mockBody);
- Mockito.when(mockBody.getOutput()).thenReturn(mockOutput);
- Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus);
- Mockito.when(mockResponseStatus.getMessage()).thenReturn(null);
-
- OperationOutcome result = operation.setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper);
- assertNull(result);
- Mockito.verify(operation).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper);
-
- Mockito.when(mockOutput.getStatus()).thenReturn(mockResponseStatus);
- Mockito.when(mockResponseStatus.getMessage()).thenReturn("sampleMessage");
- result = operation.setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper);
- assertEquals(PolicyResult.FAILURE, result.getResult());
- assertNotNull(result.getMessage());
-
- Mockito.verify(mockOutputWrapper, atLeast(1)).getBody();
- Mockito.verify(mockBody, atLeast(1)).getOutput();
- Mockito.verify(mockOutput, atLeast(1)).getStatus();
- Mockito.verify(mockResponseStatus, atLeast(1)).getMessage();
- Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.SUCCESS, mockOutputWrapper);
- Mockito.verify(operation, atLeast(1)).setOutcome(mockOperationOutcome, PolicyResult.FAILURE, mockOutputWrapper);
+ oper.setOutcome(outcome, OperationResult.SUCCESS, response);
+ assertEquals(OperationResult.SUCCESS, outcome.getResult());
+ assertEquals(MY_MESSAGE, outcome.getMessage());
+ assertSame(response, outcome.getResponse());
+
+ // failure
+ oper.setOutcome(outcome, OperationResult.FAILURE, response);
+ assertEquals(OperationResult.FAILURE, outcome.getResult());
+ assertEquals(MY_MESSAGE, outcome.getMessage());
+ assertSame(response, outcome.getResponse());
+
+ // null message
+ response.getBody().getOutput().getStatus().setMessage(null);
+ oper.setOutcome(outcome, OperationResult.SUCCESS, response);
+ assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
+ assertSame(response, outcome.getResponse());
+
+ // null status
+ response.getBody().getOutput().setStatus(null);
+ oper.setOutcome(outcome, OperationResult.SUCCESS, response);
+ assertEquals(ControlLoopOperation.SUCCESS_MSG, outcome.getMessage());
+ assertSame(response, outcome.getResponse());
}
+ @Test
+ public void testGetStatus() {
+ assertNotNull(oper.getStatus(response));
+
+ // null status
+ response.getBody().getOutput().setStatus(null);
+ assertNull(oper.getStatus(response));
+
+ // null outcome
+ response.getBody().setOutput(null);
+ assertNull(oper.getStatus(response));
+
+ // null body
+ response.setBody(null);
+ assertNull(oper.getStatus(response));
+
+ // null response
+ assertNull(oper.getStatus(null));
+ }
+
+ @Test
+ public void testOperationSupportsPayload() {
+ // these should support a payload
+ Set<String> supported = Set.of(AppcLcmConstants.OPERATION_CONFIG_MODIFY);
+
+ for (String name : supported) {
+ params = params.toBuilder().operation(name).build();
+ oper = new AppcLcmOperation(params, config);
+ assertTrue(name, oper.operationSupportsPayload());
+ }
+
+ // these should NOT support a payload
+ Set<String> unsupported = AppcLcmConstants.OPERATION_NAMES.stream().filter(name -> !supported.contains(name))
+ .collect(Collectors.toSet());
+
+ for (String name : unsupported) {
+ params = params.toBuilder().operation(name).build();
+ oper = new AppcLcmOperation(params, config);
+ assertFalse(name, oper.operationSupportsPayload());
+ }
+
+ // pick an operation that would ordinarily support payloads
+ String sup = supported.iterator().next();
+
+ // verify that it still supports payload
+ params = params.toBuilder().operation(sup).build();
+ oper = new AppcLcmOperation(params, config);
+ assertTrue(oper.operationSupportsPayload());
+
+ // try with empty payload
+ params = params.toBuilder().payload(Map.of()).build();
+ oper = new AppcLcmOperation(params, config);
+ assertFalse(oper.operationSupportsPayload());
+
+ // try with null payload
+ params = params.toBuilder().payload(null).build();
+ oper = new AppcLcmOperation(params, config);
+ assertFalse(oper.operationSupportsPayload());
+ }
+
+ @Override
+ protected void makeContext() {
+ super.makeContext();
+
+ Map<String, String> targetEntities = new HashMap<>();
+ targetEntities.put(ControlLoopOperationParams.PARAMS_ENTITY_RESOURCEID, RESOURCE_ID);
+
+ params = params.toBuilder().targetEntityIds(targetEntities).build();
+ }
+
+ @Override
+ protected Map<String, Object> makePayload() {
+ return Map.of(PAYLOAD_KEY1, PAYLOAD_VALUE1);
+ }
+
+ private AppcLcmDmaapWrapper makeResponse() {
+ AppcLcmDmaapWrapper response = new AppcLcmDmaapWrapper();
+
+ AppcLcmBody body = new AppcLcmBody();
+ response.setBody(body);
+
+ AppcLcmOutput output = new AppcLcmOutput();
+ body.setOutput(output);
+
+ AppcLcmResponseStatus status = new AppcLcmResponseStatus();
+ output.setStatus(status);
+ status.setMessage(MY_MESSAGE);
+ status.setCode(SUCCESS_CODE);
+
+ return response;
+ }
}