bd44663fdf97971e9b47aeac81606e7c0d06c31a
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / test / java / org / onap / policy / controlloop / actorserviceprovider / impl / HttpPollingOperationTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020-2021 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.actorserviceprovider.impl;
22
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;
33
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.junit.runner.RunWith;
43 import org.mockito.Mock;
44 import org.mockito.junit.MockitoJUnitRunner;
45 import org.mockito.stubbing.Answer;
46 import org.onap.policy.common.endpoints.http.client.HttpClient;
47 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
48 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
49 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
50 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
51 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpPollingConfig;
52
53 /**
54  * Tests HttpOperation when polling is enabled.
55  */
56 @RunWith(MockitoJUnitRunner.class)
57 public class HttpPollingOperationTest {
58     private static final String BASE_URI = "http://my-host:6969/base-uri/";
59     private static final String MY_PATH = "my-path";
60     private static final String FULL_PATH = BASE_URI + MY_PATH;
61     private static final int MAX_POLLS = 3;
62     private static final int POLL_WAIT_SEC = 20;
63     private static final String POLL_PATH = "my-poll-path";
64     private static final String MY_ACTOR = "my-actor";
65     private static final String MY_OPERATION = "my-operation";
66     private static final String MY_RESPONSE = "my-response";
67     private static final int RESPONSE_ACCEPT = 100;
68     private static final int RESPONSE_SUCCESS = 200;
69     private static final int RESPONSE_FAILURE = 500;
70
71     @Mock
72     private HttpPollingConfig config;
73     @Mock
74     private HttpClient client;
75     @Mock
76     private Response rawResponse;
77
78     protected ControlLoopOperationParams params;
79     private String response;
80     private OperationOutcome outcome;
81
82     private HttpOperation<String> oper;
83
84     /**
85      * Sets up.
86      */
87     @Before
88     public void setUp() throws Exception {
89         when(client.getBaseUrl()).thenReturn(BASE_URI);
90
91         when(config.getClient()).thenReturn(client);
92         when(config.getMaxPolls()).thenReturn(MAX_POLLS);
93         when(config.getPollPath()).thenReturn(POLL_PATH);
94         when(config.getPollWaitSec()).thenReturn(POLL_WAIT_SEC);
95
96         response = MY_RESPONSE;
97
98         when(rawResponse.getStatus()).thenReturn(RESPONSE_SUCCESS);
99         when(rawResponse.readEntity(String.class)).thenReturn(response);
100
101         params = ControlLoopOperationParams.builder().actor(MY_ACTOR).operation(MY_OPERATION).build();
102         outcome = params.makeOutcome();
103
104         oper = new MyOper(params, config);
105     }
106
107     @Test
108     public void testConstructor_testGetWaitMsGet() {
109         assertEquals(MY_ACTOR, oper.getActorName());
110         assertEquals(MY_OPERATION, oper.getName());
111         assertSame(config, oper.getConfig());
112         assertEquals(1000 * POLL_WAIT_SEC, oper.getPollWaitMs());
113     }
114
115     @Test
116     public void testSetUsePollExceptions() {
117         // should be no exception
118         oper.setUsePolling();
119
120         // should throw an exception if we pass a plain HttpConfig
121         HttpConfig config2 = mock(HttpConfig.class);
122
123         assertThatIllegalStateException().isThrownBy(() -> new MyOper(params, config2).setUsePolling());
124     }
125
126     @Test
127     public void testPostProcess() throws Exception {
128         // completed
129         oper.generateSubRequestId(2);
130         CompletableFuture<OperationOutcome> future2 =
131                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
132         assertTrue(future2.isDone());
133         assertSame(outcome, future2.get());
134         assertEquals(OperationResult.SUCCESS, outcome.getResult());
135         assertNotNull(oper.getSubRequestId());
136         assertSame(response, outcome.getResponse());
137
138         // failed
139         oper.generateSubRequestId(2);
140         when(rawResponse.getStatus()).thenReturn(RESPONSE_FAILURE);
141         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
142         assertTrue(future2.isDone());
143         assertSame(outcome, future2.get());
144         assertEquals(OperationResult.FAILURE, outcome.getResult());
145         assertNotNull(oper.getSubRequestId());
146         assertSame(response, outcome.getResponse());
147     }
148
149     /**
150      * Tests postProcess() when the poll is repeated a couple of times.
151      */
152     @Test
153     public void testPostProcessRepeated_testResetGetCount() throws Exception {
154         /*
155          * Two accepts and then a success - should result in two polls.
156          */
157         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT, RESPONSE_ACCEPT, RESPONSE_SUCCESS, RESPONSE_SUCCESS);
158
159         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
160
161         // use a real executor
162         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
163
164         oper = new MyOper(params, config) {
165             @Override
166             public long getPollWaitMs() {
167                 return 1;
168             }
169         };
170
171         CompletableFuture<OperationOutcome> future2 =
172                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
173
174         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
175         assertEquals(OperationResult.SUCCESS, outcome.getResult());
176         assertEquals(2, oper.getPollCount());
177
178         /*
179          * repeat - this time, the "poll" count will be exhausted, so it should fail
180          */
181         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT);
182
183         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
184
185         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
186         assertEquals(OperationResult.FAILURE_TIMEOUT, outcome.getResult());
187         assertEquals(MAX_POLLS + 1, oper.getPollCount());
188
189         oper.resetPollCount();
190         assertEquals(0, oper.getPollCount());
191         assertNull(oper.getSubRequestId());
192     }
193
194     @Test
195     public void testDetmStatus() {
196         // make an operation that does NOT override detmStatus()
197         oper = new HttpOperation<String>(params, config, String.class, Collections.emptyList()) {};
198
199         assertThatThrownBy(() -> oper.detmStatus(rawResponse, response))
200                         .isInstanceOf(UnsupportedOperationException.class);
201     }
202
203     /**
204      * Provides a response to an asynchronous HttpClient call.
205      *
206      * @param response response to be provided to the call
207      * @return a function that provides the response to the call
208      */
209     protected Answer<CompletableFuture<Response>> provideResponse(Response response) {
210         return provideResponse(response, 0);
211     }
212
213     /**
214      * Provides a response to an asynchronous HttpClient call.
215      *
216      * @param response response to be provided to the call
217      * @param index index of the callback within the arguments
218      * @return a function that provides the response to the call
219      */
220     protected Answer<CompletableFuture<Response>> provideResponse(Response response, int index) {
221         return args -> {
222             InvocationCallback<Response> cb = args.getArgument(index);
223             cb.completed(response);
224             return CompletableFuture.completedFuture(response);
225         };
226     }
227
228     private static class MyOper extends HttpOperation<String> {
229
230         public MyOper(ControlLoopOperationParams params, HttpConfig config) {
231             super(params, config, String.class, Collections.emptyList());
232
233             setUsePolling();
234         }
235
236         @Override
237         protected Status detmStatus(Response rawResponse, String response) {
238             switch (rawResponse.getStatus()) {
239                 case RESPONSE_ACCEPT:
240                     return Status.STILL_WAITING;
241                 case RESPONSE_SUCCESS:
242                     return Status.SUCCESS;
243                 default:
244                     return Status.FAILURE;
245             }
246         }
247
248         @Override
249         protected boolean isSuccess(Response rawResponse, String response) {
250             return true;
251         }
252     }
253 }