1 // Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8 #include <asiolink/io_address.h>
9 #include <dhcp/duid.h>
10 #include <dhcpsrv/csv_lease_file4.h>
11 #include <dhcpsrv/lease.h>
12 #include <dhcpsrv/testutils/lease_file_io.h>
13 #include <gtest/gtest.h>
14 #include <ctime>
15 #include <sstream>
16
17 using namespace isc;
18 using namespace isc::asiolink;
19 using namespace isc::data;
20 using namespace isc::dhcp;
21 using namespace isc::dhcp::test;
22 using namespace isc::util;
23
24 namespace {
25
26 // HWADDR values used by unit tests.
27 const uint8_t HWADDR0[] = { 0, 1, 2, 3, 4, 5 };
28 const uint8_t HWADDR1[] = { 0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf };
29
30 const uint8_t CLIENTID[] = { 1, 2, 3, 4 };
31
32 /// @brief Test fixture class for @c CSVLeaseFile4 validation.
33 class CSVLeaseFile4Test : public ::testing::Test {
34 public:
35
36 /// @brief Constructor.
37 ///
38 /// Initializes IO for lease file used by unit tests.
39 CSVLeaseFile4Test();
40
41 /// @brief Prepends the absolute path to the file specified
42 /// as an argument.
43 ///
44 /// @param filename Name of the file.
45 /// @return Absolute path to the test file.
46 static std::string absolutePath(const std::string& filename);
47
48 /// @brief Creates the lease file to be parsed by unit tests.
49 void writeSampleFile() const;
50
51 /// @brief Checks the stats for the file
52 ///
53 /// This method is passed a leasefile and the values for the statistics it
54 /// should have for comparison.
55 ///
56 /// @param lease_file A reference to the file we are using
57 /// @param reads the number of attempted reads
58 /// @param read_leases the number of valid leases read
59 /// @param read_errs the number of errors while reading leases
60 /// @param writes the number of attempted writes
61 /// @param write_leases the number of leases successfully written
62 /// @param write_errs the number of errors while writing
checkStats(CSVLeaseFile4 & lease_file,uint32_t reads,uint32_t read_leases,uint32_t read_errs,uint32_t writes,uint32_t write_leases,uint32_t write_errs) const63 void checkStats(CSVLeaseFile4& lease_file,
64 uint32_t reads, uint32_t read_leases,
65 uint32_t read_errs, uint32_t writes,
66 uint32_t write_leases, uint32_t write_errs) const {
67 EXPECT_EQ(reads, lease_file.getReads());
68 EXPECT_EQ(read_leases, lease_file.getReadLeases());
69 EXPECT_EQ(read_errs, lease_file.getReadErrs());
70 EXPECT_EQ(writes, lease_file.getWrites());
71 EXPECT_EQ(write_leases, lease_file.getWriteLeases());
72 EXPECT_EQ(write_errs, lease_file.getWriteErrs());
73 }
74
75 /// @brief Name of the test lease file.
76 std::string filename_;
77
78 /// @brief Object providing access to lease file IO.
79 LeaseFileIO io_;
80
81 /// @brief hardware address 0 (corresponds to HWADDR0 const)
82 HWAddrPtr hwaddr0_;
83
84 /// @brief hardware address 1 (corresponds to HWADDR1 const)
85 HWAddrPtr hwaddr1_;
86
87 };
88
CSVLeaseFile4Test()89 CSVLeaseFile4Test::CSVLeaseFile4Test()
90 : filename_(absolutePath("leases4.csv")), io_(filename_) {
91 hwaddr0_.reset(new HWAddr(HWADDR0, sizeof(HWADDR0), HTYPE_ETHER));
92 hwaddr1_.reset(new HWAddr(HWADDR1, sizeof(HWADDR1), HTYPE_ETHER));
93 }
94
95 std::string
absolutePath(const std::string & filename)96 CSVLeaseFile4Test::absolutePath(const std::string& filename) {
97 std::ostringstream s;
98 s << DHCP_DATA_DIR << "/" << filename;
99 return (s.str());
100 }
101
102 void
writeSampleFile() const103 CSVLeaseFile4Test::writeSampleFile() const {
104 io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
105 "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
106 "192.0.2.1,06:07:08:09:0a:bc,,200,200,8,1,1,"
107 "host.example.com,0,\n"
108 "192.0.2.2,,,200,200,8,1,1,host.example.com,0,\n"
109 "192.0.2.3,dd:de:ba:0d:1b:2e:3e:4f,0a:00:01:04,100,100,7,"
110 "0,0,,1,{ \"foobar\": true }\n"
111 "192.0.2.4,,11:22:33:44:55:66,200,200,8,1,1,host.example.com,0,\n"
112 "192.0.2.5,,,200,200,8,1,1,,1,\n");
113 }
114
115 // This test checks the capability to read and parse leases from the file.
TEST_F(CSVLeaseFile4Test,parse)116 TEST_F(CSVLeaseFile4Test, parse) {
117 // Create a file to be parsed.
118 writeSampleFile();
119
120 // Open the lease file.
121 CSVLeaseFile4 lf(filename_);
122 ASSERT_NO_THROW(lf.open());
123
124 // Verify the counters are cleared
125 {
126 SCOPED_TRACE("Check stats are empty");
127 checkStats(lf, 0, 0, 0, 0, 0, 0);
128 }
129
130 Lease4Ptr lease;
131 // Reading first read should be successful.
132 {
133 SCOPED_TRACE("First lease valid");
134 EXPECT_TRUE(lf.next(lease));
135 ASSERT_TRUE(lease);
136 checkStats(lf, 1, 1, 0, 0, 0, 0);
137
138 // Verify that the lease attributes are correct.
139 EXPECT_EQ("192.0.2.1", lease->addr_.toText());
140 HWAddr hwaddr1(*lease->hwaddr_);
141 EXPECT_EQ("06:07:08:09:0a:bc", hwaddr1.toText(false));
142 EXPECT_FALSE(lease->client_id_);
143 EXPECT_EQ(200, lease->valid_lft_);
144 EXPECT_EQ(0, lease->cltt_);
145 EXPECT_EQ(8, lease->subnet_id_);
146 EXPECT_TRUE(lease->fqdn_fwd_);
147 EXPECT_TRUE(lease->fqdn_rev_);
148 EXPECT_EQ("host.example.com", lease->hostname_);
149 EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
150 EXPECT_FALSE(lease->getContext());
151 }
152
153 // Second lease is malformed - has no HW address or client id and state
154 // is not declined.
155 {
156 SCOPED_TRACE("Second lease malformed");
157 EXPECT_FALSE(lf.next(lease));
158 EXPECT_FALSE(lease);
159 checkStats(lf, 2, 1, 1, 0, 0, 0);
160 }
161
162 // Even though parsing previous lease failed, reading the next lease should be
163 // successful.
164 {
165 SCOPED_TRACE("Third lease valid");
166 EXPECT_TRUE(lf.next(lease));
167 ASSERT_TRUE(lease);
168 checkStats(lf, 3, 2, 1, 0, 0, 0);
169
170 // Verify that the third lease is correct.
171 EXPECT_EQ("192.0.2.3", lease->addr_.toText());
172 HWAddr hwaddr3(*lease->hwaddr_);
173 EXPECT_EQ("dd:de:ba:0d:1b:2e:3e:4f", hwaddr3.toText(false));
174 ASSERT_TRUE(lease->client_id_);
175 EXPECT_EQ("0a:00:01:04", lease->client_id_->toText());
176 EXPECT_EQ(100, lease->valid_lft_);
177 EXPECT_EQ(0, lease->cltt_);
178 EXPECT_EQ(7, lease->subnet_id_);
179 EXPECT_FALSE(lease->fqdn_fwd_);
180 EXPECT_FALSE(lease->fqdn_rev_);
181 EXPECT_TRUE(lease->hostname_.empty());
182 EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
183 ASSERT_TRUE(lease->getContext());
184 EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
185 }
186
187 // Fourth lease has no hardware address but has client id
188 {
189 SCOPED_TRACE("Fourth lease valid");
190 EXPECT_TRUE(lf.next(lease));
191 ASSERT_TRUE(lease);
192 checkStats(lf, 4, 3, 1, 0, 0, 0);
193
194 EXPECT_EQ("192.0.2.4", lease->addr_.toText());
195 ASSERT_TRUE(lease->hwaddr_);
196 EXPECT_TRUE(lease->hwaddr_->hwaddr_.empty());
197 ASSERT_TRUE(lease->client_id_);
198 EXPECT_EQ("11:22:33:44:55:66", lease->client_id_->toText());
199 }
200
201 // Fifth lease has no hardware address or client id but is declined
202 {
203 SCOPED_TRACE("Fifth lease valid");
204 EXPECT_TRUE(lf.next(lease));
205 ASSERT_TRUE(lease);
206 checkStats(lf, 5, 4, 1, 0, 0, 0);
207
208 EXPECT_EQ("192.0.2.5", lease->addr_.toText());
209 ASSERT_TRUE(lease->hwaddr_);
210 EXPECT_TRUE(lease->hwaddr_->hwaddr_.empty());
211 ASSERT_FALSE(lease->client_id_);
212 EXPECT_EQ(lease->state_, Lease::STATE_DECLINED);
213 }
214
215 // There are no more leases. Reading should cause no error, but the returned
216 // lease pointer should be NULL.
217 {
218 SCOPED_TRACE("Sixth read empty");
219 EXPECT_TRUE(lf.next(lease));
220 EXPECT_FALSE(lease);
221 checkStats(lf, 6, 4, 1, 0, 0, 0);
222 }
223
224 // We should be able to do it again.
225 {
226 SCOPED_TRACE("Seventh read empty");
227 EXPECT_TRUE(lf.next(lease));
228 EXPECT_FALSE(lease);
229 checkStats(lf, 7, 4, 1, 0, 0, 0);
230 }
231 }
232
233 // This test checks creation of the lease file and writing leases.
TEST_F(CSVLeaseFile4Test,recreate)234 TEST_F(CSVLeaseFile4Test, recreate) {
235 CSVLeaseFile4 lf(filename_);
236 ASSERT_NO_THROW(lf.recreate());
237 ASSERT_TRUE(io_.exists());
238
239 // Verify the counters are cleared
240 checkStats(lf, 0, 0, 0, 0, 0, 0);
241
242 // Create first lease, with NULL client id.
243 Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
244 hwaddr0_,
245 NULL, 0,
246 200, 0, 8, true, true,
247 "host.example.com"));
248 lease->state_ = Lease::STATE_EXPIRED_RECLAIMED;
249 {
250 SCOPED_TRACE("First write");
251 ASSERT_NO_THROW(lf.append(*lease));
252 checkStats(lf, 0, 0, 0, 1, 1, 0);
253 }
254
255 // Create second lease, with non-NULL client id and user context.
256 lease.reset(new Lease4(IOAddress("192.0.3.10"),
257 hwaddr1_,
258 CLIENTID, sizeof(CLIENTID),
259 100, 0, 7));
260 lease->setContext(Element::fromJSON("{ \"foobar\": true }"));
261 {
262 SCOPED_TRACE("Second write");
263 ASSERT_NO_THROW(lf.append(*lease));
264 checkStats(lf, 0, 0, 0, 2, 2, 0);
265 }
266
267 // Close the lease file.
268 lf.close();
269 // Check that the contents of the csv file are correct.
270 EXPECT_EQ("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
271 "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
272 "192.0.3.2,00:01:02:03:04:05,,200,200,8,1,1,host.example.com,"
273 "2,\n"
274 "192.0.3.10,0d:0e:0a:0d:0b:0e:0e:0f,01:02:03:04,100,100,7,0,"
275 "0,,0,{ \"foobar\": true }\n",
276 io_.readFile());
277 }
278
279 // Verifies that a schema 1.0 file with records from
280 // schema 1.0 and 2.0 loads correctly.
TEST_F(CSVLeaseFile4Test,mixedSchemaload)281 TEST_F(CSVLeaseFile4Test, mixedSchemaload) {
282 // Create mixed schema file
283 io_.writeFile(
284 // schema 1.0 header
285 "address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
286 "fqdn_fwd,fqdn_rev,hostname\n"
287 // schema 1.0 record
288 "192.0.2.1,06:07:08:09:1a:bc,,200,200,8,1,1,"
289 "one.example.com\n"
290 // schema 2.0 record - has state
291 "192.0.2.2,06:07:08:09:2a:bc,,200,200,8,1,1,"
292 "two.example.com,1\n"
293 // schema 2.1 record - has state and user context
294 "192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
295 "three.example.com,2,{ \"foobar\": true }\n"
296 );
297
298 // Open the lease file.
299 CSVLeaseFile4 lf(filename_);
300 ASSERT_NO_THROW(lf.open());
301
302 Lease4Ptr lease;
303
304 // Reading first read should be successful.
305 {
306 SCOPED_TRACE("First lease valid");
307 EXPECT_TRUE(lf.next(lease));
308 ASSERT_TRUE(lease);
309
310 // Verify that the lease attributes are correct.
311 EXPECT_EQ("192.0.2.1", lease->addr_.toText());
312 HWAddr hwaddr1(*lease->hwaddr_);
313 EXPECT_EQ("06:07:08:09:1a:bc", hwaddr1.toText(false));
314 EXPECT_FALSE(lease->client_id_);
315 EXPECT_EQ(200, lease->valid_lft_);
316 EXPECT_EQ(0, lease->cltt_);
317 EXPECT_EQ(8, lease->subnet_id_);
318 EXPECT_TRUE(lease->fqdn_fwd_);
319 EXPECT_TRUE(lease->fqdn_rev_);
320 EXPECT_EQ("one.example.com", lease->hostname_);
321 // Verify that added state is DEFAULT
322 EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
323 EXPECT_FALSE(lease->getContext());
324 }
325
326 {
327 SCOPED_TRACE("Second lease valid");
328 EXPECT_TRUE(lf.next(lease));
329 ASSERT_TRUE(lease);
330
331 // Verify that the lease attributes are correct.
332 EXPECT_EQ("192.0.2.2", lease->addr_.toText());
333 HWAddr hwaddr1(*lease->hwaddr_);
334 EXPECT_EQ("06:07:08:09:2a:bc", hwaddr1.toText(false));
335 EXPECT_FALSE(lease->client_id_);
336 EXPECT_EQ(200, lease->valid_lft_);
337 EXPECT_EQ(0, lease->cltt_);
338 EXPECT_EQ(8, lease->subnet_id_);
339 EXPECT_TRUE(lease->fqdn_fwd_);
340 EXPECT_TRUE(lease->fqdn_rev_);
341 EXPECT_EQ("two.example.com", lease->hostname_);
342 EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
343 EXPECT_FALSE(lease->getContext());
344 }
345
346 {
347 SCOPED_TRACE("Third lease valid");
348 EXPECT_TRUE(lf.next(lease));
349 ASSERT_TRUE(lease);
350
351 // Verify that the third lease is correct.
352 EXPECT_EQ("192.0.2.3", lease->addr_.toText());
353 HWAddr hwaddr1(*lease->hwaddr_);
354 EXPECT_EQ("06:07:08:09:3a:bc", hwaddr1.toText(false));
355 EXPECT_FALSE(lease->client_id_);
356 EXPECT_EQ(200, lease->valid_lft_);
357 EXPECT_EQ(0, lease->cltt_);
358 EXPECT_EQ(8, lease->subnet_id_);
359 EXPECT_TRUE(lease->fqdn_fwd_);
360 EXPECT_TRUE(lease->fqdn_rev_);
361 EXPECT_EQ("three.example.com", lease->hostname_);
362 EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
363 ASSERT_TRUE(lease->getContext());
364 EXPECT_EQ("{ \"foobar\": true }", lease->getContext()->str());
365 }
366 }
367
368
369 // Verifies that a lease file with fewer header columns than the
370 // minimum allowed will not open.
TEST_F(CSVLeaseFile4Test,tooFewHeaderColumns)371 TEST_F(CSVLeaseFile4Test, tooFewHeaderColumns) {
372 // Create 1.0 file
373 io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
374 "fqdn_fwd,fqdn_rev\n");
375
376 // Open the lease file.
377 CSVLeaseFile4 lf(filename_);
378 ASSERT_THROW(lf.open(), CSVFileError);
379 }
380
381 // Verifies that a lease file with an unrecognized column header
382 // will not open.
TEST_F(CSVLeaseFile4Test,invalidHeaderColumn)383 TEST_F(CSVLeaseFile4Test, invalidHeaderColumn) {
384 // Create 1.0 file
385 io_.writeFile("address,hwaddr,BOGUS,valid_lifetime,expire,subnet_id,"
386 "fqdn_fwd,fqdn_rev,hostname,state,user_context\n");
387
388 // Open the lease file.
389 CSVLeaseFile4 lf(filename_);
390 ASSERT_THROW(lf.open(), CSVFileError);
391 }
392
393 // Verifies that a lease file with more header columns than defined
394 // columns will downgrade.
TEST_F(CSVLeaseFile4Test,downGrade)395 TEST_F(CSVLeaseFile4Test, downGrade) {
396 // Create 2.0 PLUS a column file
397 io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
398 "fqdn_fwd,fqdn_rev,hostname,state,user_context,FUTURE_COL\n"
399
400 "192.0.2.3,06:07:08:09:3a:bc,,200,200,8,1,1,"
401 "three.example.com,2,,BOGUS\n");
402
403 // Lease file should open and report as needing downgrade.
404 CSVLeaseFile4 lf(filename_);
405 ASSERT_NO_THROW(lf.open());
406 EXPECT_TRUE(lf.needsConversion());
407 EXPECT_EQ(util::VersionedCSVFile::NEEDS_DOWNGRADE,
408 lf.getInputSchemaState());
409 Lease4Ptr lease;
410
411 {
412 SCOPED_TRACE("First lease valid");
413 EXPECT_TRUE(lf.next(lease));
414 ASSERT_TRUE(lease);
415
416 // Verify that the third lease is correct.
417 EXPECT_EQ("192.0.2.3", lease->addr_.toText());
418 HWAddr hwaddr1(*lease->hwaddr_);
419 EXPECT_EQ("06:07:08:09:3a:bc", hwaddr1.toText(false));
420 EXPECT_FALSE(lease->client_id_);
421 EXPECT_EQ(200, lease->valid_lft_);
422 EXPECT_EQ(0, lease->cltt_);
423 EXPECT_EQ(8, lease->subnet_id_);
424 EXPECT_TRUE(lease->fqdn_fwd_);
425 EXPECT_TRUE(lease->fqdn_rev_);
426 EXPECT_EQ("three.example.com", lease->hostname_);
427 EXPECT_EQ(Lease::STATE_EXPIRED_RECLAIMED, lease->state_);
428 EXPECT_FALSE(lease->getContext());
429 }
430 }
431
432 // Verifies that leases with no hardware address are only permitted
433 // if they are in the declined state.
TEST_F(CSVLeaseFile4Test,declinedLeaseTest)434 TEST_F(CSVLeaseFile4Test, declinedLeaseTest) {
435 io_.writeFile("address,hwaddr,client_id,valid_lifetime,expire,subnet_id,"
436 "fqdn_fwd,fqdn_rev,hostname,state,user_context\n"
437 "192.0.2.1,,,200,200,8,1,1,host.example.com,0,\n"
438 "192.0.2.1,,,200,200,8,1,1,host.example.com,1,\n");
439
440 CSVLeaseFile4 lf(filename_);
441 ASSERT_NO_THROW(lf.open());
442 EXPECT_FALSE(lf.needsConversion());
443 EXPECT_EQ(util::VersionedCSVFile::CURRENT, lf.getInputSchemaState());
444 Lease4Ptr lease;
445
446 {
447 SCOPED_TRACE("No hardware and not declined, invalid");
448 EXPECT_FALSE(lf.next(lease));
449 ASSERT_FALSE(lease);
450 EXPECT_EQ(lf.getReadErrs(),1);
451 }
452
453 {
454 SCOPED_TRACE("No hardware and declined, valid");
455 EXPECT_TRUE(lf.next(lease));
456 ASSERT_TRUE(lease);
457 EXPECT_EQ(lf.getReadErrs(),1);
458 }
459 }
460
461 // Verifies that it is possible to output a lease with very high valid
462 // lifetime (infinite in RFC2131 terms) and current time, and then read
463 // back this lease.
TEST_F(CSVLeaseFile4Test,highLeaseLifetime)464 TEST_F(CSVLeaseFile4Test, highLeaseLifetime) {
465 CSVLeaseFile4 lf(filename_);
466 ASSERT_NO_THROW(lf.recreate());
467 ASSERT_TRUE(io_.exists());
468
469 // Write lease with very high lease lifetime and current time.
470 Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
471 hwaddr0_,
472 NULL, 0,
473 0xFFFFFFFF, time(0),
474 8, true, true,
475 "host.example.com"));
476 // Write this lease out to the lease file.
477 ASSERT_NO_THROW(lf.append(*lease));
478
479 // Close the lease file.
480 lf.close();
481
482 Lease4Ptr lease_read;
483
484 // Re-open the file for reading.
485 ASSERT_NO_THROW(lf.open());
486
487 // Read the lease and make sure it is successful.
488 EXPECT_TRUE(lf.next(lease_read));
489 ASSERT_TRUE(lease_read);
490
491 // The valid lifetime and the cltt should match with the original lease.
492 EXPECT_EQ(lease->valid_lft_, lease_read->valid_lft_);
493 EXPECT_EQ(lease->cltt_, lease_read->cltt_);
494 }
495
496 // Verifies that it is not possible to output a lease with empty hwaddr in other
497 // than the declined state
TEST_F(CSVLeaseFile4Test,emptyHWAddrDefaultStateOnly)498 TEST_F(CSVLeaseFile4Test, emptyHWAddrDefaultStateOnly) {
499 CSVLeaseFile4 lf(filename_);
500 ASSERT_NO_THROW(lf.recreate());
501 ASSERT_TRUE(io_.exists());
502
503 HWAddrPtr hwaddr;
504
505 // Create lease with null hwaddr and default state
506 Lease4Ptr lease_null_hwaddr(new Lease4(IOAddress("192.0.3.2"),
507 hwaddr,
508 NULL, 0,
509 0xFFFFFFFF, time(0),
510 8, true, true,
511 "host.example.com"));
512 // Try to write this lease out to the lease file.
513 ASSERT_THROW(lf.append(*lease_null_hwaddr), BadValue);
514
515 hwaddr.reset(new HWAddr());
516
517 // Create lease with empty hwaddr and default state
518 Lease4Ptr lease_empty_hwaddr(new Lease4(IOAddress("192.0.3.2"),
519 hwaddr,
520 NULL, 0,
521 0xFFFFFFFF, time(0),
522 8, true, true,
523 "host.example.com"));
524 // Try to write this lease out to the lease file.
525 ASSERT_THROW(lf.append(*lease_empty_hwaddr), BadValue);
526
527 // Create lease with hwaddr and current time.
528 Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
529 hwaddr0_,
530 NULL, 0,
531 0xFFFFFFFF, time(0),
532 8, true, true,
533 "host.example.com"));
534
535 // Decline the lease
536 lease->decline(1000);
537 ASSERT_TRUE(lease->hwaddr_);
538 EXPECT_EQ(lease->hwaddr_->toText(false), "");
539
540 // Write this lease out to the lease file.
541 ASSERT_NO_THROW(lf.append(*lease));
542
543 // Close the lease file.
544 lf.close();
545
546 Lease4Ptr lease_read;
547
548 // Re-open the file for reading.
549 ASSERT_NO_THROW(lf.open());
550
551 // Read the lease and make sure it is successful.
552 EXPECT_TRUE(lf.next(lease_read));
553 ASSERT_TRUE(lease_read);
554
555 // The valid lifetime and the cltt should match with the original lease.
556 EXPECT_EQ(lease->valid_lft_, lease_read->valid_lft_);
557 EXPECT_EQ(lease->cltt_, lease_read->cltt_);
558 }
559
560 // Verifies that it is possible to write and read a lease with commas
561 // in hostname and user context.
TEST_F(CSVLeaseFile4Test,embeddedCommas)562 TEST_F(CSVLeaseFile4Test, embeddedCommas) {
563 CSVLeaseFile4 lf(filename_);
564 ASSERT_NO_THROW(lf.recreate());
565 ASSERT_TRUE(io_.exists());
566
567 std::string hostname("host,example,com");
568 std::string context_str("{ \"bar\": true, \"foo\": false, \"x\": \"factor\" }");
569
570 // Create a lease with commas in the hostname.
571 Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
572 hwaddr0_,
573 NULL, 0,
574 0xFFFFFFFF, time(0),
575 8, true, true,
576 hostname));
577
578 // Add the user context with commas.
579 lease->setContext(Element::fromJSON(context_str));
580
581 // Write this lease out to the lease file.
582 ASSERT_NO_THROW(lf.append(*lease));
583
584 // Close the lease file.
585 lf.close();
586
587 Lease4Ptr lease_read;
588
589 // Re-open the file for reading.
590 ASSERT_NO_THROW(lf.open());
591
592 // Read the lease and make sure it is successful.
593 EXPECT_TRUE(lf.next(lease_read));
594 ASSERT_TRUE(lease_read);
595
596 // Expect the hostname and user context to retain the commas
597 // they started with.
598 EXPECT_EQ(hostname, lease->hostname_);
599 EXPECT_EQ(context_str, lease->getContext()->str());
600 }
601
602 // Verifies that it is possible to write and read a lease with
603 // escape tags and sequences in hostname and user context.
TEST_F(CSVLeaseFile4Test,embeddedEscapes)604 TEST_F(CSVLeaseFile4Test, embeddedEscapes) {
605 CSVLeaseFile4 lf(filename_);
606 ASSERT_NO_THROW(lf.recreate());
607 ASSERT_TRUE(io_.exists());
608
609 std::string hostname("hostxampleˌom");
610 std::string context_str("{ \"ºr\": true, \"foo\": false, \"x\": \"fac,tor\" }");
611
612 // Create a lease with commas in the hostname.
613 Lease4Ptr lease(new Lease4(IOAddress("192.0.3.2"),
614 hwaddr0_,
615 NULL, 0,
616 0xFFFFFFFF, time(0),
617 8, true, true,
618 hostname));
619
620 // Add the user context with commas.
621 lease->setContext(Element::fromJSON(context_str));
622
623 // Write this lease out to the lease file.
624 ASSERT_NO_THROW(lf.append(*lease));
625
626 // Close the lease file.
627 lf.close();
628
629 Lease4Ptr lease_read;
630
631 // Re-open the file for reading.
632 ASSERT_NO_THROW(lf.open());
633
634 // Read the lease and make sure it is successful.
635 EXPECT_TRUE(lf.next(lease_read));
636 ASSERT_TRUE(lease_read);
637
638 // Expect the hostname and user context to retain the commas
639 // they started with.
640 EXPECT_EQ(hostname, lease->hostname_);
641 EXPECT_EQ(context_str, lease->getContext()->str());
642 }
643
644 /// @todo Currently we don't check invalid lease attributes, such as invalid
645 /// lease type, invalid preferred lifetime vs valid lifetime etc. The Lease6
646 /// should be extended with the function that validates lease attributes. Once
647 /// this is implemented we should provide more tests for malformed leases
648 /// in the CSV file. See http://oldkea.isc.org/ticket/2405.
649
650 } // end of anonymous namespace
651