rippled
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 <ripple/basics/BasicConfig.h>
21 #include <ripple/overlay/Cluster.h>
22 #include <ripple/overlay/ClusterNode.h>
23 #include <ripple/protocol/SecretKey.h>
24 #include <test/jtx/TestSuite.h>
25 #include <test/unit_test/SuiteJournal.h>
26 
27 namespace ripple {
28 namespace tests {
29 
31 {
33 
34 public:
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 
50  PublicKey
52  {
54  }
55 
56  void
58  {
59  // The servers on the network
60  std::vector<PublicKey> 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 
77  std::vector<PublicKey> cluster;
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 
90  std::vector<PublicKey> cluster(
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 
113  std::vector<PublicKey> cluster(
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
197  std::vector<PublicKey> 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  {
263  testMembership();
264  testUpdating();
265  testConfigLoad();
266  }
267 };
268 
269 BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple);
270 
271 } // namespace tests
272 } // namespace ripple
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:42
ripple::tests::cluster_test::cluster_test
cluster_test()
Definition: cluster_test.cpp:35
std::vector
STL class.
std::find
T find(T... args)
std::vector::size
T size(T... args)
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::tests::cluster_test::testConfigLoad
void testConfigLoad()
Definition: cluster_test.cpp:190
ripple::tests::cluster_test
Definition: cluster_test.cpp:30
ripple::tests::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(cluster, overlay, ripple)
ripple::tests::cluster_test::create
std::unique_ptr< Cluster > create(std::vector< PublicKey > const &nodes)
Definition: cluster_test.cpp:40
ripple::tests::cluster_test::testMembership
void testMembership()
Definition: cluster_test.cpp:57
ripple::Section::append
void append(std::vector< std::string > const &lines)
Append a set of lines to this section.
Definition: BasicConfig.cpp:38
ripple::tests::cluster_test::testUpdating
void testUpdating()
Definition: cluster_test.cpp:132
std::vector::push_back
T push_back(T... args)
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
std::chrono::time_point
std::uint32_t
ripple::tests::cluster_test::randomNode
PublicKey randomNode()
Definition: cluster_test.cpp:51
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::KeyType::secp256k1
@ secp256k1
ripple::TestSuite
Definition: TestSuite.h:28
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::vector::begin
T begin(T... args)
ripple::tests::cluster_test::run
void run() override
Definition: cluster_test.cpp:261
ripple::TokenType::NodePublic
@ NodePublic
std::unique_ptr
STL class.
ripple::tests::cluster_test::journal_
test::SuiteJournal journal_
Definition: cluster_test.cpp:32
ripple::randomSecretKey
SecretKey randomSecretKey()
Create a secret key using secure random numbers.
Definition: SecretKey.cpp:281