3c94029720c27e7451ed87a6e5661cd18dd08822
[dcaegen2/collectors/datafile.git] /
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2018, 2020-2022 Nokia. All rights reserved.
4  * Copyright (C) 2018-2019 Nordix Foundation. All rights reserved.
5  * ===============================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7  * in compliance with the License. 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 distributed under the License
12  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13  * or implied. See the License for the specific language governing permissions and limitations under
14  * the License.
15  * ============LICENSE_END========================================================================
16  */
17
18 package org.onap.dcaegen2.collectors.datafile.configuration;
19
20 import ch.qos.logback.classic.spi.ILoggingEvent;
21 import ch.qos.logback.core.read.ListAppender;
22 import com.google.common.base.Charsets;
23 import com.google.common.io.Resources;
24 import com.google.gson.JsonElement;
25 import com.google.gson.JsonIOException;
26 import com.google.gson.JsonObject;
27 import com.google.gson.JsonParser;
28 import com.google.gson.JsonSyntaxException;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.BeforeEach;
31 import org.junit.jupiter.api.Test;
32 import org.onap.dcaegen2.collectors.datafile.exceptions.DatafileTaskException;
33 import org.onap.dcaegen2.collectors.datafile.model.logging.MappedDiagnosticContext;
34 import org.onap.dcaegen2.collectors.datafile.utils.LoggingUtils;
35 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.CbsClient;
36 import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.CbsClientConfiguration;
37 import org.onap.dcaegen2.services.sdk.rest.services.dmaap.client.model.MessageRouterSubscribeRequest;
38 import org.onap.dcaegen2.services.sdk.security.ssl.SecurityKeys;
39 import reactor.core.publisher.Flux;
40 import reactor.core.publisher.Mono;
41 import reactor.test.StepVerifier;
42
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.Map;
50 import java.util.Properties;
51
52 import static org.assertj.core.api.Assertions.assertThat;
53 import static org.assertj.core.api.Assertions.assertThatThrownBy;
54 import static org.junit.jupiter.api.Assertions.assertTrue;
55 import static org.mockito.ArgumentMatchers.any;
56 import static org.mockito.Mockito.doReturn;
57 import static org.mockito.Mockito.mock;
58 import static org.mockito.Mockito.spy;
59 import static org.mockito.Mockito.times;
60 import static org.mockito.Mockito.verify;
61 import static org.mockito.Mockito.when;
62
63 /**
64  * Tests the AppConfig.
65  *
66  * @author <a href="mailto:przemyslaw.wasala@nokia.com">Przemysław Wąsala</a> on 4/9/18
67  * @author <a href="mailto:henrik.b.andersson@est.tech">Henrik Andersson</a>
68  */
69 class AppConfigTest {
70
71     public static final String CHANGE_IDENTIFIER = "PM_MEAS_FILES";
72
73     private static final PublisherConfiguration CORRECT_PUBLISHER_CONFIG = //
74         ImmutablePublisherConfiguration.builder() //
75             .publishUrl("https://localhost:3907/publish/1") //
76             .logUrl("https://localhost:3907/feedlog/1") //
77             .trustStorePath("src/test/resources/trust.jks") //
78             .trustStorePasswordPath("src/test/resources/trust.pass") //
79             .keyStorePath("src/test/resources/cert.jks") //
80             .keyStorePasswordPath("src/test/resources/jks.pass") //
81             .enableDmaapCertAuth(true) //
82             .changeIdentifier("PM_MEAS_FILES") //
83             .userName("CYE9fl40") //
84             .password("izBJD8nLjawq0HMG") //
85             .build();
86
87     private static final ImmutableCertificateConfig CORRECT_CERTIFICATE_CONFIGURATION = //
88         new ImmutableCertificateConfig.Builder() //
89             .keyCert("/src/test/resources/dfc.jks") //
90             .keyPasswordPath("/src/test/resources/dfc.jks.pass") //
91             .trustedCa("/src/test/resources/cert.jks") //
92             .trustedCaPasswordPath("/src/test/resources/cert.jks.pass") //
93             .httpsHostnameVerify(true)
94             .enableCertAuth(true)
95             .build();
96
97     private AppConfig appConfigUnderTest;
98     private final Map<String, String> context = MappedDiagnosticContext.initializeTraceContext();
99     CbsClient cbsClient = mock(CbsClient.class);
100     CbsClientConfiguration cbsClientConfiguration = mock(CbsClientConfiguration.class);
101
102     @BeforeEach
103     void setUp() {
104         appConfigUnderTest = spy(AppConfig.class);
105         appConfigUnderTest.systemEnvironment = new Properties();
106
107     }
108
109     @Test
110     void whenTheConfigurationFits() throws IOException, DatafileTaskException {
111         // When
112         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
113         appConfigUnderTest.initialize();
114
115         // Then
116         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
117
118         ConsumerConfiguration consumerCfg = appConfigUnderTest.getDmaapConsumerConfiguration();
119         Assertions.assertNotNull(consumerCfg);
120         assertThat(consumerCfg).satisfies(this::checkCorrectConsumerConfiguration);
121
122         PublisherConfiguration publisherCfg = appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER);
123         Assertions.assertNotNull(publisherCfg);
124         assertThat(publisherCfg).isEqualToComparingFieldByField(CORRECT_PUBLISHER_CONFIG);
125
126         CertificateConfig certificateConfig = appConfigUnderTest.getCertificateConfiguration();
127         assertThat(certificateConfig)
128             .isNotNull()
129             .isEqualToComparingFieldByField(CORRECT_CERTIFICATE_CONFIGURATION);
130     }
131
132     @Test
133     void shouldInitializeApplicationWithoutCertificates() throws IOException {
134         // When
135         doReturn(getCorrectConfigWithoutTLS()).when(appConfigUnderTest).createInputStream(any());
136         appConfigUnderTest.initialize();
137
138         // Then
139         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
140
141         CertificateConfig certificateConfig = appConfigUnderTest.getCertificateConfiguration();
142         assertThat(certificateConfig).isNotNull();
143     }
144
145     @Test
146     void whenTheConfigurationFits_twoProducers() throws IOException, DatafileTaskException {
147         // When
148         doReturn(getCorrectJsonTwoProducers()).when(appConfigUnderTest).createInputStream(any());
149         appConfigUnderTest.loadConfigurationFromFile();
150
151         // Then
152         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
153         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
154         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER));
155         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("XX_FILES"));
156         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("YY_FILES"));
157
158         assertThat(appConfigUnderTest.getPublisherConfiguration("XX_FILES").publishUrl())
159             .isEqualTo("feed01::publish_url");
160         assertThat(appConfigUnderTest.getPublisherConfiguration("YY_FILES").publishUrl())
161             .isEqualTo("feed01::publish_url");
162     }
163
164     @Test
165     void whenFileIsNotExist_ThrowException() throws DatafileTaskException {
166         // Given
167         appConfigUnderTest.setFilepath("/temp.json");
168
169         // When
170         appConfigUnderTest.loadConfigurationFromFile();
171
172         // Then
173         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
174         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
175             .hasMessageContaining("No PublishingConfiguration loaded, changeIdentifier: PM_MEAS_FILES");
176
177         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
178     }
179
180     @Test
181     void whenFileIsExistsButJsonIsIncorrect() throws IOException, DatafileTaskException {
182
183         // When
184         doReturn(getIncorrectJson()).when(appConfigUnderTest).createInputStream(any());
185         appConfigUnderTest.loadConfigurationFromFile();
186
187         // Then
188         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
189         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
190         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
191             .hasMessageContaining(CHANGE_IDENTIFIER);
192         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
193     }
194
195     @Test
196     void whenTheConfigurationFits_ButRootElementIsNotAJsonObject() throws IOException, DatafileTaskException {
197
198         // When
199         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
200         JsonElement jsonElement = mock(JsonElement.class);
201         when(jsonElement.isJsonObject()).thenReturn(false);
202         doReturn(jsonElement).when(appConfigUnderTest).getJsonElement(any(InputStream.class));
203         appConfigUnderTest.loadConfigurationFromFile();
204
205         // Then
206         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
207         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
208         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
209             .hasMessageContaining(CHANGE_IDENTIFIER);
210         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
211     }
212
213     @Test
214     void whenPeriodicConfigRefreshNoEnvironmentVariables() {
215         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
216         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
217
218         StepVerifier //
219             .create(task) //
220             .expectSubscription() //
221             .verifyComplete(); //
222
223         assertTrue(logAppender.list.toString().contains("CbsClientConfigurationException"));
224     }
225
226     @Test
227     void whenPeriodicConfigRefreshNoConsul() {
228         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
229         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
230         Flux<JsonObject> err = Flux.error(new IOException());
231         doReturn(err).when(cbsClient).updates(any(), any(), any());
232
233         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
234         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
235
236         StepVerifier //
237             .create(task) //
238             .expectSubscription() //
239             .verifyComplete();
240
241         assertTrue(
242             logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException"));
243     }
244
245     @Test
246     void whenPeriodicConfigRefreshSuccess() throws JsonIOException, JsonSyntaxException, IOException {
247         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
248         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
249
250         Flux<JsonObject> json = Flux.just(getJsonRootObject());
251         doReturn(json).when(cbsClient).updates(any(), any(), any());
252
253         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
254
255         StepVerifier //
256             .create(task) //
257             .expectSubscription() //
258             .expectNext(appConfigUnderTest) //
259             .verifyComplete();
260
261         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
262     }
263
264     @Test
265     void whenPeriodicConfigRefreshSuccess2() throws JsonIOException, JsonSyntaxException, IOException {
266         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
267         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
268
269         Flux<JsonObject> json = Flux.just(getJsonRootObject());
270         Flux<JsonObject> err = Flux.error(new IOException()); // no config entry created by the
271         // dmaap plugin
272
273         doReturn(json, err).when(cbsClient).updates(any(), any(), any());
274
275         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
276
277         StepVerifier //
278             .create(task) //
279             .expectSubscription() //
280             .expectNext(appConfigUnderTest) //
281             .verifyComplete();
282
283         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
284     }
285
286     private void checkCorrectConsumerConfiguration(ConsumerConfiguration consumerConfiguration) {
287         MessageRouterSubscribeRequest messageRouterSubscribeRequest =
288                 consumerConfiguration.getMessageRouterSubscribeRequest();
289         assertThat(messageRouterSubscribeRequest.consumerGroup()).isEqualTo("OpenDcae-c12");
290         assertThat(messageRouterSubscribeRequest.consumerId()).isEqualTo("C12");
291         assertThat(messageRouterSubscribeRequest.sourceDefinition().topicUrl())
292                 .isEqualTo("http://localhost:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT");
293         SecurityKeys securityKeys = consumerConfiguration.getMessageRouterSubscriberConfig().securityKeys();
294         assertThat(securityKeys.keyStore().path().toString()).hasToString("src/test/resources/cert.jks");
295         assertThat(securityKeys.trustStore().path().toString()).hasToString("src/test/resources/trust.jks");
296         assertThat(consumerConfiguration.getMessageRouterSubscriber()).isNotNull();
297     }
298
299     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
300         JsonObject rootObject = JsonParser.parseReader(new InputStreamReader(getCorrectJson())).getAsJsonObject();
301         return rootObject;
302     }
303
304     private static InputStream getCorrectJson() throws IOException {
305         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test.json");
306         String string = Resources.toString(url, Charsets.UTF_8);
307         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
308     }
309
310     private static InputStream getCorrectConfigWithoutTLS() throws IOException {
311         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_test_config_no_tls.json");
312         String string = Resources.toString(url, Charsets.UTF_8);
313         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
314     }
315
316     private static InputStream getCorrectJsonTwoProducers() throws IOException {
317         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test_2producers.json");
318         String string = Resources.toString(url, Charsets.UTF_8);
319         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
320     }
321
322     private static InputStream getIncorrectJson() {
323         String string = "{" + //
324             "    \"configs\": {" + //
325             "        \"dmaap\": {"; //
326         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
327     }
328 }