blob: 43c385558531e221b5cebaaaa5084efc1c9ace99 [file] [log] [blame]
Vince Lehman09131122014-09-09 17:10:11 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Muktadir R Chowdhury800833b2016-07-29 13:43:59 -05003 * Copyright (c) 2014-2016, The University of Memphis,
Vince Lehmanc2acdcb2015-04-29 11:14:35 -05004 * Regents of the University of California,
5 * Arizona Board of Regents.
Vince Lehman09131122014-09-09 17:10:11 -05006 *
7 * This file is part of NLSR (Named-data Link State Routing).
8 * See AUTHORS.md for complete list of NLSR authors and contributors.
9 *
10 * NLSR is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * NLSR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * NLSR, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Vince Lehman09131122014-09-09 17:10:11 -050020 **/
21
Vince Lehman02e32992015-03-11 12:31:20 -050022#include "test-common.hpp"
Vince Lehman199e9cf2015-04-07 13:22:16 -050023#include "control-commands.hpp"
Vince Lehman09131122014-09-09 17:10:11 -050024
Vince Lehman02e32992015-03-11 12:31:20 -050025#include "nlsr.hpp"
26
27#include <ndn-cxx/management/nfd-face-event-notification.hpp>
28#include <ndn-cxx/util/dummy-client-face.hpp>
Vince Lehman09131122014-09-09 17:10:11 -050029
30namespace nlsr {
31namespace test {
32
Vince Lehman09131122014-09-09 17:10:11 -050033using ndn::shared_ptr;
34
Vince Lehmanf7eec4f2015-05-08 19:02:31 -050035class NlsrFixture : public UnitTestTimeFixture
36{
37public:
38 NlsrFixture()
39 : face(make_shared<ndn::util::DummyClientFace>())
40 , nlsr(g_ioService, g_scheduler, ndn::ref(*face))
41 , lsdb(nlsr.getLsdb())
42 , neighbors(nlsr.getAdjacencyList())
43 {
44 }
45
46 void
47 receiveHelloData(const ndn::Name& sender, const ndn::Name& receiver)
48 {
49 ndn::Name dataName(sender);
50 dataName.append("NLSR").append("INFO").append(receiver.wireEncode()).appendVersion();
51
52 shared_ptr<ndn::Data> data = make_shared<ndn::Data>(dataName);
53
54 nlsr.m_helloProtocol.onContentValidated(data);
55 }
56
57public:
58 shared_ptr<ndn::util::DummyClientFace> face;
59 Nlsr nlsr;
60 Lsdb& lsdb;
61 AdjacencyList& neighbors;
62};
63
64BOOST_FIXTURE_TEST_SUITE(TestNlsr, NlsrFixture)
Vince Lehman09131122014-09-09 17:10:11 -050065
66BOOST_AUTO_TEST_CASE(HyperbolicOn_ZeroCostNeighbors)
67{
Vince Lehman09131122014-09-09 17:10:11 -050068 // Simulate loading configuration file
Vince Lehman09131122014-09-09 17:10:11 -050069 Adjacent neighborA("/ndn/neighborA", "uri://faceA", 25, Adjacent::STATUS_INACTIVE, 0, 0);
70 neighbors.insert(neighborA);
71
72 Adjacent neighborB("/ndn/neighborB", "uri://faceB", 10, Adjacent::STATUS_INACTIVE, 0, 0);
73 neighbors.insert(neighborB);
74
75 Adjacent neighborC("/ndn/neighborC", "uri://faceC", 17, Adjacent::STATUS_INACTIVE, 0, 0);
76 neighbors.insert(neighborC);
77
78 nlsr.getConfParameter().setHyperbolicState(HYPERBOLIC_STATE_ON);
79
80 nlsr.initialize();
81
82 std::list<Adjacent> neighborList = neighbors.getAdjList();
83 for (std::list<Adjacent>::iterator it = neighborList.begin(); it != neighborList.end(); ++it) {
84 BOOST_CHECK_EQUAL(it->getLinkCost(), 0);
85 }
86}
87
88BOOST_AUTO_TEST_CASE(HyperbolicOff_LinkStateCost)
89{
Vince Lehman09131122014-09-09 17:10:11 -050090 // Simulate loading configuration file
Vince Lehman09131122014-09-09 17:10:11 -050091 Adjacent neighborA("/ndn/neighborA", "uri://faceA", 25, Adjacent::STATUS_INACTIVE, 0, 0);
92 neighbors.insert(neighborA);
93
94 Adjacent neighborB("/ndn/neighborB", "uri://faceB", 10, Adjacent::STATUS_INACTIVE, 0, 0);
95 neighbors.insert(neighborB);
96
97 Adjacent neighborC("/ndn/neighborC", "uri://faceC", 17, Adjacent::STATUS_INACTIVE, 0, 0);
98 neighbors.insert(neighborC);
99
100 nlsr.initialize();
101
102 std::list<Adjacent> neighborList = neighbors.getAdjList();
103 for (std::list<Adjacent>::iterator it = neighborList.begin(); it != neighborList.end(); ++it) {
104 BOOST_CHECK(it->getLinkCost() != 0);
105 }
106}
107
Vince Lehman7b616582014-10-17 16:25:39 -0500108BOOST_AUTO_TEST_CASE(SetEventIntervals)
109{
Vince Lehman7b616582014-10-17 16:25:39 -0500110 // Simulate loading configuration file
111 ConfParameter& conf = nlsr.getConfParameter();
112 conf.setAdjLsaBuildInterval(3);
113 conf.setFirstHelloInterval(6);
114 conf.setRoutingCalcInterval(9);
115
116 nlsr.initialize();
117
Vince Lehman50df6b72015-03-03 12:06:40 -0600118 const Lsdb& lsdb = nlsr.getLsdb();
Vince Lehman7b616582014-10-17 16:25:39 -0500119 const RoutingTable& rt = nlsr.getRoutingTable();
120
Vince Lehman50df6b72015-03-03 12:06:40 -0600121 BOOST_CHECK_EQUAL(lsdb.getAdjLsaBuildInterval(), ndn::time::seconds(3));
Vince Lehman7b616582014-10-17 16:25:39 -0500122 BOOST_CHECK_EQUAL(nlsr.getFirstHelloInterval(), 6);
123 BOOST_CHECK_EQUAL(rt.getRoutingCalcInterval(), ndn::time::seconds(9));
124}
125
Vince Lehman02e32992015-03-11 12:31:20 -0500126BOOST_FIXTURE_TEST_CASE(FaceDestroyEvent, UnitTestTimeFixture)
127{
Muktadir R Chowdhuryc69da0a2015-12-18 13:24:38 -0600128 shared_ptr<ndn::util::DummyClientFace> face = make_shared<ndn::util::DummyClientFace>(g_ioService);
Vince Lehman02e32992015-03-11 12:31:20 -0500129 Nlsr nlsr(g_ioService, g_scheduler, ndn::ref(*face));
Vince Lehman41b173e2015-05-07 14:13:26 -0500130 Lsdb& lsdb = nlsr.getLsdb();
Vince Lehman02e32992015-03-11 12:31:20 -0500131
132 // Simulate loading configuration file
133 ConfParameter& conf = nlsr.getConfParameter();
134 conf.setNetwork("/ndn");
135 conf.setSiteName("/site");
136 conf.setRouterName("/%C1.router/this-router");
137 conf.setAdjLsaBuildInterval(0);
138 conf.setRoutingCalcInterval(0);
139
140 // Add active neighbors
141 AdjacencyList& neighbors = nlsr.getAdjacencyList();
Vince Lehman02e32992015-03-11 12:31:20 -0500142 uint64_t destroyFaceId = 128;
143
144 // Create a neighbor whose Face will be destroyed
145 Adjacent failNeighbor("/ndn/neighborA", "uri://faceA", 10, Adjacent::STATUS_ACTIVE, 0,
146 destroyFaceId);
147 neighbors.insert(failNeighbor);
148
149 // Create an additional neighbor so an adjacency LSA can be built after the face is destroyed
Vince Lehman41b173e2015-05-07 14:13:26 -0500150 Adjacent otherNeighbor("/ndn/neighborB", "uri://faceB", 10, Adjacent::STATUS_ACTIVE, 0, 256);
Vince Lehman02e32992015-03-11 12:31:20 -0500151 neighbors.insert(otherNeighbor);
152
153 nlsr.initialize();
154
155 // Simulate successful HELLO responses
Vince Lehman41b173e2015-05-07 14:13:26 -0500156 lsdb.scheduleAdjLsaBuild();
157
158 // Set up adjacency LSAs
159 // This router
160 Adjacent thisRouter(conf.getRouterPrefix(), "uri://faceB", 10, Adjacent::STATUS_ACTIVE, 0, 256);
161
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600162 AdjLsa ownAdjLsa(conf.getRouterPrefix(), 10, ndn::time::system_clock::now(), 1, neighbors);
Vince Lehman41b173e2015-05-07 14:13:26 -0500163 lsdb.installAdjLsa(ownAdjLsa);
164
165 // Router that will fail
166 AdjacencyList failAdjacencies;
167 failAdjacencies.insert(thisRouter);
168
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600169 AdjLsa failAdjLsa("/ndn/neighborA", 10,
Vince Lehman41b173e2015-05-07 14:13:26 -0500170 ndn::time::system_clock::now() + ndn::time::seconds(3600), 1, failAdjacencies);
171
172 lsdb.installAdjLsa(failAdjLsa);
173
174 // Other router
175 AdjacencyList otherAdjacencies;
176 otherAdjacencies.insert(thisRouter);
177
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600178 AdjLsa otherAdjLsa("/ndn/neighborB", 10,
Vince Lehman41b173e2015-05-07 14:13:26 -0500179 ndn::time::system_clock::now() + ndn::time::seconds(3600), 1, otherAdjacencies);
180
181 lsdb.installAdjLsa(otherAdjLsa);
Vince Lehman02e32992015-03-11 12:31:20 -0500182
183 // Run the scheduler to build an adjacency LSA
184 this->advanceClocks(ndn::time::milliseconds(1));
185
186 // Make sure an adjacency LSA was built
187 ndn::Name key = ndn::Name(nlsr.getConfParameter().getRouterPrefix()).append(AdjLsa::TYPE_STRING);
Vince Lehman41b173e2015-05-07 14:13:26 -0500188 AdjLsa* lsa = lsdb.findAdjLsa(key);
Vince Lehman02e32992015-03-11 12:31:20 -0500189 BOOST_REQUIRE(lsa != nullptr);
190
alvy46ccaae2015-06-25 14:13:39 -0500191 uint32_t lastAdjLsaSeqNo = lsa->getLsSeqNo();
192 nlsr.getSequencingManager().setAdjLsaSeq(lastAdjLsaSeqNo);
Vince Lehman02e32992015-03-11 12:31:20 -0500193
194 // Make sure the routing table was calculated
195 RoutingTableEntry* rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
196 BOOST_REQUIRE(rtEntry != nullptr);
197 BOOST_REQUIRE_EQUAL(rtEntry->getNexthopList().getSize(), 1);
198
199 // Receive FaceEventDestroyed notification
200 ndn::nfd::FaceEventNotification event;
201 event.setKind(ndn::nfd::FACE_EVENT_DESTROYED)
202 .setFaceId(destroyFaceId);
203
204 shared_ptr<ndn::Data> data = make_shared<ndn::Data>("/localhost/nfd/faces/events/%FE%00");
205 data->setContent(event.wireEncode());
206 nlsr.getKeyChain().sign(*data);
207
208 face->receive(*data);
209
210 // Run the scheduler to build an adjacency LSA
211 this->advanceClocks(ndn::time::milliseconds(1));
212
213 Adjacent updatedNeighbor = neighbors.getAdjacent(failNeighbor.getName());
214
215 BOOST_CHECK_EQUAL(updatedNeighbor.getFaceId(), 0);
216 BOOST_CHECK_EQUAL(updatedNeighbor.getInterestTimedOutNo(),
217 nlsr.getConfParameter().getInterestRetryNumber());
218 BOOST_CHECK_EQUAL(updatedNeighbor.getStatus(), Adjacent::STATUS_INACTIVE);
alvy46ccaae2015-06-25 14:13:39 -0500219
220 lsa = lsdb.findAdjLsa(key);
221 BOOST_REQUIRE(lsa != nullptr);
222
223 BOOST_CHECK_EQUAL(lsa->getLsSeqNo(), lastAdjLsaSeqNo + 1);
Vince Lehman02e32992015-03-11 12:31:20 -0500224
225 // Make sure the routing table was recalculated
226 rtEntry = nlsr.getRoutingTable().findRoutingTableEntry(failNeighbor.getName());
227 BOOST_CHECK(rtEntry == nullptr);
228}
229
Vince Lehman199e9cf2015-04-07 13:22:16 -0500230// Bug #2733
231// This test checks that when a face for an inactive node is destroyed, an
232// Adjacency LSA build does not postpone the LSA refresh and cause RIB
233// entries for other nodes' name prefixes to not be refreshed.
234//
235// This test is invalid when Issue #2732 is implemented since an Adjacency LSA
236// refresh will not cause RIB entries for other nodes' name prefixes to be refreshed.
237BOOST_FIXTURE_TEST_CASE(FaceDestroyEventInactive, UnitTestTimeFixture)
238{
Muktadir R Chowdhuryc69da0a2015-12-18 13:24:38 -0600239 shared_ptr<ndn::util::DummyClientFace> face = make_shared<ndn::util::DummyClientFace>(g_ioService);
Vince Lehman199e9cf2015-04-07 13:22:16 -0500240 Nlsr nlsr(g_ioService, g_scheduler, ndn::ref(*face));
241 Lsdb& lsdb = nlsr.getLsdb();
242
243 // Simulate loading configuration file
244 ConfParameter& conf = nlsr.getConfParameter();
245 conf.setNetwork("/ndn");
246 conf.setSiteName("/site");
247 conf.setRouterName("/%C1.router/this-router");
248 conf.setFirstHelloInterval(0);
249 conf.setAdjLsaBuildInterval(0);
250 conf.setRoutingCalcInterval(0);
251
252 // Add neighbors
253 AdjacencyList& neighbors = nlsr.getAdjacencyList();
254
255 uint64_t destroyFaceId = 128;
256
257 // Create an inactive neighbor whose Face will be destroyed
258 Adjacent failNeighbor("/ndn/neighborA", "uri://faceA", 10, Adjacent::STATUS_INACTIVE, 3,
259 destroyFaceId);
260 neighbors.insert(failNeighbor);
261
262 // Create an additional active neighbor so an adjacency LSA can be built
263 Adjacent otherNeighbor("/ndn/neighborB", "uri://faceB", 25, Adjacent::STATUS_ACTIVE, 0, 256);
264 neighbors.insert(otherNeighbor);
265
266 // Add a name for the neighbor to advertise
267 NamePrefixList nameList;
268 ndn::Name nameToAdvertise("/ndn/neighborB/name");
269 nameList.insert(nameToAdvertise);
270
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600271 NameLsa nameLsa("/ndn/neighborB", 25, ndn::time::system_clock::now(), nameList);
Vince Lehman199e9cf2015-04-07 13:22:16 -0500272 lsdb.installNameLsa(nameLsa);
273
274 nlsr.initialize();
275
276 // Simulate successful HELLO responses from neighbor B
277 lsdb.scheduleAdjLsaBuild();
278
Vince Lehman41b173e2015-05-07 14:13:26 -0500279 // Set up adjacency LSAs
280 // This router
281 Adjacent thisRouter(conf.getRouterPrefix(), "uri://faceB", 25, Adjacent::STATUS_ACTIVE, 0, 256);
282
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600283 AdjLsa ownAdjLsa(conf.getRouterPrefix(), 10, ndn::time::system_clock::now(), 1, neighbors);
Vince Lehman41b173e2015-05-07 14:13:26 -0500284 lsdb.installAdjLsa(ownAdjLsa);
285
286 // Other ACTIVE router
287 AdjacencyList otherAdjacencies;
288 otherAdjacencies.insert(thisRouter);
289
Ashlesh Gawanded02c3882015-12-29 16:02:51 -0600290 AdjLsa otherAdjLsa("/ndn/neighborB", 10,
Vince Lehman41b173e2015-05-07 14:13:26 -0500291 ndn::time::system_clock::now() + ndn::time::seconds(3600), 1, otherAdjacencies);
292
293 lsdb.installAdjLsa(otherAdjLsa);
294
Vince Lehman199e9cf2015-04-07 13:22:16 -0500295 // Run the scheduler to build an adjacency LSA
296 this->advanceClocks(ndn::time::milliseconds(1));
297
298 ndn::Name key = ndn::Name(nlsr.getConfParameter().getRouterPrefix()).append(AdjLsa::TYPE_STRING);
299 AdjLsa* lsa = lsdb.findAdjLsa(key);
300 BOOST_REQUIRE(lsa != nullptr);
301
302 // Cancel previous LSA expiration event
303 g_scheduler.cancelEvent(lsa->getExpiringEventId());
304
305 // Set expiration time for own Adjacency LSA to earlier value for unit-test
306 //
307 // Expiration time is negative to offset the GRACE_PERIOD (10 seconds) automatically applied
308 // to expiration times
309 ndn::EventId id = lsdb.scheduleAdjLsaExpiration(key, lsa->getLsSeqNo(), -ndn::time::seconds(9));
310 lsa->setExpiringEventId(id);
311
312 // Generate a FaceEventDestroyed notification
313 ndn::nfd::FaceEventNotification event;
314 event.setKind(ndn::nfd::FACE_EVENT_DESTROYED)
315 .setFaceId(destroyFaceId);
316
317 shared_ptr<ndn::Data> data = make_shared<ndn::Data>("/localhost/nfd/faces/events/%FE%00");
318 data->setContent(event.wireEncode());
319 nlsr.getKeyChain().sign(*data);
320
321 // Receive the FaceEventDestroyed notification
322 face->receive(*data);
323
324 // Run the scheduler to expire the Adjacency LSA. The expiration should refresh the RIB
325 // entries associated with Neighbor B's advertised prefix.
326 face->sentInterests.clear();
327 this->advanceClocks(ndn::time::seconds(1));
328
329 // The Face should have two sent Interests: the face event and a RIB registration
330 BOOST_REQUIRE(face->sentInterests.size() > 0);
331 const ndn::Interest& interest = face->sentInterests.back();
332
333 ndn::nfd::ControlParameters parameters;
334 ndn::Name::Component verb;
335 BOOST_REQUIRE_NO_THROW(extractRibCommandParameters(interest, verb, parameters));
336
337 BOOST_CHECK_EQUAL(verb, ndn::Name::Component("register"));
338 BOOST_CHECK_EQUAL(parameters.getName(), nameToAdvertise);
339}
340
Vince Lehmanf7eec4f2015-05-08 19:02:31 -0500341BOOST_AUTO_TEST_CASE(GetCertificate)
Vince Lehmanc2acdcb2015-04-29 11:14:35 -0500342{
Vince Lehmanc2acdcb2015-04-29 11:14:35 -0500343 // Create certificate
344 ndn::Name identity("/TestNLSR/identity");
345 identity.appendVersion();
346
347 ndn::KeyChain keyChain;
348 keyChain.createIdentity(identity);
349 ndn::Name certName = keyChain.getDefaultCertificateNameForIdentity(identity);
350 shared_ptr<ndn::IdentityCertificate> certificate = keyChain.getCertificate(certName);
351
352 const ndn::Name certKey = certificate->getName().getPrefix(-1);
353
354 BOOST_CHECK(nlsr.getCertificate(certKey) == nullptr);
355
356 // Certificate should be retrievable from the CertificateStore
357 nlsr.loadCertToPublish(certificate);
358
359 BOOST_CHECK(nlsr.getCertificate(certKey) != nullptr);
360
361 nlsr.getCertificateStore().clear();
362
363 // Certificate should be retrievable from the cache
364 nlsr.addCertificateToCache(certificate);
365 this->advanceClocks(ndn::time::milliseconds(10));
366
367 BOOST_CHECK(nlsr.getCertificate(certKey) != nullptr);
368}
369
Vince Lehmanf7eec4f2015-05-08 19:02:31 -0500370BOOST_AUTO_TEST_CASE(SetRouterCommandPrefix)
Muktadir R Chowdhury3ac07282016-06-17 16:30:29 -0500371{
Muktadir R Chowdhury3ac07282016-06-17 16:30:29 -0500372 // Simulate loading configuration file
373 ConfParameter& conf = nlsr.getConfParameter();
374 conf.setNetwork("/ndn");
375 conf.setSiteName("/site");
376 conf.setRouterName("/%C1.router/this-router");
377
378 nlsr.initialize();
379
380 BOOST_CHECK_EQUAL(nlsr.getLsdbDatasetHandler().getRouterNameCommandPrefix(),
381 ndn::Name("/ndn/site/%C1.router/this-router/lsdb"));
382}
383
Vince Lehmanf7eec4f2015-05-08 19:02:31 -0500384BOOST_AUTO_TEST_CASE(BuildAdjLsaAfterHelloResponse)
385{
386 // Configure NLSR
387 ConfParameter& conf = nlsr.getConfParameter();
388 conf.setNetwork("/ndn");
389 conf.setSiteName("/site");
390
391 ndn::Name routerName("/%C1.Router/this-router");
392 conf.setRouterName(routerName);
393
394 conf.setAdjLsaBuildInterval(1);
395
396 // Add neighbors
397 // Router A
398 ndn::Name neighborAName("/ndn/site/%C1.router/routerA");
399 Adjacent neighborA(neighborAName, "uri://faceA", 0, Adjacent::STATUS_INACTIVE, 0, 0);
400 neighbors.insert(neighborA);
401
402 // Router B
403 ndn::Name neighborBName("/ndn/site/%C1.router/routerB");
404 Adjacent neighborB(neighborBName, "uri://faceA", 0, Adjacent::STATUS_INACTIVE, 0, 0);
405 neighbors.insert(neighborB);
406
407 nlsr.initialize();
408 this->advanceClocks(ndn::time::milliseconds(1));
409
410 // Receive HELLO response from Router A
411 receiveHelloData(neighborAName, conf.getRouterPrefix());
412 this->advanceClocks(ndn::time::seconds(1));
413
414 ndn::Name lsaKey = ndn::Name(conf.getRouterPrefix()).append(AdjLsa::TYPE_STRING);
415
416 // Adjacency LSA should be built even though other router is INACTIVE
417 AdjLsa* lsa = lsdb.findAdjLsa(lsaKey);
418 BOOST_REQUIRE(lsa != nullptr);
419 BOOST_CHECK_EQUAL(lsa->getAdl().getSize(), 1);
420
421 // Receive HELLO response from Router B
422 receiveHelloData(neighborBName, conf.getRouterPrefix());
423
424 // Both routers become INACTIVE and HELLO Interests have timed out
425 for (Adjacent& adjacency : neighbors.getAdjList()) {
426 adjacency.setStatus(Adjacent::STATUS_INACTIVE);
427 adjacency.setInterestTimedOutNo(HELLO_RETRIES_DEFAULT);
428 }
429
430 this->advanceClocks(ndn::time::seconds(1));
431
432 // Adjacency LSA should have been removed since this router's adjacencies are INACTIVE
433 // and have timed out
434 lsa = lsdb.findAdjLsa(lsaKey);
435 BOOST_CHECK(lsa == nullptr);
436
437 // Receive HELLO response from Router A and B
438 receiveHelloData(neighborAName, conf.getRouterPrefix());
439 receiveHelloData(neighborBName, conf.getRouterPrefix());
440 this->advanceClocks(ndn::time::seconds(1));
441
442 // Adjacency LSA should be built
443 lsa = lsdb.findAdjLsa(lsaKey);
444 BOOST_REQUIRE(lsa != nullptr);
445 BOOST_CHECK_EQUAL(lsa->getAdl().getSize(), 2);
446}
447
Vince Lehman09131122014-09-09 17:10:11 -0500448BOOST_AUTO_TEST_SUITE_END()
449
Nick Gordonfad8e252016-08-11 14:21:38 -0500450} // namespace test
451} // namespace nlsr