blob: 521be9bac3156d317e5d7010eeddc2e5fd1c4e99 [file] [log] [blame]
Yingdi Yu6ff31932015-03-23 13:30:07 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014, Regents of the University of California
4 *
5 * This file is part of NSL (NDN Signature Logger).
6 * See AUTHORS.md for complete list of NSL authors and contributors.
7 *
8 * NSL is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * NSL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * NSL, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of nsl authors and contributors.
20 */
21
22#include "logger.hpp"
23#include "identity-fixture.hpp"
24#include "db-fixture.hpp"
25#include <ndn-cxx/util/dummy-client-face.hpp>
26#include <ndn-cxx/util/io.hpp>
27
28#include "boost-test.hpp"
29
30namespace nsl {
31namespace tests {
32
33class LoggerFixture : public IdentityFixture
34 , public DbFixture
35{
36public:
37 LoggerFixture()
38 : face1(ndn::util::makeDummyClientFace(io, {true, true}))
39 , face2(ndn::util::makeDummyClientFace(io, {true, true}))
40 , readInterestOffset1(0)
41 , readDataOffset1(0)
42 , readInterestOffset2(0)
43 , readDataOffset2(0)
44 {
45 }
46
47 ~LoggerFixture()
48 {
49 }
50
51 bool
52 passPacket()
53 {
54 bool hasPassed = false;
55
56 checkFace(face1->sentInterests, readInterestOffset1, *face2, hasPassed);
57 checkFace(face1->sentDatas, readDataOffset1, *face2, hasPassed);
58 checkFace(face2->sentInterests, readInterestOffset2, *face1, hasPassed);
59 checkFace(face2->sentDatas, readDataOffset2, *face1, hasPassed);
60
61 return hasPassed;
62 }
63
64 template<typename Packet>
65 void
66 checkFace(std::vector<Packet>& receivedPackets,
67 size_t& readPacketOffset,
68 ndn::util::DummyClientFace& receiver,
69 bool& hasPassed)
70 {
71 while (receivedPackets.size() > readPacketOffset) {
72 receiver.receive(receivedPackets[readPacketOffset]);
73 readPacketOffset++;
74 hasPassed = true;
75 }
76 }
77
78 void
79 clear()
80 {
81 face1->sentDatas.clear();
82 face1->sentInterests.clear();
83 face2->sentDatas.clear();
84 face2->sentInterests.clear();
85
86 readInterestOffset1 = 0;
87 readDataOffset1 = 0;
88 readInterestOffset2 = 0;
89 readDataOffset2 = 0;
90 }
91
92public:
93 shared_ptr<ndn::util::DummyClientFace> face1;
94 shared_ptr<ndn::util::DummyClientFace> face2;
95
96 size_t readInterestOffset1;
97 size_t readDataOffset1;
98 size_t readInterestOffset2;
99 size_t readDataOffset2;
100};
101
102BOOST_FIXTURE_TEST_SUITE(TestLogger, LoggerFixture)
103
104const std::string CONFIG =
105 "logger-name /test/logger \n"
106 "policy \n"
107 "{ \n"
108 " rule \n"
109 " { \n"
110 " id \"Simple Rule\" \n"
111 " for data \n"
112 " checker \n"
113 " { \n"
114 " type customized \n"
115 " sig-type rsa-sha256 \n"
116 " key-locator \n"
117 " { \n"
118 " type name \n"
119 " hyper-relation \n"
120 " { \n"
121 " k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
122 " k-expand \\\\1\\\\2 \n"
123 " h-relation is-strict-prefix-of \n"
124 " p-regex ^(<>*)$ \n"
125 " p-expand \\\\1 \n"
126 " } \n"
127 " } \n"
128 " } \n"
129 " } \n"
130 "} \n"
131 "validator \n"
132 "{ \n"
133 " rule \n"
134 " { \n"
135 " id \"Request Rule\" \n"
136 " for interest \n"
137 " filter \n"
138 " { \n"
139 " type name \n"
140 " name /test/logger/log \n"
141 " relation is-strict-prefix-of \n"
142 " } \n"
143 " checker \n"
144 " { \n"
145 " type customized \n"
146 " sig-type rsa-sha256 \n"
147 " key-locator \n"
148 " { \n"
149 " type name \n"
150 " regex ^[^<KEY>]*<KEY><>*<><ID-CERT>$ \n"
151 " } \n"
152 " } \n"
153 " } \n"
154 " rule \n"
155 " { \n"
156 " id \"Simple Rule\" \n"
157 " for data \n"
158 " checker \n"
159 " { \n"
160 " type customized \n"
161 " sig-type rsa-sha256 \n"
162 " key-locator \n"
163 " { \n"
164 " type name \n"
165 " hyper-relation \n"
166 " { \n"
167 " k-regex ^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>$ \n"
168 " k-expand \\\\1\\\\2 \n"
169 " h-relation is-strict-prefix-of \n"
170 " p-regex ^(<>*)$ \n"
171 " p-expand \\\\1 \n"
172 " } \n"
173 " } \n"
174 " } \n"
175 " } \n"
176 " trust-anchor \n"
177 " { \n"
178 " type file \n"
179 " file-name \"trust-anchor.cert\" \n"
180 " } \n"
181 "} \n";
182
183BOOST_AUTO_TEST_CASE(Basic)
184{
185 namespace fs = boost::filesystem;
186
187 fs::create_directory(fs::path(TEST_LOGGER_PATH));
188
189 fs::path configPath = fs::path(TEST_LOGGER_PATH) / "logger-test.conf";
190 std::ofstream os(configPath.c_str());
191 os << CONFIG;
192 os.close();
193
194 Name root("/ndn");
195 addIdentity(root);
196 auto rootCert = m_keyChain.getCertificate(m_keyChain.getDefaultCertificateNameForIdentity(root));
197 fs::path certPath = fs::path(TEST_LOGGER_PATH) / "trust-anchor.cert";
198 ndn::io::save(*rootCert, certPath.string());
199
200 Logger logger(*face1, configPath.string());
201
202 BOOST_CHECK_EQUAL(logger.getLoggerName(), Name("/test/logger"));
203 BOOST_CHECK_EQUAL(logger.getTreePrefix(), Name("/test/logger/tree"));
204 BOOST_CHECK_EQUAL(logger.getLeafPrefix(), Name("/test/logger/leaf"));
205 BOOST_CHECK_EQUAL(logger.getLogPrefix(), Name("/test/logger/log"));
206
207 advanceClocks(time::milliseconds(2), 100);
208
209 Timestamp rootTs = time::toUnixTimestamp(time::system_clock::now()).count() / 1000;
210 NonNegativeInteger rootSeqNo = logger.addSelfSignedCert(*rootCert, rootTs);
211 BOOST_CHECK_EQUAL(rootSeqNo, 0);
212
213 Name leafInterestName("/test/logger/leaf");
214 leafInterestName.appendNumber(0);
215 auto leafInterest = make_shared<Interest>(leafInterestName);
216
217 face1->receive(*leafInterest);
218 advanceClocks(time::milliseconds(2), 100);
219
220 BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
221 BOOST_CHECK(leafInterestName.isPrefixOf(face1->sentDatas[0].getName()));
222
223 face1->sentDatas.clear();
224
225 Name treeInterestName("/test/logger/tree");
226 treeInterestName.appendNumber(0);
227 treeInterestName.appendNumber(0);
228 auto treeInterest = make_shared<Interest>(treeInterestName);
229
230 face1->receive(*treeInterest);
231 advanceClocks(time::milliseconds(2), 100);
232
233 BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
234 BOOST_CHECK(treeInterestName.isPrefixOf(face1->sentDatas[0].getName()));
235
236 face1->sentDatas.clear();
237
238 Name tld("/ndn/tld");
239 Name tldKeyName = m_keyChain.generateRsaKeyPair(tld);
240 std::vector<ndn::CertificateSubjectDescription> subjectDescription;
241 auto tldCert =
242 m_keyChain.prepareUnsignedIdentityCertificate(tldKeyName, root,
243 time::system_clock::now(),
244 time::system_clock::now() + time::days(1),
245 subjectDescription);
246 m_keyChain.signByIdentity(*tldCert, root);
247 m_keyChain.addCertificate(*tldCert);
248
249 face2->setInterestFilter(tldCert->getName().getPrefix(-1),
250 [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*tldCert); },
251 ndn::RegisterPrefixSuccessCallback(),
252 [] (const Name&, const std::string&) {});
253 advanceClocks(time::milliseconds(2), 100);
254 clear();
255
256 Name logInterestName("/test/logger/log");
257 logInterestName.append(tldCert->getFullName().wireEncode());
258 logInterestName.appendNumber(0);
259 auto logInterest = make_shared<Interest>(logInterestName);
260 m_keyChain.sign(*logInterest, tldCert->getName());
261
262 face1->receive(*logInterest);
263 do {
264 advanceClocks(time::milliseconds(2), 100);
265 } while (passPacket());
266 clear();
267
268 BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 2);
269 auto leafResult1 = logger.getDb().getLeaf(1);
270 BOOST_CHECK(leafResult1.first != nullptr);
271 BOOST_CHECK(leafResult1.second != nullptr);
272
273
274
275 Name leafInterestName2("/test/logger/leaf");
276 leafInterestName2.appendNumber(1);
277 auto leafInterest2 = make_shared<Interest>(leafInterestName2);
278
279 face1->receive(*leafInterest2);
280 advanceClocks(time::milliseconds(2), 100);
281
282 BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
283 BOOST_CHECK(leafInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
284 clear();
285
286
287
288 Name treeInterestName2("/test/logger/tree");
289 treeInterestName2.appendNumber(1);
290 treeInterestName2.appendNumber(0);
291 auto treeInterest2 = make_shared<Interest>(treeInterestName2);
292
293 face1->receive(*treeInterest2);
294 advanceClocks(time::milliseconds(2), 100);
295
296 BOOST_CHECK_EQUAL(face1->sentDatas.size(), 1);
297 BOOST_CHECK(treeInterestName2.isPrefixOf(face1->sentDatas[0].getName()));
298 clear();
299
300
301 auto data = make_shared<Data>(Name("/ndn/tld/data"));
302 m_keyChain.sign(*data, tldCert->getName());
303
304 face2->setInterestFilter(data->getName(),
305 [&] (const ndn::InterestFilter&, const Interest&) { face2->put(*data); },
306 ndn::RegisterPrefixSuccessCallback(),
307 [] (const Name&, const std::string&) {});
308 advanceClocks(time::milliseconds(2), 100);
309 clear();
310
311 Name logInterestName2("/test/logger/log");
312 logInterestName2.append(data->getFullName().wireEncode());
313 logInterestName2.appendNumber(1);
314 auto logInterest2 = make_shared<Interest>(logInterestName2);
315 m_keyChain.sign(*logInterest2, tldCert->getName());
316
317 face1->receive(*logInterest2);
318 do {
319 advanceClocks(time::milliseconds(2), 100);
320 } while (passPacket());
321 clear();
322
323 BOOST_CHECK_EQUAL(logger.getDb().getMaxLeafSeq(), 3);
324 auto leafResult2 = logger.getDb().getLeaf(2);
325 BOOST_CHECK(leafResult2.first != nullptr);
326 BOOST_CHECK(leafResult2.second == nullptr);
327
328
329 fs::remove_all(fs::path(TEST_LOGGER_PATH));
330}
331
332BOOST_AUTO_TEST_SUITE_END()
333
334} // namespace tests
335} // namespace nsl