Add Sentinel change notification handling logic
[ric-plt/sdl.git] / tst / configurationreader_test.cpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
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
17 #include <gtest/gtest.h>
18 #include <gmock/gmock.h>
19 #include <memory>
20 #include <boost/property_tree/ptree.hpp>
21 #include <boost/property_tree/json_parser.hpp>
22 #include "private/configurationreader.hpp"
23 #include "private/createlogger.hpp"
24 #include "private/logger.hpp"
25 #include "private/tst/databaseconfigurationmock.hpp"
26 #include "private/tst/gettopsrcdir.hpp"
27 #include "private/tst/namespaceconfigurationsmock.hpp"
28 #include "private/tst/systemmock.hpp"
29
30 using namespace shareddatalayer;
31 using namespace shareddatalayer::tst;
32 using namespace testing;
33
34 namespace
35 {
36     class ConfigurationReaderBaseTest: public testing::Test
37     {
38     public:
39         const std::string someKnownInputSource;
40         const Directories noDirectories;
41         DatabaseConfigurationMock databaseConfigurationMock;
42         NamespaceConfigurationsMock namespaceConfigurationsMock;
43         std::unique_ptr<ConfigurationReader> configurationReader;
44         SystemMock systemMock;
45         std::shared_ptr<Logger> logger;
46
47         ConfigurationReaderBaseTest(std::string inputSourceName):
48             someKnownInputSource(inputSourceName),
49             logger(createLogger(SDL_LOG_PREFIX))
50         {
51             EXPECT_CALL(databaseConfigurationMock, isEmpty()).WillRepeatedly(Return(true));
52             EXPECT_CALL(namespaceConfigurationsMock, isEmpty()).WillRepeatedly(Return(true));
53         }
54
55         void expectDbTypeConfigurationCheckAndApply(const std::string& type)
56         {
57             EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(type));
58         }
59
60         void expectDBServerAddressConfigurationCheckAndApply(const std::string& address)
61         {
62             EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(address));
63         }
64
65         void expectDatabaseConfigurationIsEmpty_returnFalse()
66         {
67             EXPECT_CALL(databaseConfigurationMock, isEmpty()).
68                 WillOnce(Return(false));
69         }
70
71         void tryToReadDatabaseConfigurationToNonEmptyContainer()
72         {
73             expectDatabaseConfigurationIsEmpty_returnFalse();
74             configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
75         }
76
77         void expectNamespaceConfigurationIsEmpty_returnFalse()
78         {
79             EXPECT_CALL(namespaceConfigurationsMock, isEmpty()).
80                 WillOnce(Return(false));
81         }
82
83         void tryToReadNamespaceConfigurationToNonEmptyContainer()
84         {
85             expectNamespaceConfigurationIsEmpty_returnFalse();
86             configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
87         }
88
89         void expectAddNamespaceConfiguration(const std::string&  namespacePrefix, bool useDbBackend,
90                                              bool enableNotifications)
91         {
92             NamespaceConfiguration expectedNamespaceConfiguration{namespacePrefix, useDbBackend,
93                                                                   enableNotifications,
94                                                                   someKnownInputSource};
95             EXPECT_CALL(namespaceConfigurationsMock, addNamespaceConfiguration(expectedNamespaceConfiguration));
96         }
97
98         void expectGetEnvironmentString(const char* returnValue)
99         {
100             EXPECT_CALL(systemMock, getenv(_))
101                 .WillOnce(Return(returnValue));
102         }
103
104         void initializeReaderWithoutDirectories()
105         {
106             configurationReader.reset(new ConfigurationReader(noDirectories, systemMock, logger));
107         }
108
109         void initializeReaderWithSDLconfigFileDirectory()
110         {
111             configurationReader.reset(new ConfigurationReader({getTopSrcDir() + "/conf"}, systemMock, logger));
112         }
113     };
114
115     class ConfigurationReaderSDLConfigFileTest: public ConfigurationReaderBaseTest
116     {
117     public:
118
119         ConfigurationReaderSDLConfigFileTest():
120             ConfigurationReaderBaseTest("ConfFileFromSDLrepo")
121         {
122             expectGetEnvironmentString(nullptr);
123             initializeReaderWithSDLconfigFileDirectory();
124         }
125     };
126
127     class ConfigurationReaderInputStreamTest: public ConfigurationReaderBaseTest
128     {
129     public:
130
131         ConfigurationReaderInputStreamTest():
132             ConfigurationReaderBaseTest("<istream>")
133         {
134             expectGetEnvironmentString(nullptr);
135             initializeReaderWithoutDirectories();
136         }
137
138         void readConfigurationAndExpectJsonParserException(const std::istringstream& is)
139         {
140             const std::string expectedError("error in SDL configuration <istream> at line 7: expected ':'");
141
142             EXPECT_THROW( {
143                 try
144                 {
145                     configurationReader->readConfigurationFromInputStream(is);
146                     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
147                     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
148                 }
149                 catch (const std::exception& e)
150                 {
151                     EXPECT_EQ(expectedError, e.what());
152                     throw;
153                 }
154             }, Exception);
155         }
156
157         void readConfigurationAndExpectBadValueException(const std::istringstream& is,
158                                                          const std::string& param)
159         {
160             std::ostringstream os;
161             os << "Configuration error in " << someKnownInputSource << ": "
162                << "invalid \"" << param << "\": \"bad-value\"";
163
164             EXPECT_THROW( {
165                 try
166                 {
167                     configurationReader->readConfigurationFromInputStream(is);
168                     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
169                     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
170                 }
171                 catch (const std::exception& e)
172                 {
173                     EXPECT_EQ(os.str(), e.what());
174                     throw;
175                 }
176             }, Exception);
177         }
178
179         void readConfigurationAndExpectDbTypeException(const std::istringstream& is)
180         {
181             std::ostringstream os;
182             os << "Configuration error in " << someKnownInputSource << ": some error";
183
184             EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(_))
185                 .WillOnce(Throw(Exception("some error")));
186
187             EXPECT_THROW( {
188                 try
189                 {
190                     configurationReader->readConfigurationFromInputStream(is);
191                     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
192                 }
193                 catch (const std::exception& e)
194                 {
195                     EXPECT_EQ(os.str(), e.what());
196                     throw;
197                 }
198             }, Exception);
199         }
200
201         void readConfigurationAndExpectAddressException(const std::istringstream& is,
202                                                         const std::string& addressValue)
203         {
204             std::ostringstream os;
205             os << "Configuration error in " << someKnownInputSource << ": "
206                << "invalid \"address\": \"" << addressValue << "\" some error";
207
208             EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(_))
209                 .WillOnce(Throw(Exception("some error")));
210
211             EXPECT_THROW( {
212                 try
213                 {
214                     configurationReader->readConfigurationFromInputStream(is);
215                     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
216                 }
217                 catch (const std::exception& e)
218                 {
219                     EXPECT_EQ(os.str(), e.what());
220                     throw;
221                 }
222             }, Exception);
223         }
224
225         void readConfigurationAndExpectMissingParameterException(const std::istringstream& is, const std::string& param)
226         {
227             std::ostringstream os;
228             os << "Configuration error in " << someKnownInputSource << ": "
229                << "missing \"" << param << "\"";
230
231             EXPECT_THROW( {
232                 try
233                 {
234                     configurationReader->readConfigurationFromInputStream(is);
235                     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
236                     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
237                 }
238                 catch (const std::exception& e)
239                 {
240                     EXPECT_EQ(os.str(), e.what());
241                     throw;
242                 }
243             }, Exception);
244         }
245
246         void readConfigurationAndExpectNamespacePrefixValidationException(const std::istringstream& is,
247                                                                           const std::string& namespacePrefix)
248         {
249             std::ostringstream os;
250             os << "Configuration error in " << someKnownInputSource << ": "
251                << "\"namespacePrefix\": \"" << namespacePrefix << "\""
252                << " contains some of these disallowed characters: ,{}";
253
254             EXPECT_THROW( {
255                 try
256                 {
257                     configurationReader->readConfigurationFromInputStream(is);
258                     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
259                 }
260                 catch (const std::exception& e)
261                 {
262                     EXPECT_EQ(os.str(), e.what() );
263                     throw;
264                 }
265             }, Exception);
266         }
267
268         void readConfigurationAndExpectEnableNotificationsValidationException(const std::istringstream& is)
269         {
270             std::ostringstream os;
271             os << "Configuration error in " << someKnownInputSource << ": "
272                << "\"enableNotifications\" cannot be true, when \"useDbBackend\" is false";
273
274             EXPECT_THROW( {
275                 try
276                 {
277                     configurationReader->readConfigurationFromInputStream(is);
278                     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
279                 }
280                 catch (const std::exception& e)
281                 {
282                     EXPECT_EQ(os.str(), e.what() );
283                     throw;
284                 }
285             }, Exception);
286         }
287
288     };
289 }
290
291 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfiguration)
292 {
293     InSequence dummy;
294     std::istringstream is(R"JSON(
295         {
296             "database":
297             {
298                 "type": "redis-standalone",
299                 "servers":
300                 [
301                     {
302                         "address": "someKnownDbAddress:65535"
303                     }
304                 ]
305             }
306         })JSON");
307     expectDbTypeConfigurationCheckAndApply("redis-standalone");
308     expectDBServerAddressConfigurationCheckAndApply("someKnownDbAddress:65535");
309     configurationReader->readConfigurationFromInputStream(is);
310     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
311 }
312
313 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfigurationWithMultipleServerAddresses)
314 {
315     InSequence dummy;
316     std::istringstream is(R"JSON(
317         {
318             "database":
319             {
320                 "type": "redis-cluster",
321                 "servers":
322                 [
323                     {
324                         "address": "10.20.30.40:50000"
325                     },
326                     {
327                         "address": "10.20.30.50:50001"
328                     }
329                 ]
330             }
331         })JSON");
332
333     expectDbTypeConfigurationCheckAndApply("redis-cluster");
334     expectDBServerAddressConfigurationCheckAndApply("10.20.30.40:50000");
335     expectDBServerAddressConfigurationCheckAndApply("10.20.30.50:50001");
336     configurationReader->readConfigurationFromInputStream(is);
337     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
338 }
339
340 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONDatabaseConfigurationWithMultipleReadOperations)
341 {
342     InSequence dummy;
343     std::istringstream isOne(R"JSON(
344         {
345             "database":
346             {
347                 "type": "redis-cluster",
348                 "servers":
349                 [
350                     {
351                         "address": "10.20.30.40:50000"
352                     }
353                 ]
354             }
355         })JSON");
356     std::istringstream isTwo(R"JSON(
357         {
358             "database":
359             {
360                 "type": "redis-cluster",
361                 "servers":
362                 [
363                     {
364                         "address": "10.20.30.50:50001"
365                     }
366                 ]
367             }
368         })JSON");
369
370     expectDbTypeConfigurationCheckAndApply("redis-cluster");
371     expectDBServerAddressConfigurationCheckAndApply("10.20.30.40:50000");
372     expectDbTypeConfigurationCheckAndApply("redis-cluster");
373     expectDBServerAddressConfigurationCheckAndApply("10.20.30.50:50001");
374     configurationReader->readConfigurationFromInputStream(isOne);
375     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
376     configurationReader->readConfigurationFromInputStream(isTwo);
377     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
378 }
379
380 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseTypeParameter)
381 {
382     InSequence dummy;
383     std::istringstream is(R"JSON(
384         {
385             "database":
386             {
387                 "servers":
388                 [
389                     {
390                         "address": "10.20.30.50:50001"
391                     }
392                 ]
393             }
394         })JSON");
395
396     readConfigurationAndExpectMissingParameterException(is, "type");
397 }
398
399 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseServersArray)
400 {
401     InSequence dummy;
402     std::istringstream is(R"JSON(
403         {
404             "database":
405             {
406                 "type": "redis-standalone"
407             }
408         })JSON");
409
410     expectDbTypeConfigurationCheckAndApply("redis-standalone");
411     readConfigurationAndExpectMissingParameterException(is, "servers");
412 }
413
414 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryDatabaseServerAddressParameter)
415 {
416     InSequence dummy;
417     std::istringstream is(R"JSON(
418         {
419             "database":
420             {
421                 "type": "redis-standalone",
422                 "servers":
423                 [
424                     {
425                     }
426                 ]
427             }
428         })JSON");
429
430     expectDbTypeConfigurationCheckAndApply("redis-standalone");
431     readConfigurationAndExpectMissingParameterException(is, "address");
432 }
433
434 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowDatabaseConfigurationDbTypeError)
435 {
436     InSequence dummy;
437     std::istringstream is(R"JSON(
438         {
439             "database":
440             {
441                 "type": "someBadType",
442                 "servers":
443                 [
444                     {
445                         "address": "10.20.30.50:50001"
446                     }
447                 ]
448             }
449         })JSON");
450
451     readConfigurationAndExpectDbTypeException(is);
452 }
453
454 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowDatabaseConfigurationAddressError)
455 {
456     InSequence dummy;
457     std::istringstream is(R"JSON(
458         {
459             "database":
460             {
461                 "type": "redis-standalone",
462                 "servers":
463                 [
464                     {
465                         "address": "someBadAddress"
466                     }
467                 ]
468             }
469         })JSON");
470
471     expectDbTypeConfigurationCheckAndApply("redis-standalone");
472     readConfigurationAndExpectAddressException(is, "someBadAddress");
473 }
474
475 TEST_F(ConfigurationReaderInputStreamTest, CanHandleJSONWithoutAnyConfiguration)
476 {
477     InSequence dummy;
478     std::istringstream is(R"JSON(
479         {
480         })JSON");
481
482     EXPECT_CALL(databaseConfigurationMock, checkAndApplyServerAddress(_))
483         .Times(0);
484     EXPECT_CALL(namespaceConfigurationsMock, addNamespaceConfiguration(_))
485         .Times(0);
486     configurationReader->readConfigurationFromInputStream(is);
487 }
488
489 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfiguration)
490 {
491     InSequence dummy;
492     std::istringstream is(R"JSON(
493         {
494             "sharedDataLayer":
495             [
496                 {
497                     "namespacePrefix": "someKnownNamespacePrefix",
498                     "useDbBackend": true,
499                     "enableNotifications": true
500                 },
501                 {
502                     "namespacePrefix": "anotherKnownNamespace",
503                     "useDbBackend": false,
504                     "enableNotifications": false
505                 }
506             ]
507         })JSON");
508
509     expectAddNamespaceConfiguration("anotherKnownNamespace", false, false);
510     expectAddNamespaceConfiguration("someKnownNamespacePrefix", true, true);
511     configurationReader->readConfigurationFromInputStream(is);
512     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
513 }
514
515 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfigurationWithMultipleReadOperations)
516 {
517     InSequence dummy;
518     std::istringstream isOne(R"JSON(
519         {
520             "sharedDataLayer":
521             [
522                 {
523                     "namespacePrefix": "someKnownNamespacePrefix",
524                     "useDbBackend": true,
525                     "enableNotifications": true
526                 }
527             ]
528         })JSON");
529
530     std::istringstream isTwo(R"JSON(
531         {
532             "sharedDataLayer":
533             [
534                 {
535                     "namespacePrefix": "anotherKnownNamespace",
536                     "useDbBackend": false,
537                     "enableNotifications": false
538                 }
539             ]
540         })JSON");
541
542     expectAddNamespaceConfiguration("someKnownNamespacePrefix", true, true);
543     expectAddNamespaceConfiguration("anotherKnownNamespace", false, false);
544     configurationReader->readConfigurationFromInputStream(isOne);
545     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
546     configurationReader->readConfigurationFromInputStream(isTwo);
547     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
548 }
549
550 TEST_F(ConfigurationReaderInputStreamTest, CanReadJSONSharedDataLayerConfigurationWithEmptyNamespacePrefixValue)
551 {
552     InSequence dummy;
553     std::istringstream is(R"JSON(
554         {
555             "sharedDataLayer":
556             [
557                 {
558                     "namespacePrefix": "",
559                     "useDbBackend": false,
560                     "enableNotifications": false
561                 }
562             ]
563         })JSON");
564
565     expectAddNamespaceConfiguration("", false, false);
566     configurationReader->readConfigurationFromInputStream(is);
567     configurationReader->readNamespaceConfigurations(namespaceConfigurationsMock);
568 }
569
570 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowJSONSyntaxError)
571 {
572     InSequence dummy;
573     std::istringstream is(R"JSON(
574         {
575             "sharedDataLayer":
576             [
577                 {
578                     "abc"
579                 }
580             ]
581         })JSON");
582
583     readConfigurationAndExpectJsonParserException(is);
584 }
585
586 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowParameterUseDbBackendBadValue)
587 {
588     InSequence dummy;
589     std::istringstream is(R"JSON(
590         {
591             "sharedDataLayer":
592             [
593                 {
594                     "namespacePrefix": "someKnownNamespacePrefix",
595                     "useDbBackend": "bad-value",
596                     "enableNotifications": false
597                 }
598             ]
599         })JSON");
600
601     readConfigurationAndExpectBadValueException(is, "useDbBackend");
602 }
603
604 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowParameterEnableNotificationsBadValue)
605 {
606     InSequence dummy;
607     std::istringstream is(R"JSON(
608         {
609             "sharedDataLayer":
610             [
611                 {
612                     "namespacePrefix": "someKnownNamespacePrefix",
613                     "useDbBackend": true,
614                     "enableNotifications": "bad-value"
615                 }
616             ]
617         })JSON");
618
619     readConfigurationAndExpectBadValueException(is, "enableNotifications");
620 }
621
622 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryNamespacePrefixParameter)
623 {
624     InSequence dummy;
625     std::istringstream is(R"JSON(
626         {
627             "sharedDataLayer":
628             [
629                 {
630                     "useDbBackend": true,
631                     "enableNotifications": true
632                 }
633             ]
634         })JSON");
635
636     readConfigurationAndExpectMissingParameterException(is, "namespacePrefix");
637 }
638
639 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryUseDbBackendParameter)
640 {
641     InSequence dummy;
642     std::istringstream is(R"JSON(
643         {
644             "sharedDataLayer":
645             [
646                 {
647                     "namespacePrefix": "someKnownNamespacePrefix",
648                     "enableNotifications": true
649                 }
650             ]
651         })JSON");
652
653     readConfigurationAndExpectMissingParameterException(is, "useDbBackend");
654 }
655
656 TEST_F(ConfigurationReaderInputStreamTest, CanCatchAndThrowMisingMandatoryEnableNotificationsParameter)
657 {
658     InSequence dummy;
659     std::istringstream is(R"JSON(
660         {
661             "sharedDataLayer":
662             [
663                 {
664                     "namespacePrefix": "someKnownNamespacePrefix",
665                     "useDbBackend": true
666                 }
667             ]
668         })JSON");
669
670     readConfigurationAndExpectMissingParameterException(is, "enableNotifications");
671 }
672
673 TEST_F(ConfigurationReaderInputStreamTest, CanThrowValidationErrorForNamespacePrefixWithDisallowedCharacters)
674 {
675     InSequence dummy;
676     std::istringstream is(R"JSON(
677         {
678             "sharedDataLayer":
679             [
680                 {
681                     "namespacePrefix": "a,b{c}",
682                     "useDbBackend": true,
683                     "enableNotifications": true
684                 }
685             ]
686         })JSON");
687
688     readConfigurationAndExpectNamespacePrefixValidationException(is, "a,b{c}");
689 }
690
691 TEST_F(ConfigurationReaderInputStreamTest, CanThrowValidationErrorForEnableNotificationsWithNoDbBackend)
692 {
693     InSequence dummy;
694     std::istringstream is(R"JSON(
695         {
696             "sharedDataLayer":
697             [
698                 {
699                     "namespacePrefix": "someKnownNamespacePrefix",
700                     "useDbBackend": false,
701                     "enableNotifications": true
702                 }
703             ]
704         })JSON");
705
706     readConfigurationAndExpectEnableNotificationsValidationException(is);
707 }
708
709 TEST_F(ConfigurationReaderInputStreamTest, WillNotReadDatabaseConfigurationToNonEmptyContainer)
710 {
711     EXPECT_EXIT(tryToReadDatabaseConfigurationToNonEmptyContainer(),
712         KilledBySignal(SIGABRT), "ABORT.*configurationreader\\.cpp");
713 }
714
715 TEST_F(ConfigurationReaderInputStreamTest, WillNotReadNamespaceConfigurationToNonEmptyContainer)
716 {
717     EXPECT_EXIT(tryToReadNamespaceConfigurationToNonEmptyContainer(),
718         KilledBySignal(SIGABRT), "ABORT.*configurationreader\\.cpp");
719 }
720
721 class ConfigurationReaderEnvironmentVariableTest: public ConfigurationReaderBaseTest
722 {
723 public:
724     std::string dbHostEnvVariableValue;
725     std::string dbPortEnvVariableValue;
726     std::istringstream is{R"JSON(
727         {
728             "database":
729             {
730                 "type": "redis-cluster",
731                 "servers":
732                 [
733                     {
734                         "address": "10.20.30.40:50000"
735                     },
736                     {
737                         "address": "10.20.30.50:50001"
738                     }
739                 ]
740             }
741         })JSON"};
742
743     ConfigurationReaderEnvironmentVariableTest():
744         ConfigurationReaderBaseTest(DB_HOST_ENV_VAR_NAME)
745     {
746     }
747
748     void readEnvironmentConfigurationAndExpectConfigurationErrorException()
749     {
750         std::ostringstream os;
751         os << "Configuration error in " << someKnownInputSource << ": some error";
752
753         EXPECT_CALL(databaseConfigurationMock, checkAndApplyDbType(_))
754             .WillOnce(Throw(Exception("some error")));
755
756         EXPECT_THROW( {
757             try
758             {
759                 EXPECT_CALL(systemMock, getenv(_))
760                                     .Times(2)
761                     .WillOnce(Return(dbHostEnvVariableValue.c_str()))
762                     .WillOnce(Return(nullptr));
763                 initializeReaderWithoutDirectories();
764                 configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
765             }
766             catch (const std::exception& e)
767             {
768                 EXPECT_EQ(os.str(), e.what());
769                 throw;
770             }
771         }, Exception);
772     }
773 };
774
775 TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationCanOverrideJSONDatabaseConfiguration)
776 {
777     InSequence dummy;
778     dbHostEnvVariableValue = "unknownAddress.local";
779     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
780     dbPortEnvVariableValue = "12345";
781     expectGetEnvironmentString(dbPortEnvVariableValue.c_str());
782
783     expectDbTypeConfigurationCheckAndApply("redis-standalone");
784     expectDBServerAddressConfigurationCheckAndApply("unknownAddress.local:12345");
785     initializeReaderWithSDLconfigFileDirectory();
786     configurationReader->readConfigurationFromInputStream(is);
787     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
788 }
789
790 TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationWithoutPortIsAccepted)
791 {
792     InSequence dummy;
793     dbHostEnvVariableValue = "server.local";
794     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
795     expectGetEnvironmentString(nullptr);
796
797     expectDbTypeConfigurationCheckAndApply("redis-standalone");
798     expectDBServerAddressConfigurationCheckAndApply("server.local");
799     initializeReaderWithoutDirectories();
800     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
801 }
802
803 TEST_F(ConfigurationReaderEnvironmentVariableTest, EmptyEnvironmentVariableThrows)
804 {
805     dbHostEnvVariableValue = "";
806     readEnvironmentConfigurationAndExpectConfigurationErrorException();
807 }
808
809 TEST_F(ConfigurationReaderEnvironmentVariableTest, IllegalCharacterInEnvironmentVariableThrows)
810 {
811     dbHostEnvVariableValue = "@";
812     readEnvironmentConfigurationAndExpectConfigurationErrorException();
813 }
814
815 TEST_F(ConfigurationReaderEnvironmentVariableTest, EnvironmentConfigurationAcceptIPv6Address)
816 {
817     InSequence dummy;
818     dbHostEnvVariableValue = "[2001::123]:12345";
819     expectGetEnvironmentString(dbHostEnvVariableValue.c_str());
820     expectGetEnvironmentString(nullptr);
821
822     expectDbTypeConfigurationCheckAndApply("redis-standalone");
823     expectDBServerAddressConfigurationCheckAndApply("[2001::123]:12345");
824     initializeReaderWithoutDirectories();
825     configurationReader->readDatabaseConfiguration(databaseConfigurationMock);
826 }