Removing deprecated DMAAP library
[policy/drools-pdp.git] / policy-utils / src / test / java / org / onap / policy / drools / utils / PropertyUtilTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2021 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.utils;
23
24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 import static org.junit.jupiter.api.Assertions.assertTrue;
26
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.io.IOException;
30 import java.util.Arrays;
31 import java.util.Objects;
32 import java.util.Properties;
33 import java.util.Set;
34 import java.util.TreeSet;
35 import java.util.UUID;
36 import org.apache.commons.lang3.StringUtils;
37 import org.junit.jupiter.api.AfterAll;
38 import org.junit.jupiter.api.BeforeAll;
39 import org.junit.jupiter.api.Test;
40 import org.onap.policy.common.utils.logging.LoggerUtils;
41 import org.onap.policy.common.utils.security.CryptoUtils;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 public class PropertyUtilTest {
46     /*
47      * Note: to generate the encrypted values, invoke CryptoUtils passing both the value
48      * to be encrypted and the crypto key.
49      *
50      * The INTERPOLATION_CRYPTO_KEY is a 16 or 32 character string, base-64 encoded.
51      *
52      * For "INTERPOLATION_ENC_HELLOWORLD", the encrypted value was generated via:
53      *  java org.onap.policy.common.utils.security.CryptoUtils enc HelloWorld MTIzNDU2Nzg5MDEyMzQ1Ng==
54      *
55      * The generated value should also be placed into the following properties within
56      * the file, interpolation.properties:
57      *  interpolation.enc
58      *  interpolation.enc2
59      *  interpolation.envenc
60      */
61
62     private static final String INTERPOLATION_PROPERTIES = "src/test/resources/interpolation.properties";
63     private static final String INTERPOLATION_CRYPTO_KEY = "MTIzNDU2Nzg5MDEyMzQ1Ng==";
64     private static final String INTERPOLATION_PLAINTEXT = "HelloWorld";
65     private static final String INTERPOLATION_ENVD_DEFAULT_VALUE = "default";
66     private static final String INTERPOLATION_ENC_HELLOWORLD =
67                     "enc:MjGhDZTTIx1ihB7KvxLnOJcvb0WN/CSgpw7sY1hDnvL1VHa8wGRzOX3X";
68     private static final String INTERPOLATION_ENC_HELLOWORLD_VAR = "${" + INTERPOLATION_ENC_HELLOWORLD + "}";
69
70     private static final String INTERPOLATION_NO = "interpolation.no";
71     private static final String INTERPOLATION_ENV = "interpolation.env";
72     private static final String INTERPOLATION_ENVD = "interpolation.envd";
73     private static final String INTERPOLATION_CONST = "interpolation.const";
74     private static final String INTERPOLATION_SYS = "interpolation.sys";
75     private static final String INTERPOLATION_ENVD_NONE = "interpolation.envd.none";
76     private static final String INTERPOLATION_ENVD_DEFAULT = "interpolation.envd.default";
77     private static final String INTERPOLATION_ENVD_NO_DEFAULT = "interpolation.envd.nodefault";
78     private static final String INTERPOLATION_ENC = "interpolation.enc";
79     private static final String INTERPOLATION_ENC2 = "interpolation.enc2";
80     private static final String INTERPOLATION_ENVENC = "interpolation.envenc";
81
82
83     private static final Logger logger = LoggerFactory.getLogger(PropertyUtilTest.class);
84
85     private static File directory = null;
86
87     /**
88      * Test Setup -- Create a directory for temporary files.
89      */
90     @BeforeAll
91     public static void setup() {
92         logger.info("setup: creating a temporary directory");
93
94         // create a directory for temporary files
95         directory = new File(UUID.randomUUID().toString());
96         directory.mkdir();
97     }
98
99     /**
100      * Test Cleanup -- Remove temporary files.
101      */
102     @AfterAll
103     public static void teardown() {
104         logger.info("teardown: remove the temporary directory");
105
106         // the assumption is that we only have one level of temporary files
107         for (File file : Objects.requireNonNull(directory.listFiles())) {
108             assertTrue(file.delete());
109         }
110         assertTrue(directory.delete());
111     }
112
113     /**
114      * Utility method to write a properties file.
115      *
116      * @param name the file name, relative to the temporary directory
117      * @param properties to store in the file
118      * @return a File instance associated with the newly-created file
119      * @throws IOException if the file can't be created for some reason
120      */
121     File createFile(String name, Properties properties) throws IOException {
122         File file = new File(directory, name);
123         try (FileOutputStream fos = new FileOutputStream(file)) {
124             properties.store(fos, "Property file '" + name + "'");
125         }
126         return (file);
127     }
128
129     /**
130      * Create a 'PropertyUtil.Listener' subclass, which receives property
131      * file updates. It stores the latest values in an array, and notifies
132      * any thread waiting on this array.
133      *
134      * @param returns this is an array of length 2 -- the first entry will
135      *     contain the 'properties' value, and the second will contain
136      *     'changedKeys'. It is also used to signal any waiting thread
137      *     using 'returns.notifyAll()'.
138      */
139     PropertyUtil.Listener createListenerThread(final Object[] returns) {
140         return (new PropertyUtil.Listener() {
141             public void propertiesChanged(Properties properties, Set<String> changedKeys) {
142                 // When a notification is received, store the values in the
143                 // 'returns' array, and signal using the same array.
144                 logger.info("Listener invoked: properties=" + properties
145                         + ", changedKeys=" + changedKeys);
146                 returns[0] = properties;
147                 returns[1] = changedKeys;
148                 synchronized (returns) {
149                     returns.notifyAll();
150                 }
151             }
152         });
153     }
154
155     /**
156      * Test the basic properties file interface.
157      */
158     @Test
159     void testGetProperties() throws Exception {
160         logger.info("testGetProperties: test the basic properties file interface");
161
162         // copy system properties
163         logger.info("Copy system properties to a file");
164         Properties prop1 = System.getProperties();
165         File file1 = createFile("createAndReadPropertyFile-1", prop1);
166
167         // read in properties, and compare
168         logger.info("Read in properties from new file");
169         Properties prop2 = PropertyUtil.getProperties(file1);
170
171         // they should match
172         assertEquals(prop1, prop2);
173
174         // tests performed in sequence
175         testGetCryptoCoderArg();
176         testGetNoCryptoProps();
177         testGetDefaultCryptoProps();
178         testGetNoCryptoSystemProps();
179         testGetCryptoArgSystemProps();
180         testGetDefaultCryptoSystemProps();
181
182     }
183
184     private void testGetDefaultCryptoSystemProps() throws IOException {
185         // system properties + default crypto coder
186         PropertyUtil.setDefaultCryptoCoder(new CryptoUtils(INTERPOLATION_CRYPTO_KEY));
187         PropertyUtil.setSystemProperties(PropertyUtil.getPropertiesFile(new File(INTERPOLATION_PROPERTIES)));
188         assertPropInterpolation(System.getProperties());
189         assertPropEncInterpolation(System.getProperties());
190     }
191
192     private void testGetCryptoArgSystemProps() throws IOException {
193         // system properties + crypto coder passed in
194         PropertyUtil
195             .setSystemProperties(PropertyUtil
196                 .getPropertiesFile(new File(INTERPOLATION_PROPERTIES)), new CryptoUtils(INTERPOLATION_CRYPTO_KEY));
197         assertPropInterpolation(System.getProperties());
198         assertPropEncInterpolation(System.getProperties());
199     }
200
201     private void testGetNoCryptoSystemProps() throws IOException {
202         /* system properties + no crypto coder */
203         PropertyUtil.setDefaultCryptoCoder(null);
204         PropertyUtil.setSystemProperties(PropertyUtil.getPropertiesFile(new File(INTERPOLATION_PROPERTIES)));
205         assertPropInterpolation(System.getProperties());
206         assertPropNoEncInterpolation(System.getProperties());
207     }
208
209     private void testGetDefaultCryptoProps() throws IOException {
210         /* properties + default crypto coder */
211         PropertyUtil.setDefaultCryptoCoder(new CryptoUtils(INTERPOLATION_CRYPTO_KEY));
212         Properties props = PropertyUtil.getProperties(INTERPOLATION_PROPERTIES);
213         assertPropInterpolation(props);
214         assertPropEncInterpolation(props);
215     }
216
217     private void testGetNoCryptoProps() throws IOException {
218         /* properties + no crypto coder */
219         Properties props = PropertyUtil.getProperties(INTERPOLATION_PROPERTIES);
220         assertPropInterpolation(props);
221         assertPropNoEncInterpolation(props);
222     }
223
224     private void testGetCryptoCoderArg() throws IOException {
225         /* properties + crypto coder passed in */
226         Properties props =
227             PropertyUtil.getProperties(INTERPOLATION_PROPERTIES, new CryptoUtils(INTERPOLATION_CRYPTO_KEY));
228         assertPropInterpolation(props);
229         assertPropEncInterpolation(props);
230     }
231
232     private void assertPropNoEncInterpolation(Properties props) {
233         assertEquals(INTERPOLATION_ENC_HELLOWORLD_VAR, props.getProperty(INTERPOLATION_ENC));
234         assertEquals(INTERPOLATION_ENC_HELLOWORLD, props.getProperty(INTERPOLATION_ENC2));
235         assertEquals(INTERPOLATION_ENC_HELLOWORLD, props.getProperty(INTERPOLATION_ENVENC));
236     }
237
238     private void assertPropEncInterpolation(Properties props) {
239         assertEquals(INTERPOLATION_PLAINTEXT, props.getProperty(INTERPOLATION_ENC));
240         assertEquals(INTERPOLATION_PLAINTEXT, props.getProperty(INTERPOLATION_ENC2));
241         assertEquals(INTERPOLATION_PLAINTEXT, props.getProperty(INTERPOLATION_ENVENC));
242     }
243
244     private void assertPropInterpolation(Properties props) {
245         assertEquals("no", props.getProperty(INTERPOLATION_NO));
246         assertEquals(System.getenv("HOME"), props.getProperty(INTERPOLATION_ENV));
247         assertEquals(System.getenv("HOME"), props.getProperty(INTERPOLATION_ENVD));
248         assertEquals(StringUtils.EMPTY, props.getProperty(INTERPOLATION_ENVD_NONE));
249         assertEquals(StringUtils.EMPTY, props.getProperty(INTERPOLATION_ENVD_NO_DEFAULT));
250         assertEquals(LoggerUtils.ROOT_LOGGER, props.getProperty(INTERPOLATION_CONST));
251         assertEquals(System.getProperty("user.home"), props.getProperty(INTERPOLATION_SYS));
252         assertEquals(INTERPOLATION_ENVD_DEFAULT_VALUE, props.getProperty(INTERPOLATION_ENVD_DEFAULT));
253     }
254
255     /**
256      * This tests the 'PropertyUtil.Listener' interface.
257      */
258     @Test
259     void testListenerInterface() throws Exception {
260         logger.info("testListenerInterface: test receipt of dynamic updates");
261
262         // create initial property file
263         Properties prop1 = new Properties();
264         prop1.setProperty("p1", "p1 value");
265         prop1.setProperty("p2", "p2 value");
266         prop1.setProperty("p3", "p3 value");
267         logger.info("Create initial properties file: " + prop1);
268         File file1 = createFile("createAndReadPropertyFile-2", prop1);
269
270         // create a listener for the notification interface
271         Object[] returns = new Object[2];
272         PropertyUtil.Listener listener = createListenerThread(returns);
273
274         // read it in, and do a comparison
275         Properties prop2 = PropertyUtil.getProperties(file1, listener);
276         logger.info("Read in properties: " + prop2);
277         assertEquals(prop1, prop2);
278         assertEquals("p1 value", prop2.getProperty("p1"));
279         assertEquals("p2 value", prop2.getProperty("p2"));
280         assertEquals("p3 value", prop2.getProperty("p3"));
281
282         // make some changes, and update the file (p3 is left unchanged)
283         prop2.remove("p1"); // remove one property
284         prop2.setProperty("p2", "new p2 value");    // change one property
285         prop2.setProperty("p4", "p4 value");        // add a new property
286         logger.info("Modified properties: " + prop2);
287
288         // now, update the file, and wait for notification
289         synchronized (returns) {
290             createFile("createAndReadPropertyFile-2", prop2);
291
292             // wait up to 60 seconds, although we should receive notification
293             // in 10 seconds or less (if things are working)
294             returns.wait(60000L);
295         }
296
297         // verify we have the updates
298         assertEquals(prop2, returns[0]);
299
300         // verify that we have the expected set of keys
301         assertEquals(new TreeSet<String>(Arrays.asList(new String[]{"p1", "p2", "p4"})),
302                 returns[1]);
303     }
304 }