c20dc2f37d9e74d59ba22904813aaeb4df897742
[dcaegen2/collectors/datafile.git] /
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2018 NOKIA Intellectual Property, 2018-2019 Nordix Foundation. All rights reserved.
4  * ===============================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
6  * in compliance with the License. You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software distributed under the License
11  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12  * or implied. See the License for the specific language governing permissions and limitations under
13  * the License.
14  * ============LICENSE_END========================================================================
15  */
16
17 package org.onap.dcaegen2.collectors.datafile.configuration;
18
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.assertj.core.api.Assertions.assertThatThrownBy;
21 import static org.junit.Assert.assertTrue;
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.Mockito.doReturn;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.spy;
26 import static org.mockito.Mockito.times;
27 import static org.mockito.Mockito.verify;
28 import static org.mockito.Mockito.when;
29
30 import ch.qos.logback.classic.spi.ILoggingEvent;
31 import ch.qos.logback.core.read.ListAppender;
32
33 import com.google.common.base.Charsets;
34 import com.google.common.io.Resources;
35 import com.google.gson.JsonElement;
36 import com.google.gson.JsonIOException;
37 import com.google.gson.JsonObject;
38 import com.google.gson.JsonParser;
39 import com.google.gson.JsonSyntaxException;
40
41 import java.io.ByteArrayInputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.InputStreamReader;
45 import java.net.URL;
46 import java.nio.charset.StandardCharsets;
47 import java.util.Map;
48 import java.util.Properties;
49
50 import org.junit.jupiter.api.Assertions;
51 import org.junit.jupiter.api.BeforeEach;
52 import org.junit.jupiter.api.Test;
53 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
54 import org.onap.dcaegen2.collectors.datafile.model.logging.MappedDiagnosticContext;
55 import org.onap.dcaegen2.collectors.datafile.utils.LoggingUtils;
56 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.CbsClient;
57 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties;
58 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.ImmutableEnvProperties;
59 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapConsumerConfiguration;
60 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapPublisherConfiguration;
61
62 import reactor.core.publisher.Flux;
63 import reactor.core.publisher.Mono;
64 import reactor.test.StepVerifier;
65
66 /**
67  * Tests the AppConfig.
68  *
69  * @author <a href="mailto:przemyslaw.wasala@nokia.com">Przemysław Wąsala</a> on 4/9/18
70  * @author <a href="mailto:henrik.b.andersson@est.tech">Henrik Andersson</a>
71  */
72 public class AppConfigTest {
73
74     public static final String CHANGE_IDENTIFIER = "PM_MEAS_FILES";
75
76     public static final ImmutableDmaapConsumerConfiguration CORRECT_DMAAP_CONSUMER_CONFIG = //
77         new ImmutableDmaapConsumerConfiguration.Builder() //
78             .endpointUrl(
79                 "http://dradmin:dradmin@localhost:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT/OpenDcae-c12/C12")
80             .timeoutMs(-1) //
81             .dmaapHostName("localhost") //
82             .dmaapUserName("dradmin") //
83             .dmaapUserPassword("dradmin") //
84             .dmaapTopicName("events/unauthenticated.VES_NOTIFICATION_OUTPUT") //
85             .dmaapPortNumber(2222) //
86             .dmaapContentType("application/json") //
87             .messageLimit(-1) //
88             .dmaapProtocol("http") //
89             .consumerId("C12") //
90             .consumerGroup("OpenDcae-c12") //
91             .trustStorePath("trustStorePath") //
92             .trustStorePasswordPath("trustStorePasswordPath") //
93             .keyStorePath("keyStorePath") //
94             .keyStorePasswordPath("keyStorePasswordPath") //
95             .enableDmaapCertAuth(true) //
96             .build();
97
98     public static final ConsumerConfiguration CORRECT_CONSUMER_CONFIG = ImmutableConsumerConfiguration.builder() //
99         .topicUrl(
100             "http://dradmin:dradmin@localhost:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT/OpenDcae-c12/C12")
101         .trustStorePath("trustStorePath") //
102         .trustStorePasswordPath("trustStorePasswordPath") //
103         .keyStorePath("keyStorePath") //
104         .keyStorePasswordPath("keyStorePasswordPath") //
105         .enableDmaapCertAuth(true) //
106         .build();
107
108     private static final PublisherConfiguration CORRECT_PUBLISHER_CONFIG = //
109         ImmutablePublisherConfiguration.builder() //
110             .publishUrl("https://localhost:3907/publish/1") //
111             .logUrl("https://localhost:3907/feedlog/1") //
112             .trustStorePath("trustStorePath") //
113             .trustStorePasswordPath("trustStorePasswordPath") //
114             .keyStorePath("keyStorePath") //
115             .keyStorePasswordPath("keyStorePasswordPath") //
116             .enableDmaapCertAuth(true) //
117             .changeIdentifier("PM_MEAS_FILES") //
118             .userName("CYE9fl40") //
119             .passWord("izBJD8nLjawq0HMG") //
120             .build();
121
122     private static final ImmutableFtpesConfig CORRECT_FTPES_CONFIGURATION = //
123         new ImmutableFtpesConfig.Builder() //
124             .keyCert("/config/dfc.jks") //
125             .keyPassword("secret") //
126             .trustedCa("config/ftp.jks") //
127             .trustedCaPassword("secret") //
128             .build();
129
130     private static final ImmutableDmaapPublisherConfiguration CORRECT_DMAAP_PUBLISHER_CONFIG = //
131         new ImmutableDmaapPublisherConfiguration.Builder() //
132             .endpointUrl("https://localhost:3907/publish/1") //
133             .dmaapTopicName("/publish/1") //
134             .dmaapUserPassword("izBJD8nLjawq0HMG") //
135             .dmaapPortNumber(3907) //
136             .dmaapProtocol("https") //
137             .dmaapContentType("application/octet-stream") //
138             .dmaapHostName("localhost") //
139             .dmaapUserName("CYE9fl40") //
140             .trustStorePath("trustStorePath") //
141             .trustStorePasswordPath("trustStorePasswordPath") //
142             .keyStorePath("keyStorePath") //
143             .keyStorePasswordPath("keyStorePasswordPath") //
144             .enableDmaapCertAuth(true) //
145             .build();
146
147     private static EnvProperties properties() {
148         return ImmutableEnvProperties.builder() //
149             .consulHost("host") //
150             .consulPort(123) //
151             .cbsName("cbsName") //
152             .appName("appName") //
153             .build();
154     }
155
156     private AppConfig appConfigUnderTest;
157     private final Map<String, String> context = MappedDiagnosticContext.initializeTraceContext();
158     CbsClient cbsClient = mock(CbsClient.class);
159
160     @BeforeEach
161     void setUp() {
162         appConfigUnderTest = spy(AppConfig.class);
163         appConfigUnderTest.systemEnvironment = new Properties();
164
165     }
166
167     @Test
168     public void whenTheConfigurationFits() throws IOException, DatafileTaskException {
169         // When
170         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
171         appConfigUnderTest.initialize();
172
173         // Then
174         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
175
176         ConsumerConfiguration consumerCfg = appConfigUnderTest.getDmaapConsumerConfiguration();
177         Assertions.assertNotNull(consumerCfg);
178         assertThat(consumerCfg.toDmaap()).isEqualToComparingFieldByField(CORRECT_DMAAP_CONSUMER_CONFIG);
179         assertThat(consumerCfg).isEqualToComparingFieldByField(CORRECT_CONSUMER_CONFIG);
180
181         PublisherConfiguration publisherCfg = appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER);
182         Assertions.assertNotNull(publisherCfg);
183         assertThat(publisherCfg).isEqualToComparingFieldByField(CORRECT_PUBLISHER_CONFIG);
184         assertThat(publisherCfg.toDmaap()).isEqualToComparingFieldByField(CORRECT_DMAAP_PUBLISHER_CONFIG);
185
186         FtpesConfig ftpesConfig = appConfigUnderTest.getFtpesConfiguration();
187         assertThat(ftpesConfig).isNotNull();
188         assertThat(ftpesConfig).isEqualToComparingFieldByField(CORRECT_FTPES_CONFIGURATION);
189     }
190
191     @Test
192     public void whenTheConfigurationFits_twoProducers() throws IOException, DatafileTaskException {
193         // When
194         doReturn(getCorrectJsonTwoProducers()).when(appConfigUnderTest).createInputStream(any());
195         appConfigUnderTest.loadConfigurationFromFile();
196
197         // Then
198         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
199         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
200         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER));
201         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("XX_FILES"));
202         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("YY_FILES"));
203
204         assertThat(appConfigUnderTest.getPublisherConfiguration("XX_FILES").publishUrl())
205             .isEqualTo("feed01::publish_url");
206         assertThat(appConfigUnderTest.getPublisherConfiguration("YY_FILES").publishUrl())
207             .isEqualTo("feed01::publish_url");
208     }
209
210     @Test
211     public void whenFileIsNotExist_ThrowException() throws DatafileTaskException {
212         // Given
213         appConfigUnderTest.setFilepath("/temp.json");
214
215         // When
216         appConfigUnderTest.loadConfigurationFromFile();
217
218         // Then
219         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
220         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
221             .hasMessageContaining("No PublishingConfiguration loaded, changeIdentifier: PM_MEAS_FILES");
222
223         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
224     }
225
226     @Test
227     public void whenFileIsExistsButJsonIsIncorrect() throws IOException, DatafileTaskException {
228
229         // When
230         doReturn(getIncorrectJson()).when(appConfigUnderTest).createInputStream(any());
231         appConfigUnderTest.loadConfigurationFromFile();
232
233         // Then
234         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
235         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
236         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
237             .hasMessageContaining(CHANGE_IDENTIFIER);
238         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
239     }
240
241     @Test
242     public void whenTheConfigurationFits_ButRootElementIsNotAJsonObject() throws IOException, DatafileTaskException {
243
244         // When
245         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
246         JsonElement jsonElement = mock(JsonElement.class);
247         when(jsonElement.isJsonObject()).thenReturn(false);
248         doReturn(jsonElement).when(appConfigUnderTest).getJsonElement(any(JsonParser.class), any(InputStream.class));
249         appConfigUnderTest.loadConfigurationFromFile();
250
251         // Then
252         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
253         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
254         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
255             .hasMessageContaining(CHANGE_IDENTIFIER);
256         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
257     }
258
259     @Test
260     public void whenPeriodicConfigRefreshNoEnvironmentVariables() {
261         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
262         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask(context);
263
264         StepVerifier //
265             .create(task) //
266             .expectSubscription() //
267             .verifyComplete(); //
268
269         assertTrue(logAppender.list.toString().contains("$CONSUL_HOST environment has not been defined"));
270     }
271
272     @Test
273     public void whenPeriodicConfigRefreshNoConsul() {    
274         EnvProperties props = properties();
275         doReturn(Mono.just(props)).when(appConfigUnderTest).getEnvironment(any(), any());
276
277         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(props);
278         Flux<JsonObject> err = Flux.error(new IOException());
279         doReturn(err).when(cbsClient).updates(any(), any(), any());
280
281         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
282         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask(context);
283
284         StepVerifier //
285             .create(task) //
286             .expectSubscription() //
287             .verifyComplete();
288
289         assertTrue(
290             logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException"));
291     }
292
293     @Test
294     public void whenPeriodicConfigRefreshSuccess() throws JsonIOException, JsonSyntaxException, IOException {
295         EnvProperties props = properties();
296         doReturn(Mono.just(props)).when(appConfigUnderTest).getEnvironment(any(), any());
297         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(props);
298
299         Flux<JsonObject> json = Flux.just(getJsonRootObject());
300         doReturn(json).when(cbsClient).updates(any(), any(), any());
301
302         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask(context);
303
304         StepVerifier //
305             .create(task) //
306             .expectSubscription() //
307             .expectNext(appConfigUnderTest) //
308             .verifyComplete();
309
310         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
311     }
312
313     @Test
314     public void whenPeriodicConfigRefreshSuccess2() throws JsonIOException, JsonSyntaxException, IOException {
315         EnvProperties props = properties();
316         doReturn(Mono.just(props)).when(appConfigUnderTest).getEnvironment(any(), any());
317
318         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(props);
319
320         Flux<JsonObject> json = Flux.just(getJsonRootObject());
321         Flux<JsonObject> err = Flux.error(new IOException()); // no config entry created by the
322         // dmaap plugin
323
324         doReturn(json, err).when(cbsClient).updates(any(), any(), any());
325
326         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask(context);
327
328         StepVerifier //
329             .create(task) //
330             .expectSubscription() //
331             .expectNext(appConfigUnderTest) //
332             .verifyComplete();
333
334         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
335     }
336
337     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
338         JsonObject rootObject = (new JsonParser()).parse(new InputStreamReader(getCorrectJson())).getAsJsonObject();
339         return rootObject;
340     }
341
342     private static InputStream getCorrectJson() throws IOException {
343         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test.json");
344         String string = Resources.toString(url, Charsets.UTF_8);
345         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
346     }
347
348     private static InputStream getCorrectJsonTwoProducers() throws IOException {
349         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test_2producers.json");
350         String string = Resources.toString(url, Charsets.UTF_8);
351         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
352     }
353
354     private static InputStream getIncorrectJson() {
355         String string = "{" + //
356             "    \"configs\": {" + //
357             "        \"dmaap\": {"; //
358         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
359     }
360 }