839a9a18f871e1d2481775c997375eed11d4680a
[dcaegen2/collectors/datafile.git] /
1 /*-
2  * ============LICENSE_START======================================================================
3  * Copyright (C) 2018, 2020-2021 NOKIA Intellectual Property, 2018-2019 Nordix Foundation.
4  * 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             .build();
95
96     private AppConfig appConfigUnderTest;
97     private final Map<String, String> context = MappedDiagnosticContext.initializeTraceContext();
98     CbsClient cbsClient = mock(CbsClient.class);
99     CbsClientConfiguration cbsClientConfiguration = mock(CbsClientConfiguration.class);
100
101     @BeforeEach
102     void setUp() {
103         appConfigUnderTest = spy(AppConfig.class);
104         appConfigUnderTest.systemEnvironment = new Properties();
105
106     }
107
108     @Test
109     void whenTheConfigurationFits() throws IOException, DatafileTaskException {
110         // When
111         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
112         appConfigUnderTest.initialize();
113
114         // Then
115         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
116
117         ConsumerConfiguration consumerCfg = appConfigUnderTest.getDmaapConsumerConfiguration();
118         Assertions.assertNotNull(consumerCfg);
119         assertThat(consumerCfg).satisfies(this::checkCorrectConsumerConfiguration);
120
121         PublisherConfiguration publisherCfg = appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER);
122         Assertions.assertNotNull(publisherCfg);
123         assertThat(publisherCfg).isEqualToComparingFieldByField(CORRECT_PUBLISHER_CONFIG);
124
125         CertificateConfig certificateConfig = appConfigUnderTest.getCertificateConfiguration();
126         assertThat(certificateConfig)
127             .isNotNull()
128             .isEqualToComparingFieldByField(CORRECT_CERTIFICATE_CONFIGURATION);
129     }
130
131     @Test
132     void whenTheConfigurationFits_twoProducers() throws IOException, DatafileTaskException {
133         // When
134         doReturn(getCorrectJsonTwoProducers()).when(appConfigUnderTest).createInputStream(any());
135         appConfigUnderTest.loadConfigurationFromFile();
136
137         // Then
138         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
139         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
140         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER));
141         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("XX_FILES"));
142         Assertions.assertNotNull(appConfigUnderTest.getPublisherConfiguration("YY_FILES"));
143
144         assertThat(appConfigUnderTest.getPublisherConfiguration("XX_FILES").publishUrl())
145             .isEqualTo("feed01::publish_url");
146         assertThat(appConfigUnderTest.getPublisherConfiguration("YY_FILES").publishUrl())
147             .isEqualTo("feed01::publish_url");
148     }
149
150     @Test
151     void whenFileIsNotExist_ThrowException() throws DatafileTaskException {
152         // Given
153         appConfigUnderTest.setFilepath("/temp.json");
154
155         // When
156         appConfigUnderTest.loadConfigurationFromFile();
157
158         // Then
159         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
160         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
161             .hasMessageContaining("No PublishingConfiguration loaded, changeIdentifier: PM_MEAS_FILES");
162
163         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
164     }
165
166     @Test
167     void whenFileIsExistsButJsonIsIncorrect() throws IOException, DatafileTaskException {
168
169         // When
170         doReturn(getIncorrectJson()).when(appConfigUnderTest).createInputStream(any());
171         appConfigUnderTest.loadConfigurationFromFile();
172
173         // Then
174         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
175         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
176         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
177             .hasMessageContaining(CHANGE_IDENTIFIER);
178         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
179     }
180
181     @Test
182     void whenTheConfigurationFits_ButRootElementIsNotAJsonObject() throws IOException, DatafileTaskException {
183
184         // When
185         doReturn(getCorrectJson()).when(appConfigUnderTest).createInputStream(any());
186         JsonElement jsonElement = mock(JsonElement.class);
187         when(jsonElement.isJsonObject()).thenReturn(false);
188         doReturn(jsonElement).when(appConfigUnderTest).getJsonElement(any(InputStream.class));
189         appConfigUnderTest.loadConfigurationFromFile();
190
191         // Then
192         verify(appConfigUnderTest, times(1)).loadConfigurationFromFile();
193         Assertions.assertNull(appConfigUnderTest.getDmaapConsumerConfiguration());
194         assertThatThrownBy(() -> appConfigUnderTest.getPublisherConfiguration(CHANGE_IDENTIFIER))
195             .hasMessageContaining(CHANGE_IDENTIFIER);
196         Assertions.assertNull(appConfigUnderTest.getCertificateConfiguration());
197     }
198
199     @Test
200     void whenPeriodicConfigRefreshNoEnvironmentVariables() {
201         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
202         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
203
204         StepVerifier //
205             .create(task) //
206             .expectSubscription() //
207             .verifyComplete(); //
208
209         assertTrue(logAppender.list.toString().contains("CbsClientConfigurationException"));
210     }
211
212     @Test
213     void whenPeriodicConfigRefreshNoConsul() {
214         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
215         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
216         Flux<JsonObject> err = Flux.error(new IOException());
217         doReturn(err).when(cbsClient).updates(any(), any(), any());
218
219         final ListAppender<ILoggingEvent> logAppender = LoggingUtils.getLogListAppender(AppConfig.class);
220         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
221
222         StepVerifier //
223             .create(task) //
224             .expectSubscription() //
225             .verifyComplete();
226
227         assertTrue(
228             logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException"));
229     }
230
231     @Test
232     void whenPeriodicConfigRefreshSuccess() throws JsonIOException, JsonSyntaxException, IOException {
233         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
234         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
235
236         Flux<JsonObject> json = Flux.just(getJsonRootObject());
237         doReturn(json).when(cbsClient).updates(any(), any(), any());
238
239         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
240
241         StepVerifier //
242             .create(task) //
243             .expectSubscription() //
244             .expectNext(appConfigUnderTest) //
245             .verifyComplete();
246
247         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
248     }
249
250     @Test
251     void whenPeriodicConfigRefreshSuccess2() throws JsonIOException, JsonSyntaxException, IOException {
252         doReturn(Mono.just(cbsClientConfiguration)).when(appConfigUnderTest).createCbsClientConfiguration();
253         doReturn(Mono.just(cbsClient)).when(appConfigUnderTest).createCbsClient(cbsClientConfiguration);
254
255         Flux<JsonObject> json = Flux.just(getJsonRootObject());
256         Flux<JsonObject> err = Flux.error(new IOException()); // no config entry created by the
257         // dmaap plugin
258
259         doReturn(json, err).when(cbsClient).updates(any(), any(), any());
260
261         Flux<AppConfig> task = appConfigUnderTest.createRefreshTask();
262
263         StepVerifier //
264             .create(task) //
265             .expectSubscription() //
266             .expectNext(appConfigUnderTest) //
267             .verifyComplete();
268
269         Assertions.assertNotNull(appConfigUnderTest.getDmaapConsumerConfiguration());
270     }
271
272     private void checkCorrectConsumerConfiguration(ConsumerConfiguration consumerConfiguration) {
273         MessageRouterSubscribeRequest messageRouterSubscribeRequest =
274                 consumerConfiguration.getMessageRouterSubscribeRequest();
275         assertThat(messageRouterSubscribeRequest.consumerGroup()).isEqualTo("OpenDcae-c12");
276         assertThat(messageRouterSubscribeRequest.consumerId()).isEqualTo("C12");
277         assertThat(messageRouterSubscribeRequest.sourceDefinition().topicUrl())
278                 .isEqualTo("http://localhost:2222/events/unauthenticated.VES_NOTIFICATION_OUTPUT");
279         SecurityKeys securityKeys = consumerConfiguration.getMessageRouterSubscriberConfig().securityKeys();
280         assertThat(securityKeys.keyStore().path().toString()).hasToString("src/test/resources/cert.jks");
281         assertThat(securityKeys.trustStore().path().toString()).hasToString("src/test/resources/trust.jks");
282         assertThat(consumerConfiguration.getMessageRouterSubscriber()).isNotNull();
283     }
284
285     private JsonObject getJsonRootObject() throws JsonIOException, JsonSyntaxException, IOException {
286         JsonObject rootObject = JsonParser.parseReader(new InputStreamReader(getCorrectJson())).getAsJsonObject();
287         return rootObject;
288     }
289
290     private static InputStream getCorrectJson() throws IOException {
291         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test.json");
292         String string = Resources.toString(url, Charsets.UTF_8);
293         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
294     }
295
296     private static InputStream getCorrectJsonTwoProducers() throws IOException {
297         URL url = CloudConfigParser.class.getClassLoader().getResource("datafile_endpoints_test_2producers.json");
298         String string = Resources.toString(url, Charsets.UTF_8);
299         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
300     }
301
302     private static InputStream getIncorrectJson() {
303         String string = "{" + //
304             "    \"configs\": {" + //
305             "        \"dmaap\": {"; //
306         return new ByteArrayInputStream((string.getBytes(StandardCharsets.UTF_8)));
307     }
308 }