2 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
22 package org.onap.policy.controlloop.actorserviceprovider.impl;
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;
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;
52 @ExtendWith(MockitoExtension.class)
53 class BidirectionalTopicActorTest {
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;
63 private BidirectionalTopicHandler handler1;
65 private BidirectionalTopicHandler handler2;
67 private BidirectionalTopicActor<BidirectionalTopicActorParams> actor;
71 * Configures the endpoints.
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);
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);
86 static void tearDownAfterClass() {
87 // clear all topics after the tests
88 TopicEndpointManager.getManager().shutdown();
96 actor = new MyActor();
97 actor.configure(Util.translateToMap(ACTOR, makeParams()));
101 void testDoStart() throws BidirectionalTopicClientException {
102 // allocate some handlers
103 actor.getTopicHandler(MY_SINK, MY_SOURCE1);
104 actor.getTopicHandler(MY_SINK, MY_SOURCE2);
109 verify(handler1).start();
110 verify(handler2).start();
112 verify(handler1, never()).stop();
113 verify(handler2, never()).stop();
115 verify(handler1, never()).shutdown();
116 verify(handler2, never()).shutdown();
120 void testDoStop() throws BidirectionalTopicClientException {
121 // allocate some handlers
122 actor.getTopicHandler(MY_SINK, MY_SOURCE1);
123 actor.getTopicHandler(MY_SINK, MY_SOURCE2);
131 verify(handler1).stop();
132 verify(handler2).stop();
134 verify(handler1, never()).shutdown();
135 verify(handler2, never()).shutdown();
139 void testDoShutdown() throws BidirectionalTopicClientException {
141 // allocate some handlers
142 actor.getTopicHandler(MY_SINK, MY_SOURCE1);
143 actor.getTopicHandler(MY_SINK, MY_SOURCE2);
151 verify(handler1).shutdown();
152 verify(handler2).shutdown();
154 verify(handler1, never()).stop();
155 verify(handler2, never()).stop();
159 void testMakeOperatorParameters() {
160 BidirectionalTopicActorParams params = makeParams();
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));
167 assertNull(maker.apply(UNKNOWN));
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());
173 assertEquals("{sinkTopic=my-sink, sourceTopic=topicB, timeoutSec=10}",
174 new TreeMap<>(maker.apply("operB")).toString());
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);
184 void testBidirectionalTopicActor() {
185 assertEquals(ACTOR, actor.getName());
186 assertEquals(ACTOR, actor.getFullName());
190 void testGetTopicHandler() throws BidirectionalTopicClientException {
191 assertSame(handler1, actor.getTopicHandler(MY_SINK, MY_SOURCE1));
192 assertSame(handler2, actor.getTopicHandler(MY_SINK, MY_SOURCE2));
194 assertThatIllegalArgumentException().isThrownBy(() -> actor.getTopicHandler(UNKNOWN, MY_SOURCE1));
198 void testMakeTopicHandler() throws BidirectionalTopicClientException {
200 actor = new BidirectionalTopicActor<>(ACTOR, BidirectionalTopicActorParams.class);
202 handler1 = actor.getTopicHandler(MY_SINK, MY_SOURCE1);
203 handler2 = actor.getTopicHandler(MY_SINK, MY_SOURCE2);
205 assertNotNull(handler1);
206 assertNotNull(handler2);
207 assertNotSame(handler1, handler2);
211 private BidirectionalTopicActorParams makeParams() {
212 BidirectionalTopicActorParams params = new BidirectionalTopicActorParams();
213 params.setSinkTopic(MY_SINK);
214 params.setSourceTopic(MY_SOURCE1);
215 params.setTimeoutSec(TIMEOUT);
218 params.setOperations(Map.of(
220 "operB", Map.of("sourceTopic", "topicB")));
225 private class MyActor extends BidirectionalTopicActor<BidirectionalTopicActorParams> {
228 super(ACTOR, BidirectionalTopicActorParams.class);
232 protected BidirectionalTopicHandler makeTopicHandler(String sinkTopic, String sourceTopic)
233 throws BidirectionalTopicClientException {
235 if (MY_SINK.equals(sinkTopic)) {
236 if (MY_SOURCE1.equals(sourceTopic)) {
238 } else if (MY_SOURCE2.equals(sourceTopic)) {
243 throw new BidirectionalTopicClientException("no topic " + sinkTopic + "/" + sourceTopic);