7e4543eca2b352c63e398e2094b61159ed5de72d
[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.impl;
23
24 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
25 import static org.assertj.core.api.Assertions.assertThatThrownBy;
26 import static org.junit.jupiter.api.Assertions.assertEquals;
27 import static org.junit.jupiter.api.Assertions.assertNotNull;
28 import static org.junit.jupiter.api.Assertions.assertNotSame;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertSame;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.verify;
33
34 import java.util.Map;
35 import java.util.Properties;
36 import java.util.TreeMap;
37 import java.util.function.Function;
38 import org.junit.jupiter.api.AfterAll;
39 import org.junit.jupiter.api.BeforeAll;
40 import org.junit.jupiter.api.BeforeEach;
41 import org.junit.jupiter.api.Test;
42 import org.junit.jupiter.api.extension.ExtendWith;
43 import org.mockito.Mock;
44 import org.mockito.junit.jupiter.MockitoExtension;
45 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
46 import org.onap.policy.common.endpoints.event.comm.client.BidirectionalTopicClientException;
47 import org.onap.policy.controlloop.actorserviceprovider.Util;
48 import org.onap.policy.controlloop.actorserviceprovider.parameters.BidirectionalTopicActorParams;
49 import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException;
50 import org.onap.policy.controlloop.actorserviceprovider.topic.BidirectionalTopicHandler;
51
52 @ExtendWith(MockitoExtension.class)
53 class BidirectionalTopicActorTest {
54
55     private static final String ACTOR = "my-actor";
56     private static final String UNKNOWN = "unknown";
57     private static final String MY_SINK = "my-sink";
58     private static final String MY_SOURCE1 = "my-source-A";
59     private static final String MY_SOURCE2 = "my-source-B";
60     private static final int TIMEOUT = 10;
61
62     @Mock
63     private BidirectionalTopicHandler handler1;
64     @Mock
65     private BidirectionalTopicHandler handler2;
66
67     private BidirectionalTopicActor<BidirectionalTopicActorParams> actor;
68
69
70     /**
71      * Configures the endpoints.
72      */
73     @BeforeAll
74     static void setUpBeforeClass() {
75         Properties props = new Properties();
76         props.setProperty("noop.sink.topics", MY_SINK);
77         props.setProperty("noop.source.topics", MY_SOURCE1 + "," + MY_SOURCE2);
78
79         // clear all topics and then configure one sink and two sources
80         TopicEndpointManager.getManager().shutdown();
81         TopicEndpointManager.getManager().addTopicSinks(props);
82         TopicEndpointManager.getManager().addTopicSources(props);
83     }
84
85     @AfterAll
86     static void tearDownAfterClass() {
87         // clear all topics after the tests
88         TopicEndpointManager.getManager().shutdown();
89     }
90
91     /**
92      * Sets up.
93      */
94     @BeforeEach
95     void setUp() {
96         actor = new MyActor();
97         actor.configure(Util.translateToMap(ACTOR, makeParams()));
98     }
99
100     @Test
101     void testDoStart() {
102         // allocate some handlers
103         actor.getTopicHandler(MY_SINK, MY_SOURCE1);
104         actor.getTopicHandler(MY_SINK, MY_SOURCE2);
105
106         // start it
107         actor.start();
108
109         verify(handler1).start();
110         verify(handler2).start();
111
112         verify(handler1, never()).stop();
113         verify(handler2, never()).stop();
114
115         verify(handler1, never()).shutdown();
116         verify(handler2, never()).shutdown();
117     }
118
119     @Test
120     void testDoStop() {
121         // allocate some handlers
122         actor.getTopicHandler(MY_SINK, MY_SOURCE1);
123         actor.getTopicHandler(MY_SINK, MY_SOURCE2);
124
125         // start it
126         actor.start();
127
128         // stop it
129         actor.stop();
130
131         verify(handler1).stop();
132         verify(handler2).stop();
133
134         verify(handler1, never()).shutdown();
135         verify(handler2, never()).shutdown();
136     }
137
138     @Test
139     void testDoShutdown() {
140
141         // allocate some handlers
142         actor.getTopicHandler(MY_SINK, MY_SOURCE1);
143         actor.getTopicHandler(MY_SINK, MY_SOURCE2);
144
145         // start it
146         actor.start();
147
148         // stop it
149         actor.shutdown();
150
151         verify(handler1).shutdown();
152         verify(handler2).shutdown();
153
154         verify(handler1, never()).stop();
155         verify(handler2, never()).stop();
156     }
157
158     @Test
159     void testMakeOperatorParameters() {
160         BidirectionalTopicActorParams params = makeParams();
161
162         final BidirectionalTopicActor<BidirectionalTopicActorParams> prov =
163             new BidirectionalTopicActor<>(ACTOR, BidirectionalTopicActorParams.class);
164         Function<String, Map<String, Object>> maker =
165             prov.makeOperatorParameters(Util.translateToMap(prov.getName(), params));
166
167         assertNull(maker.apply(UNKNOWN));
168
169         // use a TreeMap to ensure the properties are sorted
170         assertEquals("{sinkTopic=my-sink, sourceTopic=my-source-A, timeoutSec=10}",
171             new TreeMap<>(maker.apply("operA")).toString());
172
173         assertEquals("{sinkTopic=my-sink, sourceTopic=topicB, timeoutSec=10}",
174             new TreeMap<>(maker.apply("operB")).toString());
175
176         // with invalid actor parameters
177         params.setOperations(null);
178         Map<String, Object> map = Util.translateToMap(prov.getName(), params);
179         assertThatThrownBy(() -> prov.makeOperatorParameters(map))
180             .isInstanceOf(ParameterValidationRuntimeException.class);
181     }
182
183     @Test
184     void testBidirectionalTopicActor() {
185         assertEquals(ACTOR, actor.getName());
186         assertEquals(ACTOR, actor.getFullName());
187     }
188
189     @Test
190      void testGetTopicHandler() {
191         assertSame(handler1, actor.getTopicHandler(MY_SINK, MY_SOURCE1));
192         assertSame(handler2, actor.getTopicHandler(MY_SINK, MY_SOURCE2));
193
194         assertThatIllegalArgumentException().isThrownBy(() -> actor.getTopicHandler(UNKNOWN, MY_SOURCE1));
195     }
196
197     @Test
198      void testMakeTopicHandler() {
199         // use a real actor
200         actor = new BidirectionalTopicActor<>(ACTOR, BidirectionalTopicActorParams.class);
201
202         handler1 = actor.getTopicHandler(MY_SINK, MY_SOURCE1);
203         handler2 = actor.getTopicHandler(MY_SINK, MY_SOURCE2);
204
205         assertNotNull(handler1);
206         assertNotNull(handler2);
207         assertNotSame(handler1, handler2);
208     }
209
210
211     private BidirectionalTopicActorParams makeParams() {
212         BidirectionalTopicActorParams params = new BidirectionalTopicActorParams();
213         params.setSinkTopic(MY_SINK);
214         params.setSourceTopic(MY_SOURCE1);
215         params.setTimeoutSec(TIMEOUT);
216
217         // @formatter:off
218         params.setOperations(Map.of(
219             "operA", Map.of(),
220             "operB", Map.of("sourceTopic", "topicB")));
221         // @formatter:on
222         return params;
223     }
224
225     private class MyActor extends BidirectionalTopicActor<BidirectionalTopicActorParams> {
226
227         MyActor() {
228             super(ACTOR, BidirectionalTopicActorParams.class);
229         }
230
231         @Override
232         protected BidirectionalTopicHandler makeTopicHandler(String sinkTopic, String sourceTopic)
233             throws BidirectionalTopicClientException {
234
235             if (MY_SINK.equals(sinkTopic)) {
236                 if (MY_SOURCE1.equals(sourceTopic)) {
237                     return handler1;
238                 } else if (MY_SOURCE2.equals(sourceTopic)) {
239                     return handler2;
240                 }
241             }
242
243             throw new BidirectionalTopicClientException("no topic " + sinkTopic + "/" + sourceTopic);
244         }
245     }
246 }