2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 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.pap.main.comm;
23 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertSame;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.Matchers.any;
30 import static org.mockito.Matchers.eq;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.times;
33 import static org.mockito.Mockito.verify;
34 import static org.mockito.Mockito.when;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.stream.Collectors;
41 import javax.ws.rs.core.Response.Status;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.mockito.ArgumentCaptor;
45 import org.mockito.Captor;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 import org.onap.policy.models.base.PfModelException;
49 import org.onap.policy.models.pdp.concepts.Pdp;
50 import org.onap.policy.models.pdp.concepts.PdpGroup;
51 import org.onap.policy.models.pdp.concepts.PdpMessage;
52 import org.onap.policy.models.pdp.concepts.PdpStateChange;
53 import org.onap.policy.models.pdp.concepts.PdpStatus;
54 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
55 import org.onap.policy.models.pdp.concepts.PdpUpdate;
56 import org.onap.policy.models.pdp.enums.PdpState;
57 import org.onap.policy.pap.main.comm.msgdata.Request;
58 import org.onap.policy.pap.main.comm.msgdata.RequestListener;
59 import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams;
60 import org.powermock.reflect.Whitebox;
62 public class PdpModifyRequestMapTest extends CommonRequestBase {
63 private static final String MY_REASON = "my reason";
66 * Used to capture input to dao.createPdpGroups().
69 private ArgumentCaptor<List<PdpGroup>> createCaptor;
73 * Used to capture input to dao.updatePdpGroups().
76 private ArgumentCaptor<List<PdpGroup>> updateCaptor;
79 private PdpRequests requests;
82 private PdpUpdate update;
83 private PdpStateChange change;
84 private PdpStatus response;
89 * @throws Exception if an error occurs
92 public void setUp() throws Exception {
95 MockitoAnnotations.initMocks(this);
97 response = new PdpStatus();
99 update = makeUpdate(PDP1, MY_GROUP, MY_SUBGROUP);
100 change = makeStateChange(PDP1, MY_STATE);
102 when(requests.getPdpName()).thenReturn(PDP1);
104 response.setName(MY_NAME);
105 response.setState(MY_STATE);
106 response.setPdpGroup(update.getPdpGroup());
107 response.setPdpSubgroup(update.getPdpSubgroup());
108 response.setPolicies(Collections.emptyList());
110 map = new MyMap(mapParams);
114 public void testPdpModifyRequestMap() {
115 assertSame(mapParams, Whitebox.getInternalState(map, "params"));
116 assertSame(lock, Whitebox.getInternalState(map, "modifyLock"));
117 assertSame(daoFactory, Whitebox.getInternalState(map, "daoFactory"));
121 public void testStopPublishing() {
122 // try with non-existent PDP
123 map.stopPublishing(PDP1);
125 // now start a PDP and try it
126 map.addRequest(change);
127 map.stopPublishing(PDP1);
128 verify(requests).stopPublishing();
130 // try again - it shouldn't stop publishing again
131 map.stopPublishing(PDP1);
132 verify(requests, times(1)).stopPublishing();
136 public void testAddRequestPdpUpdatePdpStateChange_BothNull() {
137 // nulls should be ok
138 map.addRequest(null, null);
142 public void testAddRequestPdpUpdatePdpStateChange_NullUpdate() {
143 map.addRequest(null, change);
145 Request req = getSingletons(1).get(0);
146 assertSame(change, req.getMessage());
147 assertEquals("pdp_1 PdpStateChange", req.getName());
151 public void testAddRequestPdpUpdatePdpStateChange_NullStateChange() {
152 map.addRequest(update, null);
154 Request req = getSingletons(1).get(0);
155 assertSame(update, req.getMessage());
156 assertEquals("pdp_1 PdpUpdate", req.getName());
160 public void testAddRequestPdpUpdatePdpStateChange_BothProvided() {
161 map.addRequest(update, change);
163 // should have only allocated one request structure
164 assertEquals(1, map.nalloc);
166 // both requests should have been added
167 List<Request> values = getSingletons(2);
169 Request req = values.remove(0);
170 assertSame(update, req.getMessage());
171 assertEquals("pdp_1 PdpUpdate", req.getName());
173 req = values.remove(0);
174 assertSame(change, req.getMessage());
175 assertEquals("pdp_1 PdpStateChange", req.getName());
179 public void testAddRequestPdpUpdatePdpStateChange() {
181 map.addRequest(null, null);
183 map.addRequest(change);
185 Request req = getSingletons(1).get(0);
186 assertSame(change, req.getMessage());
187 assertEquals("pdp_1 PdpStateChange", req.getName());
189 // broadcast should throw an exception
190 change.setName(null);
191 assertThatIllegalArgumentException().isThrownBy(() -> map.addRequest(change))
192 .withMessageStartingWith("unexpected broadcast message: PdpStateChange");
196 public void testAddRequestPdpUpdate() {
198 map.addRequest((PdpUpdate) null);
200 map.addRequest(update);
202 Request req = getSingletons(1).get(0);
203 assertSame(update, req.getMessage());
204 assertEquals("pdp_1 PdpUpdate", req.getName());
206 // broadcast should throw an exception
207 update.setName(null);
208 assertThatIllegalArgumentException().isThrownBy(() -> map.addRequest(update))
209 .withMessageStartingWith("unexpected broadcast message: PdpUpdate");
213 public void testAddRequestPdpStateChange() {
215 map.addRequest((PdpStateChange) null);
217 map.addRequest(change);
219 Request req = getSingletons(1).get(0);
220 assertSame(change, req.getMessage());
221 assertEquals("pdp_1 PdpStateChange", req.getName());
223 // broadcast should throw an exception
224 change.setName(null);
225 assertThatIllegalArgumentException().isThrownBy(() -> map.addRequest(change))
226 .withMessageStartingWith("unexpected broadcast message: PdpStateChange");
230 public void testAddSingleton() {
231 map.addRequest(change);
232 assertEquals(1, map.nalloc);
234 // should have one singleton
237 // add another request with the same PDP
238 map.addRequest(makeStateChange(PDP1, MY_STATE));
239 assertEquals(1, map.nalloc);
241 // should now have another singleton
245 // add another request with a different PDP
246 map.addRequest(makeStateChange(DIFFERENT, MY_STATE));
248 // should now have another allocation
249 assertEquals(2, map.nalloc);
251 // should now have another singleton
256 public void testStartNextRequest_NoMore() {
257 map.addRequest(change);
260 getListener(getSingletons(1).get(0)).success(PDP1);
263 * the above should have removed the requests so next time should allocate a new
266 map.addRequest(change);
267 assertEquals(2, map.nalloc);
271 public void testStartNextRequest_HaveMore() {
272 map.addRequest(update);
273 map.addRequest(change);
275 Request updateReq = getSingletons(2).get(0);
277 // indicate success with the update
278 when(requests.startNextRequest(updateReq)).thenReturn(true);
279 getListener(updateReq).success(PDP1);
281 // should have started the next request
282 verify(requests).startNextRequest(updateReq);
285 * requests should still be there, so adding another request should not allocate a
288 map.addRequest(update);
289 assertEquals(1, map.nalloc);
293 public void testDisablePdp() throws Exception {
294 map.addRequest(update);
296 // put the PDP in a group
297 PdpGroup group = makeGroup(MY_GROUP);
298 group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, PDP1)));
300 when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group));
303 invokeFailureHandler(1);
305 // should have stopped publishing
306 verify(requests).stopPublishing();
308 // should have generated a notification
309 verify(notifier).removePdp(PDP1);
311 // should have published a new update
312 PdpMessage msg2 = getSingletons(3).get(1).getMessage();
314 assertTrue(msg2 instanceof PdpUpdate);
316 // update should have null group & subgroup
317 update = (PdpUpdate) msg2;
318 assertEquals(PDP1, update.getName());
319 assertNull(update.getPdpGroup());
320 assertNull(update.getPdpSubgroup());
322 // should have published a state-change
323 msg2 = getSingletons(3).get(2).getMessage();
325 assertTrue(msg2 instanceof PdpStateChange);
327 change = (PdpStateChange) msg2;
328 assertEquals(PDP1, change.getName());
329 assertEquals(PdpState.PASSIVE, change.getState());
333 public void testDisablePdp_NotInGroup() {
334 map.addRequest(update);
337 invokeFailureHandler(1);
339 // should have stopped publishing
340 verify(requests).stopPublishing();
342 // should have published a new state-change
343 PdpMessage msg2 = getSingletons(2).get(1).getMessage();
345 assertTrue(msg2 instanceof PdpStateChange);
347 change = (PdpStateChange) msg2;
348 assertEquals(PDP1, change.getName());
349 assertEquals(PdpState.PASSIVE, change.getState());
353 public void testDisablePdp_AlreadyRemoved() {
354 map.addRequest(change);
355 map.stopPublishing(PDP1);
357 invokeFailureHandler(1);
359 // should not have stopped publishing a second time
360 verify(requests, times(1)).stopPublishing();
364 public void testDisablePdp_NoGroup() {
365 map.addRequest(change);
367 invokeFailureHandler(1);
369 // should not have stopped publishing
370 verify(requests).stopPublishing();
374 public void testRemoveFromGroup() throws Exception {
375 map.addRequest(change);
377 PdpGroup group = makeGroup(MY_GROUP);
378 group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP + "a", PDP1 + "a"),
379 makeSubGroup(MY_SUBGROUP, PDP1), makeSubGroup(MY_SUBGROUP + "c", PDP1 + "c")));
381 when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group));
383 invokeFailureHandler(1);
385 // verify that the PDP was removed from the subgroup
386 List<PdpGroup> groups = getGroupUpdates();
387 assertEquals(1, groups.size());
388 assertSame(group, groups.get(0));
390 List<PdpSubGroup> subgroups = group.getPdpSubgroups();
391 assertEquals(3, subgroups.size());
392 assertEquals("[pdp_1a]", getPdpNames(subgroups.get(0)));
393 assertEquals("[]", getPdpNames(subgroups.get(1)));
394 assertEquals("[pdp_1c]", getPdpNames(subgroups.get(2)));
398 public void testRemoveFromGroup_DaoEx() throws Exception {
399 map.addRequest(change);
401 when(dao.getFilteredPdpGroups(any())).thenThrow(new PfModelException(Status.BAD_REQUEST, "expected exception"));
403 invokeFailureHandler(1);
405 // should still stop publishing
406 verify(requests).stopPublishing();
408 // requests should have been removed from the map so this should allocate another
409 map.addRequest(update);
410 assertEquals(2, map.nalloc);
414 public void testRemoveFromGroup_NoGroups() throws Exception {
415 map.addRequest(change);
417 invokeFailureHandler(1);
419 verify(dao, never()).updatePdpGroups(any());
423 public void testRemoveFromGroup_NoMatchingSubgroup() throws Exception {
424 map.addRequest(change);
426 PdpGroup group = makeGroup(MY_GROUP);
427 group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, DIFFERENT)));
429 when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group));
431 invokeFailureHandler(1);
433 verify(dao, never()).updatePdpGroups(any());
437 public void testRemoveFromSubgroup() throws Exception {
438 map.addRequest(change);
440 PdpGroup group = makeGroup(MY_GROUP);
441 group.setPdpSubgroups(Arrays.asList(makeSubGroup(MY_SUBGROUP, PDP1, PDP1 + "x", PDP1 + "y")));
443 when(dao.getFilteredPdpGroups(any())).thenReturn(Arrays.asList(group));
445 invokeFailureHandler(1);
447 // verify that the PDP was removed from the subgroup
448 List<PdpGroup> groups = getGroupUpdates();
449 assertEquals(1, groups.size());
450 assertSame(group, groups.get(0));
452 PdpSubGroup subgroup = group.getPdpSubgroups().get(0);
453 assertEquals(2, subgroup.getCurrentInstanceCount());
454 assertEquals("[pdp_1x, pdp_1y]", getPdpNames(subgroup));
458 public void testMakePdpRequests() {
459 // this should invoke the real method without throwing an exception
460 new PdpModifyRequestMap(mapParams).addRequest(change);
462 QueueToken<PdpMessage> token = queue.poll();
463 assertNotNull(token);
464 assertSame(change, token.get());
466 verify(dispatcher).register(eq(change.getRequestId()), any());
467 verify(timers).register(eq(change.getRequestId()), any());
471 public void testSingletonListenerFailure() throws Exception {
472 map.addRequest(change);
475 invokeFailureHandler(1);
477 verify(requests).stopPublishing();
481 public void testSingletonListenerFailure_WrongPdpName() throws Exception {
482 map.addRequest(change);
484 // invoke the method - has wrong PDP name
485 when(requests.getPdpName()).thenReturn(DIFFERENT);
486 invokeFailureHandler(1);
488 verify(requests, never()).stopPublishing();
492 public void testSingletonListenerSuccess_LastRequest() throws Exception {
493 map.addRequest(change);
496 invokeSuccessHandler(1);
498 verify(requests, never()).stopPublishing();
500 // requests should have been removed from the map so this should allocate another
501 map.addRequest(update);
502 assertEquals(2, map.nalloc);
506 public void testSingletonListenerSuccess_NameMismatch() throws Exception {
507 map.addRequest(change);
509 // invoke the method - with a different name
510 when(requests.getPdpName()).thenReturn(DIFFERENT);
511 invokeSuccessHandler(1);
513 verify(requests, never()).stopPublishing();
515 // no effect on the map
516 map.addRequest(update);
517 assertEquals(1, map.nalloc);
521 public void testSingletonListenerSuccess_AlreadyStopped() throws Exception {
522 map.addRequest(change);
524 map.stopPublishing(PDP1);
527 invokeSuccessHandler(1);
529 // should have called this a second time
530 verify(requests, times(2)).stopPublishing();
532 // requests should have been removed from the map so this should allocate another
533 map.addRequest(update);
534 assertEquals(2, map.nalloc);
538 public void testSingletonListenerRetryCountExhausted() throws Exception {
539 map.addRequest(change);
542 getListener(getSingletons(1).get(0)).retryCountExhausted();
544 verify(requests).stopPublishing();
549 * Invokes the first request's listener.success() method.
551 * @param count expected number of requests
553 private void invokeSuccessHandler(int count) {
554 getListener(getSingletons(count).get(0)).success(PDP1);
558 * Invokes the first request's listener.failure() method.
560 * @param count expected number of requests
562 private void invokeFailureHandler(int count) {
563 getListener(getSingletons(count).get(0)).failure(PDP1, MY_REASON);
567 * Gets the name of the PDPs contained within a subgroup.
569 * @param subgroup subgroup of interest
570 * @return the name of the PDPs contained within the subgroup
572 private String getPdpNames(PdpSubGroup subgroup) {
573 return subgroup.getPdpInstances().stream().map(Pdp::getInstanceId).collect(Collectors.toList()).toString();
577 * Gets the singleton requests added to {@link #requests}.
579 * @param count number of singletons expected
580 * @return the singleton requests
582 private List<Request> getSingletons(int count) {
583 ArgumentCaptor<Request> captor = ArgumentCaptor.forClass(Request.class);
585 verify(requests, times(count)).addSingleton(captor.capture());
586 return captor.getAllValues();
590 * Gets the listener from a request.
592 * @param request request of interest
593 * @return the request's listener
595 private RequestListener getListener(Request request) {
596 return Whitebox.getInternalState(request, "listener");
599 private PdpGroup makeGroup(String name) {
600 PdpGroup group = new PdpGroup();
607 private PdpSubGroup makeSubGroup(String pdpType, String... pdpNames) {
608 PdpSubGroup subgroup = new PdpSubGroup();
610 subgroup.setPdpType(pdpType);
611 subgroup.setPdpInstances(Arrays.asList(pdpNames).stream().map(this::makePdp).collect(Collectors.toList()));
616 private Pdp makePdp(String pdpName) {
618 pdp.setInstanceId(pdpName);
624 * Gets the input to the method.
626 * @return the input that was passed to the dao.updatePdpGroups() method
627 * @throws Exception if an error occurred
629 private List<PdpGroup> getGroupUpdates() throws Exception {
630 verify(dao).updatePdpGroups(updateCaptor.capture());
632 return copyList(updateCaptor.getValue());
636 * Copies a list and sorts it by group name.
638 * @param source source list to copy
639 * @return a copy of the source list
641 private List<PdpGroup> copyList(List<PdpGroup> source) {
642 List<PdpGroup> newlst = new ArrayList<>(source);
643 Collections.sort(newlst, (left, right) -> left.getName().compareTo(right.getName()));
647 private class MyMap extends PdpModifyRequestMap {
649 * Number of times requests were allocated.
651 private int nalloc = 0;
653 public MyMap(PdpModifyRequestMapParams params) {
658 protected PdpRequests makePdpRequests(String pdpName) {