e050416f50dd63646d2f579706e2701c481b7c9b
[policy/models.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2024 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.topic;
23
24 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.doThrow;
27 import static org.mockito.Mockito.never;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30
31 import java.util.Arrays;
32 import java.util.Map;
33 import java.util.function.BiConsumer;
34 import org.junit.jupiter.api.BeforeAll;
35 import org.junit.jupiter.api.BeforeEach;
36 import org.junit.jupiter.api.Test;
37 import org.junit.jupiter.api.TestInstance;
38 import org.junit.jupiter.api.extension.ExtendWith;
39 import org.mockito.Mock;
40 import org.mockito.junit.jupiter.MockitoExtension;
41 import org.onap.policy.common.utils.coder.StandardCoderObject;
42 import org.onap.policy.controlloop.actorserviceprovider.Util;
43
44 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
45 @ExtendWith(MockitoExtension.class)
46 class ForwarderTest {
47     private static final String TEXT = "some text";
48
49     private static final String KEY1 = "requestId";
50     private static final String KEY2 = "container";
51     private static final String SUBKEY = "subRequestId";
52
53     private static final String VALUEA_REQID = "hello";
54     private static final String VALUEA_SUBREQID = "world";
55
56     // request id is shared with value A
57     private static final String VALUEB_REQID = "hello";
58     private static final String VALUEB_SUBREQID = "another world";
59
60     // unique values
61     private static final String VALUEC_REQID = "bye";
62     private static final String VALUEC_SUBREQID = "bye-bye";
63
64     @Mock
65     private BiConsumer<String, StandardCoderObject> listener1;
66
67     @Mock
68     private BiConsumer<String, StandardCoderObject> listener1b;
69
70     @Mock
71     private BiConsumer<String, StandardCoderObject> listener2;
72
73     @Mock
74     private BiConsumer<String, StandardCoderObject> listener3;
75
76     private Forwarder forwarder;
77
78
79     /**
80      * Sets up.
81      */
82     @BeforeEach
83     void setUp() {
84         forwarder = new Forwarder(Arrays.asList(new SelectorKey(KEY1), new SelectorKey(KEY2, SUBKEY)));
85
86         forwarder.register(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1);
87         forwarder.register(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1b);
88         forwarder.register(Arrays.asList(VALUEB_REQID, VALUEB_SUBREQID), listener2);
89         forwarder.register(Arrays.asList(VALUEC_REQID, VALUEC_SUBREQID), listener3);
90     }
91
92     @Test
93     void testRegister() {
94         // key size mismatches
95         assertThatIllegalArgumentException().isThrownBy(() -> forwarder.register(Arrays.asList(), listener1))
96                         .withMessage("key/value mismatch");
97         assertThatIllegalArgumentException()
98                         .isThrownBy(() -> forwarder.register(Arrays.asList(VALUEA_REQID), listener1))
99                         .withMessage("key/value mismatch");
100     }
101
102     @Test
103     void testUnregister() {
104         // remove listener1b
105         forwarder.unregister(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1b);
106
107         StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
108         forwarder.onMessage(TEXT, sco);
109
110         verify(listener1).accept(TEXT, sco);
111         verify(listener1b, never()).accept(any(), any());
112
113         // remove listener1
114         forwarder.unregister(Arrays.asList(VALUEA_REQID, VALUEA_SUBREQID), listener1);
115         forwarder.onMessage(TEXT, sco);
116
117         // route a message to listener2
118         sco = makeMessage(Map.of(KEY1, VALUEB_REQID, KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
119         forwarder.onMessage(TEXT, sco);
120         verify(listener2).accept(TEXT, sco);
121
122         // no more messages to listener1 or 1b
123         verify(listener1).accept(any(), any());
124         verify(listener1b, never()).accept(any(), any());
125     }
126
127     @Test
128      void testOnMessage() {
129         StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
130         forwarder.onMessage(TEXT, sco);
131
132         verify(listener1).accept(TEXT, sco);
133         verify(listener1b).accept(TEXT, sco);
134
135         // repeat - counts should increment
136         forwarder.onMessage(TEXT, sco);
137
138         verify(listener1, times(2)).accept(TEXT, sco);
139         verify(listener1b, times(2)).accept(TEXT, sco);
140
141         // should not have been invoked
142         verify(listener2, never()).accept(any(), any());
143         verify(listener3, never()).accept(any(), any());
144
145         // try other listeners now
146         sco = makeMessage(Map.of(KEY1, VALUEB_REQID, KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
147         forwarder.onMessage(TEXT, sco);
148         verify(listener2).accept(TEXT, sco);
149
150         sco = makeMessage(Map.of(KEY1, VALUEC_REQID, KEY2, Map.of(SUBKEY, VALUEC_SUBREQID)));
151         forwarder.onMessage(TEXT, sco);
152         verify(listener3).accept(TEXT, sco);
153
154         // message has no listeners
155         sco = makeMessage(Map.of(KEY1, "xyzzy", KEY2, Map.of(SUBKEY, VALUEB_SUBREQID)));
156         forwarder.onMessage(TEXT, sco);
157
158         // message doesn't have both keys
159         sco = makeMessage(Map.of(KEY1, VALUEA_REQID));
160         forwarder.onMessage(TEXT, sco);
161
162         // counts should not have incremented
163         verify(listener1, times(2)).accept(any(), any());
164         verify(listener1b, times(2)).accept(any(), any());
165         verify(listener2).accept(any(), any());
166         verify(listener3).accept(any(), any());
167     }
168
169     /*
170      * Tests onMessage() when listener1 throws an exception.
171      */
172     @Test
173      void testOnMessageListenerException1() {
174         doThrow(new IllegalStateException("expected exception")).when(listener1).accept(any(), any());
175
176         StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
177         forwarder.onMessage(TEXT, sco);
178
179         verify(listener1b).accept(TEXT, sco);
180     }
181
182     /*
183      * Tests onMessage() when listener1b throws an exception.
184      */
185     @Test
186      void testOnMessageListenerException1b() {
187         doThrow(new IllegalStateException("expected exception")).when(listener1b).accept(any(), any());
188
189         StandardCoderObject sco = makeMessage(Map.of(KEY1, VALUEA_REQID, KEY2, Map.of(SUBKEY, VALUEA_SUBREQID)));
190         forwarder.onMessage(TEXT, sco);
191
192         verify(listener1).accept(TEXT, sco);
193     }
194
195     /**
196      * Makes a message from a map.
197      */
198     private StandardCoderObject makeMessage(Map<String, Object> map) {
199         return Util.translate("", map, StandardCoderObject.class);
200     }
201 }