Fix sonar issues in dcaegen2-analytics-tca-gen2
[dcaegen2/analytics/tca-gen2.git] / dcae-analytics / dcae-analytics-test / src / main / java / org / onap / dcae / analytics / test / BaseAnalyticsTest.java
1 /*
2  * ================================================================================
3  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  * ============LICENSE_END=========================================================
17  *
18  */
19
20 package org.onap.dcae.analytics.test;
21
22 import static java.nio.file.Files.deleteIfExists;
23 import static java.nio.file.Files.exists;
24 import static org.assertj.core.api.Assertions.assertThat;
25
26 import com.fasterxml.jackson.core.JsonProcessingException;
27 import com.fasterxml.jackson.databind.ObjectMapper;
28
29 import java.io.BufferedReader;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.io.InputStreamReader;
35 import java.io.ObjectOutputStream;
36 import java.io.OutputStreamWriter;
37 import java.lang.invoke.MethodHandles;
38 import java.lang.reflect.Field;
39 import java.net.URL;
40 import java.net.URLClassLoader;
41 import java.net.URLConnection;
42 import java.net.URLStreamHandler;
43 import java.nio.charset.Charset;
44 import java.nio.file.Paths;
45 import java.security.AccessController;
46 import java.security.PrivilegedAction;
47 import java.util.Arrays;
48 import java.util.Collections;
49 import java.util.Map;
50 import java.util.Optional;
51 import java.util.function.Function;
52
53 import org.json.JSONException;
54 import org.skyscreamer.jsonassert.JSONAssert;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 /**
59  * Base common test class for all DCAE Analytics Test e.g. unit tests, integration test etc.
60  *
61  * @author Rajiv Singla
62  */
63 abstract class BaseAnalyticsTest {
64
65     protected static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
66
67     /**
68      * Asserts if expected Json String and actual Json String contain the same properties ignoring
69      * property order. Simple String assertion might fail as property order during serialization and deserialization
70      * is generally non-deterministic. Also proper error message are generated more missing or unexpected
71      * properties
72      *
73      * @param expectedJsonString expected Json String
74      * @param actualJsonString actual Json String
75      *
76      * @throws JSONException Json Exception
77      */
78     public static void assertJson(final String expectedJsonString, final String actualJsonString) throws JSONException {
79         JSONAssert.assertEquals(expectedJsonString, actualJsonString, true);
80     }
81
82     /**
83      * Converts given file location to String
84      *
85      * @param fileLocation location of the file which needs to be converted to String
86      *
87      * @return Contents of file as string
88      */
89     public static String fromStream(final String fileLocation) {
90         try (InputStream fileInputStream = asInputStream(fileLocation);
91              BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, Charset.forName
92                      ("UTF-8")))) {
93             final StringBuilder result = new StringBuilder();
94             final String newLine = System.getProperty("line.separator");
95             String line = reader.readLine();
96             while (line != null) {
97                 result.append(line).append(newLine);
98                 line = reader.readLine();
99             }
100             return result.toString();
101         } catch (IOException e) {
102             throw new RuntimeException("Unable to get contents for file Location: " + fileLocation, e);
103         }
104     }
105
106     /**
107      * Converts given file location to input stream
108      *
109      * @param fileLocation file location
110      *
111      * @return input stream of given file location
112      */
113     public static InputStream asInputStream(final String fileLocation) {
114         final InputStream fileInputStream =
115                 BaseAnalyticsTest.class.getClassLoader().getResourceAsStream(fileLocation);
116         assertThat(fileInputStream).as("Input File Location must be valid").isNotNull();
117         return fileInputStream;
118     }
119
120     /**
121      * Checks if object can be serialized properly
122      *
123      * @param object input object
124      * @param callingClass calling class
125      */
126     public static void testSerialization(final Object object, final Class<?> callingClass) {
127
128         final URL location = callingClass.getProtectionDomain().getCodeSource().getLocation();
129         final File serializedOutputFile =
130                 new File(location.getPath() + String.format("serialization/%s.ser", object.getClass().getSimpleName()));
131         try {
132             // Maybe file already exists try deleting it first
133             final boolean deleteIfExists = deleteIfExists(Paths.get(serializedOutputFile.getPath()));
134
135             if (deleteIfExists) {
136                 logger.warn("Previous serialization file was overwritten at location: {}",
137                         serializedOutputFile.getPath());
138             }
139
140             boolean mkdirs = true;
141             if (!Paths.get(serializedOutputFile.getParentFile().getPath()).toFile().exists()) {
142                 mkdirs = serializedOutputFile.getParentFile().mkdirs();
143             }
144             if (mkdirs) {
145                 try (FileOutputStream fileOutputStream = new FileOutputStream(serializedOutputFile);
146                      ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)) {
147                     objectOutputStream.writeObject(object);
148                     logger.debug("Successfully created serialization file at location: {}", serializedOutputFile
149                             .getPath());
150                 }
151             }
152
153         } catch (IOException ex) {
154             throw new IllegalStateException(
155                     String.format("Failed to create location to store serialization file: %s", serializedOutputFile));
156         }
157     }
158
159     /**
160      * Writes Text to Output file
161      *
162      * @param textFileLocation location of text file e.g. textfiles/fileName.json
163      * @param content file content
164      * @param callingClass calling class
165      *
166      * @throws IOException ioException
167      */
168     public static void writeToOutputTextFile(final String textFileLocation,
169                                              final String content, Class<?> callingClass) throws IOException {
170         final URL location = callingClass.getProtectionDomain().getCodeSource().getLocation();
171         final File fileLocation = new File(location.getPath() + textFileLocation);
172
173         // Maybe file already try deleting it first
174         final boolean deleteIfExists = deleteIfExists(Paths.get(fileLocation.getPath()));
175
176         if (deleteIfExists) {
177             logger.warn("Previous file will be overwritten at location: {}", fileLocation.getPath());
178         }
179
180         boolean mkdirs = true;
181         if (!exists(Paths.get(fileLocation.getParentFile().getPath()))) {
182             mkdirs = fileLocation.getParentFile().mkdirs();
183         }
184         if (mkdirs) {
185             try (
186                     FileOutputStream fileOutputStream = new FileOutputStream(fileLocation);
187                     OutputStreamWriter outputStream =
188                             new OutputStreamWriter(fileOutputStream, Charset.forName("UTF-8"))) {
189                 outputStream.write(content);
190                 logger.debug("Successfully created text file at location: {}", fileLocation.getPath());
191             }
192         } else {
193             throw new IllegalStateException(
194                     String.format("Failed to create location to store text file: %s", fileLocation));
195         }
196
197     }
198
199     /**
200      * For testing purposes only sometime we may want to access private fields of underlying
201      * object to confirm the values are setup correctly.
202      * This method uses java reflection to get the value to private object in the class
203      *
204      * @param object Actual object which has the private field you want to check
205      * @param fieldName Field name in the Actual Object you want to get the value of
206      * @param privateFieldClass Type of the private field
207      * @param <T> Class of Actual Object
208      * @param <U> Class of private field
209      *
210      * @return value of the private field
211      */
212     @SuppressWarnings("unchecked")
213     public static <T, U> U getPrivateFiledValue(final T object, final String fieldName,
214                                                 final Class<U> privateFieldClass) {
215
216         final Class<?> objectClass = object.getClass();
217         try {
218             final Field privateField = objectClass.getDeclaredField(fieldName);
219
220             // mark private field to be accessible for testing purposes
221             AccessController.doPrivileged((PrivilegedAction) () -> {
222                 privateField.setAccessible(true);
223                 return null;
224             });
225
226             return privateFieldClass.cast(privateField.get(object));
227
228         } catch (IllegalAccessException e) {
229             logger.error("Unable to access field: {}", fieldName);
230             throw new IllegalStateException(e);
231         } catch (NoSuchFieldException e) {
232             logger.error("Unable to locate field name: {} in class: {}", fieldName,
233                     objectClass.getSimpleName());
234             throw new IllegalStateException(e);
235         }
236
237     }
238
239     /**
240      * For testing purposes only sometime we may want to print classpath jars which are visible inside the class
241      *
242      * @param classLoader classloader of the calling class
243      */
244     public static void dumpClasspath(final ClassLoader classLoader) {
245
246         logger.info("Dumping ClassPath for classloader: {}", classLoader);
247
248         if (classLoader instanceof URLClassLoader) {
249
250             URLClassLoader ucl = (URLClassLoader) classLoader;
251             logger.info("\t ==========>>>" + Arrays.toString(ucl.getURLs()));
252
253         } else {
254             logger.info("\t(cannot display components as it is not a URLClassLoader)");
255         }
256
257         if (classLoader.getParent() != null) {
258             dumpClasspath(classLoader.getParent());
259         }
260     }
261
262     /**
263      * Deserialize given Json file location to given model class and returns it back without any validation check.
264      *
265      * @param jsonFileLocation Classpath location of the json file
266      * @param modelClass Model Class type
267      * @param <T> Json Model Type
268      * @param objectMapper Jackson Json Object Mapper
269      *
270      * @return Deserialized Model Object
271      */
272     public static <T> T deserializeJsonFileToModel(final String jsonFileLocation, final Class<T> modelClass,
273                                                    final ObjectMapper objectMapper) {
274         try( final InputStream jsonFileInputStream =
275                 BaseAnalyticsTest.class.getClassLoader().getResourceAsStream(jsonFileLocation)) {
276             assertThat(jsonFileInputStream).as("Input JSON File location must be valid").isNotNull();
277             return objectMapper.readValue(jsonFileInputStream, modelClass);
278         } catch (IOException ex) {
279             logger.error("Error while doing assert Json for fileLocation: {}, modelClass: {}, Exception {}",
280                     jsonFileLocation, modelClass, ex);
281             throw new RuntimeException(ex);
282         }
283     }
284
285     /**
286      * Serialize model to json string
287      *
288      * @param model model object
289      * @param objectMapper Jackson Json Object Mapper
290      *
291      * @return json
292      *
293      * @throws JsonProcessingException when fails to process object
294      */
295     public static String serializeModelToJson(final Object model, final ObjectMapper objectMapper) throws
296             JsonProcessingException {
297         return objectMapper.writeValueAsString(model);
298     }
299
300     /**
301      * Converts given model to json string and compare it with json present at given file location.
302      *
303      * @param model Model which needs to be compared
304      * @param expectedJsonFileLocation Location of file containing expected json string
305      * @param objectMapper Jackson Json Object Mapper
306      * @param <T> Json Model Type
307      *
308      * @return If assertion passes returns the input model
309      */
310     public static <T> T assertJsonSerialization(final T model, final String expectedJsonFileLocation,
311                                                 final ObjectMapper objectMapper) {
312         try {
313             final String actualModelString = serializeModelToJson(model, objectMapper);
314             final String expectedModelString = fromStream(expectedJsonFileLocation);
315             assertJson(expectedModelString, actualModelString);
316             return model;
317         } catch (IOException | JSONException ex) {
318             logger.error("Error while doing assert Json serialization Assertion: model: {}, "
319                     + "expected Json File Location: {}, Exception {}", model, expectedJsonFileLocation, ex);
320             throw new RuntimeException(ex);
321         }
322     }
323
324     /**
325      * Checks both serialization and deserialization.
326      * <p>
327      * First checks deserialization and then serialize the deserialized object back to json
328      * and check if matches the given json file location string
329      *
330      * @param jsonFileLocation Classpath location of the json file
331      * @param modelClass Class type
332      * @param <T> Json Model Type
333      * @param objectMapper Jackson Json Object Mapper
334      *
335      * @return If assertion passes, returns deserialized object
336      */
337
338     public static <T> T assertJsonConversions(final String jsonFileLocation, final Class<T> modelClass,
339                                               final ObjectMapper objectMapper) {
340         //first check deserialization
341         final T actualValue = deserializeJsonFileToModel(jsonFileLocation, modelClass, objectMapper);
342         //then check serialization
343         assertJsonSerialization(actualValue, jsonFileLocation, objectMapper);
344
345         return actualValue;
346     }
347
348
349     public static <T> T assertJsonConversions(final String jsonFileLocation,
350                                               final Function<String, Optional<T>> jsonConversionFunction,
351                                               final ObjectMapper objectMapper) {
352         final Optional<T> actualValueOptional = jsonConversionFunction.apply(fromStream(jsonFileLocation));
353         assertThat(actualValueOptional).isPresent();
354         if (actualValueOptional.isPresent()) {
355             assertJsonSerialization(actualValueOptional.get(), jsonFileLocation, objectMapper);
356             return actualValueOptional.get();
357         }
358         return null;
359     }
360
361
362     /**
363      * Creates a mock URL Stream Handler
364      *
365      * @param mockURLConnection mock URL Connection
366      *
367      * @return Mock URL Stream Handler
368      */
369     public static URLStreamHandler createMockURLStreamHandler(final URLConnection mockURLConnection) {
370         return new URLStreamHandler() {
371             @Override
372             protected URLConnection openConnection(final URL url)
373                     throws IOException {
374                 return mockURLConnection;
375             }
376         };
377     }
378
379     /**
380      * Sets up environment variables for testing purposes
381      *
382      * @param testEnvironmentVariables key value map containing test environment variables
383      *
384      * @throws ClassNotFoundException class not found exception
385      * @throws IllegalAccessException illegal access exception
386      * @throws NoSuchFieldException no such method exception
387      */
388     @SuppressWarnings("unchecked")
389     public static void setEnvironmentVariables(final Map<String, String> testEnvironmentVariables)
390             throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
391         try {
392             final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
393             final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
394
395             AccessController.doPrivileged((PrivilegedAction) () -> {
396                 theEnvironmentField.setAccessible(true);
397                 return null;
398             });
399
400             final Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
401             env.putAll(testEnvironmentVariables);
402             Field theCaseInsensitiveEnvironmentField =
403                     processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
404             AccessController.doPrivileged((PrivilegedAction) () -> {
405                 theCaseInsensitiveEnvironmentField.setAccessible(true);
406                 return null;
407             });
408             Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
409             cienv.putAll(testEnvironmentVariables);
410         } catch (NoSuchFieldException e) {
411             logger.error("NoSuchFieldException in setEnvironmentVariables", e);
412             Class[] classes = Collections.class.getDeclaredClasses();
413             Map<String, String> env = System.getenv();
414             for (Class cl : classes) {
415                 if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
416                     Field field = cl.getDeclaredField("m");
417                     AccessController.doPrivileged((PrivilegedAction) () -> {
418                         field.setAccessible(true);
419                         return null;
420                     });
421                     Object obj = field.get(env);
422                     Map<String, String> map = (Map<String, String>) obj;
423                     map.clear();
424                     map.putAll(testEnvironmentVariables);
425                 }
426             }
427         }
428     }
429
430     /**
431      * Contains Locations for various files used for testing purposes
432      */
433     public abstract static class TestFileLocation {
434
435         public static final String CEF_JSON_MESSAGE = "data/json/cef/cef_message.json";
436         public static final String CEF_UNESCAPED_MESSAGES = "data/json/cef/cef_unescaped_messages.txt";
437         public static final String CEF_JSON_MESSAGE_WITH_VIOLATION = "data/json/cef/cef_message_with_violation.json";
438         public static final String CEF_JSON_MESSAGE_WITH_INAPPLICABLE_EVENT_NAME =
439                 "data/json/cef/cef_meesage_with_inapplicable_event_name.json";
440         public static final String CEF_JSON_MESSAGE_WITH_ABATEMENT = "data/json/cef/cef_message_with_abatement.json";
441         public static final String CEF_JSON_MESSAGES = "data/json/cef/cef_messages.json";
442
443         public static final String TCA_POLICY_JSON = "data/json/policy/tca_policy.json";
444         public static final String TCA_APP_CONFIG_JSON = "data/json/config/tca_app_config.json";
445         public static final String TCA_ALERT_JSON = "data/json/facade/tca_alert.json";
446
447
448         public static final String CONFIG_SERVICE_BINDINGS_JSON =
449                 "data/json/configservice/config_service_bindings.json";
450
451
452         public static final String TEST_JSON_MESSAGE = "data/json/test/test_message.json";
453     }
454
455
456 }