2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018-2021-2022 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.drools.protocol.coders;
24 import static org.assertj.core.api.Assertions.assertThat;
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.assertFalse;
28 import static org.junit.jupiter.api.Assertions.assertNotNull;
29 import static org.junit.jupiter.api.Assertions.assertNull;
30 import static org.junit.jupiter.api.Assertions.assertSame;
31 import static org.junit.jupiter.api.Assertions.assertThrows;
32 import static org.mockito.ArgumentMatchers.any;
33 import static org.mockito.ArgumentMatchers.anyInt;
34 import static org.mockito.ArgumentMatchers.anyString;
35 import static org.mockito.Mockito.doCallRealMethod;
36 import static org.mockito.Mockito.mock;
37 import static org.mockito.Mockito.when;
39 import com.google.gson.Gson;
40 import com.google.gson.GsonBuilder;
41 import java.io.IOException;
42 import java.nio.file.Paths;
43 import java.util.List;
44 import java.util.Properties;
45 import lombok.AllArgsConstructor;
47 import org.junit.jupiter.api.AfterEach;
48 import org.junit.jupiter.api.BeforeAll;
49 import org.junit.jupiter.api.BeforeEach;
50 import org.junit.jupiter.api.Test;
51 import org.kie.api.builder.ReleaseId;
52 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
53 import org.onap.policy.common.endpoints.event.comm.TopicSink;
54 import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties;
55 import org.onap.policy.drools.controller.DroolsController;
56 import org.onap.policy.drools.controller.DroolsControllerConstants;
57 import org.onap.policy.drools.controller.internal.MavenDroolsControllerTest;
58 import org.onap.policy.drools.properties.DroolsPropertyConstants;
59 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
60 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
61 import org.onap.policy.drools.util.KieUtils;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.springframework.test.util.ReflectionTestUtils;
67 * ProtocolCoder Toolset Junits.
69 public class ProtocolCoderToolsetTest {
70 private static final String JUNIT_PROTOCOL_CODER_ARTIFACT_ID = "protocolcoder";
71 private static final String JUNIT_PROTOCOL_CODER_TOPIC = JUNIT_PROTOCOL_CODER_ARTIFACT_ID;
72 private static final String CONTROLLER_ID = "blah";
74 private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolsetTest.class);
76 private static volatile ReleaseId releaseId;
78 // customCoder has to be public to be accessed in tests below
79 public static final Gson customCoder = new GsonBuilder().create(); // NOSONAR actually being used in the test
81 private DroolsController controller;
84 * Test Class Initialization.
87 public static void setUpClass() throws IOException {
88 releaseId = KieUtils.installArtifact(Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_PATH).toFile(),
89 Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(),
90 MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH,
91 Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile());
99 controller = createController();
106 public void tearDown() {
107 if (controller != null) {
108 DroolsControllerConstants.getFactory().destroy(controller);
113 void testToolsets() {
114 testGsonToolset(createFilterSet());
118 void testExceptions() {
119 // should fail without params
120 assertThrows(IllegalArgumentException.class,
121 () -> new GsonProtocolCoderToolset(null, "controller"));
123 // should fail without controller ID
124 assertThrows(IllegalArgumentException.class,
125 () -> new GsonProtocolCoderToolset(mock(EventProtocolParams.class), ""));
127 // set mock under test - always call real method under test
128 var toolset = mock(GsonProtocolCoderToolset.class);
129 when(toolset.getCoder("")).thenCallRealMethod();
131 // should fail calling with empty classname
132 assertThatThrownBy(() -> toolset.getCoder(""))
133 .isInstanceOf(IllegalArgumentException.class)
134 .hasMessageContaining("no classname provided");
136 // should fail when trying to add coder with empty event class
137 doCallRealMethod().when(toolset).addCoder(anyString(), any(JsonProtocolFilter.class), anyInt());
138 assertThatThrownBy(() -> toolset.addCoder("", mock(JsonProtocolFilter.class), 1))
139 .isInstanceOf(IllegalArgumentException.class)
140 .hasMessageContaining("no event class provided");
142 // should fail when trying to remove coder with empty event
143 doCallRealMethod().when(toolset).removeCoders(anyString());
144 assertThatThrownBy(() -> toolset.removeCoders(""))
145 .isInstanceOf(IllegalArgumentException.class)
146 .hasMessageContaining("no event class provided");
148 // set coders to empty list
149 when(toolset.filter(anyString())).thenCallRealMethod();
150 ReflectionTestUtils.setField(toolset, "coders", List.of());
152 // should fail when trying to find a filter from an empty list
153 assertThatThrownBy(() -> toolset.filter(""))
154 .isInstanceOf(IllegalStateException.class)
155 .hasMessageContaining("No coders available");
157 // there is a coder in the list, but can't check if accepts json when coder doesn't have filter
158 var mockCoderFilter = mock(CoderFilters.class);
159 when(mockCoderFilter.getFilter()).thenReturn(null);
160 ReflectionTestUtils.setField(toolset, "coders", List.of(mockCoderFilter));
162 assertNull(toolset.filter("json"));
167 * Test the Gson toolset.
169 * @param protocolFilter protocol filter
171 private void testGsonToolset(JsonProtocolFilter protocolFilter) {
172 GsonProtocolCoderToolset gsonToolset =
173 new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC)
174 .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId())
175 .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter)
176 .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID);
178 assertNotNull(gsonToolset.getEncoder());
179 assertNotNull(gsonToolset.getDecoder());
180 assertThat(gsonToolset.toString()).startsWith("GsonProtocolCoderToolset [");
181 assertThat(gsonToolset.toString()).contains("=ProtocolCoderToolset [");
182 assertThat(gsonToolset.toString()).contains("[CoderFilters [");
184 testToolset(protocolFilter, gsonToolset);
186 ThreeStrings triple = createTriple();
187 gsonToolset.setCustomCoder(new CustomGsonCoder(this.getClass().getName(), "customCoder"));
188 String tripleEncoded = encode(gsonToolset, triple);
189 decode(protocolFilter, gsonToolset, triple, tripleEncoded);
192 private ThreeStrings createTriple() {
193 return new ThreeStrings("v1", "v2", "v3");
196 private void testToolset(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
198 validateInitialization(protocolFilter, coderToolset);
200 updateCoderFilterRule(coderToolset);
202 addRemoveCoder(coderToolset);
204 /* restore original filters */
205 coderToolset.addCoder(ThreeStrings.class.getName(), protocolFilter, 654321);
207 ThreeStrings triple = createTriple();
209 String tripleEncoded = encode(coderToolset, triple);
211 decode(protocolFilter, coderToolset, triple, tripleEncoded);
214 private void decode(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset,
215 ThreeStrings triple, String tripleEncoded) {
218 coderToolset.decode(tripleEncoded);
219 } catch (UnsupportedOperationException e) {
221 logger.trace("Junit expected exception - decode does not pass filtering", e);
224 CoderFilters coderFilters = coderToolset.getCoder(ThreeStrings.class.getName());
225 assertSame(coderFilters.getFactClass(), ThreeStrings.class.getName());
226 assertSame(coderFilters.getFilter(), protocolFilter);
227 assertNotNull(coderFilters.getFilter().getRule());
229 coderFilters.getFilter().setRule("[?($.second =~ /^v2$/ && $.third =~ /.*v3.*/)]");
231 ThreeStrings tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
233 assertEquals(triple.getFirst(), tripleDecoded.getFirst());
234 assertEquals(triple.getSecond(), tripleDecoded.getSecond());
235 assertEquals(triple.getThird(), tripleDecoded.getThird());
237 coderFilters.getFilter().setRule(null);
238 assertEquals("[?($ =~ /.*/)]", coderFilters.getFilter().getRule());
240 tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
242 assertEquals(tripleDecoded.getFirst(), triple.getFirst());
243 assertEquals(tripleDecoded.getSecond(), triple.getSecond());
244 assertEquals(tripleDecoded.getThird(), triple.getThird());
246 coderFilters.getFilter().setRule("[?($.third =~ /.*v3.*/)]");
249 private String encode(ProtocolCoderToolset coderToolset, ThreeStrings triple) {
250 String tripleEncoded = coderToolset.encode(triple);
251 assertFalse(tripleEncoded.isEmpty());
252 return tripleEncoded;
255 private void addRemoveCoder(ProtocolCoderToolset coderToolset) {
256 coderToolset.addCoder(this.getClass().getName(), new JsonProtocolFilter("[?($.second =~ /.*/)]"), 654321);
257 assertEquals(2, coderToolset.getCoders().size());
259 coderToolset.removeCoders(this.getClass().getName());
260 assertEquals(1, coderToolset.getCoders().size());
263 private void updateCoderFilterRule(ProtocolCoderToolset coderToolset) {
264 coderToolset.addCoder(ThreeStrings.class.getName(), new JsonProtocolFilter("[?($.third =~ /.*/)]"), 654321);
266 assertEquals(1, coderToolset.getCoders().size());
268 assertEquals(654321, coderToolset.getCoder(ThreeStrings.class.getName()).getModelClassLoaderHash());
270 assertNotNull(coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
272 assertEquals("[?($.third =~ /.*/)]",
273 coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
276 private void validateInitialization(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
277 assertEquals(CONTROLLER_ID, coderToolset.getControllerId());
278 assertEquals(releaseId.getGroupId(), coderToolset.getGroupId());
279 assertEquals(releaseId.getArtifactId(), coderToolset.getArtifactId());
280 assertNull(coderToolset.getCustomCoder());
282 assertEquals(1, coderToolset.getCoders().size());
284 CoderFilters coderFilters = coderToolset.getCoder(CONTROLLER_ID);
285 assertNull(coderFilters);
287 coderFilters = coderToolset.getCoder(ThreeStrings.class.getName());
288 assertNotNull(coderFilters);
290 assertEquals(coderFilters.getFilter(), protocolFilter);
293 private DroolsController createController() {
294 if (releaseId == null) {
295 throw new IllegalStateException("no prereq artifact installed in maven repository");
298 Properties sinkConfig = new Properties();
299 sinkConfig.put(PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS, JUNIT_PROTOCOL_CODER_TOPIC);
300 final List<TopicSink> noopTopics = TopicEndpointManager.getManager().addTopicSinks(sinkConfig);
302 Properties droolsControllerConfig = getDroolsControllerConfig();
304 return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics);
307 private static Properties getDroolsControllerConfig() {
308 Properties droolsControllerConfig = new Properties();
309 droolsControllerConfig.put(DroolsPropertyConstants.RULES_GROUPID, releaseId.getGroupId());
310 droolsControllerConfig.put(DroolsPropertyConstants.RULES_ARTIFACTID, releaseId.getArtifactId());
311 droolsControllerConfig.put(DroolsPropertyConstants.RULES_VERSION, releaseId.getVersion());
312 droolsControllerConfig.put(
313 PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC
314 + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX,
315 ThreeStrings.class.getName());
316 return droolsControllerConfig;
319 private JsonProtocolFilter createFilterSet() {
320 return new JsonProtocolFilter("[?($.first =~ /.*/ && $.second =~ /^blah.*/ && $.third =~ /^hello$/)]");
324 * Note: We need an object that can be constructed, but the apache Triple cannot, thus
325 * we create our own class just for these tests.
329 public static class ThreeStrings {
330 private String first;
331 private String second;
332 private String third;