rippled
Loading...
Searching...
No Matches
cluster_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright 2015 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx/TestSuite.h>
21#include <test/unit_test/SuiteJournal.h>
22#include <xrpld/overlay/Cluster.h>
23#include <xrpl/basics/BasicConfig.h>
24#include <xrpl/protocol/SecretKey.h>
25
26namespace ripple {
27namespace tests {
28
30{
32
33public:
34 cluster_test() : journal_("cluster_test", *this)
35 {
36 }
37
40 {
41 auto cluster = std::make_unique<Cluster>(journal_);
42
43 for (auto const& n : nodes)
44 cluster->update(n, "Test");
45
46 return cluster;
47 }
48
51 {
53 }
54
55 void
57 {
58 // The servers on the network
60
61 while (network.size() != 128)
62 network.push_back(randomNode());
63
64 {
65 testcase("Membership: Empty cluster");
66
67 auto c = create({});
68
69 for (auto const& n : network)
70 BEAST_EXPECT(!c->member(n));
71 }
72
73 {
74 testcase("Membership: Non-empty cluster and none present");
75
77 while (cluster.size() != 32)
78 cluster.push_back(randomNode());
79
80 auto c = create(cluster);
81
82 for (auto const& n : network)
83 BEAST_EXPECT(!c->member(n));
84 }
85
86 {
87 testcase("Membership: Non-empty cluster and some present");
88
90 network.begin(), network.begin() + 16);
91
92 while (cluster.size() != 32)
93 cluster.push_back(randomNode());
94
95 auto c = create(cluster);
96
97 for (auto const& n : cluster)
98 BEAST_EXPECT(c->member(n));
99
100 for (auto const& n : network)
101 {
102 auto found = std::find(cluster.begin(), cluster.end(), n);
103 BEAST_EXPECT(
104 static_cast<bool>(c->member(n)) ==
105 (found != cluster.end()));
106 }
107 }
108
109 {
110 testcase("Membership: Non-empty cluster and all present");
111
113 network.begin(), network.begin() + 32);
114
115 auto c = create(cluster);
116
117 for (auto const& n : cluster)
118 BEAST_EXPECT(c->member(n));
119
120 for (auto const& n : network)
121 {
122 auto found = std::find(cluster.begin(), cluster.end(), n);
123 BEAST_EXPECT(
124 static_cast<bool>(c->member(n)) ==
125 (found != cluster.end()));
126 }
127 }
128 }
129
130 void
132 {
133 testcase("Updating");
134
135 auto c = create({});
136
137 auto const node = randomNode();
138 auto const name = toBase58(TokenType::NodePublic, node);
139 std::uint32_t load = 0;
140 NetClock::time_point tick = {};
141
142 // Initial update
143 BEAST_EXPECT(c->update(node, "", load, tick));
144 {
145 auto member = c->member(node);
146 BEAST_EXPECT(static_cast<bool>(member));
147 BEAST_EXPECT(member->empty());
148 }
149
150 // Updating too quickly: should fail
151 BEAST_EXPECT(!c->update(node, name, load, tick));
152 {
153 auto member = c->member(node);
154 BEAST_EXPECT(static_cast<bool>(member));
155 BEAST_EXPECT(member->empty());
156 }
157
158 using namespace std::chrono_literals;
159
160 // Updating the name (empty updates to non-empty)
161 tick += 1s;
162 BEAST_EXPECT(c->update(node, name, load, tick));
163 {
164 auto member = c->member(node);
165 BEAST_EXPECT(static_cast<bool>(member));
166 BEAST_EXPECT(member->compare(name) == 0);
167 }
168
169 // Updating the name (non-empty doesn't go to empty)
170 tick += 1s;
171 BEAST_EXPECT(c->update(node, "", load, tick));
172 {
173 auto member = c->member(node);
174 BEAST_EXPECT(static_cast<bool>(member));
175 BEAST_EXPECT(member->compare(name) == 0);
176 }
177
178 // Updating the name (non-empty updates to new non-empty)
179 tick += 1s;
180 BEAST_EXPECT(c->update(node, "test", load, tick));
181 {
182 auto member = c->member(node);
183 BEAST_EXPECT(static_cast<bool>(member));
184 BEAST_EXPECT(member->compare("test") == 0);
185 }
186 }
187
188 void
190 {
191 testcase("Config Load");
192
193 auto c = std::make_unique<Cluster>(journal_);
194
195 // The servers on the network
197
198 while (network.size() != 8)
199 network.push_back(randomNode());
200
201 auto format = [](PublicKey const& publicKey,
202 char const* comment = nullptr) {
203 auto ret = toBase58(TokenType::NodePublic, publicKey);
204
205 if (comment)
206 ret += comment;
207
208 return ret;
209 };
210
211 Section s1;
212
213 // Correct (empty) configuration
214 BEAST_EXPECT(c->load(s1));
215 BEAST_EXPECT(c->size() == 0);
216
217 // Correct configuration
218 s1.append(format(network[0]));
219 s1.append(format(network[1], " "));
220 s1.append(format(network[2], " Comment"));
221 s1.append(format(network[3], " Multi Word Comment"));
222 s1.append(format(network[4], " Leading Whitespace"));
223 s1.append(format(network[5], " Trailing Whitespace "));
224 s1.append(format(network[6], " Leading & Trailing Whitespace "));
225 s1.append(format(
226 network[7], " Leading, Trailing & Internal Whitespace "));
227
228 BEAST_EXPECT(c->load(s1));
229
230 for (auto const& n : network)
231 BEAST_EXPECT(c->member(n));
232
233 // Incorrect configurations
234 Section s2;
235 s2.append("NotAPublicKey");
236 BEAST_EXPECT(!c->load(s2));
237
238 Section s3;
239 s3.append(format(network[0], "!"));
240 BEAST_EXPECT(!c->load(s3));
241
242 Section s4;
243 s4.append(format(network[0], "! Comment"));
244 BEAST_EXPECT(!c->load(s4));
245
246 // Check if we properly terminate when we encounter
247 // a malformed or unparseable entry:
248 auto const node1 = randomNode();
249 auto const node2 = randomNode();
250
251 Section s5;
252 s5.append(format(node1, "XXX"));
253 s5.append(format(node2));
254 BEAST_EXPECT(!c->load(s5));
255 BEAST_EXPECT(!c->member(node1));
256 BEAST_EXPECT(!c->member(node2));
257 }
258
259 void
260 run() override
261 {
263 testUpdating();
265 }
266};
267
268BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple);
269
270} // namespace tests
271} // namespace ripple
T begin(T... args)
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
A public key.
Definition: PublicKey.h:62
Holds a collection of configuration values.
Definition: BasicConfig.h:45
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:47
void run() override
Runs the suite.
test::SuiteJournal journal_
std::unique_ptr< Cluster > create(std::vector< PublicKey > const &nodes)
T end(T... args)
T find(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:330
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:298
T push_back(T... args)
T size(T... args)