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;
38 import static org.onap.policy.common.message.bus.properties.MessageBusProperties.PROPERTY_NOOP_SINK_TOPICS;
39 import static org.onap.policy.drools.system.PolicyEngineConstants.PROPERTY_TOPIC_EVENTS_SUFFIX;
41 import com.google.gson.Gson;
42 import com.google.gson.GsonBuilder;
43 import java.io.IOException;
44 import java.nio.file.Paths;
45 import java.util.List;
46 import java.util.Properties;
47 import lombok.AllArgsConstructor;
49 import org.junit.jupiter.api.AfterEach;
50 import org.junit.jupiter.api.BeforeAll;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53 import org.kie.api.builder.ReleaseId;
54 import org.onap.policy.common.message.bus.event.TopicEndpointManager;
55 import org.onap.policy.common.message.bus.event.TopicSink;
56 import org.onap.policy.drools.controller.DroolsController;
57 import org.onap.policy.drools.controller.DroolsControllerConstants;
58 import org.onap.policy.drools.controller.internal.MavenDroolsControllerTest;
59 import org.onap.policy.drools.properties.DroolsPropertyConstants;
60 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
61 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
62 import org.onap.policy.drools.util.KieUtils;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65 import org.springframework.test.util.ReflectionTestUtils;
68 * ProtocolCoder Toolset Junits.
70 public class ProtocolCoderToolsetTest {
71 private static final String JUNIT_PROTOCOL_CODER_ARTIFACT_ID = "protocolcoder";
72 private static final String JUNIT_PROTOCOL_CODER_TOPIC = JUNIT_PROTOCOL_CODER_ARTIFACT_ID;
73 private static final String CONTROLLER_ID = "blah";
75 private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolsetTest.class);
77 private static volatile ReleaseId releaseId;
79 // customCoder has to be public to be accessed in tests below
80 public static final Gson customCoder = new GsonBuilder().create(); // NOSONAR actually being used in the test
82 private DroolsController controller;
85 * Test Class Initialization.
88 public static void setUpClass() throws IOException {
89 releaseId = KieUtils.installArtifact(Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_PATH).toFile(),
90 Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_POM_PATH).toFile(),
91 MavenDroolsControllerTest.JUNIT_ECHO_KJAR_DRL_PATH,
92 Paths.get(MavenDroolsControllerTest.JUNIT_ECHO_KMODULE_DRL_PATH).toFile());
100 controller = createController();
107 public void tearDown() {
108 if (controller != null) {
109 DroolsControllerConstants.getFactory().destroy(controller);
114 void testToolsets() {
115 testGsonToolset(createFilterSet());
119 void testExceptions() {
120 // should fail without params
121 assertThrows(IllegalArgumentException.class,
122 () -> new GsonProtocolCoderToolset(null, "controller"));
124 // should fail without controller ID
125 assertThrows(IllegalArgumentException.class,
126 () -> new GsonProtocolCoderToolset(mock(EventProtocolParams.class), ""));
128 // set mock under test - always call real method under test
129 var toolset = mock(GsonProtocolCoderToolset.class);
130 when(toolset.getCoder("")).thenCallRealMethod();
132 // should fail calling with empty classname
133 assertThatThrownBy(() -> toolset.getCoder(""))
134 .isInstanceOf(IllegalArgumentException.class)
135 .hasMessageContaining("no classname provided");
137 // should fail when trying to add coder with empty event class
138 doCallRealMethod().when(toolset).addCoder(anyString(), any(JsonProtocolFilter.class), anyInt());
139 assertThatThrownBy(() -> toolset.addCoder("", mock(JsonProtocolFilter.class), 1))
140 .isInstanceOf(IllegalArgumentException.class)
141 .hasMessageContaining("no event class provided");
143 // should fail when trying to remove coder with empty event
144 doCallRealMethod().when(toolset).removeCoders(anyString());
145 assertThatThrownBy(() -> toolset.removeCoders(""))
146 .isInstanceOf(IllegalArgumentException.class)
147 .hasMessageContaining("no event class provided");
149 // set coders to empty list
150 when(toolset.filter(anyString())).thenCallRealMethod();
151 ReflectionTestUtils.setField(toolset, "coders", List.of());
153 // should fail when trying to find a filter from an empty list
154 assertThatThrownBy(() -> toolset.filter(""))
155 .isInstanceOf(IllegalStateException.class)
156 .hasMessageContaining("No coders available");
158 // there is a coder in the list, but can't check if accepts json when coder doesn't have filter
159 var mockCoderFilter = mock(CoderFilters.class);
160 when(mockCoderFilter.getFilter()).thenReturn(null);
161 ReflectionTestUtils.setField(toolset, "coders", List.of(mockCoderFilter));
163 assertNull(toolset.filter("json"));
168 * Test the Gson toolset.
170 * @param protocolFilter protocol filter
172 private void testGsonToolset(JsonProtocolFilter protocolFilter) {
173 GsonProtocolCoderToolset gsonToolset =
174 new GsonProtocolCoderToolset(EventProtocolParams.builder().topic(JUNIT_PROTOCOL_CODER_TOPIC)
175 .groupId(releaseId.getGroupId()).artifactId(releaseId.getArtifactId())
176 .eventClass(ThreeStrings.class.getName()).protocolFilter(protocolFilter)
177 .customGsonCoder(null).modelClassLoaderHash(12345678).build(), CONTROLLER_ID);
179 assertNotNull(gsonToolset.getEncoder());
180 assertNotNull(gsonToolset.getDecoder());
181 assertThat(gsonToolset.toString()).startsWith("GsonProtocolCoderToolset [");
182 assertThat(gsonToolset.toString()).contains("=ProtocolCoderToolset [");
183 assertThat(gsonToolset.toString()).contains("[CoderFilters [");
185 testToolset(protocolFilter, gsonToolset);
187 ThreeStrings triple = createTriple();
188 gsonToolset.setCustomCoder(new CustomGsonCoder(this.getClass().getName(), "customCoder"));
189 String tripleEncoded = encode(gsonToolset, triple);
190 decode(protocolFilter, gsonToolset, triple, tripleEncoded);
193 private ThreeStrings createTriple() {
194 return new ThreeStrings("v1", "v2", "v3");
197 private void testToolset(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
199 validateInitialization(protocolFilter, coderToolset);
201 updateCoderFilterRule(coderToolset);
203 addRemoveCoder(coderToolset);
205 /* restore original filters */
206 coderToolset.addCoder(ThreeStrings.class.getName(), protocolFilter, 654321);
208 ThreeStrings triple = createTriple();
210 String tripleEncoded = encode(coderToolset, triple);
212 decode(protocolFilter, coderToolset, triple, tripleEncoded);
215 private void decode(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset,
216 ThreeStrings triple, String tripleEncoded) {
219 coderToolset.decode(tripleEncoded);
220 } catch (UnsupportedOperationException e) {
222 logger.trace("Junit expected exception - decode does not pass filtering", e);
225 CoderFilters coderFilters = coderToolset.getCoder(ThreeStrings.class.getName());
226 assertSame(coderFilters.getFactClass(), ThreeStrings.class.getName());
227 assertSame(coderFilters.getFilter(), protocolFilter);
228 assertNotNull(coderFilters.getFilter().getRule());
230 coderFilters.getFilter().setRule("[?($.second =~ /^v2$/ && $.third =~ /.*v3.*/)]");
232 ThreeStrings tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
234 assertEquals(triple.getFirst(), tripleDecoded.getFirst());
235 assertEquals(triple.getSecond(), tripleDecoded.getSecond());
236 assertEquals(triple.getThird(), tripleDecoded.getThird());
238 coderFilters.getFilter().setRule(null);
239 assertEquals("[?($ =~ /.*/)]", coderFilters.getFilter().getRule());
241 tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
243 assertEquals(tripleDecoded.getFirst(), triple.getFirst());
244 assertEquals(tripleDecoded.getSecond(), triple.getSecond());
245 assertEquals(tripleDecoded.getThird(), triple.getThird());
247 coderFilters.getFilter().setRule("[?($.third =~ /.*v3.*/)]");
250 private String encode(ProtocolCoderToolset coderToolset, ThreeStrings triple) {
251 String tripleEncoded = coderToolset.encode(triple);
252 assertFalse(tripleEncoded.isEmpty());
253 return tripleEncoded;
256 private void addRemoveCoder(ProtocolCoderToolset coderToolset) {
257 coderToolset.addCoder(this.getClass().getName(), new JsonProtocolFilter("[?($.second =~ /.*/)]"), 654321);
258 assertEquals(2, coderToolset.getCoders().size());
260 coderToolset.removeCoders(this.getClass().getName());
261 assertEquals(1, coderToolset.getCoders().size());
264 private void updateCoderFilterRule(ProtocolCoderToolset coderToolset) {
265 coderToolset.addCoder(ThreeStrings.class.getName(), new JsonProtocolFilter("[?($.third =~ /.*/)]"), 654321);
267 assertEquals(1, coderToolset.getCoders().size());
269 assertEquals(654321, coderToolset.getCoder(ThreeStrings.class.getName()).getModelClassLoaderHash());
271 assertNotNull(coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
273 assertEquals("[?($.third =~ /.*/)]",
274 coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
277 private void validateInitialization(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
278 assertEquals(CONTROLLER_ID, coderToolset.getControllerId());
279 assertEquals(releaseId.getGroupId(), coderToolset.getGroupId());
280 assertEquals(releaseId.getArtifactId(), coderToolset.getArtifactId());
281 assertNull(coderToolset.getCustomCoder());
283 assertEquals(1, coderToolset.getCoders().size());
285 CoderFilters coderFilters = coderToolset.getCoder(CONTROLLER_ID);
286 assertNull(coderFilters);
288 coderFilters = coderToolset.getCoder(ThreeStrings.class.getName());
289 assertNotNull(coderFilters);
291 assertEquals(coderFilters.getFilter(), protocolFilter);
294 private DroolsController createController() {
295 if (releaseId == null) {
296 throw new IllegalStateException("no prereq artifact installed in maven repository");
299 Properties sinkConfig = new Properties();
300 sinkConfig.put(PROPERTY_NOOP_SINK_TOPICS, JUNIT_PROTOCOL_CODER_TOPIC);
301 final List<TopicSink> noopTopics = TopicEndpointManager.getManager().addTopicSinks(sinkConfig);
303 Properties droolsControllerConfig = getDroolsControllerConfig();
305 return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics);
308 private static Properties getDroolsControllerConfig() {
309 Properties droolsControllerConfig = new Properties();
310 droolsControllerConfig.put(DroolsPropertyConstants.RULES_GROUPID, releaseId.getGroupId());
311 droolsControllerConfig.put(DroolsPropertyConstants.RULES_ARTIFACTID, releaseId.getArtifactId());
312 droolsControllerConfig.put(DroolsPropertyConstants.RULES_VERSION, releaseId.getVersion());
313 droolsControllerConfig.put(
314 PROPERTY_NOOP_SINK_TOPICS + "." + JUNIT_PROTOCOL_CODER_TOPIC
315 + PROPERTY_TOPIC_EVENTS_SUFFIX,
316 ThreeStrings.class.getName());
317 return droolsControllerConfig;
320 private JsonProtocolFilter createFilterSet() {
321 return new JsonProtocolFilter("[?($.first =~ /.*/ && $.second =~ /^blah.*/ && $.third =~ /^hello$/)]");
325 * Note: We need an object that can be constructed, but the apache Triple cannot, thus
326 * we create our own class just for these tests.
330 public static class ThreeStrings {
331 private String first;
332 private String second;
333 private String third;