cb4397c8d76d618619b9f8f432371c499eb2e189
[policy/drools-pdp.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
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
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.drools.protocol.coders;
23
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
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;
46 import lombok.Getter;
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;
65
66 /**
67  * ProtocolCoder Toolset Junits.
68  */
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";
73
74     private static final Logger logger = LoggerFactory.getLogger(ProtocolCoderToolsetTest.class);
75
76     private static volatile ReleaseId releaseId;
77
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
80
81     private DroolsController controller;
82
83     /**
84      * Test Class Initialization.
85      */
86     @BeforeAll
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());
92     }
93
94     /**
95      * Test Set Up.
96      */
97     @BeforeEach
98     public void setUp() {
99         controller = createController();
100     }
101
102     /**
103      * Test Termination.
104      */
105     @AfterEach
106     public void tearDown() {
107         if (controller != null) {
108             DroolsControllerConstants.getFactory().destroy(controller);
109         }
110     }
111
112     @Test
113     void testToolsets() {
114         testGsonToolset(createFilterSet());
115     }
116
117     @Test
118     void testExceptions() {
119         // should fail without params
120         assertThrows(IllegalArgumentException.class,
121             () -> new GsonProtocolCoderToolset(null, "controller"));
122
123         // should fail without controller ID
124         assertThrows(IllegalArgumentException.class,
125             () -> new GsonProtocolCoderToolset(mock(EventProtocolParams.class), ""));
126
127         // set mock under test - always call real method under test
128         var toolset = mock(GsonProtocolCoderToolset.class);
129         when(toolset.getCoder("")).thenCallRealMethod();
130
131         // should fail calling with empty classname
132         assertThatThrownBy(() -> toolset.getCoder(""))
133             .isInstanceOf(IllegalArgumentException.class)
134             .hasMessageContaining("no classname provided");
135
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");
141
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");
147
148         // set coders to empty list
149         when(toolset.filter(anyString())).thenCallRealMethod();
150         ReflectionTestUtils.setField(toolset, "coders", List.of());
151
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");
156
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));
161
162         assertNull(toolset.filter("json"));
163
164     }
165
166     /**
167      * Test the Gson toolset.
168      *
169      * @param protocolFilter protocol filter
170      */
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);
177
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 [");
183
184         testToolset(protocolFilter, gsonToolset);
185
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);
190     }
191
192     private ThreeStrings createTriple() {
193         return new ThreeStrings("v1", "v2", "v3");
194     }
195
196     private void testToolset(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
197
198         validateInitialization(protocolFilter, coderToolset);
199
200         updateCoderFilterRule(coderToolset);
201
202         addRemoveCoder(coderToolset);
203
204         /* restore original filters */
205         coderToolset.addCoder(ThreeStrings.class.getName(), protocolFilter, 654321);
206
207         ThreeStrings triple = createTriple();
208
209         String tripleEncoded = encode(coderToolset, triple);
210
211         decode(protocolFilter, coderToolset, triple, tripleEncoded);
212     }
213
214     private void decode(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset,
215                         ThreeStrings triple, String tripleEncoded) {
216
217         try {
218             coderToolset.decode(tripleEncoded);
219         } catch (UnsupportedOperationException e) {
220             /* OK */
221             logger.trace("Junit expected exception - decode does not pass filtering", e);
222         }
223
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());
228
229         coderFilters.getFilter().setRule("[?($.second =~ /^v2$/ && $.third =~ /.*v3.*/)]");
230
231         ThreeStrings tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
232
233         assertEquals(triple.getFirst(), tripleDecoded.getFirst());
234         assertEquals(triple.getSecond(), tripleDecoded.getSecond());
235         assertEquals(triple.getThird(), tripleDecoded.getThird());
236
237         coderFilters.getFilter().setRule(null);
238         assertEquals("[?($ =~ /.*/)]", coderFilters.getFilter().getRule());
239
240         tripleDecoded = (ThreeStrings) coderToolset.decode(tripleEncoded);
241
242         assertEquals(tripleDecoded.getFirst(), triple.getFirst());
243         assertEquals(tripleDecoded.getSecond(), triple.getSecond());
244         assertEquals(tripleDecoded.getThird(), triple.getThird());
245
246         coderFilters.getFilter().setRule("[?($.third =~ /.*v3.*/)]");
247     }
248
249     private String encode(ProtocolCoderToolset coderToolset, ThreeStrings triple) {
250         String tripleEncoded = coderToolset.encode(triple);
251         assertFalse(tripleEncoded.isEmpty());
252         return tripleEncoded;
253     }
254
255     private void addRemoveCoder(ProtocolCoderToolset coderToolset) {
256         coderToolset.addCoder(this.getClass().getName(), new JsonProtocolFilter("[?($.second =~ /.*/)]"), 654321);
257         assertEquals(2, coderToolset.getCoders().size());
258
259         coderToolset.removeCoders(this.getClass().getName());
260         assertEquals(1, coderToolset.getCoders().size());
261     }
262
263     private void updateCoderFilterRule(ProtocolCoderToolset coderToolset) {
264         coderToolset.addCoder(ThreeStrings.class.getName(), new JsonProtocolFilter("[?($.third =~ /.*/)]"), 654321);
265
266         assertEquals(1, coderToolset.getCoders().size());
267
268         assertEquals(654321, coderToolset.getCoder(ThreeStrings.class.getName()).getModelClassLoaderHash());
269
270         assertNotNull(coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
271
272         assertEquals("[?($.third =~ /.*/)]",
273             coderToolset.getCoder(ThreeStrings.class.getName()).getFilter().getRule());
274     }
275
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());
281
282         assertEquals(1, coderToolset.getCoders().size());
283
284         CoderFilters coderFilters = coderToolset.getCoder(CONTROLLER_ID);
285         assertNull(coderFilters);
286
287         coderFilters = coderToolset.getCoder(ThreeStrings.class.getName());
288         assertNotNull(coderFilters);
289
290         assertEquals(coderFilters.getFilter(), protocolFilter);
291     }
292
293     private DroolsController createController() {
294         if (releaseId == null) {
295             throw new IllegalStateException("no prereq artifact installed in maven repository");
296         }
297
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);
301
302         Properties droolsControllerConfig = getDroolsControllerConfig();
303
304         return DroolsControllerConstants.getFactory().build(droolsControllerConfig, null, noopTopics);
305     }
306
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;
317     }
318
319     private JsonProtocolFilter createFilterSet() {
320         return new JsonProtocolFilter("[?($.first =~ /.*/ && $.second =~ /^blah.*/ && $.third =~ /^hello$/)]");
321     }
322
323     /**
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.
326      */
327     @Getter
328     @AllArgsConstructor
329     public static class ThreeStrings {
330         private String first;
331         private String second;
332         private String third;
333     }
334 }