d9ca7871f56451b9b8a7eb438c17359955c4b217
[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.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertThrows;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.Mockito.doReturn;
27 import static org.mockito.Mockito.mock;
28 import static org.mockito.Mockito.spy;
29 import static org.mockito.Mockito.times;
30 import static org.mockito.Mockito.verify;
31 import static org.mockito.Mockito.verifyNoMoreInteractions;
32 import static org.mockito.Mockito.when;
33
34 import ch.qos.logback.classic.spi.ILoggingEvent;
35 import ch.qos.logback.core.read.ListAppender;
36 import com.google.common.base.Charsets;
37 import com.google.common.io.Resources;
38 import com.google.gson.JsonElement;
39 import com.google.gson.JsonIOException;
40 import com.google.gson.JsonObject;
41 import com.google.gson.JsonParser;
42 import com.google.gson.JsonSyntaxException;
43 import java.io.ByteArrayInputStream;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.InputStreamReader;
47 import java.net.URL;
48 import java.nio.charset.StandardCharsets;
49 import java.util.HashMap;
50 import java.util.Map;
51 import java.util.Properties;
52 import org.junit.jupiter.api.Assertions;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
56 import org.onap.dcaegen2.collectors.datafile.model.logging.MappedDiagnosticContext;
57 import org.onap.dcaegen2.collectors.datafile.utils.LoggingUtils;
58 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.http.configuration.EnvProperties;
59 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.http.configuration.ImmutableEnvProperties;
60 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.providers.CloudConfigurationProvider;
61 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapConsumerConfiguration;
62 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.DmaapPublisherConfiguration;
63 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapConsumerConfiguration;
64 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.config.ImmutableDmaapPublisherConfiguration;
65 import reactor.core.Disposable;
66 import reactor.core.publisher.Flux;
67 import reactor.core.publisher.Mono;
68 import reactor.test.StepVerifier;
69
70 /**
71  * Tests the AppConfig.
72  *
73  * @author <a href="mailto:przemyslaw.wasala@nokia.com">Przemysław Wąsala</a> on 4/9/18
74  * @author <a href="mailto:henrik.b.andersson@est.tech">Henrik Andersson</a>
75  */
76 class AppConfigTest {
77
78     private static final String CHANGE_IDENTIFIER = "PM_MEAS_FILES";
79
80     private static final DmaapConsumerConfiguration CORRECT_DMAAP_CONSUMER_CONFIG = //
81         new ImmutableDmaapConsumerConfiguration.Builder() //
82             .timeoutMs(-1) //
83             .dmaapHostName("message-router.onap.svc.cluster.local") //
84             .dmaapUserName("admin") //
85             .dmaapUserPassword("admin") //
86             .dmaapTopicName("events/unauthenticated.VES_NOTIFICATION_OUTPUT") //
87             .dmaapPortNumber(2222) //
88             .dmaapContentType("application/json") //
89             .messageLimit(-1) //
90             .dmaapProtocol("http") //
91             .consumerId("C12") //
92             .consumerGroup("OpenDcae-c12") //
93             .trustStorePath("trustStorePath") //
94             .trustStorePasswordPath("trustStorePasswordPath") //
95             .keyStorePath("keyStorePath") //
96             .keyStorePasswordPath("keyStorePasswordPath") //
97             .enableDmaapCertAuth(true) //
98             .build();
99
100     private static final ConsumerConfiguration CORRECT_CONSUMER_CONFIG = ImmutableConsumerConfiguration.builder() //
101         .topicUrl(
102             "http://admin:admin@message-router.onap.svc.cluster.local:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT/OpenDcae-c12/C12")
103         .trustStorePath("trustStorePath") //
104         .trustStorePasswordPath("trustStorePasswordPath") //
105         .keyStorePath("keyStorePath") //
106         .keyStorePasswordPath("keyStorePasswordPath") //
107         .enableDmaapCertAuth(true) //
108         .build();
109
110     private static final PublisherConfiguration CORRECT_PUBLISHER_CONFIG = //
111         ImmutablePublisherConfiguration.builder() //
112             .publishUrl("https://message-router.onap.svc.cluster.local:3907/publish/1") //
113             .logUrl("https://dmaap.example.com/feedlog/972").trustStorePath("trustStorePath") //
114             .trustStorePasswordPath("trustStorePasswordPath") //
115             .keyStorePath("keyStorePath") //
116             .keyStorePasswordPath("keyStorePasswordPath") //
117             .enableDmaapCertAuth(true) //
118             .changeIdentifier("PM_MEAS_FILES") //
119             .userName("user") //
120             .passWord("password") //
121             .build();
122
123     private static final FtpesConfig CORRECT_FTPES_CONFIGURATION = //
124         new ImmutableFtpesConfig.Builder() //
125             .keyCert("/config/dfc.jks") //
126             .keyPassword("secret") //
127             .trustedCa("config/ftp.jks") //
128             .trustedCaPassword("secret") //
129             .build();
130
131     private static final DmaapPublisherConfiguration CORRECT_DMAAP_PUBLISHER_CONFIG = //
132         new ImmutableDmaapPublisherConfiguration.Builder() //
133             .dmaapTopicName("/publish/1") //
134             .dmaapUserPassword("password") //
135             .dmaapPortNumber(3907) //
136             .dmaapProtocol("https") //
137             .dmaapContentType("application/octet-stream") //
138             .dmaapHostName("message-router.onap.svc.cluster.local") //
139             .dmaapUserName("user") //
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 CloudConfigurationProvider cloudConfigurationProvider = mock(CloudConfigurationProvider.class);
158     private final Map<String, String> context = MappedDiagnosticContext.initializeTraceContext();
159
160     @BeforeEach
161     public void setUp() {
162         appConfigUnderTest = spy(AppConfig.class);
163         appConfigUnderTest.setCloudConfigurationProvider(cloudConfigurationProvider);
164         appConfigUnderTest.systemEnvironment = new Properties();
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         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
216
217         // When
218         appConfigUnderTest.loadConfigurationFromFile();
219
220         // Then
221         assertTrue("Error message missing in log.",
222             logAppender.list.toString().contains("[WARN] Local configuration file not loaded: /temp.json"));
223         logAppender.stop();
224
225         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
226         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
227             .hasMessageContaining("No PublishingConfiguration loaded, changeIdentifier: PM_MEAS_FILES");
228         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
229     }
230
231     @Test
232     public void whenFileIsExistsButJsonIsIncorrect() throws IOException, DatafileTaskException {
233
234         // When
235         doReturn(getIncorrectJson()).when(appConfigUnderTest).createInputStream(any());
236         appConfigUnderTest.loadConfigurationFromFile();
237
238         // Then
239         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
240         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
241         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
242             .hasMessageContaining(CHANGE_IDENTIFIER);
243         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
244     }
245
246     @Test
247     public void whenTheConfigurationFits_ButRootElementIsNotAJsonObject() throws IOException, DatafileTaskException {
248
249         // When
250         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
251         JsonElement jsonElement = mock(JsonElement.class);
252         when(jsonElement.isJsonObject()).thenReturn(false);
253         doReturn(jsonElement).when(appConfigUnderTest).getJsonElement(any(JsonParser.class), any(InputStream.class));
254         appConfigUnderTest.loadConfigurationFromFile();
255
256         // Then
257         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
258         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
259         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
260             .hasMessageContaining(CHANGE_IDENTIFIER);
261         Assertions.assertNull(appConfigUnderTest.getFtpesConfiguration());
262     }
263
264     @Test
265     public void whenPeriodicConfigRefreshNoEnvironmentVariables() {
266         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
267
268         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
269
270         StepVerifier //
271             .create(task) //
272             .expectSubscription() //
273             .expectNextCount(0) //
274             .verifyComplete();
275
276         assertTrue(logAppender.list.toString().contains("$CONSUL_HOST environment has not been defined"));
277     }
278
279     @Test
280     public void whenPeriodicConfigRefreshNoConsul() {
281
282         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
283         Mono<JsonObject> err = Mono.error(new IOException());
284         doReturn(err).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
285
286         ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
287         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
288
289         StepVerifier //
290             .create(task) //
291             .expectSubscription() //
292             .expectNextCount(0) //
293             .verifyComplete();
294
295         assertTrue(
296             logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException"));
297     }
298
299     @Test
300     public void whenPeriodicConfigRefreshSuccess() throws JsonIOException, JsonSyntaxException, IOException {
301         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
302
303         Mono<JsonObject> json = Mono.just(getJsonRootObject());
304
305         doReturn(json, json).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
306
307         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
308
309         StepVerifier //
310             .create(task) //
311             .expectSubscription() //
312             .expectNext(appConfigUnderTest) //
313             .verifyComplete();
314
315         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
316     }
317
318     @Test
319     public void whenPeriodicConfigRefreshSuccess2() throws JsonIOException, JsonSyntaxException, IOException {
320         doReturn(Mono.just(properties())).when(appConfigUnderTest).readEnvironmentVariables(any(), any());
321
322         Mono<JsonObject> json = Mono.just(getJsonRootObject());
323         Mono<JsonObject> err = Mono.error(new IOException()); // no config entry created by the dmaap plugin
324
325         doReturn(json, err).when(cloudConfigurationProvider).callForServiceConfigurationReactive(any());
326
327         Flux<AppConfig> task = appConfigUnderTest.createRefreshConfigurationTask(1L, context);
328
329         StepVerifier //
330             .create(task) //
331             .expectSubscription() //
332             .expectNext(appConfigUnderTest) //
333             .verifyComplete();
334
335         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
336     }
337
338     @Test
339     public void whenStopSuccess() {
340         Disposable disposableMock = mock(Disposable.class);
341         appConfigUnderTest.refreshConfigTask = disposableMock;
342
343         appConfigUnderTest.stop();
344
345         verify(disposableMock).dispose();
346         verifyNoMoreInteractions(disposableMock);
347         assertNull(appConfigUnderTest.refreshConfigTask);
348     }
349
350     @Test
351     public void whenNoPublisherConfigurationThrowException() throws DatafileTaskException {
352         appConfigUnderTest.publishingConfigurations = new HashMap<>();
353
354         DatafileTaskException exception = assertThrows(DatafileTaskException.class,
355             () -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER));
356         assertEquals("Cannot find getPublishingConfiguration for changeIdentifier: " + CHANGE_IDENTIFIER,
357             exception.getMessage());
358     }
359
360     @Test
361     public void whenFeedIsConfiguredReturnTrue() {
362         HashMap<String, PublisherConfiguration> publishingConfigs = new HashMap<>();
363         publishingConfigs.put(CHANGE_IDENTIFIER, null);
364         appConfigUnderTest.publishingConfigurations = publishingConfigs;
365
366         assertTrue(appConfigUnderTest.isFeedConfigured(CHANGE_IDENTIFIER));
367     }
368
369     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
370         JsonObject rootObject = (new JsonParser()).parse(new InputStreamReader(getCorrectJson())).getAsJsonObject();
371         return rootObject;
372     }
373
374     private static InputStream getCorrectJson() throws IOException {
375         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test.json");
376         String string = Resources.toString(url, Charsets.UTF_8);
377         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
378     }
379
380     private static InputStream getCorrectJsonTwoProducers() throws IOException {
381         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test_2producers.json");
382         String string = Resources.toString(url, Charsets.UTF_8);
383         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
384     }
385
386     private static InputStream getIncorrectJson() {
387         String string = "{" + //
388             "    \"configs\": {" + //
389             "        \"dmaap\": {"; //
390         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
391     }
392 }