Java 17 Upgrade
[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  * Modifications Copyright (C) 2023 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.controlloop.actorserviceprovider.impl;
23
24 import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
25 import static org.assertj.core.api.Assertions.assertThatThrownBy;
26 import static org.junit.Assert.assertEquals;
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;
34
35 import jakarta.ws.rs.client.InvocationCallback;
36 import jakarta.ws.rs.core.Response;
37 import java.util.Collections;
38 import java.util.concurrent.CompletableFuture;
39 import java.util.concurrent.ForkJoinPool;
40 import java.util.concurrent.TimeUnit;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.mockito.Mock;
45 import org.mockito.junit.MockitoJUnitRunner;
46 import org.mockito.stubbing.Answer;
47 import org.onap.policy.common.endpoints.http.client.HttpClient;
48 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
49 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
50 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
51 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
52 import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpPollingConfig;
53
54 /**
55  * Tests HttpOperation when polling is enabled.
56  */
57 @RunWith(MockitoJUnitRunner.class)
58 public class HttpPollingOperationTest {
59     private static final String BASE_URI = "http://my-host:6969/base-uri/";
60     private static final String MY_PATH = "my-path";
61     private static final String FULL_PATH = BASE_URI + MY_PATH;
62     private static final int MAX_POLLS = 3;
63     private static final int POLL_WAIT_SEC = 20;
64     private static final String POLL_PATH = "my-poll-path";
65     private static final String MY_ACTOR = "my-actor";
66     private static final String MY_OPERATION = "my-operation";
67     private static final String MY_RESPONSE = "my-response";
68     private static final int RESPONSE_ACCEPT = 100;
69     private static final int RESPONSE_SUCCESS = 200;
70     private static final int RESPONSE_FAILURE = 500;
71
72     @Mock
73     private HttpPollingConfig config;
74     @Mock
75     private HttpClient client;
76     @Mock
77     private Response rawResponse;
78
79     protected ControlLoopOperationParams params;
80     private String response;
81     private OperationOutcome outcome;
82
83     private HttpOperation<String> oper;
84
85     /**
86      * Sets up.
87      */
88     @Before
89     public void setUp() throws Exception {
90         when(client.getBaseUrl()).thenReturn(BASE_URI);
91
92         when(config.getClient()).thenReturn(client);
93         when(config.getMaxPolls()).thenReturn(MAX_POLLS);
94         when(config.getPollPath()).thenReturn(POLL_PATH);
95         when(config.getPollWaitSec()).thenReturn(POLL_WAIT_SEC);
96
97         response = MY_RESPONSE;
98
99         when(rawResponse.getStatus()).thenReturn(RESPONSE_SUCCESS);
100         when(rawResponse.readEntity(String.class)).thenReturn(response);
101
102         params = ControlLoopOperationParams.builder().actor(MY_ACTOR).operation(MY_OPERATION).build();
103         outcome = params.makeOutcome();
104
105         oper = new MyOper(params, config);
106     }
107
108     @Test
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());
114     }
115
116     @Test
117     public void testSetUsePollExceptions() {
118         // should be no exception
119         oper.setUsePolling();
120
121         // should throw an exception if we pass a plain HttpConfig
122         HttpConfig config2 = mock(HttpConfig.class);
123
124         assertThatIllegalStateException().isThrownBy(() -> new MyOper(params, config2).setUsePolling());
125     }
126
127     @Test
128     public void testPostProcess() throws Exception {
129         // completed
130         oper.generateSubRequestId(2);
131         CompletableFuture<OperationOutcome> future2 =
132                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
133         assertTrue(future2.isDone());
134         assertSame(outcome, future2.get());
135         assertEquals(OperationResult.SUCCESS, outcome.getResult());
136         assertNotNull(oper.getSubRequestId());
137         assertSame(response, outcome.getResponse());
138
139         // failed
140         oper.generateSubRequestId(2);
141         when(rawResponse.getStatus()).thenReturn(RESPONSE_FAILURE);
142         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
143         assertTrue(future2.isDone());
144         assertSame(outcome, future2.get());
145         assertEquals(OperationResult.FAILURE, outcome.getResult());
146         assertNotNull(oper.getSubRequestId());
147         assertSame(response, outcome.getResponse());
148     }
149
150     /**
151      * Tests postProcess() when the poll is repeated a couple of times.
152      */
153     @Test
154     public void testPostProcessRepeated_testResetGetCount() throws Exception {
155         /*
156          * Two accepts and then a success - should result in two polls.
157          */
158         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT, RESPONSE_ACCEPT, RESPONSE_SUCCESS, RESPONSE_SUCCESS);
159
160         when(client.get(any(), any(), any())).thenAnswer(provideResponse(rawResponse));
161
162         // use a real executor
163         params = params.toBuilder().executor(ForkJoinPool.commonPool()).build();
164
165         oper = new MyOper(params, config) {
166             @Override
167             public long getPollWaitMs() {
168                 return 1;
169             }
170         };
171
172         CompletableFuture<OperationOutcome> future2 =
173                         oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
174
175         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
176         assertEquals(OperationResult.SUCCESS, outcome.getResult());
177         assertEquals(2, oper.getPollCount());
178
179         /*
180          * repeat - this time, the "poll" count will be exhausted, so it should fail
181          */
182         when(rawResponse.getStatus()).thenReturn(RESPONSE_ACCEPT);
183
184         future2 = oper.postProcessResponse(outcome, FULL_PATH, rawResponse, response);
185
186         assertSame(outcome, future2.get(5, TimeUnit.SECONDS));
187         assertEquals(OperationResult.FAILURE_TIMEOUT, outcome.getResult());
188         assertEquals(MAX_POLLS + 1, oper.getPollCount());
189
190         oper.resetPollCount();
191         assertEquals(0, oper.getPollCount());
192         assertNull(oper.getSubRequestId());
193     }
194
195     @Test
196     public void testDetmStatus() {
197         // make an operation that does NOT override detmStatus()
198         oper = new HttpOperation<String>(params, config, String.class, Collections.emptyList()) {};
199
200         assertThatThrownBy(() -> oper.detmStatus(rawResponse, response))
201                         .isInstanceOf(UnsupportedOperationException.class);
202     }
203
204     /**
205      * Provides a response to an asynchronous HttpClient call.
206      *
207      * @param response response to be provided to the call
208      * @return a function that provides the response to the call
209      */
210     protected Answer<CompletableFuture<Response>> provideResponse(Response response) {
211         return provideResponse(response, 0);
212     }
213
214     /**
215      * Provides a response to an asynchronous HttpClient call.
216      *
217      * @param response response to be provided to the call
218      * @param index index of the callback within the arguments
219      * @return a function that provides the response to the call
220      */
221     protected Answer<CompletableFuture<Response>> provideResponse(Response response, int index) {
222         return args -> {
223             InvocationCallback<Response> cb = args.getArgument(index);
224             cb.completed(response);
225             return CompletableFuture.completedFuture(response);
226         };
227     }
228
229     private static class MyOper extends HttpOperation<String> {
230
231         public MyOper(ControlLoopOperationParams params, HttpConfig config) {
232             super(params, config, String.class, Collections.emptyList());
233
234             setUsePolling();
235         }
236
237         @Override
238         protected Status detmStatus(Response rawResponse, String response) {
239             switch (rawResponse.getStatus()) {
240                 case RESPONSE_ACCEPT:
241                     return Status.STILL_WAITING;
242                 case RESPONSE_SUCCESS:
243                     return Status.SUCCESS;
244                 default:
245                     return Status.FAILURE;
246             }
247         }
248
249         @Override
250         protected boolean isSuccess(Response rawResponse, String response) {
251             return true;
252         }
253     }
254 }