Standalone TCA with EELF Logger
[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             try {
220
221                 // mark private field to be accessible for testing purposes
222                 AccessController.doPrivileged((PrivilegedAction) () -> {
223                     privateField.setAccessible(true);
224                     return null;
225                 });
226
227                 return privateFieldClass.cast(privateField.get(object));
228
229             } catch (IllegalAccessException e) {
230                 logger.error("Unable to access field: {}", fieldName);
231                 throw new IllegalStateException(e);
232             }
233         } catch (NoSuchFieldException e) {
234             logger.error("Unable to locate field name: {} in class: {}", fieldName, objectClass.getSimpleName());
235             throw new IllegalStateException(e);
236         }
237
238     }
239
240     /**
241      * For testing purposes only sometime we may want to print classpath jars which are visible inside the class
242      *
243      * @param classLoader classloader of the calling class
244      */
245     public static void dumpClasspath(final ClassLoader classLoader) {
246
247         logger.info("Dumping ClassPath for classloader: {}", classLoader);
248
249         if (classLoader instanceof URLClassLoader) {
250
251             URLClassLoader ucl = (URLClassLoader) classLoader;
252             logger.info("\t ==========>>>" + Arrays.toString(ucl.getURLs()));
253
254         } else {
255             logger.info("\t(cannot display components as it is not a URLClassLoader)");
256         }
257
258         if (classLoader.getParent() != null) {
259             dumpClasspath(classLoader.getParent());
260         }
261     }
262
263     /**
264      * Deserialize given Json file location to given model class and returns it back without any validation check.
265      *
266      * @param jsonFileLocation Classpath location of the json file
267      * @param modelClass Model Class type
268      * @param <T> Json Model Type
269      * @param objectMapper Jackson Json Object Mapper
270      *
271      * @return Deserialized Model Object
272      */
273     public static <T> T deserializeJsonFileToModel(final String jsonFileLocation, final Class<T> modelClass,
274                                                    final ObjectMapper objectMapper) {
275         final InputStream jsonFileInputStream =
276                 BaseAnalyticsTest.class.getClassLoader().getResourceAsStream(jsonFileLocation);
277         assertThat(jsonFileInputStream).as("Input JSON File location must be valid").isNotNull();
278         try {
279             return objectMapper.readValue(jsonFileInputStream, modelClass);
280         } catch (IOException ex) {
281             logger.error("Error while doing assert Json for fileLocation: {}, modelClass: {}, Exception {}",
282                     jsonFileLocation, modelClass, ex);
283             throw new RuntimeException(ex);
284         } finally {
285             try {
286                 jsonFileInputStream.close();
287             } catch (IOException e) {
288                 logger.error("Error while closing input stream at file location: {}", jsonFileLocation);
289                 throw new RuntimeException(e);
290             }
291         }
292     }
293
294     /**
295      * Serialize model to json string
296      *
297      * @param model model object
298      * @param objectMapper Jackson Json Object Mapper
299      *
300      * @return json
301      *
302      * @throws JsonProcessingException when fails to process object
303      */
304     public static String serializeModelToJson(final Object model, final ObjectMapper objectMapper) throws
305             JsonProcessingException {
306         return objectMapper.writeValueAsString(model);
307     }
308
309     /**
310      * Converts given model to json string and compare it with json present at given file location.
311      *
312      * @param model Model which needs to be compared
313      * @param expectedJsonFileLocation Location of file containing expected json string
314      * @param objectMapper Jackson Json Object Mapper
315      * @param <T> Json Model Type
316      *
317      * @return If assertion passes returns the input model
318      */
319     public static <T> T assertJsonSerialization(final T model, final String expectedJsonFileLocation,
320                                                 final ObjectMapper objectMapper) {
321         try {
322             final String actualModelString = serializeModelToJson(model, objectMapper);
323             final String expectedModelString = fromStream(expectedJsonFileLocation);
324             assertJson(expectedModelString, actualModelString);
325             return model;
326         } catch (IOException | JSONException ex) {
327             logger.error("Error while doing assert Json serialization Assertion: model: {}, "
328                     + "expected Json File Location: {}, Exception {}", model, expectedJsonFileLocation, ex);
329             throw new RuntimeException(ex);
330         }
331     }
332
333     /**
334      * Checks both serialization and deserialization.
335      * <p>
336      * First checks deserialization and then serialize the deserialized object back to json
337      * and check if matches the given json file location string
338      *
339      * @param jsonFileLocation Classpath location of the json file
340      * @param modelClass Class type
341      * @param <T> Json Model Type
342      * @param objectMapper Jackson Json Object Mapper
343      *
344      * @return If assertion passes, returns deserialized object
345      */
346
347     public static <T> T assertJsonConversions(final String jsonFileLocation, final Class<T> modelClass,
348                                               final ObjectMapper objectMapper) {
349         //first check deserialization
350         final T actualValue = deserializeJsonFileToModel(jsonFileLocation, modelClass, objectMapper);
351         //then check serialization
352         assertJsonSerialization(actualValue, jsonFileLocation, objectMapper);
353
354         return actualValue;
355     }
356
357
358     public static <T> T assertJsonConversions(final String jsonFileLocation,
359                                               final Function<String, Optional<T>> jsonConversionFunction,
360                                               final ObjectMapper objectMapper) {
361         final Optional<T> actualValueOptional = jsonConversionFunction.apply(fromStream(jsonFileLocation));
362         assertThat(actualValueOptional).isPresent();
363         if (actualValueOptional.isPresent()) {
364             assertJsonSerialization(actualValueOptional.get(), jsonFileLocation, objectMapper);
365             return actualValueOptional.get();
366         }
367         return null;
368     }
369
370
371     /**
372      * Creates a mock URL Stream Handler
373      *
374      * @param mockURLConnection mock URL Connection
375      *
376      * @return Mock URL Stream Handler
377      */
378     public static URLStreamHandler createMockURLStreamHandler(final URLConnection mockURLConnection) {
379         return new URLStreamHandler() {
380             @Override
381             protected URLConnection openConnection(final URL url)
382                     throws IOException {
383                 return mockURLConnection;
384             }
385         };
386     }
387
388     /**
389      * Sets up environment variables for testing purposes
390      *
391      * @param testEnvironmentVariables key value map containing test environment variables
392      *
393      * @throws ClassNotFoundException class not found exception
394      * @throws IllegalAccessException illegal access exception
395      * @throws NoSuchFieldException no such method exception
396      */
397     @SuppressWarnings("unchecked")
398     protected static void setEnvironmentVariables(final Map<String, String> testEnvironmentVariables)
399             throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException {
400         try {
401             final Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
402             final Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
403
404             AccessController.doPrivileged((PrivilegedAction) () -> {
405                 theEnvironmentField.setAccessible(true);
406                 return null;
407             });
408
409             final Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
410             env.putAll(testEnvironmentVariables);
411             Field theCaseInsensitiveEnvironmentField =
412                     processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
413             AccessController.doPrivileged((PrivilegedAction) () -> {
414                 theCaseInsensitiveEnvironmentField.setAccessible(true);
415                 return null;
416             });
417             Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
418             cienv.putAll(testEnvironmentVariables);
419         } catch (NoSuchFieldException e) {
420             Class[] classes = Collections.class.getDeclaredClasses();
421             Map<String, String> env = System.getenv();
422             for (Class cl : classes) {
423                 if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
424                     Field field = cl.getDeclaredField("m");
425                     AccessController.doPrivileged((PrivilegedAction) () -> {
426                         field.setAccessible(true);
427                         return null;
428                     });
429                     Object obj = field.get(env);
430                     Map<String, String> map = (Map<String, String>) obj;
431                     map.clear();
432                     map.putAll(testEnvironmentVariables);
433                 }
434             }
435         }
436     }
437
438     /**
439      * Contains Locations for various files used for testing purposes
440      */
441     public abstract static class TestFileLocation {
442
443         public static final String CEF_JSON_MESSAGE = "data/json/cef/cef_message.json";
444         public static final String CEF_UNESCAPED_MESSAGES = "data/json/cef/cef_unescaped_messages.txt";
445         public static final String CEF_JSON_MESSAGE_WITH_VIOLATION = "data/json/cef/cef_message_with_violation.json";
446         public static final String CEF_JSON_MESSAGE_WITH_INAPPLICABLE_EVENT_NAME =
447                 "data/json/cef/cef_meesage_with_inapplicable_event_name.json";
448         public static final String CEF_JSON_MESSAGE_WITH_ABATEMENT = "data/json/cef/cef_message_with_abatement.json";
449         public static final String CEF_JSON_MESSAGES = "data/json/cef/cef_messages.json";
450
451         public static final String TCA_POLICY_JSON = "data/json/policy/tca_policy.json";
452         public static final String TCA_APP_CONFIG_JSON = "data/json/config/tca_app_config.json";
453         public static final String TCA_ALERT_JSON = "data/json/facade/tca_alert.json";
454
455
456         public static final String CONFIG_SERVICE_BINDINGS_JSON =
457                 "data/json/configservice/config_service_bindings.json";
458
459
460         public static final String TEST_JSON_MESSAGE = "data/json/test/test_message.json";
461     }
462
463
464 }