v31.1-roots.1 · Commit 7: [PATCH 07/17] feat(rpc): preserve Roots operator interfaces on v31
src/test/getarg_tests.cpp
Before: src/test/getarg_tests.cpp · After: src/test/getarg_tests.cpp
File metadata
index d349ceea44b6bae8d7ce76bcb2d866394112bfcc..f2c9df2701a2ce614b2c5b727cdd7f9a5537a1b9 100644
Download original patch · Release notes
Diff rows 1–227 of 227. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. The two line-number columns refer to before and after.
src/test/getarg_tests.cpp
CHANGED
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
#include <univalue.h>
|
|
11
11
|
#include <util/strencodings.h>
|
|
12
12
|
|
|
13
|
+
#include <fstream>
|
|
13
14
|
#include <limits>
|
|
15
|
+
#include <sstream>
|
|
16
|
+
#include <streambuf>
|
|
14
17
|
#include <string>
|
|
15
18
|
#include <utility>
|
|
16
19
|
#include <vector>
|
|
@@ -48,6 +51,43 @@ void SetupArgs(ArgsManager& local_args, const std::vector<std::pair<std::string,
|
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
namespace {
|
|
55
|
+
// Report a real I/O failure after a chosen number of bytes, optionally only
|
|
56
|
+
// after the formatter rewinds to copy an invalid file into comments.
|
|
57
|
+
class FailingConfigBuffer : public std::streambuf {
|
|
58
|
+
std::string m_text;
|
|
59
|
+
size_t m_position{0};
|
|
60
|
+
size_t m_fail_at;
|
|
61
|
+
bool m_fail_after_rewind;
|
|
62
|
+
bool m_rewound{false};
|
|
63
|
+
|
|
64
|
+
int_type underflow() override
|
|
65
|
+
{
|
|
66
|
+
if (m_position == m_fail_at && (!m_fail_after_rewind || m_rewound)) {
|
|
67
|
+
throw std::ios_base::failure("Injected config read failure");
|
|
68
|
+
}
|
|
69
|
+
if (m_position == m_text.size()) return traits_type::eof();
|
|
70
|
+
return traits_type::to_int_type(m_text[m_position]);
|
|
71
|
+
}
|
|
72
|
+
int_type uflow() override
|
|
73
|
+
{
|
|
74
|
+
const auto value{underflow()};
|
|
75
|
+
if (!traits_type::eq_int_type(value, traits_type::eof())) ++m_position;
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
pos_type seekoff(off_type offset, std::ios_base::seekdir direction, std::ios_base::openmode) override
|
|
79
|
+
{
|
|
80
|
+
if (direction != std::ios_base::beg || offset != 0) return pos_type{off_type{-1}};
|
|
81
|
+
m_position = 0;
|
|
82
|
+
m_rewound = true;
|
|
83
|
+
return pos_type{0};
|
|
84
|
+
}
|
|
85
|
+
public:
|
|
86
|
+
FailingConfigBuffer(std::string text, size_t fail_at, bool fail_after_rewind = false)
|
|
87
|
+
: m_text(std::move(text)), m_fail_at(fail_at), m_fail_after_rewind(fail_after_rewind) {}
|
|
88
|
+
};
|
|
89
|
+
} // namespace
|
|
90
|
+
|
|
51
91
|
// Test behavior of GetArg functions when string, integer, and boolean types
|
|
52
92
|
// are specified in the settings.json file. GetArg functions are convenience
|
|
53
93
|
// functions. The GetSetting method can always be used instead of GetArg
|
|
@@ -105,22 +145,22 @@ BOOST_AUTO_TEST_CASE(setting_args)
|
|
|
105
145
|
BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "99");
|
|
106
146
|
BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "99");
|
|
107
147
|
BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 99);
|
|
108
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error);
|
|
109
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error);
|
|
148
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true);
|
|
149
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true);
|
|
110
150
|
|
|
111
151
|
set_foo(3.25);
|
|
112
152
|
BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "3.25");
|
|
113
153
|
BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "3.25");
|
|
114
154
|
BOOST_CHECK_THROW(args.GetIntArg("foo", 100), std::runtime_error);
|
|
115
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error);
|
|
116
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error);
|
|
155
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), true);
|
|
156
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), true);
|
|
117
157
|
|
|
118
158
|
set_foo(0);
|
|
119
159
|
BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "0");
|
|
120
160
|
BOOST_CHECK_EQUAL(args.GetArg("foo", "default"), "0");
|
|
121
161
|
BOOST_CHECK_EQUAL(args.GetIntArg("foo", 100), 0);
|
|
122
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", true), std::runtime_error);
|
|
123
|
-
BOOST_CHECK_THROW(args.GetBoolArg("foo", false), std::runtime_error);
|
|
162
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", true), false);
|
|
163
|
+
BOOST_CHECK_EQUAL(args.GetBoolArg("foo", false), false);
|
|
124
164
|
|
|
125
165
|
set_foo(true);
|
|
126
166
|
BOOST_CHECK_EQUAL(args.GetSetting("foo").write(), "true");
|
|
@@ -458,6 +498,9 @@ BOOST_AUTO_TEST_CASE(logargs)
|
|
|
458
498
|
str += s;
|
|
459
499
|
});
|
|
460
500
|
|
|
501
|
+
local_args.LockSettings([](common::Settings& settings) {
|
|
502
|
+
settings.rw_config["dontlog"] = {"private-rw42"};
|
|
503
|
+
});
|
|
461
504
|
// Log the arguments
|
|
462
505
|
local_args.LogArgs();
|
|
463
506
|
|
|
@@ -468,6 +511,137 @@ BOOST_AUTO_TEST_CASE(logargs)
|
|
|
468
511
|
BOOST_CHECK(str.find("Command-line arg: okaylog=\"public\"") != std::string::npos);
|
|
469
512
|
BOOST_CHECK(str.find("dontlog=****") != std::string::npos);
|
|
470
513
|
BOOST_CHECK(str.find("private42") == std::string::npos);
|
|
514
|
+
BOOST_CHECK(str.find("private-rw42") == std::string::npos);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
BOOST_AUTO_TEST_CASE(rw_config_stream)
|
|
518
|
+
{
|
|
519
|
+
std::istringstream input{"# operator settings\nprune=5\n[regtest]\nprune=1\n"};
|
|
520
|
+
std::ostringstream output;
|
|
521
|
+
ModifyRWConfigStream(input, output, {{"listen", "0"}, {"prune", "550"}});
|
|
522
|
+
BOOST_CHECK_EQUAL(output.str(), "# operator settings\nprune=550\nlisten=0\n[regtest]\nprune=1\n");
|
|
523
|
+
|
|
524
|
+
std::istringstream empty;
|
|
525
|
+
std::ostringstream rejected;
|
|
526
|
+
BOOST_CHECK_THROW(ModifyRWConfigStream(empty, rejected, {{"listen", "0\nprune=0"}}), std::invalid_argument);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
BOOST_AUTO_TEST_CASE(config_read_failures)
|
|
530
|
+
{
|
|
531
|
+
class ReadArgs : public ArgsManager {
|
|
532
|
+
public:
|
|
533
|
+
using ArgsManager::ReadConfigStream;
|
|
534
|
+
};
|
|
535
|
+
const std::string text{"foo=original\nbar=tail"};
|
|
536
|
+
for (const size_t fail_at : {size_t{0}, size_t{4}, text.size() - 1}) {
|
|
537
|
+
FailingConfigBuffer buffer{text, fail_at};
|
|
538
|
+
std::istream input{&buffer};
|
|
539
|
+
std::ostringstream output;
|
|
540
|
+
BOOST_CHECK_THROW(ModifyRWConfigStream(input, output, {{"foo", "new"}}), std::ios_base::failure);
|
|
541
|
+
BOOST_CHECK(input.bad());
|
|
542
|
+
|
|
543
|
+
FailingConfigBuffer parser_buffer{text, fail_at};
|
|
544
|
+
std::istream parser_input{&parser_buffer};
|
|
545
|
+
ReadArgs args;
|
|
546
|
+
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}, {"-bar", ArgsManager::ALLOW_ANY}});
|
|
547
|
+
std::map<std::string, std::vector<common::SettingsValue>> target{{"foo", {"kept"}}};
|
|
548
|
+
std::string error;
|
|
549
|
+
BOOST_CHECK(!args.ReadConfigStream(parser_input, "fault.conf", error, false, &target));
|
|
550
|
+
BOOST_CHECK_EQUAL(error, "Failed to read config file \"fault.conf\".");
|
|
551
|
+
BOOST_CHECK_EQUAL(target.size(), 1U);
|
|
552
|
+
BOOST_CHECK_EQUAL(target.at("foo").front().get_str(), "kept");
|
|
553
|
+
BOOST_CHECK(!args.IsArgSet("-foo"));
|
|
554
|
+
}
|
|
555
|
+
FailingConfigBuffer copy_buffer{"invalid\nfoo=old", 12, /*fail_after_rewind=*/true};
|
|
556
|
+
std::istream copy_input{©_buffer};
|
|
557
|
+
std::ostringstream copy_output;
|
|
558
|
+
BOOST_CHECK_THROW(ModifyRWConfigStream(copy_input, copy_output, {{"foo", "new"}}), std::ios_base::failure);
|
|
559
|
+
BOOST_CHECK(copy_input.bad());
|
|
560
|
+
|
|
561
|
+
std::istringstream failed_input{"foo=old"};
|
|
562
|
+
failed_input.setstate(std::ios::failbit);
|
|
563
|
+
std::ostringstream failed_output;
|
|
564
|
+
BOOST_CHECK_THROW(ModifyRWConfigStream(failed_input, failed_output, {{"foo", "new"}}), std::ios_base::failure);
|
|
565
|
+
|
|
566
|
+
for (const std::string original : {"", "foo=old", "foo=old\n"}) {
|
|
567
|
+
std::istringstream input{original};
|
|
568
|
+
std::ostringstream output;
|
|
569
|
+
ModifyRWConfigStream(input, output, {{"foo", "new"}});
|
|
570
|
+
BOOST_CHECK_EQUAL(output.str(), original.empty() || original.ends_with('\n') ? "foo=new\n" : "foo=new");
|
|
571
|
+
}
|
|
572
|
+
std::istringstream invalid_final{"invalid"};
|
|
573
|
+
std::ostringstream repaired;
|
|
574
|
+
ModifyRWConfigStream(invalid_final, repaired, {{"foo", "new"}});
|
|
575
|
+
BOOST_CHECK_EQUAL(repaired.str(), "foo=new\n[INVALID]\n# Error parsing line 1: invalid\n#invalid");
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
BOOST_AUTO_TEST_CASE(rw_config_precedence)
|
|
579
|
+
{
|
|
580
|
+
ArgsManager args;
|
|
581
|
+
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}});
|
|
582
|
+
args.SelectConfigNetwork("regtest");
|
|
583
|
+
args.LockSettings([](common::Settings& settings) {
|
|
584
|
+
settings.ro_config[""]["foo"] = {"default"};
|
|
585
|
+
settings.ro_config["regtest"]["foo"] = {"network"};
|
|
586
|
+
settings.rw_settings["foo"] = "json";
|
|
587
|
+
settings.rw_config["foo"] = {"rw-first", "rw-second"};
|
|
588
|
+
});
|
|
589
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "rw-first");
|
|
590
|
+
ResetArgs(args, "-foo=cli-first -foo=cli-last");
|
|
591
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "cli-last");
|
|
592
|
+
args.ForceSetArg("-foo", "forced");
|
|
593
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "forced");
|
|
594
|
+
args.LockSettings([](common::Settings& settings) {
|
|
595
|
+
settings.forced_settings.clear();
|
|
596
|
+
settings.command_line_options.clear();
|
|
597
|
+
settings.rw_config["foo"] = {false, "after-negation"};
|
|
598
|
+
});
|
|
599
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "after-negation");
|
|
600
|
+
args.LockSettings([](common::Settings& settings) { settings.rw_config.clear(); });
|
|
601
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "json");
|
|
602
|
+
args.LockSettings([](common::Settings& settings) { settings.rw_settings.clear(); });
|
|
603
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "network");
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
BOOST_AUTO_TEST_CASE(rw_config_file_failures)
|
|
607
|
+
{
|
|
608
|
+
class RWArgs : public ArgsManager {
|
|
609
|
+
public:
|
|
610
|
+
explicit RWArgs(const fs::path& path) { LOCK(cs_args); m_rwconf_path = path; }
|
|
611
|
+
};
|
|
612
|
+
const auto path{m_args.GetDataDirBase() / "rw_config_test.conf"};
|
|
613
|
+
RWArgs args{path};
|
|
614
|
+
SetupArgs(args, {{"-foo", ArgsManager::ALLOW_ANY}});
|
|
615
|
+
args.ModifyRWConfigFile("foo", "original", /*also_settings_json=*/false);
|
|
616
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "original");
|
|
617
|
+
BOOST_CHECK_THROW(args.ModifyRWConfigFile("foo", "bad\nvalue", false), std::invalid_argument);
|
|
618
|
+
BOOST_CHECK_EQUAL(args.GetArg("-foo", "unset"), "original");
|
|
619
|
+
std::ifstream input{path.std_path()};
|
|
620
|
+
std::string line;
|
|
621
|
+
std::getline(input, line);
|
|
622
|
+
BOOST_CHECK_EQUAL(line, "foo=original");
|
|
623
|
+
input.close();
|
|
624
|
+
args.EraseRWConfigFile();
|
|
625
|
+
BOOST_CHECK(!fs::exists(path));
|
|
626
|
+
auto reset_path{path};
|
|
627
|
+
reset_path += ".reset";
|
|
628
|
+
BOOST_CHECK(fs::exists(reset_path));
|
|
629
|
+
|
|
630
|
+
const auto directory{m_args.GetDataDirBase() / "rw_config_unreadable"};
|
|
631
|
+
fs::create_directory(directory);
|
|
632
|
+
RWArgs unreadable{directory};
|
|
633
|
+
SetupArgs(unreadable, {{"-foo", ArgsManager::ALLOW_ANY}});
|
|
634
|
+
unreadable.LockSettings([](common::Settings& settings) { settings.rw_config["foo"] = {"kept"}; });
|
|
635
|
+
BOOST_CHECK_THROW(unreadable.ModifyRWConfigFile("foo", "new", false), std::ios_base::failure);
|
|
636
|
+
BOOST_CHECK(fs::is_directory(directory));
|
|
637
|
+
BOOST_CHECK_EQUAL(unreadable.GetArg("-foo", "unset"), "kept");
|
|
638
|
+
auto temporary_path{directory};
|
|
639
|
+
temporary_path += ".new";
|
|
640
|
+
BOOST_CHECK(!fs::exists(temporary_path));
|
|
641
|
+
|
|
642
|
+
RWArgs missing{path / "missing" / "config"};
|
|
643
|
+
BOOST_CHECK_THROW(missing.ModifyRWConfigFile("foo", "new", false), std::ios_base::failure);
|
|
644
|
+
BOOST_CHECK(!fs::exists(missing.GetRWConfigFilePath()));
|
|
471
645
|
}
|
|
472
646
|
|
|
473
647
|
BOOST_AUTO_TEST_SUITE_END()
|