blob: d9f4f6d3dd14be646f857e579305a7cdd1f27bf5 [file] [log] [blame]
Rolf Badorekef2bf512019-08-20 11:17:15 +03001/*
Petri Ovaska5bdca622022-03-10 09:59:23 +02002 Copyright (c) 2018-2022 Nokia.
Rolf Badorekef2bf512019-08-20 11:17:15 +03003
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 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
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
Timo Tietavainena0745d22019-11-28 09:55:22 +020017/*
18 * This source code is part of the near-RT RIC (RAN Intelligent Controller)
19 * platform project (RICP).
20*/
21
Rolf Badorekef2bf512019-08-20 11:17:15 +030022#include <gtest/gtest.h>
23#include <gmock/gmock.h>
24#include <memory>
25#include <boost/property_tree/ptree.hpp>
26#include <boost/property_tree/json_parser.hpp>
27#include "private/configurationreader.hpp"
28#include "private/createlogger.hpp"
29#include "private/logger.hpp"
30#include "private/tst/databaseconfigurationmock.hpp"
31#include "private/tst/gettopsrcdir.hpp"
32#include "private/tst/namespaceconfigurationsmock.hpp"
33#include "private/tst/systemmock.hpp"
34
35using namespace shareddatalayer;
36using namespace shareddatalayer::tst;
37using namespace testing;
38
39namespace
40{
41 class ConfigurationReaderBaseTest: public testing::Test
42 {
43 public:
44 const std::string someKnownInputSource;
45 const Directories noDirectories;
46 DatabaseConfigurationMock databaseConfigurationMock;
47 NamespaceConfigurationsMock namespaceConfigurationsMock;
48 std::unique_ptr<ConfigurationReader> configurationReader;
49 SystemMock systemMock;
50 std::shared_ptr<Logger> logger;
51
52 ConfigurationReaderBaseTest(std::string inputSourceName):
53 someKnownInputSource(inputSourceName),
54 logger(createLogger(SDL_LOG_PREFIX))
55 {
56 EXPECT_CALL(databaseConfigurationMock, isEmpty()).WillRepeatedly(Return(true));
57 EXPECT_CALL(namespaceConfigurationsMock, isEmpty()).WillRepeatedly(Return(true));
58 }
59
60 void expectDbTypeConfigurationCheckAndApply(const std::string& type)
61 {
62 EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(type));
63 }
64
Petri Ovaska1c4a6052021-05-31 14:06:32 +030065 void expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType type)
66 {
67 EXPECT_CALL(databaseConfigurationMock, getDbType())
68 .WillOnce(Return(type));
69 }
70
Rolf Badorekef2bf512019-08-20 11:17:15 +030071 void expectDBServerAddressConfigurationCheckAndApply(const std::string& address)
72 {
73 EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(address));
74 }
75
Petri Ovaska5bdca622022-03-10 09:59:23 +020076 void expectCheckAndApplySentinelPorts(const std::string& portsEnvStr)
Rolf Badorek2dcf9402019-10-01 18:33:58 +030077 {
Petri Ovaska5bdca622022-03-10 09:59:23 +020078 EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelPorts(portsEnvStr));
Rolf Badorek2dcf9402019-10-01 18:33:58 +030079 }
80
81 void expectSentinelMasterNameConfigurationCheckAndApply(const std::string& address)
82 {
Petri Ovaska5bdca622022-03-10 09:59:23 +020083 EXPECT_CALL(databaseConfigurationMock, checkAndApplySentinelMasterNames(address));
Rolf Badorek2dcf9402019-10-01 18:33:58 +030084 }
85
Rolf Badorekef2bf512019-08-20 11:17:15 +030086 void expectDatabaseConfigurationIsEmpty_returnFalse()
87 {
88 EXPECT_CALL(databaseConfigurationMock, isEmpty()).
89 WillOnce(Return(false));
90 }
91
92 void tryToReadDatabaseConfigurationToNonEmptyContainer()
93 {
94 expectDatabaseConfigurationIsEmpty_returnFalse();
95 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
96 }
97
98 void expectNamespaceConfigurationIsEmpty_returnFalse()
99 {
100 EXPECT_CALL(namespaceConfigurationsMock, isEmpty()).
101 WillOnce(Return(false));
102 }
103
104 void tryToReadNamespaceConfigurationToNonEmptyContainer()
105 {
106 expectNamespaceConfigurationIsEmpty_returnFalse();
107 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
108 }
109
110 void expectAddNamespaceConfiguration(const std::string& namespacePrefix, bool useDbBackend,
111 bool enableNotifications)
112 {
113 NamespaceConfiguration expectedNamespaceConfiguration{namespacePrefix, useDbBackend,
114 enableNotifications,
115 someKnownInputSource};
116 EXPECT_CALL(namespaceConfigurationsMock, addNamespaceConfiguration(expectedNamespaceConfiguration));
117 }
118
119 void expectGetEnvironmentString(const char* returnValue)
120 {
121 EXPECT_CALL(systemMock, getenv(_))
122 .WillOnce(Return(returnValue));
123 }
124
125 void initializeReaderWithoutDirectories()
126 {
127 configurationReader.reset(new ConfigurationReader(noDirectories, systemMock, logger));
128 }
129
130 void initializeReaderWithSDLconfigFileDirectory()
131 {
132 configurationReader.reset(new ConfigurationReader({getTopSrcDir() + "/conf"}, systemMock, logger));
133 }
134 };
135
136 class ConfigurationReaderSDLConfigFileTest: public ConfigurationReaderBaseTest
137 {
138 public:
139
140 ConfigurationReaderSDLConfigFileTest():
141 ConfigurationReaderBaseTest("ConfFileFromSDLrepo")
142 {
143 expectGetEnvironmentString(nullptr);
144 initializeReaderWithSDLconfigFileDirectory();
145 }
146 };
147
148 class ConfigurationReaderInputStreamTest: public ConfigurationReaderBaseTest
149 {
150 public:
151
152 ConfigurationReaderInputStreamTest():
153 ConfigurationReaderBaseTest("<istream>")
154 {
155 expectGetEnvironmentString(nullptr);
156 initializeReaderWithoutDirectories();
157 }
158
159 void readConfigurationAndExpectJsonParserException(const std::istringstream& is)
160 {
161 const std::string expectedError("error in SDL configuration <istream> at line 7: expected ':'");
162
163 EXPECT_THROW( {
164 try
165 {
166 configurationReader->readConfigurationFromInputStream(is);
167 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
168 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
169 }
170 catch (const std::exception& e)
171 {
172 EXPECT_EQ(expectedError, e.what());
173 throw;
174 }
175 }, Exception);
176 }
177
178 void readConfigurationAndExpectBadValueException(const std::istringstream& is,
179 const std::string& param)
180 {
181 std::ostringstream os;
182 os << "Configuration error in " << someKnownInputSource << ": "
183 << "invalid \"" << param << "\": \"bad-value\"";
184
185 EXPECT_THROW( {
186 try
187 {
188 configurationReader->readConfigurationFromInputStream(is);
189 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
190 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
191 }
192 catch (const std::exception& e)
193 {
194 EXPECT_EQ(os.str(), e.what());
195 throw;
196 }
197 }, Exception);
198 }
199
200 void readConfigurationAndExpectDbTypeException(const std::istringstream& is)
201 {
202 std::ostringstream os;
203 os << "Configuration error in " << someKnownInputSource << ": some error";
204
205 EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(_))
206 .WillOnce(Throw(Exception("some error")));
207
208 EXPECT_THROW( {
209 try
210 {
211 configurationReader->readConfigurationFromInputStream(is);
212 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
213 }
214 catch (const std::exception& e)
215 {
216 EXPECT_EQ(os.str(), e.what());
217 throw;
218 }
219 }, Exception);
220 }
221
222 void readConfigurationAndExpectAddressException(const std::istringstream& is,
223 const std::string& addressValue)
224 {
225 std::ostringstream os;
226 os << "Configuration error in " << someKnownInputSource << ": "
227 << "invalid \"address\": \"" << addressValue << "\" some error";
228
229 EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(_))
230 .WillOnce(Throw(Exception("some error")));
231
232 EXPECT_THROW( {
233 try
234 {
235 configurationReader->readConfigurationFromInputStream(is);
236 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
237 }
238 catch (const std::exception& e)
239 {
240 EXPECT_EQ(os.str(), e.what());
241 throw;
242 }
243 }, Exception);
244 }
245
246 void readConfigurationAndExpectMissingParameterException(const std::istringstream& is, const std::string& param)
247 {
248 std::ostringstream os;
249 os << "Configuration error in " << someKnownInputSource << ": "
250 << "missing \"" << param << "\"";
251
252 EXPECT_THROW( {
253 try
254 {
255 configurationReader->readConfigurationFromInputStream(is);
256 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
257 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
258 }
259 catch (const std::exception& e)
260 {
261 EXPECT_EQ(os.str(), e.what());
262 throw;
263 }
264 }, Exception);
265 }
266
267 void readConfigurationAndExpectNamespacePrefixValidationException(const std::istringstream& is,
268 const std::string& namespacePrefix)
269 {
270 std::ostringstream os;
271 os << "Configuration error in " << someKnownInputSource << ": "
272 << "\"namespacePrefix\": \"" << namespacePrefix << "\""
273 << " contains some of these disallowed characters: ,{}";
274
275 EXPECT_THROW( {
276 try
277 {
278 configurationReader->readConfigurationFromInputStream(is);
279 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
280 }
281 catch (const std::exception& e)
282 {
283 EXPECT_EQ(os.str(), e.what() );
284 throw;
285 }
286 }, Exception);
287 }
288
289 void readConfigurationAndExpectEnableNotificationsValidationException(const std::istringstream& is)
290 {
291 std::ostringstream os;
292 os << "Configuration error in " << someKnownInputSource << ": "
293 << "\"enableNotifications\" cannot be true, when \"useDbBackend\" is false";
294
295 EXPECT_THROW( {
296 try
297 {
298 configurationReader->readConfigurationFromInputStream(is);
299 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
300 }
301 catch (const std::exception& e)
302 {
303 EXPECT_EQ(os.str(), e.what() );
304 throw;
305 }
306 }, Exception);
307 }
308
309 };
310}
311
312TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfiguration)
313{
314 InSequence dummy;
315 std::istringstream is(R"JSON(
316 {
317 "database":
318 {
319 "type": "redis-standalone",
320 "servers":
321 [
322 {
323 "address": "someKnownDbAddress:65535"
324 }
325 ]
326 }
327 })JSON");
328 expectDbTypeConfigurationCheckAndApply("redis-standalone");
329 expectDBServerAddressConfigurationCheckAndApply("someKnownDbAddress:65535");
330 configurationReader->readConfigurationFromInputStream(is);
331 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
332}
333
334TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfigurationWithMultipleServerAddresses)
335{
336 InSequence dummy;
337 std::istringstream is(R"JSON(
338 {
339 "database":
340 {
341 "type": "redis-cluster",
342 "servers":
343 [
344 {
345 "address": "10.20.30.40:50000"
346 },
347 {
348 "address": "10.20.30.50:50001"
349 }
350 ]
351 }
352 })JSON");
353
354 expectDbTypeConfigurationCheckAndApply("redis-cluster");
355 expectDBServerAddressConfigurationCheckAndApply("10.20.30.40:50000");
356 expectDBServerAddressConfigurationCheckAndApply("10.20.30.50:50001");
357 configurationReader->readConfigurationFromInputStream(is);
358 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
359}
360
361TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfigurationWithMultipleReadOperations)
362{
363 InSequence dummy;
364 std::istringstream isOne(R"JSON(
365 {
366 "database":
367 {
368 "type": "redis-cluster",
369 "servers":
370 [
371 {
372 "address": "10.20.30.40:50000"
373 }
374 ]
375 }
376 })JSON");
377 std::istringstream isTwo(R"JSON(
378 {
379 "database":
380 {
381 "type": "redis-cluster",
382 "servers":
383 [
384 {
385 "address": "10.20.30.50:50001"
386 }
387 ]
388 }
389 })JSON");
390
391 expectDbTypeConfigurationCheckAndApply("redis-cluster");
392 expectDBServerAddressConfigurationCheckAndApply("10.20.30.40:50000");
393 expectDbTypeConfigurationCheckAndApply("redis-cluster");
394 expectDBServerAddressConfigurationCheckAndApply("10.20.30.50:50001");
395 configurationReader->readConfigurationFromInputStream(isOne);
396 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
397 configurationReader->readConfigurationFromInputStream(isTwo);
398 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
399}
400
401TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseTypeParameter)
402{
403 InSequence dummy;
404 std::istringstream is(R"JSON(
405 {
406 "database":
407 {
408 "servers":
409 [
410 {
411 "address": "10.20.30.50:50001"
412 }
413 ]
414 }
415 })JSON");
416
417 readConfigurationAndExpectMissingParameterException(is, "type");
418}
419
420TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseServersArray)
421{
422 InSequence dummy;
423 std::istringstream is(R"JSON(
424 {
425 "database":
426 {
427 "type": "redis-standalone"
428 }
429 })JSON");
430
431 expectDbTypeConfigurationCheckAndApply("redis-standalone");
432 readConfigurationAndExpectMissingParameterException(is, "servers");
433}
434
435TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseServerAddressParameter)
436{
437 InSequence dummy;
438 std::istringstream is(R"JSON(
439 {
440 "database":
441 {
442 "type": "redis-standalone",
443 "servers":
444 [
445 {
446 }
447 ]
448 }
449 })JSON");
450
451 expectDbTypeConfigurationCheckAndApply("redis-standalone");
452 readConfigurationAndExpectMissingParameterException(is, "address");
453}
454
455TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowDatabaseConfigurationDbTypeError)
456{
457 InSequence dummy;
458 std::istringstream is(R"JSON(
459 {
460 "database":
461 {
462 "type": "someBadType",
463 "servers":
464 [
465 {
466 "address": "10.20.30.50:50001"
467 }
468 ]
469 }
470 })JSON");
471
472 readConfigurationAndExpectDbTypeException(is);
473}
474
475TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowDatabaseConfigurationAddressError)
476{
477 InSequence dummy;
478 std::istringstream is(R"JSON(
479 {
480 "database":
481 {
482 "type": "redis-standalone",
483 "servers":
484 [
485 {
486 "address": "someBadAddress"
487 }
488 ]
489 }
490 })JSON");
491
492 expectDbTypeConfigurationCheckAndApply("redis-standalone");
493 readConfigurationAndExpectAddressException(is, "someBadAddress");
494}
495
496TEST_F(ConfigurationReaderInputStreamTest, CanHandleJSONWithoutAnyConfiguration)
497{
498 InSequence dummy;
499 std::istringstream is(R"JSON(
500 {
501 })JSON");
502
503 EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(_))
504 .Times(0);
505 EXPECT_CALL(namespaceConfigurationsMock, addNamespaceConfiguration(_))
506 .Times(0);
507 configurationReader->readConfigurationFromInputStream(is);
508}
509
510TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfiguration)
511{
512 InSequence dummy;
513 std::istringstream is(R"JSON(
514 {
515 "sharedDataLayer":
516 [
517 {
518 "namespacePrefix": "someKnownNamespacePrefix",
519 "useDbBackend": true,
520 "enableNotifications": true
521 },
522 {
523 "namespacePrefix": "anotherKnownNamespace",
524 "useDbBackend": false,
525 "enableNotifications": false
526 }
527 ]
528 })JSON");
529
530 expectAddNamespaceConfiguration("anotherKnownNamespace", false, false);
531 expectAddNamespaceConfiguration("someKnownNamespacePrefix", true, true);
532 configurationReader->readConfigurationFromInputStream(is);
533 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
534}
535
536TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfigurationWithMultipleReadOperations)
537{
538 InSequence dummy;
539 std::istringstream isOne(R"JSON(
540 {
541 "sharedDataLayer":
542 [
543 {
544 "namespacePrefix": "someKnownNamespacePrefix",
545 "useDbBackend": true,
546 "enableNotifications": true
547 }
548 ]
549 })JSON");
550
551 std::istringstream isTwo(R"JSON(
552 {
553 "sharedDataLayer":
554 [
555 {
556 "namespacePrefix": "anotherKnownNamespace",
557 "useDbBackend": false,
558 "enableNotifications": false
559 }
560 ]
561 })JSON");
562
563 expectAddNamespaceConfiguration("someKnownNamespacePrefix", true, true);
564 expectAddNamespaceConfiguration("anotherKnownNamespace", false, false);
565 configurationReader->readConfigurationFromInputStream(isOne);
566 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
567 configurationReader->readConfigurationFromInputStream(isTwo);
568 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
569}
570
571TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfigurationWithEmptyNamespacePrefixValue)
572{
573 InSequence dummy;
574 std::istringstream is(R"JSON(
575 {
576 "sharedDataLayer":
577 [
578 {
579 "namespacePrefix": "",
580 "useDbBackend": false,
581 "enableNotifications": false
582 }
583 ]
584 })JSON");
585
586 expectAddNamespaceConfiguration("", false, false);
587 configurationReader->readConfigurationFromInputStream(is);
588 configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
589}
590
591TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowJSONSyntaxError)
592{
593 InSequence dummy;
594 std::istringstream is(R"JSON(
595 {
596 "sharedDataLayer":
597 [
598 {
599 "abc"
600 }
601 ]
602 })JSON");
603
604 readConfigurationAndExpectJsonParserException(is);
605}
606
607TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowParameterUseDbBackendBadValue)
608{
609 InSequence dummy;
610 std::istringstream is(R"JSON(
611 {
612 "sharedDataLayer":
613 [
614 {
615 "namespacePrefix": "someKnownNamespacePrefix",
616 "useDbBackend": "bad-value",
617 "enableNotifications": false
618 }
619 ]
620 })JSON");
621
622 readConfigurationAndExpectBadValueException(is, "useDbBackend");
623}
624
625TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowParameterEnableNotificationsBadValue)
626{
627 InSequence dummy;
628 std::istringstream is(R"JSON(
629 {
630 "sharedDataLayer":
631 [
632 {
633 "namespacePrefix": "someKnownNamespacePrefix",
634 "useDbBackend": true,
635 "enableNotifications": "bad-value"
636 }
637 ]
638 })JSON");
639
640 readConfigurationAndExpectBadValueException(is, "enableNotifications");
641}
642
643TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryNamespacePrefixParameter)
644{
645 InSequence dummy;
646 std::istringstream is(R"JSON(
647 {
648 "sharedDataLayer":
649 [
650 {
651 "useDbBackend": true,
652 "enableNotifications": true
653 }
654 ]
655 })JSON");
656
657 readConfigurationAndExpectMissingParameterException(is, "namespacePrefix");
658}
659
660TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryUseDbBackendParameter)
661{
662 InSequence dummy;
663 std::istringstream is(R"JSON(
664 {
665 "sharedDataLayer":
666 [
667 {
668 "namespacePrefix": "someKnownNamespacePrefix",
669 "enableNotifications": true
670 }
671 ]
672 })JSON");
673
674 readConfigurationAndExpectMissingParameterException(is, "useDbBackend");
675}
676
677TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryEnableNotificationsParameter)
678{
679 InSequence dummy;
680 std::istringstream is(R"JSON(
681 {
682 "sharedDataLayer":
683 [
684 {
685 "namespacePrefix": "someKnownNamespacePrefix",
686 "useDbBackend": true
687 }
688 ]
689 })JSON");
690
691 readConfigurationAndExpectMissingParameterException(is, "enableNotifications");
692}
693
694TEST_F(ConfigurationReaderInputStreamTest, CanThrowValidationErrorForNamespacePrefixWithDisallowedCharacters)
695{
696 InSequence dummy;
697 std::istringstream is(R"JSON(
698 {
699 "sharedDataLayer":
700 [
701 {
702 "namespacePrefix": "a,b{c}",
703 "useDbBackend": true,
704 "enableNotifications": true
705 }
706 ]
707 })JSON");
708
709 readConfigurationAndExpectNamespacePrefixValidationException(is, "a,b{c}");
710}
711
712TEST_F(ConfigurationReaderInputStreamTest, CanThrowValidationErrorForEnableNotificationsWithNoDbBackend)
713{
714 InSequence dummy;
715 std::istringstream is(R"JSON(
716 {
717 "sharedDataLayer":
718 [
719 {
720 "namespacePrefix": "someKnownNamespacePrefix",
721 "useDbBackend": false,
722 "enableNotifications": true
723 }
724 ]
725 })JSON");
726
727 readConfigurationAndExpectEnableNotificationsValidationException(is);
728}
729
730TEST_F(ConfigurationReaderInputStreamTest, WillNotReadDatabaseConfigurationToNonEmptyContainer)
731{
732 EXPECT_EXIT(tryToReadDatabaseConfigurationToNonEmptyContainer(),
733 KilledBySignal(SIGABRT), "ABORT.*configurationreader\\.cpp");
734}
735
736TEST_F(ConfigurationReaderInputStreamTest, WillNotReadNamespaceConfigurationToNonEmptyContainer)
737{
738 EXPECT_EXIT(tryToReadNamespaceConfigurationToNonEmptyContainer(),
739 KilledBySignal(SIGABRT), "ABORT.*configurationreader\\.cpp");
740}
741
742class ConfigurationReaderEnvironmentVariableTest: public ConfigurationReaderBaseTest
743{
744public:
745 std::string dbHostEnvVariableValue;
746 std::string dbPortEnvVariableValue;
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300747 std::string sentinelPortEnvVariableValue;
748 std::string sentinelMasterNameEnvVariableValue;
Petri Ovaskaece67082021-04-15 11:08:13 +0300749 std::string dbClusterAddrListEnvVariableValue;
Rolf Badorekef2bf512019-08-20 11:17:15 +0300750 std::istringstream is{R"JSON(
751 {
752 "database":
753 {
754 "type": "redis-cluster",
755 "servers":
756 [
757 {
758 "address": "10.20.30.40:50000"
759 },
760 {
761 "address": "10.20.30.50:50001"
762 }
763 ]
764 }
765 })JSON"};
766
767 ConfigurationReaderEnvironmentVariableTest():
768 ConfigurationReaderBaseTest(DB_HOST_ENV_VAR_NAME)
769 {
770 }
771
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300772 void readEnvironmentConfigurationAndExpectConfigurationErrorException(const std::string& msg,
773 bool expectCall)
Rolf Badorekef2bf512019-08-20 11:17:15 +0300774 {
775 std::ostringstream os;
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300776 os << "Configuration error in " << someKnownInputSource << ": " << msg;
Rolf Badorekef2bf512019-08-20 11:17:15 +0300777
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300778 if (expectCall)
779 EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(_))
780 .WillOnce(Throw(Exception("some error")));
Rolf Badorekef2bf512019-08-20 11:17:15 +0300781
782 EXPECT_THROW( {
783 try
784 {
785 EXPECT_CALL(systemMock, getenv(_))
Petri Ovaskaece67082021-04-15 11:08:13 +0300786 .Times(5)
Rolf Badorekef2bf512019-08-20 11:17:15 +0300787 .WillOnce(Return(dbHostEnvVariableValue.c_str()))
Petri Ovaskaece67082021-04-15 11:08:13 +0300788 .WillOnce(Return(nullptr))
789 .WillOnce(Return(nullptr))
790 .WillOnce(Return(nullptr))
Rolf Badorekef2bf512019-08-20 11:17:15 +0300791 .WillOnce(Return(nullptr));
792 initializeReaderWithoutDirectories();
793 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
794 }
795 catch (const std::exception& e)
796 {
797 EXPECT_EQ(os.str(), e.what());
798 throw;
799 }
800 }, Exception);
801 }
802};
803
804TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationCanOverrideJSONDatabaseConfiguration)
805{
806 InSequence dummy;
807 dbHostEnvVariableValue = "unknownAddress.local";
808 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
809 dbPortEnvVariableValue = "12345";
810 expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300811 expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
812 expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
Petri Ovaskaece67082021-04-15 11:08:13 +0300813 expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME
Rolf Badorekef2bf512019-08-20 11:17:15 +0300814
815 expectDbTypeConfigurationCheckAndApply("redis-standalone");
816 expectDBServerAddressConfigurationCheckAndApply("unknownAddress.local:12345");
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300817 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::REDIS_STANDALONE);
Rolf Badorekef2bf512019-08-20 11:17:15 +0300818 initializeReaderWithSDLconfigFileDirectory();
819 configurationReader->readConfigurationFromInputStream(is);
820 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
821}
822
823TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithoutPortIsAccepted)
824{
825 InSequence dummy;
826 dbHostEnvVariableValue = "server.local";
827 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300828 expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
829 expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
830 expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
Petri Ovaskaece67082021-04-15 11:08:13 +0300831 expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME
Rolf Badorekef2bf512019-08-20 11:17:15 +0300832
833 expectDbTypeConfigurationCheckAndApply("redis-standalone");
834 expectDBServerAddressConfigurationCheckAndApply("server.local");
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300835 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::REDIS_STANDALONE);
Rolf Badorekef2bf512019-08-20 11:17:15 +0300836 initializeReaderWithoutDirectories();
837 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
838}
839
840TEST_F(ConfigurationReaderEnvironmentVariableTest, EmptyEnvironmentVariableThrows)
841{
842 dbHostEnvVariableValue = "";
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300843 readEnvironmentConfigurationAndExpectConfigurationErrorException("Missing environment variable configuration!",
844 false);
Rolf Badorekef2bf512019-08-20 11:17:15 +0300845}
846
847TEST_F(ConfigurationReaderEnvironmentVariableTest, IllegalCharacterInEnvironmentVariableThrows)
848{
849 dbHostEnvVariableValue = "@";
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300850 readEnvironmentConfigurationAndExpectConfigurationErrorException("some error", true);
Rolf Badorekef2bf512019-08-20 11:17:15 +0300851}
852
853TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationAcceptIPv6Address)
854{
855 InSequence dummy;
856 dbHostEnvVariableValue = "[2001::123]:12345";
857 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300858 expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
859 expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
860 expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
Petri Ovaskaece67082021-04-15 11:08:13 +0300861 expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME
Rolf Badorekef2bf512019-08-20 11:17:15 +0300862
863 expectDbTypeConfigurationCheckAndApply("redis-standalone");
864 expectDBServerAddressConfigurationCheckAndApply("[2001::123]:12345");
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300865 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::REDIS_STANDALONE);
Rolf Badorekef2bf512019-08-20 11:17:15 +0300866 initializeReaderWithoutDirectories();
867 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
868}
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300869
870TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithSentinel)
871{
872 InSequence dummy;
873 dbHostEnvVariableValue = "sentinelAddress.local";
874 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
875 dbPortEnvVariableValue = "1111";
876 expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
877 sentinelPortEnvVariableValue = "2222";
878 expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str());
879 sentinelMasterNameEnvVariableValue = "mymaster";
880 expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str());
Petri Ovaskaece67082021-04-15 11:08:13 +0300881 expectGetEnvironmentString(nullptr); //DB_CLUSTER_ENV_VAR_NAME
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300882
883 expectDbTypeConfigurationCheckAndApply("redis-sentinel");
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300884 expectDBServerAddressConfigurationCheckAndApply("sentinelAddress.local:1111");
885 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::REDIS_SENTINEL);
Petri Ovaska5bdca622022-03-10 09:59:23 +0200886 expectCheckAndApplySentinelPorts(sentinelPortEnvVariableValue);
Rolf Badorek2dcf9402019-10-01 18:33:58 +0300887 expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue);
888 initializeReaderWithoutDirectories();
889 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
890}
Petri Ovaskaece67082021-04-15 11:08:13 +0300891
892TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithSentinelAndClusterConfiguration)
893{
894 InSequence dummy;
895 dbHostEnvVariableValue = "address-0.local";
896 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300897 expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
Petri Ovaska5bdca622022-03-10 09:59:23 +0200898 sentinelPortEnvVariableValue = "2222,2223,2224";
Petri Ovaskaece67082021-04-15 11:08:13 +0300899 expectGetEnvironmentString(sentinelPortEnvVariableValue.c_str());
Petri Ovaska5bdca622022-03-10 09:59:23 +0200900 sentinelMasterNameEnvVariableValue = "mymaster-0,mymaster-1,mymaster-2";
Petri Ovaskaece67082021-04-15 11:08:13 +0300901 expectGetEnvironmentString(sentinelMasterNameEnvVariableValue.c_str());
902 dbClusterAddrListEnvVariableValue = "address-0.local,address-1.local,address-2.local";
903 expectGetEnvironmentString(dbClusterAddrListEnvVariableValue.c_str());
904
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300905 expectDbTypeConfigurationCheckAndApply("sdl-sentinel-cluster");
Petri Ovaskaece67082021-04-15 11:08:13 +0300906 expectDBServerAddressConfigurationCheckAndApply("address-0.local");
907 expectDBServerAddressConfigurationCheckAndApply("address-1.local");
908 expectDBServerAddressConfigurationCheckAndApply("address-2.local");
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300909 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::SDL_SENTINEL_CLUSTER);
Petri Ovaska5bdca622022-03-10 09:59:23 +0200910 expectCheckAndApplySentinelPorts(sentinelPortEnvVariableValue);
Petri Ovaskaece67082021-04-15 11:08:13 +0300911 expectSentinelMasterNameConfigurationCheckAndApply(sentinelMasterNameEnvVariableValue);
912 initializeReaderWithoutDirectories();
913 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
914}
Petri Ovaska1c4a6052021-05-31 14:06:32 +0300915
916TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithoutSentinelAndWithClusterConfiguration)
917{
918 InSequence dummy;
919 dbHostEnvVariableValue = "address-0.local";
920 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
921 expectGetEnvironmentString(nullptr); //DB_PORT_ENV_VAR_NAME
922 expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
923 expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
924 dbClusterAddrListEnvVariableValue = "address-0.local,address-1.local,address-2.local";
925 expectGetEnvironmentString(dbClusterAddrListEnvVariableValue.c_str());
926
927 expectDbTypeConfigurationCheckAndApply("sdl-standalone-cluster");
928 expectDBServerAddressConfigurationCheckAndApply("address-0.local");
929 expectDBServerAddressConfigurationCheckAndApply("address-1.local");
930 expectDBServerAddressConfigurationCheckAndApply("address-2.local");
931 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::SDL_STANDALONE_CLUSTER);
932 initializeReaderWithoutDirectories();
933 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
934}
935
936TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithoutSentinelAndWithClusterConfigurationAndDbPort)
937{
938 InSequence dummy;
939 dbHostEnvVariableValue = "address-0.local";
940 expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
941 dbPortEnvVariableValue = "1111";
942 expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
943 expectGetEnvironmentString(nullptr); //SENTINEL_PORT_ENV_VAR_NAME
944 expectGetEnvironmentString(nullptr); //SENTINEL_MASTER_NAME_ENV_VAR_NAME
945 dbClusterAddrListEnvVariableValue = "address-0.local,address-1.local,address-2.local";
946 expectGetEnvironmentString(dbClusterAddrListEnvVariableValue.c_str());
947
948 expectDbTypeConfigurationCheckAndApply("sdl-standalone-cluster");
949 expectDBServerAddressConfigurationCheckAndApply("address-0.local:1111");
950 expectDBServerAddressConfigurationCheckAndApply("address-1.local:1111");
951 expectDBServerAddressConfigurationCheckAndApply("address-2.local:1111");
952 expectGetDbTypeAndWillOnceReturn(DatabaseConfiguration::DbType::SDL_STANDALONE_CLUSTER);
953 initializeReaderWithoutDirectories();
954 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
955}