01efe47fea2f9e733c7afc9bd99f191b37cc2989
[nonrtric/plt/ranpm.git] / pmproducer / src / test / java / org / oran / pmproducer / filter / PmReportFilterTest.java
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2023 Nordix Foundation
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20
21 package org.oran.pmproducer.filter;
22
23 import static org.assertj.core.api.Assertions.assertThat;
24
25 import com.google.gson.Gson;
26 import com.google.gson.GsonBuilder;
27 import com.google.protobuf.AbstractMessage.Builder;
28 import com.google.protobuf.Message;
29 import com.google.protobuf.MessageOrBuilder;
30 import com.google.protobuf.util.JsonFormat;
31
32 import java.io.IOException;
33 import java.lang.invoke.MethodHandles;
34 import java.lang.reflect.InvocationTargetException;
35 import java.nio.charset.Charset;
36 import java.nio.file.Files;
37 import java.nio.file.Path;
38 import java.time.Instant;
39
40 import org.junit.jupiter.api.Test;
41 import org.oran.pmproducer.tasks.TopicListener;
42 import org.oran.pmproducer.tasks.TopicListener.DataFromTopic;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 class PmReportFilterTest {
47
48     public static class ProtoJsonUtil {
49
50         /**
51          * Makes a Json from a given message or builder
52          *
53          * @param messageOrBuilder is the instance
54          * @return The string representation
55          * @throws IOException if any error occurs
56          */
57         public static String toJson(MessageOrBuilder messageOrBuilder) throws IOException {
58             return JsonFormat.printer().print(messageOrBuilder);
59         }
60
61         /**
62          * Makes a new instance of message based on the json and the class
63          *
64          * @param <T> is the class type
65          * @param json is the json instance
66          * @param clazz is the class instance
67          * @return An instance of T based on the json values
68          * @throws IOException if any error occurs
69          */
70         @SuppressWarnings({"unchecked", "rawtypes"})
71         public static <T extends Message> T fromJson(String json, Class<T> clazz) throws IOException {
72             // https://stackoverflow.com/questions/27642021/calling-parsefrom-method-for-generic-protobuffer-class-in-java/33701202#33701202
73             Builder builder = null;
74             try {
75                 // Since we are dealing with a Message type, we can call newBuilder()
76                 builder = (Builder) clazz.getMethod("newBuilder").invoke(null);
77
78             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
79                     | NoSuchMethodException | SecurityException e) {
80                 return null;
81             }
82
83             // The instance is placed into the builder values
84             JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
85
86             // the instance will be from the build
87             return (T) builder.build();
88         }
89     }
90
91     private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
92
93     private static Gson gson = new GsonBuilder() //
94             .disableHtmlEscaping() //
95             .create(); //
96
97     private String filterReport(PmReportFilter filter) throws Exception {
98
99         TopicListener.DataFromTopic data =
100                 new TopicListener.DataFromTopic("typeId", null, null, loadReport().getBytes());
101         FilteredData filtered = filter.filter(data);
102
103         String reportAfterFilter = gson.toJson(data.getCachedPmReport());
104         String reportBeforeFilter = gson.toJson(gson.fromJson(loadReport(), PmReport.class));
105
106         assertThat(reportAfterFilter).isEqualTo(reportBeforeFilter);
107
108         return filtered.getValueAString();
109     }
110
111     @Test
112     void testPmFilterMeasTypes() throws Exception {
113
114         PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
115         filterData.addMeasTypes("UtranCell", "succImmediateAssignProcs");
116
117         PmReportFilter filter = new PmReportFilter(filterData);
118         String filtered = filterReport(filter);
119
120         assertThat(filtered).contains("succImmediateAssignProcs").doesNotContain("\"p\":2").contains("\"p\":1")
121                 .contains("Gbg-997");
122
123         // Test that no report is returned if not meas types were found
124         filterData = new PmReportFilter.FilterData();
125         filterData.addMeasTypes("junk", "succImmediateAssignProcs");
126
127         filter = new PmReportFilter(filterData);
128         filtered = filterReport(filter);
129         assertThat(filtered).isEmpty();
130     }
131
132     @Test
133     void testMeasObjInstIds() throws Exception {
134         PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
135         filterData.measObjInstIds.add("junk");
136         PmReportFilter filter = new PmReportFilter(filterData);
137         String filtered = filterReport(filter);
138         assertThat(filtered).isEmpty();
139
140         filterData = new PmReportFilter.FilterData();
141         filterData.measObjInstIds.add("UtranCell=Gbg-997");
142         filter = new PmReportFilter(filterData);
143         filtered = filterReport(filter);
144         assertThat(filtered).contains("Gbg-997").doesNotContain("Gbg-998");
145     }
146
147     @Test
148     void testMeasObjClass() throws Exception {
149         {
150             PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
151             filterData.addMeasTypes("junk");
152             PmReportFilter filter = new PmReportFilter(filterData);
153             String filtered = filterReport(filter);
154             assertThat(filtered).isEmpty();
155         }
156
157         {
158             TopicListener.DataFromTopic data =
159                     new TopicListener.DataFromTopic("typeId", null, null, loadReport().getBytes());
160
161             PmReportFilter.FilterData utranCellFilter = new PmReportFilter.FilterData();
162             utranCellFilter.addMeasTypes("UtranCell");
163             FilteredData filtered = new PmReportFilter(utranCellFilter).filter(data);
164             assertThat(filtered.getValueAString()).contains("UtranCell").doesNotContain("ENodeBFunction");
165
166             PmReportFilter.FilterData eNodeBFilter = new PmReportFilter.FilterData();
167             eNodeBFilter.addMeasTypes("ENodeBFunction");
168             filtered = new PmReportFilter(eNodeBFilter).filter(data);
169             assertThat(filtered.getValueAString()).contains("ENodeBFunction").doesNotContain("UtranCell");
170         }
171     }
172
173     @Test
174     void testSourceNames() throws Exception {
175         PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
176         filterData.sourceNames.add("junk");
177         PmReportFilter filter = new PmReportFilter(filterData);
178         String filtered = filterReport(filter);
179         assertThat(filtered).isEmpty();
180
181         filterData = new PmReportFilter.FilterData();
182         filterData.sourceNames.add("O-DU-1122");
183         filter = new PmReportFilter(filterData);
184         filtered = filterReport(filter);
185         assertThat(filtered).contains("O-DU-1122");
186     }
187
188     // @Test
189     void testSomeCharacteristics() throws Exception {
190         String path = "./src/test/resources/A20000626.2315+0200-2330+0200_HTTPS-6-73.json";
191
192         String pmReportJson = Files.readString(Path.of(path), Charset.defaultCharset());
193
194         int TIMES = 100000;
195
196         {
197             path = "./src/test/resources/A20000626.2315+0200-2330+0200_HTTPS-6-73.json.gz";
198             byte[] pmReportZipped = Files.readAllBytes(Path.of(path));
199
200             Instant startTime = Instant.now();
201             for (int i = 0; i < TIMES; ++i) {
202                 TopicListener.unzip(pmReportZipped);
203             }
204
205             printDuration("Unzip", startTime, TIMES);
206         }
207         {
208
209             PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
210             filterData.addMeasTypes("NRCellCU", "pmCounterNumber0");
211             PmReportFilter filter = new PmReportFilter(filterData);
212             DataFromTopic topicData = new DataFromTopic("typeId", null, null, pmReportJson.getBytes());
213
214             Instant startTime = Instant.now();
215             for (int i = 0; i < TIMES; ++i) {
216                 filter.filter(topicData);
217             }
218             printDuration("PM Filter", startTime, TIMES);
219         }
220         {
221             Instant startTime = Instant.now();
222             for (int i = 0; i < TIMES; ++i) {
223                 gson.fromJson(pmReportJson, PmReport.class);
224             }
225             printDuration("Json parsing", startTime, TIMES);
226         }
227
228     }
229
230     void printDuration(String str, Instant startTime, int noOfIterations) {
231         final long durationMs = Instant.now().toEpochMilli() - startTime.toEpochMilli();
232         logger.info("*** Duration (ms) " + str + " :" + durationMs + ", objects/second: "
233                 + (noOfIterations * 1000) / durationMs);
234     }
235
236     @Test
237     void testMeasuredEntityDns() throws Exception {
238         PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
239         filterData.measuredEntityDns.add("junk");
240         PmReportFilter filter = new PmReportFilter(filterData);
241         String filtered = filterReport(filter);
242         assertThat(filtered).isEmpty();
243
244         filterData = new PmReportFilter.FilterData();
245         filterData.measuredEntityDns.add("ManagedElement=RNC-Gbg-1");
246         filter = new PmReportFilter(filterData);
247         filtered = filterReport(filter);
248         assertThat(filtered).contains("ManagedElement=RNC-Gbg-1");
249     }
250
251     @Test
252     void testCrapInput() {
253         PmReportFilter.FilterData filterData = new PmReportFilter.FilterData();
254         PmReportFilter filter = new PmReportFilter(filterData);
255
256         FilteredData filtered = filter.filter(new TopicListener.DataFromTopic("typeId", null, null, "junk".getBytes()));
257         assertThat(filtered.isEmpty()).isTrue();
258
259         filtered = filter
260                 .filter(new TopicListener.DataFromTopic("typeId", null, null, reQuote("{'msg': 'test'}").getBytes()));
261         assertThat(filtered.isEmpty()).isTrue();
262
263     }
264
265     private String reQuote(String str) {
266         return str.replaceAll("'", "\\\"");
267     }
268
269     @Test
270     void testParse() throws Exception {
271         com.google.gson.Gson gson = new com.google.gson.GsonBuilder().disableHtmlEscaping().create();
272         PmReport report = gson.fromJson(loadReport(), PmReport.class);
273
274         String dn = report.event.getPerf3gppFields().getMeasDataCollection().getMeasuredEntityDn();
275         String json = gson.toJson(report);
276         report = gson.fromJson(json, PmReport.class);
277
278         // '=' is escaped to unicode by gson. but converted back
279         assertThat(report.event.getPerf3gppFields().getMeasDataCollection().getMeasuredEntityDn()).isEqualTo(dn);
280     }
281
282     private String loadReport() throws Exception {
283         String path = "./src/test/resources/pm_report.json";
284         return Files.readString(Path.of(path), Charset.defaultCharset());
285     }
286
287 }