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.actorserviceprovider.impl;
 
  23 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
 
  24 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
  25 import static org.junit.Assert.assertEquals;
 
  26 import static org.junit.Assert.assertNotNull;
 
  27 import static org.junit.Assert.assertNull;
 
  28 import static org.junit.Assert.assertSame;
 
  29 import static org.junit.Assert.assertTrue;
 
  30 import static org.mockito.ArgumentMatchers.any;
 
  31 import static org.mockito.Mockito.mock;
 
  32 import static org.mockito.Mockito.when;
 
  34 import java.util.Collections;
 
  35 import java.util.concurrent.CompletableFuture;
 
  36 import java.util.concurrent.ForkJoinPool;
 
  37 import java.util.concurrent.TimeUnit;
 
  38 import javax.ws.rs.client.InvocationCallback;
 
  39 import javax.ws.rs.core.Response;
 
  40 import org.junit.Before;
 
  41 import org.junit.Test;
 
  42 import org.mockito.Mock;
 
  43 import org.mockito.MockitoAnnotations;
 
  44 import org.mockito.stubbing.Answer;
 
  45 import org.onap.policy.common.endpoints.http.client.HttpClient;
 
  46 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 
  47 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
 
  48 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
 
  49 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
 
  50 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpPollingConfig;
 
  53  * Tests HttpOperation when polling is enabled.
 
  55 public class HttpPollingOperationTest {
 
  56     private static final String BASE_URI = "http://my-host:6969/base-uri/";
 
  57     private static final String MY_PATH = "my-path";
 
  58     private static final String FULL_PATH = BASE_URI + MY_PATH;
 
  59     private static final int MAX_POLLS = 3;
 
  60     private static final int POLL_WAIT_SEC = 20;
 
  61     private static final String POLL_PATH = "my-poll-path";
 
  62     private static final String MY_ACTOR = "my-actor";
 
  63     private static final String MY_OPERATION = "my-operation";
 
  64     private static final String MY_RESPONSE = "my-response";
 
  65     private static final int RESPONSE_ACCEPT = 100;
 
  66     private static final int RESPONSE_SUCCESS = 200;
 
  67     private static final int RESPONSE_FAILURE = 500;
 
  70     private HttpPollingConfig config;
 
  72     private HttpClient client;
 
  74     private Response rawResponse;
 
  76     protected ControlLoopOperationParams params;
 
  77     private String response;
 
  78     private OperationOutcome outcome;
 
  80     private HttpOperation<String> oper;
 
  86     public void setUp() throws Exception {
 
  87         MockitoAnnotations.initMocks(this);
 
  89         when(client.getBaseUrl()).thenReturn(BASE_URI);
 
  91         when(config.getClient()).thenReturn(client);
 
  92         when(config.getPath()).thenReturn(MY_PATH);
 
  93         when(config.getMaxPolls()).thenReturn(MAX_POLLS);
 
  94         when(config.getPollPath()).thenReturn(POLL_PATH);
 
  95         when(config.getPollWaitSec()).thenReturn(POLL_WAIT_SEC);
 
  97         response = MY_RESPONSE;
 
  99         when(rawResponse.getStatus()).thenReturn(RESPONSE_SUCCESS);
 
 100         when(rawResponse.readEntity(String.class)).thenReturn(response);
 
 102         params = ControlLoopOperationParams.builder().actor(MY_ACTOR).operation(MY_OPERATION).build();
 
 103         outcome = params.makeOutcome();
 
 105         oper = new MyOper(params, config);
 
 109     public void testConstructor_testGetWaitMsGet() {
 
 110         assertEquals(MY_ACTOR, oper.getActorName());
 
 111         assertEquals(MY_OPERATION, oper.getName());
 
 112         assertSame(config, oper.getConfig());
 
 113         assertEquals(1000 * POLL_WAIT_SEC, oper.getPollWaitMs());
 
 117     public void testSetUsePollExceptions() {
 
 118         // should be no exception
 
 119         oper.setUsePolling();
 
 121         // should throw an exception if we pass a plain HttpConfig
 
 122         HttpConfig config2 = mock(HttpConfig.class);
 
 123         when(config2.getClient()).thenReturn(client);
 
 124         when(config2.getPath()).thenReturn(MY_PATH);
 
 126         assertThatIllegalStateException().isThrownBy(() -> new MyOper(params, config2).setUsePolling());
 
 130     public void testPostProcess() throws Exception {
 
 132         oper.generateSubRequestId(2);
 
 133         CompletableFuture<OperationOutcome> future2 =
 
 134                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
 
 135         assertTrue(future2.isDone());
 
 136         assertSame(outcome, future2.get());
 
 137         assertEquals(OperationResult.SUCCESS, outcome.getResult());
 
 138         assertNotNull(oper.getSubRequestId());
 
 139         assertSame(response, outcome.getResponse());
 
 142         oper.generateSubRequestId(2);
 
 143         when(rawResponse.getStatus()).thenReturn(RESPONSE_FAILURE);
 
 144         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
 
 145         assertTrue(future2.isDone());
 
 146         assertSame(outcome, future2.get());
 
 147         assertEquals(OperationResult.FAILURE, outcome.getResult());
 
 148         assertNotNull(oper.getSubRequestId());
 
 149         assertSame(response, outcome.getResponse());
 
 153      * Tests postProcess() when the poll is repeated a couple of times.
 
 156     public void testPostProcessRepeated_testResetGetCount() throws Exception {
 
 158          * Two accepts and then a success - should result in two polls.
 
 160         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT, RESPONSE_ACCEPT, RESPONSE_SUCCESS, RESPONSE_SUCCESS);
 
 162         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
 
 164         // use a real executor
 
 165         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
 
 167         oper = new MyOper(params, config) {
 
 169             public long getPollWaitMs() {
 
 174         CompletableFuture<OperationOutcome> future2 =
 
 175                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
 
 177         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
 
 178         assertEquals(OperationResult.SUCCESS, outcome.getResult());
 
 179         assertEquals(2, oper.getPollCount());
 
 182          * repeat - this time, the "poll" count will be exhausted, so it should fail
 
 184         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT);
 
 186         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
 
 188         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
 
 189         assertEquals(OperationResult.FAILURE_TIMEOUT, outcome.getResult());
 
 190         assertEquals(MAX_POLLS + 1, oper.getPollCount());
 
 192         oper.resetPollCount();
 
 193         assertEquals(0, oper.getPollCount());
 
 194         assertNull(oper.getSubRequestId());
 
 198     public void testDetmStatus() {
 
 199         // make an operation that does NOT override detmStatus()
 
 200         oper = new HttpOperation<String>(params, config, String.class, Collections.emptyList()) {};
 
 202         assertThatThrownBy(() -> oper.detmStatus(rawResponse, response))
 
 203                         .isInstanceOf(UnsupportedOperationException.class);
 
 207      * Provides a response to an asynchronous HttpClient call.
 
 209      * @param response response to be provided to the call
 
 210      * @return a function that provides the response to the call
 
 212     protected Answer<CompletableFuture<Response>> provideResponse(Response response) {
 
 213         return provideResponse(response, 0);
 
 217      * Provides a response to an asynchronous HttpClient call.
 
 219      * @param response response to be provided to the call
 
 220      * @param index index of the callback within the arguments
 
 221      * @return a function that provides the response to the call
 
 223     protected Answer<CompletableFuture<Response>> provideResponse(Response response, int index) {
 
 225             InvocationCallback<Response> cb = args.getArgument(index);
 
 226             cb.completed(response);
 
 227             return CompletableFuture.completedFuture(response);
 
 231     private static class MyOper extends HttpOperation<String> {
 
 233         public MyOper(ControlLoopOperationParams params, HttpConfig config) {
 
 234             super(params, config, String.class, Collections.emptyList());
 
 240         protected Status detmStatus(Response rawResponse, String response) {
 
 241             switch (rawResponse.getStatus()) {
 
 242                 case RESPONSE_ACCEPT:
 
 243                     return Status.STILL_WAITING;
 
 244                 case RESPONSE_SUCCESS:
 
 245                     return Status.SUCCESS;
 
 247                     return Status.FAILURE;
 
 252         protected boolean isSuccess(Response rawResponse, String response) {