1 #include "../common/certs.hpp"
2 #include "root_path.hpp"
3
4 #include <pxp-agent/configuration.hpp>
5
6 #include "horsewhisperer/horsewhisperer.h"
7
8 #include <leatherman/util/scope_exit.hpp>
9
10 #define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.configuration_test"
11 #include <leatherman/logging/logging.hpp>
12
13 #include <boost/filesystem/operations.hpp>
14 #include <boost/filesystem/path.hpp>
15
16 #include <catch.hpp>
17
18 #include <string>
19 #include <vector>
20
21 #define ARGUMENT_COUNT(argv) (sizeof(argv)/sizeof((argv)[0]) - 1)
22
23 using namespace PXPAgent;
24
25 namespace fs = boost::filesystem;
26 namespace HW = HorseWhisperer;
27 namespace lth_log = leatherman::logging;
28 namespace lth_util = leatherman::util;
29
30 static const std::string CONFIG { std::string { PXP_AGENT_ROOT_PATH }
31 + "/lib/tests/resources/config/empty-pxp-agent.conf" };
32 static const std::string MULTI_BROKER_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
33 + "/lib/tests/resources/config/multi-broker.conf" };
34 static const std::string MULTI_URI_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
35 + "/lib/tests/resources/config/multi-broker-both-uris.conf" };
36 static const std::string MASTER_URI_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
37 + "/lib/tests/resources/config/multi-broker-master-uris.conf" };
38 static const std::string DUPLICATE_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
39 + "/lib/tests/resources/config/duplicate.conf" };
40 static const std::string BAD_BROKER_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
41 + "/lib/tests/resources/config/bad-broker.conf" };
42 static const std::string BAD_MASTER_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
43 + "/lib/tests/resources/config/bad-master.conf" };
44 static const std::string INVALID_CONFIG_NAME { std::string { PXP_AGENT_ROOT_PATH }
45 + "/lib/tests/resources/config/foo.cfg" };
46 static const std::string UNKNOWN_CONFIG { std::string { PXP_AGENT_ROOT_PATH }
47 + "/lib/tests/resources/config/unknown.conf" };
48 static const std::string TEST_BROKER_WS_URI { "wss:///test_c_t_h_u_n_broker" };
49 static const std::string CA { getCaPath() };
50 static const std::string CERT { getCertPath() };
51 static const std::string KEY { getKeyPath() };
52 static const std::string CRL { getCrlPath() };
53 static const std::string MODULES_DIR { std::string { PXP_AGENT_ROOT_PATH }
54 + "/lib/tests/resources/modules/" };
55 static const std::string MODULES_CONFIG_DIR { std::string { PXP_AGENT_ROOT_PATH }
56 + "/lib/tests/resources/modules_config" };
57 static const std::string SPOOL_DIR { std::string { PXP_AGENT_ROOT_PATH }
58 + "/lib/tests/resources/test_spool" };
59 static const std::string TASK_CACHE_DIR { std::string { PXP_AGENT_ROOT_PATH }
60 + "/lib/tests/resources/test_task_cache" };
61 static const std::string DIR_PURGE_TTL { "1h" };
62
63 static const char* ARGV[] = {
64 "test-command",
65 "--config-file", CONFIG.c_str(),
66 "--broker-ws-uri", TEST_BROKER_WS_URI.c_str(),
67 "--pcp-version=2",
68 "--ssl-ca-cert", CA.c_str(),
69 "--ssl-cert", CERT.c_str(),
70 "--ssl-key", KEY.c_str(),
71 "--ssl-crl", CRL.c_str(),
72 "--modules-dir", MODULES_DIR.c_str(),
73 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
74 "--spool-dir", SPOOL_DIR.c_str(),
75 "--spool-dir-purge-ttl", DIR_PURGE_TTL.c_str(),
76 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
77 "--task-cache-dir-purge-ttl", DIR_PURGE_TTL.c_str(),
78 "--task-download-connect-timeout", "5",
79 "--task-download-timeout", "120",
80 "--foreground=true",
81 nullptr };
82
configureTest()83 static void configureTest() {
84 if (!fs::exists(SPOOL_DIR) && !fs::create_directories(SPOOL_DIR)) {
85 FAIL("Failed to create the results directory");
86 }
87 if (!fs::exists(TASK_CACHE_DIR) && !fs::create_directories(TASK_CACHE_DIR)) {
88 FAIL("Failed to create the task cache directory");
89 }
90 if (!fs::exists(MODULES_CONFIG_DIR) && !fs::create_directories(MODULES_CONFIG_DIR)) {
91 FAIL("Failed to create the modules configuration directory");
92 }
93 Configuration::Instance().initialize(
94 [](std::vector<std::string>) {
95 return EXIT_SUCCESS;
96 });
97 }
98
resetTest()99 static void resetTest() {
100 if (fs::exists(SPOOL_DIR)) {
101 fs::remove_all(SPOOL_DIR);
102 }
103 if (fs::exists(TASK_CACHE_DIR)) {
104 fs::remove_all(TASK_CACHE_DIR);
105 }
106 if (fs::exists(MODULES_CONFIG_DIR)) {
107 fs::remove_all(MODULES_CONFIG_DIR);
108 }
109 }
110
111 TEST_CASE("Configuration - metatest", "[configuration]") {
112 lth_util::scope_exit config_cleaner { resetTest };
113
114 SECTION("Metatest - can initialize Configuration") {
115 resetTest();
116 REQUIRE_NOTHROW(configureTest());
117 }
118
119 SECTION("Metatest - we can inject CL options into HorseWhisperer") {
120 configureTest();
121 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
122 REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == CA);
123 REQUIRE(HW::GetFlag<std::string>("modules-dir") == MODULES_DIR);
124 REQUIRE(HW::GetFlag<std::string>("spool-dir") == SPOOL_DIR);
125 }
126 }
127
128 TEST_CASE("Configuration::initialize()", "[configuration]") {
129 lth_util::scope_exit config_cleaner { resetTest };
130
131 SECTION("No error when starting without setting a function") {
132 REQUIRE_NOTHROW(HW::Start());
133 }
134
135 SECTION("It does set HorseWhisperer's action correctly") {
136 Configuration::Instance().initialize(
__anoncd1ded380202(std::vector<std::string> arg) 137 [] (std::vector<std::string> arg) -> int {
138 return 42;
139 });
140 const char* args[] = { "pxp-agent", "start", nullptr };
141 HW::Parse(2, const_cast<char**>(args));
142
143 REQUIRE(HW::Start() == 42);
144 }
145 }
146
147 TEST_CASE("Configuration::set", "[configuration]") {
148 configureTest();
149 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
150 Configuration::Instance().validate();
151 lth_util::scope_exit config_cleaner { resetTest };
152
153 SECTION("can set a known flag to a valid value") {
154 REQUIRE_NOTHROW(Configuration::Instance().set<std::string>("ssl-ca-cert",
155 "value"));
156 }
157
158 SECTION("set a flag correctly") {
159 Configuration::Instance().set<std::string>("ssl-ca-cert", "value");
160 REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == "value");
161 }
162
163 SECTION("throw when setting an unknown flag") {
164 REQUIRE_THROWS_AS(Configuration::Instance()
165 .set<int>("tentacle_spawning_interval_s", 45),
166 Configuration::Error);
167 }
168
169 SECTION("throw when setting a known flag to an invalid value") {
170 HW::DefineGlobalFlag<int>("num_tentacles",
171 "number of spawn tentacles",
172 8,
__anoncd1ded380302(int v) 173 [](int v) {
174 if (v != 8) {
175 throw HW::flag_validation_error { "bad!" };
176 }
177 });
178
179 // The only valid number of tentacles is 8
180 REQUIRE_THROWS_AS(Configuration::Instance().set<int>("num_tentacles", 42),
181 Configuration::Error);
182 REQUIRE_NOTHROW(Configuration::Instance().set<int>("num_tentacles", 8));
183 }
184 }
185
186 TEST_CASE("Configuration::get", "[configuration]") {
187 lth_util::scope_exit config_cleaner { resetTest };
188 configureTest();
189
190 SECTION("When options were not parsed and validated yet") {
191 SECTION("can get a defined flag") {
192 REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
193 }
194
195 SECTION("return the default value correctly") {
196 REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
197 == DEFAULT_SPOOL_DIR);
198 }
199
200 SECTION("throw a Configuration::Error if the flag is unknown") {
201 REQUIRE_THROWS_AS(
202 Configuration::Instance().get<std::string>("dont_exist"),
203 Configuration::Error);
204 }
205 }
206
207 SECTION("After parsing and validating options") {
208 configureTest();
209
210 SECTION("can get a defined flag") {
211 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
212 Configuration::Instance().validate();
213 REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
214 }
215
216 SECTION("return the default value if the flag was not set") {
217 // NB: ignoring --foreground in ARGV since argc is set to 19
218 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV) - 1, const_cast<char**>(ARGV));
219 #ifndef _WIN32
220 HW::SetFlag<std::string>("pidfile", SPOOL_DIR + "/test.pid");
221 #endif
222 Configuration::Instance().validate();
223
224 REQUIRE_FALSE(Configuration::Instance().get<bool>("foreground"));
225 }
226
227 SECTION("return the correct value after the flag has been set") {
228 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
229 Configuration::Instance().validate();
230 Configuration::Instance().set<std::string>("spool-dir", "/fake/dir");
231 REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
232 == "/fake/dir");
233 }
234
235 SECTION("throw a Configuration::Error if the flag is unknown") {
236 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
237 Configuration::Instance().validate();
238 REQUIRE_THROWS_AS(
239 Configuration::Instance().get<std::string>("still_dont_exist"),
240 Configuration::Error);
241 }
242 }
243 }
244
245 TEST_CASE("Configuration::validate", "[configuration]") {
246 lth_util::scope_exit config_cleaner { resetTest };
247 configureTest();
248 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
249
250 SECTION("it throws an Error when the broker WebSocket URI is undefined") {
251 HW::SetFlag<std::string>("broker-ws-uri", "");
252 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
253 Configuration::Error);
254 }
255
256 SECTION("it throws an Error when the broker WebSocket URi is invalid") {
257 HW::SetFlag<std::string>("broker-ws-uri", "ws://");
258 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
259 Configuration::Error);
260 }
261
262 SECTION("it throws an Error when the PCP version is invalid") {
263 HW::SetFlag<std::string>("pcp-version", "3");
264 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
265 Configuration::Error);
266 }
267
268 SECTION("it throws an Error ssl-ca-cert is undefined") {
269 HW::SetFlag<std::string>("ssl-ca-cert", "");
270 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
271 Configuration::Error);
272 }
273
274 SECTION("it throws an Error when ssl-ca-cert file cannot be found") {
275 HW::SetFlag<std::string>("ssl-ca-cert", "/fake/file");
276 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
277 Configuration::Error);
278 }
279
280 SECTION("it throws an Error when ssl-ca-cert file is not "
281 "readable (is a directory)") {
282 HW::SetFlag<std::string>("ssl-ca-cert", "/fake");
283 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
284 Configuration::Error);
285 }
286
287 SECTION("it throws an Error when ssl-cert is undefined") {
288 HW::SetFlag<std::string>("ssl-cert", "");
289 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
290 Configuration::Error);
291 }
292
293 SECTION("it throws an Error when ssl-cert file cannot be found") {
294 HW::SetFlag<std::string>("ssl-cert", "/fake/file");
295 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
296 Configuration::Error);
297 }
298
299 SECTION("it throws an Error when ssl-cert file is not "
300 "readable (is a directory)") {
301 HW::SetFlag<std::string>("ssl-cert", "/fake");
302 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
303 Configuration::Error);
304 }
305
306 SECTION("it throws an Error when ssl-key is undefined") {
307 HW::SetFlag<std::string>("ssl-key", "");
308 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
309 Configuration::Error);
310 }
311
312 SECTION("it throws an Error when ssl-key file cannot be found") {
313 HW::SetFlag<std::string>("ssl-key", "/fake/file");
314 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
315 Configuration::Error);
316 }
317
318 SECTION("it throws an Error when ssl-key file is not "
319 "readable (is a directory)") {
320 HW::SetFlag<std::string>("ssl-key", "/fake");
321 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
322 Configuration::Error);
323 }
324
325 SECTION("it fails when --modules-dir does not exist") {
326 auto test_modules = SPOOL_DIR + "/testing_modules";
327 HW::SetFlag<std::string>("modules-dir", test_modules);
328 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
329 Configuration::Error);
330 }
331
332 SECTION("it fails when --modules-config-dir is not a directory") {
333 HW::SetFlag<std::string>("modules-dir", CONFIG);
334 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
335 Configuration::Error);
336 }
337
338 SECTION("it fails when --task-cache-dir is empty") {
339 HW::SetFlag<std::string>("task-cache-dir", "");
340 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
341 Configuration::Error);
342 }
343
344 SECTION("it fails when --task-cache-dir exists but is not a directory") {
345 HW::SetFlag<std::string>("task-cache-dir", CONFIG);
346 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
347 Configuration::Error);
348 }
349
350 SECTION("it creates --task-cache-dir when needed and with the right permissions") {
351 auto test_task_cache_dir = TASK_CACHE_DIR + "/testing_creation";
352 HW::SetFlag<std::string>("task-cache-dir", test_task_cache_dir);
353
354 REQUIRE_FALSE(fs::exists(test_task_cache_dir));
355 REQUIRE_NOTHROW(Configuration::Instance().validate());
356 REQUIRE(fs::exists(test_task_cache_dir));
357 #ifndef _WIN32
358 REQUIRE(fs::status(test_task_cache_dir).permissions() == 0750);
359 #else
360 REQUIRE(fs::status(test_task_cache_dir).permissions() == 0666);
361 #endif
362
363 fs::remove_all(test_task_cache_dir);
364 }
365
366 SECTION("it fails when -task-cache-dir-purge-ttl as not a valid timestamp") {
367 HW::SetFlag<std::string>("task-cache-dir-purge-ttl", "1.0");
368 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
369 Configuration::Error);
370 }
371
372 SECTION("it fails when --spool-dir is empty") {
373 HW::SetFlag<std::string>("spool-dir", "");
374 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
375 Configuration::Error);
376 }
377
378 SECTION("it fails when --spool-dir exists but is not a directory") {
379 HW::SetFlag<std::string>("spool-dir", CONFIG);
380 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
381 Configuration::Error);
382 }
383
384 SECTION("it creates --spool-dir when needed") {
385 auto test_spool = SPOOL_DIR + "/testing_creation";
386 HW::SetFlag<std::string>("spool-dir", test_spool);
387
388 REQUIRE_FALSE(fs::exists(test_spool));
389 REQUIRE_NOTHROW(Configuration::Instance().validate());
390 REQUIRE(fs::exists(test_spool));
391
392 fs::remove_all(test_spool);
393 }
394
395 SECTION("it fails when --spool-dir-purge-ttl as not a valid timestamp") {
396 HW::SetFlag<std::string>("spool-dir-purge-ttl", "1.0");
397 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
398 Configuration::Error);
399 }
400
401 SECTION("it fails when --task-download-connect-timeout is negative") {
402 HW::SetFlag<int>("task-download-connect-timeout", -1);
403 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
404 Configuration::Error);
405 }
406
407 SECTION("it fails when --task-download-timeout is negative") {
408 HW::SetFlag<int>("task-download-timeout", -1);
409 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
410 Configuration::Error);
411 }
412 }
413
414 TEST_CASE("Configuration::validate with unknown config options", "[configuration]") {
415 const char* altArgv[] = {
416 "test-command",
417 "--config-file", UNKNOWN_CONFIG.c_str(),
418 "--ssl-ca-cert", CA.c_str(),
419 "--ssl-cert", CERT.c_str(),
420 "--ssl-key", KEY.c_str(),
421 "--ssl-crl", CRL.c_str(),
422 "--modules-dir", MODULES_DIR.c_str(),
423 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
424 "--spool-dir", SPOOL_DIR.c_str(),
425 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
426 "--foreground=true",
427 nullptr };
428
429 lth_util::scope_exit config_cleaner { resetTest };
430 configureTest();
431 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
432
433 SECTION("it validates") {
434 REQUIRE_NOTHROW(Configuration::Instance().validate());
435 }
436 }
437
438 TEST_CASE("Configuration::validate multiple brokers", "[configuration]") {
439 const char* altArgv[] = {
440 "test-command",
441 "--config-file", MULTI_BROKER_CONFIG.c_str(),
442 "--ssl-ca-cert", CA.c_str(),
443 "--ssl-cert", CERT.c_str(),
444 "--ssl-key", KEY.c_str(),
445 "--ssl-crl", CRL.c_str(),
446 "--modules-dir", MODULES_DIR.c_str(),
447 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
448 "--spool-dir", SPOOL_DIR.c_str(),
449 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
450 "--foreground=true",
451 nullptr };
452
453 lth_util::scope_exit config_cleaner { resetTest };
454 configureTest();
455 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
456
457 SECTION("it allows broker-ws-uris in place of broker-ws-uri") {
458 HW::SetFlag<std::string>("broker-ws-uri", TEST_BROKER_WS_URI);
459 REQUIRE_NOTHROW(Configuration::Instance().validate());
460 auto uris = Configuration::Instance().get_broker_ws_uris();
461 REQUIRE(uris == std::vector<std::string>({TEST_BROKER_WS_URI}));
462 }
463
464 SECTION("it parses multiple arguments to broker-ws-uris") {
465 REQUIRE_NOTHROW(Configuration::Instance().validate());
466 auto uris = Configuration::Instance().get_broker_ws_uris();
467 REQUIRE(uris == std::vector<std::string>({"wss://test_pcp_broker", "wss://alt_pcp_broker"}));
468 }
469
470 SECTION("it parses multiple arguments to primary-uris") {
471 REQUIRE_NOTHROW(Configuration::Instance().validate());
472 auto uris = Configuration::Instance().get_primary_uris();
473 REQUIRE(uris == std::vector<std::string>({"https://test_master:8140", "https://alt_master:8140"}));
474 }
475 }
476
477 TEST_CASE("Configuration::validate primary-uris precedence", "[configuration]") {
478 const char* altArgv[] = {
479 "test-command",
480 "--config-file", MULTI_URI_CONFIG.c_str(),
481 "--ssl-ca-cert", CA.c_str(),
482 "--ssl-cert", CERT.c_str(),
483 "--ssl-key", KEY.c_str(),
484 "--modules-dir", MODULES_DIR.c_str(),
485 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
486 "--spool-dir", SPOOL_DIR.c_str(),
487 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
488 "--foreground=true",
489 nullptr };
490
491 lth_util::scope_exit config_cleaner { resetTest };
492 configureTest();
493 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
494
495 SECTION("primary-uris takes precedence over master-uris") {
496 REQUIRE_NOTHROW(Configuration::Instance().validate());
497 auto uris = Configuration::Instance().get_primary_uris();
498 REQUIRE(uris == std::vector<std::string>({"https://test_master:8140", "https://alt_master_one:8140", "https://alt_master_two:8140"}));
499 }
500 }
501
502 TEST_CASE("Configuration::validate deprecated master-uris works when no primary-uris", "[configuration]") {
503 const char* altArgv[] = {
504 "test-command",
505 "--config-file", MASTER_URI_CONFIG.c_str(),
506 "--ssl-ca-cert", CA.c_str(),
507 "--ssl-cert", CERT.c_str(),
508 "--ssl-key", KEY.c_str(),
509 "--modules-dir", MODULES_DIR.c_str(),
510 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
511 "--spool-dir", SPOOL_DIR.c_str(),
512 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
513 "--foreground=true",
514 nullptr };
515
516 lth_util::scope_exit config_cleaner { resetTest };
517 configureTest();
518 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
519
520 SECTION("it parses multiple arguments to master-uris when primary-uris not present") {
521 REQUIRE_NOTHROW(Configuration::Instance().validate());
522 auto uris = Configuration::Instance().get_primary_uris();
523 REQUIRE(uris == std::vector<std::string>({"https://test_master:8140", "https://alt_master:8140"}));
524 }
525 }
526
527 TEST_CASE("Configuration::parseOptions duplicate broker-ws-uris", "[configuration]") {
528 const char* altArgv[] = {
529 "test-command",
530 "--config-file", DUPLICATE_CONFIG.c_str(),
531 "--ssl-ca-cert", CA.c_str(),
532 "--ssl-cert", CERT.c_str(),
533 "--ssl-key", KEY.c_str(),
534 "--ssl-crl", CRL.c_str(),
535 "--modules-dir", MODULES_DIR.c_str(),
536 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
537 "--spool-dir", SPOOL_DIR.c_str(),
538 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
539 "--foreground=true",
540 nullptr };
541
542 lth_util::scope_exit config_cleaner { resetTest };
543 configureTest();
544
545 SECTION("it throws an Error when broker-ws-uri and broker-ws-uris are defined") {
546 REQUIRE_THROWS_AS(Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv)),
547 Configuration::Error);
548 }
549 }
550
551 TEST_CASE("Configuration::parseOptions invalid config-file name", "[configuration]") {
552 const char* altArgv[] = {
553 "test-command",
554 "--config-file", INVALID_CONFIG_NAME.c_str(),
555 "--ssl-ca-cert", CA.c_str(),
556 "--ssl-cert", CERT.c_str(),
557 "--ssl-key", KEY.c_str(),
558 "--ssl-crl", CRL.c_str(),
559 "--modules-dir", MODULES_DIR.c_str(),
560 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
561 "--spool-dir", SPOOL_DIR.c_str(),
562 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
563 "--foreground=true",
564 nullptr };
565
566 lth_util::scope_exit config_cleaner { resetTest };
567 configureTest();
568
569 SECTION("it throws an Error when config-file is invalid") {
570 REQUIRE_THROWS_AS(Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv)),
571 Configuration::Error);
572 }
573 }
574
575 TEST_CASE("Configuration::validate bad broker-ws-uris", "[configuration]") {
576 const char* altArgv[] = {
577 "test-command",
578 "--config-file", BAD_BROKER_CONFIG.c_str(),
579 "--ssl-ca-cert", CA.c_str(),
580 "--ssl-cert", CERT.c_str(),
581 "--ssl-key", KEY.c_str(),
582 "--ssl-crl", CRL.c_str(),
583 "--modules-dir", MODULES_DIR.c_str(),
584 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
585 "--spool-dir", SPOOL_DIR.c_str(),
586 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
587 "--foreground=true",
588 nullptr };
589
590 lth_util::scope_exit config_cleaner { resetTest };
591 configureTest();
592 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
593
594 SECTION("it throws an Error when broker-ws-uris is invalid") {
595 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
596 Configuration::Error);
597 }
598 }
599
600 TEST_CASE("Configuration::validate bad master-uris", "[configuration]") {
601 const char* altArgv[] = {
602 "test-command",
603 "--config-file", BAD_MASTER_CONFIG.c_str(),
604 "--ssl-ca-cert", CA.c_str(),
605 "--ssl-cert", CERT.c_str(),
606 "--ssl-key", KEY.c_str(),
607 "--ssl-crl", CRL.c_str(),
608 "--modules-dir", MODULES_DIR.c_str(),
609 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
610 "--spool-dir", SPOOL_DIR.c_str(),
611 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
612 "--foreground=true",
613 nullptr };
614
615 lth_util::scope_exit config_cleaner { resetTest };
616 configureTest();
617 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
618
619 SECTION("it throws an Error when master-uris is invalid") {
620 REQUIRE_THROWS_AS(Configuration::Instance().validate(),
621 Configuration::Error);
622 }
623 }
624
625 TEST_CASE("Configuration::setupLogging", "[configuration]") {
626 lth_util::scope_exit config_cleaner { resetTest };
627 configureTest();
628 Configuration::Instance().parseOptions(ARGUMENT_COUNT(ARGV), const_cast<char**>(ARGV));
629 Configuration::Instance().validate();
630
631 #ifndef _WIN32
632 SECTION("it sets log level to info by default") {
633 // NOTE(ale): we cannot test this on Windows because it won't
634 // allow us to delete the SPOOL_DIR while test.log is open
635 Configuration::Instance().set<std::string>("logfile", SPOOL_DIR + "/test.log");
636 Configuration::Instance().setupLogging();
637 REQUIRE(lth_log::get_level() == lth_log::log_level::info);
638 }
639
640 SECTION("it sets log level to none if foreground is unflagged and logfile "
641 "is set to stdout") {
642 Configuration::Instance().set<bool>("foreground", false);
643 Configuration::Instance().set<std::string>("logfile", "-");
644 Configuration::Instance().setupLogging();
645
646 REQUIRE(lth_log::get_level() == lth_log::log_level::none);
647 }
648 #endif
649 }
650
651 TEST_CASE("Configuration::validate without ssl-crl (is optional)", "[configuration]") {
652 const char* altArgv[] = {
653 "test-command",
654 "--config-file", UNKNOWN_CONFIG.c_str(),
655 "--ssl-ca-cert", CA.c_str(),
656 "--ssl-cert", CERT.c_str(),
657 "--ssl-key", KEY.c_str(),
658 "--modules-dir", MODULES_DIR.c_str(),
659 "--modules-config-dir", MODULES_CONFIG_DIR.c_str(),
660 "--spool-dir", SPOOL_DIR.c_str(),
661 "--task-cache-dir", TASK_CACHE_DIR.c_str(),
662 "--foreground=true",
663 nullptr };
664
665 lth_util::scope_exit config_cleaner { resetTest };
666 configureTest();
667 Configuration::Instance().parseOptions(ARGUMENT_COUNT(altArgv), const_cast<char**>(altArgv));
668
669 SECTION("it validates") {
670 REQUIRE_NOTHROW(Configuration::Instance().validate());
671 }
672 }
673