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 <xrpld/overlay/ClusterNode.h>
24#include <xrpl/basics/BasicConfig.h>
25#include <xrpl/protocol/SecretKey.h>
26
27namespace ripple {
28namespace tests {
29
31{
33
34public:
35 cluster_test() : journal_("cluster_test", *this)
36 {
37 }
38
41 {
42 auto cluster = std::make_unique<Cluster>(journal_);
43
44 for (auto const& n : nodes)
45 cluster->update(n, "Test");
46
47 return cluster;
48 }
49
52 {
54 }
55
56 void
58 {
59 // The servers on the network
61
62 while (network.size() != 128)
63 network.push_back(randomNode());
64
65 {
66 testcase("Membership: Empty cluster");
67
68 auto c = create({});
69
70 for (auto const& n : network)
71 BEAST_EXPECT(!c->member(n));
72 }
73
74 {
75 testcase("Membership: Non-empty cluster and none present");
76
78 while (cluster.size() != 32)
79 cluster.push_back(randomNode());
80
81 auto c = create(cluster);
82
83 for (auto const& n : network)
84 BEAST_EXPECT(!c->member(n));
85 }
86
87 {
88 testcase("Membership: Non-empty cluster and some present");
89
91 network.begin(), network.begin() + 16);
92
93 while (cluster.size() != 32)
94 cluster.push_back(randomNode());
95
96 auto c = create(cluster);
97
98 for (auto const& n : cluster)
99 BEAST_EXPECT(c->member(n));
100
101 for (auto const& n : network)
102 {
103 auto found = std::find(cluster.begin(), cluster.end(), n);
104 BEAST_EXPECT(
105 static_cast<bool>(c->member(n)) ==
106 (found != cluster.end()));
107 }
108 }
109
110 {
111 testcase("Membership: Non-empty cluster and all present");
112
114 network.begin(), network.begin() + 32);
115
116 auto c = create(cluster);
117
118 for (auto const& n : cluster)
119 BEAST_EXPECT(c->member(n));
120
121 for (auto const& n : network)
122 {
123 auto found = std::find(cluster.begin(), cluster.end(), n);
124 BEAST_EXPECT(
125 static_cast<bool>(c->member(n)) ==
126 (found != cluster.end()));
127 }
128 }
129 }
130
131 void
133 {
134 testcase("Updating");
135
136 auto c = create({});
137
138 auto const node = randomNode();
139 auto const name = toBase58(TokenType::NodePublic, node);
140 std::uint32_t load = 0;
141 NetClock::time_point tick = {};
142
143 // Initial update
144 BEAST_EXPECT(c->update(node, "", load, tick));
145 {
146 auto member = c->member(node);
147 BEAST_EXPECT(static_cast<bool>(member));
148 BEAST_EXPECT(member->empty());
149 }
150
151 // Updating too quickly: should fail
152 BEAST_EXPECT(!c->update(node, name, load, tick));
153 {
154 auto member = c->member(node);
155 BEAST_EXPECT(static_cast<bool>(member));
156 BEAST_EXPECT(member->empty());
157 }
158
159 using namespace std::chrono_literals;
160
161 // Updating the name (empty updates to non-empty)
162 tick += 1s;
163 BEAST_EXPECT(c->update(node, name, load, tick));
164 {
165 auto member = c->member(node);
166 BEAST_EXPECT(static_cast<bool>(member));
167 BEAST_EXPECT(member->compare(name) == 0);
168 }
169
170 // Updating the name (non-empty doesn't go to empty)
171 tick += 1s;
172 BEAST_EXPECT(c->update(node, "", load, tick));
173 {
174 auto member = c->member(node);
175 BEAST_EXPECT(static_cast<bool>(member));
176 BEAST_EXPECT(member->compare(name) == 0);
177 }
178
179 // Updating the name (non-empty updates to new non-empty)
180 tick += 1s;
181 BEAST_EXPECT(c->update(node, "test", load, tick));
182 {
183 auto member = c->member(node);
184 BEAST_EXPECT(static_cast<bool>(member));
185 BEAST_EXPECT(member->compare("test") == 0);
186 }
187 }
188
189 void
191 {
192 testcase("Config Load");
193
194 auto c = std::make_unique<Cluster>(journal_);
195
196 // The servers on the network
198
199 while (network.size() != 8)
200 network.push_back(randomNode());
201
202 auto format = [](PublicKey const& publicKey,
203 char const* comment = nullptr) {
204 auto ret = toBase58(TokenType::NodePublic, publicKey);
205
206 if (comment)
207 ret += comment;
208
209 return ret;
210 };
211
212 Section s1;
213
214 // Correct (empty) configuration
215 BEAST_EXPECT(c->load(s1));
216 BEAST_EXPECT(c->size() == 0);
217
218 // Correct configuration
219 s1.append(format(network[0]));
220 s1.append(format(network[1], " "));
221 s1.append(format(network[2], " Comment"));
222 s1.append(format(network[3], " Multi Word Comment"));
223 s1.append(format(network[4], " Leading Whitespace"));
224 s1.append(format(network[5], " Trailing Whitespace "));
225 s1.append(format(network[6], " Leading & Trailing Whitespace "));
226 s1.append(format(
227 network[7], " Leading, Trailing & Internal Whitespace "));
228
229 BEAST_EXPECT(c->load(s1));
230
231 for (auto const& n : network)
232 BEAST_EXPECT(c->member(n));
233
234 // Incorrect configurations
235 Section s2;
236 s2.append("NotAPublicKey");
237 BEAST_EXPECT(!c->load(s2));
238
239 Section s3;
240 s3.append(format(network[0], "!"));
241 BEAST_EXPECT(!c->load(s3));
242
243 Section s4;
244 s4.append(format(network[0], "! Comment"));
245 BEAST_EXPECT(!c->load(s4));
246
247 // Check if we properly terminate when we encounter
248 // a malformed or unparseable entry:
249 auto const node1 = randomNode();
250 auto const node2 = randomNode();
251
252 Section s5;
253 s5.append(format(node1, "XXX"));
254 s5.append(format(node2));
255 BEAST_EXPECT(!c->load(s5));
256 BEAST_EXPECT(!c->member(node1));
257 BEAST_EXPECT(!c->member(node2));
258 }
259
260 void
261 run() override
262 {
264 testUpdating();
266 }
267};
268
269BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple);
270
271} // namespace tests
272} // namespace ripple
T begin(T... args)
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
A public key.
Definition: PublicKey.h:62
Holds a collection of configuration values.
Definition: BasicConfig.h:46
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:38
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:106
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281
T push_back(T... args)
T size(T... args)