b3710fe30b9ab930c97c65dcf6b331436cba1a33
[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.http.configuration.EnvProperties;
57 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.http.configuration.ImmutableEnvProperties;
58 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.providers.CloudConfigurationProvider;
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 class AppConfigTest {
73
74     private static final String CHANGE_IDENTIFIER = "PM_MEAS_FILES";
75
76     private static final ImmutableDmaapConsumerConfiguration CORRECT_DMAAP_CONSUMER_CONFIG = //
77         new ImmutableDmaapConsumerConfiguration.Builder() //
78             .timeoutMs(-1) //
79             .dmaapHostName("message-router.onap.svc.cluster.local") //
80             .dmaapUserName("admin") //
81             .dmaapUserPassword("admin") //
82             .dmaapTopicName("events/unauthenticated.VES_NOTIFICATION_OUTPUT") //
83             .dmaapPortNumber(2222) //
84             .dmaapContentType("application/json") //
85             .messageLimit(-1) //
86             .dmaapProtocol("http") //
87             .consumerId("C12") //
88             .consumerGroup("OpenDcae-c12") //
89             .trustStorePath("trustStorePath") //
90             .trustStorePasswordPath("trustStorePasswordPath") //
91             .keyStorePath("keyStorePath") //
92             .keyStorePasswordPath("keyStorePasswordPath") //
93             .enableDmaapCertAuth(true) //
94             .build();
95
96     private static final ConsumerConfiguration CORRECT_CONSUMER_CONFIG = ImmutableConsumerConfiguration.builder() //
97         .topicUrl(
98             "http://admin:admin@message-router.onap.svc.cluster.local:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT/OpenDcae-c12/C12")
99         .trustStorePath("trustStorePath") //
100         .trustStorePasswordPath("trustStorePasswordPath") //
101         .keyStorePath("keyStorePath") //
102         .keyStorePasswordPath("keyStorePasswordPath") //
103         .enableDmaapCertAuth(true) //
104         .build();
105
106     private static final PublisherConfiguration CORRECT_PUBLISHER_CONFIG = //
107         ImmutablePublisherConfiguration.builder() //
108             .publishUrl("https://message-router.onap.svc.cluster.local:3907/publish/1") //
109             .logUrl("https://dmaap.example.com/feedlog/972").trustStorePath("trustStorePath") //
110             .trustStorePasswordPath("trustStorePasswordPath") //
111             .keyStorePath("keyStorePath") //
112             .keyStorePasswordPath("keyStorePasswordPath") //
113             .enableDmaapCertAuth(true) //
114             .changeIdentifier("PM_MEAS_FILES") //
115             .userName("user") //
116             .passWord("password") //
117             .build();
118
119     private static final ImmutableFtpesConfig CORRECT_FTPES_CONFIGURATION = //
120         new ImmutableFtpesConfig.Builder() //
121             .keyCert("/config/dfc.jks") //
122             .keyPassword("secret") //
123             .trustedCa("config/ftp.jks") //
124             .trustedCaPassword("secret") //
125             .build();
126
127     private static final ImmutableDmaapPublisherConfiguration CORRECT_DMAAP_PUBLISHER_CONFIG = //
128         new ImmutableDmaapPublisherConfiguration.Builder() //
129             .dmaapTopicName("/publish/1") //
130             .dmaapUserPassword("password") //
131             .dmaapPortNumber(3907) //
132             .dmaapProtocol("https") //
133             .dmaapContentType("application/octet-stream") //
134             .dmaapHostName("message-router.onap.svc.cluster.local") //
135             .dmaapUserName("user") //
136             .trustStorePath("trustStorePath") //
137             .trustStorePasswordPath("trustStorePasswordPath") //
138             .keyStorePath("keyStorePath") //
139             .keyStorePasswordPath("keyStorePasswordPath") //
140             .enableDmaapCertAuth(true) //
141             .build();
142
143     private static EnvProperties properties() {
144         return ImmutableEnvProperties.builder() //
145             .consulHost("host") //
146             .consulPort(123) //
147             .cbsName("cbsName") //
148             .appName("appName") //
149             .build();
150     }
151
152     private AppConfig appConfigUnderTest;
153     private CloudConfigurationProvider cloudConfigurationProvider = mock(CloudConfigurationProvider.class);
154     private final Map<String, String> context = MappedDiagnosticContext.initializeTraceContext();
155
156     @BeforeEach
157     public void setUp() {
158         appConfigUnderTest = spy(AppConfig.class);
159         appConfigUnderTest.setCloudConfigurationProvider(cloudConfigurationProvider);
160         appConfigUnderTest.systemEnvironment = new Properties();
161     }
162
163     @Test
164     public void whenTheConfigurationFits() throws IOException, DatafileTaskException {
165         // When
166         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
167         appConfigUnderTest.initialize();
168
169         // Then
170         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
171
172         ConsumerConfiguration consumerCfg = appConfigUnderTest.getDmaapConsumerConfiguration();
173         Assertions.assertNotNull(consumerCfg);
174         assertThat(consumerCfg.toDmaap()).isEqualToComparingFieldByField(CORRECT_DMAAP_CONSUMER_CONFIG);
175         assertThat(consumerCfg).isEqualToComparingFieldByField(CORRECT_CONSUMER_CONFIG);
176
177         PublisherConfiguration publisherCfg = appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER);
178         Assertions.assertNotNull(publisherCfg);
179         assertThat(publisherCfg).isEqualToComparingFieldByField(CORRECT_PUBLISHER_CONFIG);
180         assertThat(publisherCfg.toDmaap()).isEqualToComparingFieldByField(CORRECT_DMAAP_PUBLISHER_CONFIG);
181
182         FtpesConfig ftpesConfig = appConfigUnderTest.getFtpesConfiguration();
183         assertThat(ftpesConfig).isNotNull();
184         assertThat(ftpesConfig).isEqualToComparingFieldByField(CORRECT_FTPES_CONFIGURATION);
185     }
186
187     @Test
188     public void whenTheConfigurationFits_twoProducers() throws IOException, DatafileTaskException {
189         // When
190         doReturn(getCorrectJsonTwoProducers()).when(appConfigUnderTest).createInputStream(any());
191         appConfigUnderTest.loadConfigurationFromFile();
192
193         // Then
194         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
195         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
196         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER));
197         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("XX_FILES"));
198         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("YY_FILES"));
199
200         assertThat(appConfigUnderTest.getPublisherConfiguration("XX_FILES").publishUrl())
201             .isEqualTo("feed01::publish_url");
202         assertThat(appConfigUnderTest.getPublisherConfiguration("YY_FILES").publishUrl())
203             .isEqualTo("feed01::publish_url");
204     }
205
206     @Test
207     public void whenFileIsNotExist_ThrowException() throws DatafileTaskException {
208         // Given
209         appConfigUnderTest.setFilepath("/temp.json");
210
211         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
212
213         // When
214         appConfigUnderTest.loadConfigurationFromFile();
215
216         // Then
217         assertTrue("Error message missing in log.",
218             logAppender.list.toString().contains("[WARN] Local configuration file not loaded: /temp.json"));
219         logAppender.stop();
220
221         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
222         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
223             .hasMessageContaining("No PublishingConfiguration loaded, changeIdentifier: PM_MEAS_FILES");
224         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
225     }
226
227     @Test
228     public void whenFileIsExistsButJsonIsIncorrect() throws IOException, DatafileTaskException {
229
230         // When
231         doReturn(getIncorrectJson()).when(appConfigUnderTest).createInputStream(any());
232         appConfigUnderTest.loadConfigurationFromFile();
233
234         // Then
235         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
236         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
237         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
238             .hasMessageContaining(CHANGE_IDENTIFIER);
239         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
240     }
241
242     @Test
243     public void whenTheConfigurationFits_ButRootElementIsNotAJsonObject() throws IOException, DatafileTaskException {
244
245         // When
246         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
247         JsonElement jsonElement = mock(JsonElement.class);
248         when(jsonElement.isJsonObject()).thenReturn(false);
249         doReturn(jsonElement).when(appConfigUnderTest).getJsonElement(any(JsonParser.class), any(InputStream.class));
250         appConfigUnderTest.loadConfigurationFromFile();
251
252         // Then
253         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
254         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
255         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
256             .hasMessageContaining(CHANGE_IDENTIFIER);
257         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
258     }
259
260     @Test
261     public void whenPeriodicConfigRefreshNoEnvironmentVariables() {
262         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
263
264         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
265
266         StepVerifier //
267             .create(task) //
268             .expectSubscription() //
269             .expectNextCount(0) //
270             .verifyComplete();
271
272         assertTrue(logAppender.list.toString().contains("$CONSUL_HOST environment has not been defined"));
273     }
274
275     @Test
276     public void whenPeriodicConfigRefreshNoConsul() {
277
278         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
279         Mono<JsonObject> err = Mono.error(new IOException());
280         doReturn(err).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
281
282         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
283         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
284
285         StepVerifier //
286             .create(task) //
287             .expectSubscription() //
288             .expectNextCount(0) //
289             .verifyComplete();
290
291         assertTrue(
292             logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException"));
293     }
294
295     @Test
296     public void whenPeriodicConfigRefreshSuccess() throws JsonIOException, JsonSyntaxException, IOException {
297         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
298
299         Mono<JsonObject> json = Mono.just(getJsonRootObject());
300
301         doReturn(json, json).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
302
303         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
304
305         StepVerifier //
306             .create(task) //
307             .expectSubscription() //
308             .expectNext(appConfigUnderTest) //
309             .verifyComplete();
310
311         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
312     }
313
314     @Test
315     public void whenPeriodicConfigRefreshSuccess2() throws JsonIOException, JsonSyntaxException, IOException {
316         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
317
318         Mono<JsonObject> json = Mono.just(getJsonRootObject());
319         Mono<JsonObject> err = Mono.error(new IOException()); // no config entry created by the dmaap plugin
320
321         doReturn(json, err).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
322
323         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
324
325         StepVerifier //
326             .create(task) //
327             .expectSubscription() //
328             .expectNext(appConfigUnderTest) //
329             .verifyComplete();
330
331         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
332     }
333
334     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
335         JsonObject rootObject = (new JsonParser()).parse(new InputStreamReader(getCorrectJson())).getAsJsonObject();
336         return rootObject;
337     }
338
339     private static InputStream getCorrectJson() throws IOException {
340         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test.json");
341         String string = Resources.toString(url, Charsets.UTF_8);
342         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
343     }
344
345     private static InputStream getCorrectJsonTwoProducers() throws IOException {
346         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test_2producers.json");
347         String string = Resources.toString(url, Charsets.UTF_8);
348         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
349     }
350
351     private static InputStream getIncorrectJson() {
352         String string = "{" + //
353             "    \"configs\": {" + //
354             "        \"dmaap\": {"; //
355         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
356     }
357 }