database_unittest.cc 102 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
16
#include <boost/foreach.hpp>

17
18
19
#include <gtest/gtest.h>

#include <dns/name.h>
20
#include <dns/rrttl.h>
21
#include <dns/rrset.h>
22
#include <exceptions/exceptions.h>
23
24

#include <datasrc/database.h>
25
26
#include <datasrc/zone.h>
#include <datasrc/data_source.h>
27
#include <datasrc/iterator.h>
28
#include <datasrc/sqlite3_accessor.h>
29

30
31
#include <testutils/dnsmessage_test.h>

32
#include <map>
33
34
35
36

using namespace isc::datasrc;
using namespace std;
using namespace boost;
37
using namespace isc::dns;
38
39
40

namespace {

41
42
43
44
// Imaginary zone IDs used in the mock accessor below.
const int READONLY_ZONE_ID = 42;
const int WRITABLE_ZONE_ID = 4200;

45
46
47
48
49
50
// Commonly used test data
const char* const TEST_RECORDS[][5] = {
    // some plain data
    {"www.example.org.", "A", "3600", "", "192.0.2.1"},
    {"www.example.org.", "AAAA", "3600", "", "2001:db8::1"},
    {"www.example.org.", "AAAA", "3600", "", "2001:db8::2"},
51
52
    {"www.example.org.", "NSEC", "3600", "", "www2.example.org. A AAAA NSEC RRSIG"},
    {"www.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
53
54

    {"www2.example.org.", "A", "3600", "", "192.0.2.1"},
55
    {"www2.example.org.", "AAAA", "3600", "", "2001:db8::1"},
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
    {"www2.example.org.", "A", "3600", "", "192.0.2.2"},

    {"cname.example.org.", "CNAME", "3600", "", "www.example.org."},

    // some DNSSEC-'signed' data
    {"signed1.example.org.", "A", "3600", "", "192.0.2.1"},
    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    {"signed1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::1"},
    {"signed1.example.org.", "AAAA", "3600", "", "2001:db8::2"},
    {"signed1.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    {"signedcname1.example.org.", "CNAME", "3600", "", "www.example.org."},
    {"signedcname1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    // special case might fail; sig is for cname, which isn't there (should be ignored)
    // (ignoring of 'normal' other type is done above by www.)
    {"acnamesig1.example.org.", "A", "3600", "", "192.0.2.1"},
    {"acnamesig1.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"acnamesig1.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    // let's pretend we have a database that is not careful
    // about the order in which it returns data
    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::2"},
    {"signed2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE"},
    {"signed2.example.org.", "A", "3600", "", "192.0.2.1"},
    {"signed2.example.org.", "RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"signed2.example.org.", "AAAA", "3600", "", "2001:db8::1"},

    {"signedcname2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"signedcname2.example.org.", "CNAME", "3600", "", "www.example.org."},

    {"acnamesig2.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"acnamesig2.example.org.", "A", "3600", "", "192.0.2.1"},
    {"acnamesig2.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    {"acnamesig3.example.org.", "RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"acnamesig3.example.org.", "RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"acnamesig3.example.org.", "A", "3600", "", "192.0.2.1"},

    {"ttldiff1.example.org.", "A", "3600", "", "192.0.2.1"},
    {"ttldiff1.example.org.", "A", "360", "", "192.0.2.2"},

    {"ttldiff2.example.org.", "A", "360", "", "192.0.2.1"},
    {"ttldiff2.example.org.", "A", "3600", "", "192.0.2.2"},

    // also add some intentionally bad data
    {"badcname1.example.org.", "A", "3600", "", "192.0.2.1"},
    {"badcname1.example.org.", "CNAME", "3600", "", "www.example.org."},

    {"badcname2.example.org.", "CNAME", "3600", "", "www.example.org."},
    {"badcname2.example.org.", "A", "3600", "", "192.0.2.1"},

    {"badcname3.example.org.", "CNAME", "3600", "", "www.example.org."},
    {"badcname3.example.org.", "CNAME", "3600", "", "www.example2.org."},

    {"badrdata.example.org.", "A", "3600", "", "bad"},

    {"badtype.example.org.", "BAD_TYPE", "3600", "", "192.0.2.1"},

    {"badttl.example.org.", "A", "badttl", "", "192.0.2.1"},

    {"badsig.example.org.", "A", "badttl", "", "192.0.2.1"},
    {"badsig.example.org.", "RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    {"badsigtype.example.org.", "A", "3600", "", "192.0.2.1"},
    {"badsigtype.example.org.", "RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},

    // Data for testing delegation (with NS and DNAME)
    {"delegation.example.org.", "NS", "3600", "", "ns.example.com."},
    {"delegation.example.org.", "NS", "3600", "",
     "ns.delegation.example.org."},
    {"delegation.example.org.", "RRSIG", "3600", "", "NS 5 3 3600 "
     "20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
    {"ns.delegation.example.org.", "A", "3600", "", "192.0.2.1"},
    {"deep.below.delegation.example.org.", "A", "3600", "", "192.0.2.1"},

    {"dname.example.org.", "A", "3600", "", "192.0.2.1"},
    {"dname.example.org.", "DNAME", "3600", "", "dname.example.com."},
    {"dname.example.org.", "RRSIG", "3600", "",
     "DNAME 5 3 3600 20000101000000 20000201000000 12345 "
     "example.org. FAKEFAKEFAKE"},

    {"below.dname.example.org.", "A", "3600", "", "192.0.2.1"},

    // Broken NS
    {"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
    {"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},

    {"brokenns2.example.org.", "NS", "3600", "", "ns.example.com."},
    {"brokenns2.example.org.", "A", "3600", "", "192.0.2.1"},

    // Now double DNAME, to test failure mode
    {"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
    {"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},

    // Put some data into apex (including NS) so we can check our NS
    // doesn't break anything
    {"example.org.", "NS", "3600", "", "ns.example.com."},
    {"example.org.", "A", "3600", "", "192.0.2.1"},
    {"example.org.", "RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
              "20000201000000 12345 example.org. FAKEFAKEFAKE"},

    // This is because of empty domain test
    {"a.b.example.org.", "A", "3600", "", "192.0.2.1"},

    // Something for wildcards
    {"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
166
    {"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
167
168
    {"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
    {"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
169
170
171
172
173
    {"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
    {"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
    {"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
    {"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
    {"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},
174
175
    // For finding previous, this one is the last one in the zone
    {"zzz.example.org.", "NSEC", "3600", "", "example.org NSEC"},
176
177
178
179

    {NULL, NULL, NULL, NULL, NULL},
};

180
/*
181
 * An accessor with minimum implementation, keeping the original
182
 * "NotImplemented" methods.
183
 */
184
class NopAccessor : public DatabaseAccessor {
185
public:
186
187
    NopAccessor() : database_name_("mock_database")
    { }
188

189
190
    virtual std::pair<bool, int> getZone(const std::string& name) const {
        if (name == "example.org.") {
191
            return (std::pair<bool, int>(true, READONLY_ZONE_ID));
192
        } else if (name == "null.example.org.") {
193
            return (std::pair<bool, int>(true, 13));
194
        } else if (name == "empty.example.org.") {
195
            return (std::pair<bool, int>(true, 0));
196
        } else if (name == "bad.example.org.") {
197
            return (std::pair<bool, int>(true, -1));
198
199
200
201
        } else {
            return (std::pair<bool, int>(false, 0));
        }
    }
202

203
204
205
    virtual shared_ptr<DatabaseAccessor> clone() {
        return (shared_ptr<DatabaseAccessor>()); // bogus data, but unused
    }
206

JINMEI Tatuya's avatar
JINMEI Tatuya committed
207
208
209
210
211
212
    virtual std::pair<bool, int> startUpdateZone(const std::string&, bool) {
        // return dummy value.  unused anyway.
        return (pair<bool, int>(true, 0));
    }
    virtual void commitUpdateZone() {}
    virtual void rollbackUpdateZone() {}
213
214
    virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
    virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
215

216
217
218
219
    virtual const std::string& getDBName() const {
        return (database_name_);
    }

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
220
221
222
    virtual IteratorContextPtr getRecords(const std::string&, int, bool)
        const
        {
223
224
        isc_throw(isc::NotImplemented,
                  "This database datasource can't be iterated");
225
    }
226
227
228
229

    virtual IteratorContextPtr getAllRecords(int) const {
        isc_throw(isc::NotImplemented,
                  "This database datasource can't be iterated");
230
231
    }

232
233
234
235
    virtual std::string findPreviousName(int, const std::string&) const {
        isc_throw(isc::NotImplemented,
                  "This data source doesn't support DNSSEC");
    }
236
237
238
private:
    const std::string database_name_;

239
240
};

241
/*
242
 * A virtual database accessor that pretends it contains single zone --
243
244
245
246
247
 * example.org.
 *
 * It has the same getZone method as NopConnection, but it provides
 * implementation of the optional functionality.
 */
248
class MockAccessor : public NopAccessor {
249
250
251
252
    // Type of mock database "row"s
    typedef std::map<std::string, std::vector< std::vector<std::string> > >
        Domains;

253
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
254
    MockAccessor() : rollbacked_(false) {
255
256
257
        readonly_records_ = &readonly_records_master_;
        update_records_ = &update_records_master_;
        empty_records_ = &empty_records_master_;
258
259
        fillData();
    }
260
261
262
263
264
265
266
267
268
269

    virtual shared_ptr<DatabaseAccessor> clone() {
        shared_ptr<MockAccessor> cloned_accessor(new MockAccessor());
        cloned_accessor->readonly_records_ = &readonly_records_master_;
        cloned_accessor->update_records_ = &update_records_master_;
        cloned_accessor->empty_records_ = &empty_records_master_;
        latest_clone_ = cloned_accessor;
        return (cloned_accessor);
    }

270
private:
271
272
273
    class MockNameIteratorContext : public IteratorContext {
    public:
        MockNameIteratorContext(const MockAccessor& mock_accessor, int zone_id,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
274
                                const std::string& name, bool subdomains) :
275
            searched_name_(name), cur_record_(0)
276
        {
277
            // 'hardcoded' names to trigger exceptions
278
            // On these names some exceptions are thrown, to test the robustness
279
            // of the find() method.
280
281
282
283
284
285
286
287
            if (searched_name_ == "dsexception.in.search.") {
                isc_throw(DataSourceError, "datasource exception on search");
            } else if (searched_name_ == "iscexception.in.search.") {
                isc_throw(isc::Exception, "isc exception on search");
            } else if (searched_name_ == "basicexception.in.search.") {
                throw std::exception();
            }

288
289
290
            cur_record_ = 0;
            const Domains& cur_records = mock_accessor.getMockRecords(zone_id);
            if (cur_records.count(name) > 0) {
291
292
                    // we're not aiming for efficiency in this test, simply
                    // copy the relevant vector from records
293
294
295
296
297
298
299
300
301
302
303
304
                    cur_name = cur_records.find(name)->second;
            } else if (subdomains) {
                cur_name.clear();
                // Just walk everything and check if it is a subdomain.
                // If it is, just copy all data from there.
                for (Domains::const_iterator i(cur_records.begin());
                     i != cur_records.end(); ++i) {
                    const Name local(i->first);
                    if (local.compare(Name(name)).getRelation() ==
                        isc::dns::NameComparisonResult::SUBDOMAIN) {
                        cur_name.insert(cur_name.end(), i->second.begin(),
                                        i->second.end());
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
305
                    }
306
                }
307
308
            } else {
                cur_name.clear();
309
310
311
            }
        }

312
        virtual bool getNext(std::string (&columns)[COLUMN_COUNT]) {
313
314
315
316
317
318
319
320
321
            if (searched_name_ == "dsexception.in.getnext.") {
                isc_throw(DataSourceError, "datasource exception on getnextrecord");
            } else if (searched_name_ == "iscexception.in.getnext.") {
                isc_throw(isc::Exception, "isc exception on getnextrecord");
            } else if (searched_name_ == "basicexception.in.getnext.") {
                throw std::exception();
            }

            if (cur_record_ < cur_name.size()) {
322
                for (size_t i = 0; i < COLUMN_COUNT; ++i) {
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
                    columns[i] = cur_name[cur_record_][i];
                }
                cur_record_++;
                return (true);
            } else {
                return (false);
            }
        }

    private:
        const std::string searched_name_;
        int cur_record_;
        std::vector< std::vector<std::string> > cur_name;
    };

338
339
340
341
342
343
344
    class MockIteratorContext : public IteratorContext {
    private:
        int step;
    public:
        MockIteratorContext() :
            step(0)
        { }
345
        virtual bool getNext(string (&data)[COLUMN_COUNT]) {
346
347
            switch (step ++) {
                case 0:
348
349
350
351
                    data[DatabaseAccessor::NAME_COLUMN] = "example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "SOA";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "ns1.example.org. admin.example.org. "
352
353
354
                        "1234 3600 1800 2419200 7200";
                    return (true);
                case 1:
355
356
357
358
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "A";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.1";
359
360
                    return (true);
                case 2:
361
362
363
364
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "A";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.2";
365
366
                    return (true);
                case 3:
367
368
369
370
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::1";
371
372
                    return (true);
                case 4:
373
374
375
376
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::2";
377
378
379
380
381
382
383
384
385
386
387
                    return (true);
                default:
                    ADD_FAILURE() <<
                        "Request past the end of iterator context";
                case 5:
                    return (false);
            }
        }
    };
    class EmptyIteratorContext : public IteratorContext {
    public:
388
        virtual bool getNext(string(&)[COLUMN_COUNT]) {
389
390
391
392
393
394
395
396
397
398
            return (false);
        }
    };
    class BadIteratorContext : public IteratorContext {
    private:
        int step;
    public:
        BadIteratorContext() :
            step(0)
        { }
399
        virtual bool getNext(string (&data)[COLUMN_COUNT]) {
400
401
            switch (step ++) {
                case 0:
402
403
404
405
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "A";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.1";
406
407
                    return (true);
                case 1:
408
409
410
411
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "A";
                    data[DatabaseAccessor::TTL_COLUMN] = "301";
                    data[DatabaseAccessor::RDATA_COLUMN] = "192.0.2.2";
412
413
414
415
416
417
418
419
420
421
                    return (true);
                default:
                    ADD_FAILURE() <<
                        "Request past the end of iterator context";
                case 2:
                    return (false);
            }
        }
    };
public:
422
    virtual IteratorContextPtr getAllRecords(int id) const {
423
        if (id == READONLY_ZONE_ID) {
424
425
426
427
428
429
430
431
432
433
434
            return (IteratorContextPtr(new MockIteratorContext()));
        } else if (id == 13) {
            return (IteratorContextPtr());
        } else if (id == 0) {
            return (IteratorContextPtr(new EmptyIteratorContext()));
        } else if (id == -1) {
            return (IteratorContextPtr(new BadIteratorContext()));
        } else {
            isc_throw(isc::Unexpected, "Unknown zone ID");
        }
    }
435

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
436
437
438
    virtual IteratorContextPtr getRecords(const std::string& name, int id,
                                          bool subdomains) const
    {
439
440
441
442
        if (id == READONLY_ZONE_ID || id == WRITABLE_ZONE_ID) {
            return (IteratorContextPtr(
                        new MockNameIteratorContext(*this, id, name,
                                                    subdomains)));
443
444
445
446
447
        } else {
            isc_throw(isc::Unexpected, "Unknown zone ID");
        }
    }

448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
    virtual pair<bool, int> startUpdateZone(const std::string& zone_name,
                                            bool replace)
    {
        const pair<bool, int> zone_info = getZone(zone_name);
        if (!zone_info.first) {
            return (pair<bool, int>(false, 0));
        }

        // Prepare the record set for update.  If replacing the existing one,
        // we use an empty set; otherwise we use a writable copy of the
        // original.
        if (replace) {
            update_records_->clear();
        } else {
            *update_records_ = *readonly_records_;
        }

        return (pair<bool, int>(true, WRITABLE_ZONE_ID));
    }
    virtual void commitUpdateZone() {
        *readonly_records_ = *update_records_;
    }
    virtual void rollbackUpdateZone() {
471
472
473
474
475
476
477
        // Special hook: if something with a name of "throw.example.org"
        // has been added, trigger an imaginary unexpected event with an
        // exception.
        if (update_records_->count("throw.example.org.") > 0) {
            isc_throw(DataSourceError, "unexpected failure in rollback");
        }

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
        rollbacked_ = true;
    }
    virtual void addRecordToZone(const string (&columns)[ADD_COLUMN_COUNT]) {
        // Copy the current value to cur_name.  If it doesn't exist,
        // operator[] will create a new one.
        cur_name_ = (*update_records_)[columns[DatabaseAccessor::ADD_NAME]];

        vector<string> record_columns;
        record_columns.push_back(columns[DatabaseAccessor::ADD_TYPE]);
        record_columns.push_back(columns[DatabaseAccessor::ADD_TTL]);
        record_columns.push_back(columns[DatabaseAccessor::ADD_SIGTYPE]);
        record_columns.push_back(columns[DatabaseAccessor::ADD_RDATA]);
        record_columns.push_back(columns[DatabaseAccessor::ADD_NAME]);

        // copy back the added entry
        cur_name_.push_back(record_columns);
        (*update_records_)[columns[DatabaseAccessor::ADD_NAME]] = cur_name_;

        // remember this one so that test cases can check it.
        copy(columns, columns + DatabaseAccessor::ADD_COLUMN_COUNT,
             columns_lastadded_);
    }

    // Helper predicate class used in deleteRecordInZone().
    struct deleteMatch {
        deleteMatch(const string& type, const string& rdata) :
            type_(type), rdata_(rdata)
        {}
        bool operator()(const vector<string>& row) const {
            return (row[0] == type_ && row[3] == rdata_);
        }
        const string& type_;
        const string& rdata_;
    };

    virtual void deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
        vector<vector<string> >& records =
            (*update_records_)[params[DatabaseAccessor::DEL_NAME]];
        records.erase(remove_if(records.begin(), records.end(),
                                deleteMatch(
                                    params[DatabaseAccessor::DEL_TYPE],
                                    params[DatabaseAccessor::DEL_RDATA])),
                      records.end());
        if (records.empty()) {
            (*update_records_).erase(params[DatabaseAccessor::DEL_NAME]);
        }
    }

526
527
528
529
530
531
532
    //
    // Helper methods to keep track of some update related activities
    //
    bool isRollbacked() const {
        return (rollbacked_);
    }

533
    const string* getLastAdded() const {
534
535
536
537
538
539
540
541
        return (columns_lastadded_);
    }

    // This allows the test code to get the accessor used in an update context
    shared_ptr<const MockAccessor> getLatestClone() const {
        return (latest_clone_);
    }

542
    virtual std::string findPreviousName(int id, const std::string& rname)
543
544
545
546
547
548
549
        const
    {
        // Hardcoded for now, but we could compute it from the data
        // Maybe do it when it is needed some time in future?
        if (id == -1) {
            isc_throw(isc::NotImplemented, "Test not implemented behaviour");
        } else if (id == 42) {
550
            if (rname == "org.example.") {
551
                return ("zzz.example.org.");
552
553
            } else if (rname == "org.example.www2." ||
                       rname == "org.example.www1.") {
554
                return ("www.example.org.");
555
556
            } else if (rname == "org.example.notimplnsec.") {
                isc_throw(isc::NotImplemented, "Not implemented in this test");
557
558
559
560
561
562
563
564
            } else {
                isc_throw(isc::Unexpected, "Unexpected name");
            }
        } else {
            isc_throw(isc::Unexpected, "Unknown zone ID");
        }
    }

565
private:
566
567
    // The following member variables are storage and/or update work space
    // of the test zone.  The "master"s are the real objects that contain
568
    // the data, and they are shared among all accessors cloned from
569
570
571
572
573
574
575
576
577
578
579
580
    // an initially created one.  The pointer members allow the sharing.
    // "readonly" is for normal lookups.  "update" is the workspace for
    // updates.  When update starts it will be initialized either as an
    // empty set (when replacing the entire zone) or as a copy of the
    // "readonly" one.  "empty" is a sentinel to produce negative results.
    Domains readonly_records_master_;
    Domains* readonly_records_;
    Domains update_records_master_;
    Domains* update_records_;
    const Domains empty_records_master_;
    const Domains* empty_records_;

581
    // used as temporary storage during the building of the fake data
582

583
584
585
    // used as temporary storage after searchForRecord() and during
    // getNextRecord() calls, as well as during the building of the
    // fake data
586
587
588
    std::vector< std::vector<std::string> > cur_name_;

    // The columns that were most recently added via addRecordToZone()
589
    string columns_lastadded_[ADD_COLUMN_COUNT];
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605

    // Whether rollback operation has been performed for the database.
    // Not useful except for purely testing purpose.
    bool rollbacked_;

    // Remember the mock accessor that was last cloned
    boost::shared_ptr<MockAccessor> latest_clone_;

    const Domains& getMockRecords(int zone_id) const {
        if (zone_id == READONLY_ZONE_ID) {
            return (*readonly_records_);
        } else if (zone_id == WRITABLE_ZONE_ID) {
            return (*update_records_);
        }
        return (*empty_records_);
    }
606

607
608
609
    // Adds one record to the current name in the database
    // The actual data will not be added to 'records' until
    // addCurName() is called
610
611
    void addRecord(const std::string& type,
                   const std::string& ttl,
612
613
614
615
                   const std::string& sigtype,
                   const std::string& rdata) {
        std::vector<std::string> columns;
        columns.push_back(type);
616
        columns.push_back(ttl);
617
618
        columns.push_back(sigtype);
        columns.push_back(rdata);
619
        cur_name_.push_back(columns);
620
621
    }

622
    // Adds all records we just built with calls to addRecords
623
    // to the actual fake database. This will clear cur_name_,
624
    // so we can immediately start adding new records.
625
    void addCurName(const std::string& name) {
626
        ASSERT_EQ(0, readonly_records_->count(name));
627
628
        // Append the name to all of them
        for (std::vector<std::vector<std::string> >::iterator
629
             i(cur_name_.begin()); i != cur_name_.end(); ++ i) {
630
631
            i->push_back(name);
        }
632
633
        (*readonly_records_)[name] = cur_name_;
        cur_name_.clear();
634
635
    }

636
637
638
639
640
641
642
643
644
645
    // Fills the database with zone data.
    // This method constructs a number of resource records (with addRecord),
    // which will all be added for one domain name to the fake database
    // (with addCurName). So for instance the first set of calls create
    // data for the name 'www.example.org', which will consist of one A RRset
    // of one record, and one AAAA RRset of two records.
    // The order in which they are added is the order in which getNextRecord()
    // will return them (so we can test whether find() etc. support data that
    // might not come in 'normal' order)
    // It shall immediately fail if you try to add the same name twice.
646
    void fillData() {
647
648
649
650
651
652
653
654
655
656
657
        const char* prev_name = NULL;
        for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
            if (prev_name != NULL &&
                strcmp(prev_name, TEST_RECORDS[i][0]) != 0) {
                addCurName(prev_name);
            }
            prev_name = TEST_RECORDS[i][0];
            addRecord(TEST_RECORDS[i][1], TEST_RECORDS[i][2],
                      TEST_RECORDS[i][3], TEST_RECORDS[i][4]);
        }
        addCurName(prev_name);
658
    }
659
660
};

661
662
// This tests the default getRecords behaviour, throwing NotImplemented
TEST(DatabaseConnectionTest, getRecords) {
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
663
    EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
664
665
666
                 isc::NotImplemented);
}

667
668
// This tests the default getAllRecords behaviour, throwing NotImplemented
TEST(DatabaseConnectionTest, getAllRecords) {
669
    // The parameters don't matter
670
    EXPECT_THROW(NopAccessor().getAllRecords(1),
671
672
673
                 isc::NotImplemented);
}

674
675
676
677
// This test fixture is templated so that we can share (most of) the test
// cases with different types of data sources.  Note that in test cases
// we need to use 'this' to refer to member variables of the test class.
template <typename ACCESSOR_TYPE>
678
679
class DatabaseClientTest : public ::testing::Test {
public:
680
681
682
683
    DatabaseClientTest() : zname_("example.org"), qname_("www.example.org"),
                           qclass_(RRClass::IN()), qtype_(RRType::A()),
                           rrttl_(3600)
    {
684
        createClient();
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705

        // set up the commonly used finder.
        DataSourceClient::FindResult zone(client_->findZone(zname_));
        assert(zone.code == result::SUCCESS);
        finder_ = dynamic_pointer_cast<DatabaseClient::Finder>(
            zone.zone_finder);

        // Test IN/A RDATA to be added in update tests.  Intentionally using
        // different data than the initial data configured in the MockAccessor.
        rrset_.reset(new RRset(qname_, qclass_, qtype_, rrttl_));
        rrset_->addRdata(rdata::createRdata(rrset_->getType(),
                                            rrset_->getClass(), "192.0.2.2"));

        // And its RRSIG.  Also different from the configured one.
        rrsigset_.reset(new RRset(qname_, qclass_, RRType::RRSIG(),
                                  rrttl_));
        rrsigset_->addRdata(rdata::createRdata(rrsigset_->getType(),
                                               rrsigset_->getClass(),
                                               "A 5 3 0 20000101000000 "
                                               "20000201000000 0 example.org. "
                                               "FAKEFAKEFAKE"));
706
    }
707

708
709
710
711
712
    /*
     * We initialize the client from a function, so we can call it multiple
     * times per test.
     */
    void createClient() {
713
714
        current_accessor_ = new ACCESSOR_TYPE();
        is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_) != NULL);
715
        client_.reset(new DatabaseClient(qclass_,
716
                                         shared_ptr<ACCESSOR_TYPE>(
717
                                             current_accessor_)));
718
    }
719

720
721
    /**
     * Check the zone finder is a valid one and references the zone ID and
722
     * database available here.
723
724
725
726
727
728
729
     */
    void checkZoneFinder(const DataSourceClient::FindResult& zone) {
        ASSERT_NE(ZoneFinderPtr(), zone.zone_finder) << "No zone finder";
        shared_ptr<DatabaseClient::Finder> finder(
            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
        ASSERT_NE(shared_ptr<DatabaseClient::Finder>(), finder) <<
            "Wrong type of finder";
730
731
732
        if (is_mock_) {
            EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
        }
733
        EXPECT_EQ(current_accessor_, &finder->getAccessor());
734
    }
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
735
736

    shared_ptr<DatabaseClient::Finder> getFinder() {
737
        DataSourceClient::FindResult zone(client_->findZone(zname_));
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
738
739
740
        EXPECT_EQ(result::SUCCESS, zone.code);
        shared_ptr<DatabaseClient::Finder> finder(
            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
741
742
743
        if (is_mock_) {
            EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
        }
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
744
745
746
747

        return (finder);
    }

748
    // Helper methods for update tests
749
750
751
752
753
754
755
756
    bool isRollbacked(bool expected = false) const {
        if (is_mock_) {
            const MockAccessor& mock_accessor =
                dynamic_cast<const MockAccessor&>(*update_accessor_);
            return (mock_accessor.isRollbacked());
        } else {
            return (expected);
        }
757
758
759
    }

    void checkLastAdded(const char* const expected[]) const {
760
761
762
763
764
765
766
        if (is_mock_) {
            const MockAccessor* mock_accessor =
                dynamic_cast<const MockAccessor*>(current_accessor_);
            for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
                EXPECT_EQ(expected[i],
                          mock_accessor->getLatestClone()->getLastAdded()[i]);
            }
767
768
769
770
        }
    }

    void setUpdateAccessor() {
771
772
773
774
775
        if (is_mock_) {
            const MockAccessor* mock_accessor =
                dynamic_cast<const MockAccessor*>(current_accessor_);
            update_accessor_ = mock_accessor->getLatestClone();
        }
776
777
    }

778
779
780
781
    // Some tests only work for MockAccessor.  We remember whether our accessor
    // is of that type.
    bool is_mock_;

782
    // Will be deleted by client_, just keep the current value for comparison.
783
    ACCESSOR_TYPE* current_accessor_;
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
    shared_ptr<DatabaseClient> client_;
    const std::string database_name_;

    // The zone finder of the test zone commonly used in various tests.
    shared_ptr<DatabaseClient::Finder> finder_;

    // Some shortcut variables for commonly used test parameters
    const Name zname_; // the zone name stored in the test data source
    const Name qname_; // commonly used name to be found
    const RRClass qclass_;      // commonly used RR class used with qname
    const RRType qtype_;        // commonly used RR type used with qname
    const RRTTL rrttl_;         // commonly used RR TTL
    RRsetPtr rrset_;            // for adding/deleting an RRset
    RRsetPtr rrsigset_;         // for adding/deleting an RRset

    // update related objects to be tested
    ZoneUpdaterPtr updater_;
801
    shared_ptr<const DatabaseAccessor> update_accessor_;
802
803
804

    // placeholders
    const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
805
806
    std::vector<std::string> expected_rdatas_;
    std::vector<std::string> expected_sig_rdatas_;
807
808
};

809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
class TestSQLite3Accessor : public SQLite3Accessor {
public:
    TestSQLite3Accessor() : SQLite3Accessor(
        TEST_DATA_BUILDDIR "/rwtest.sqlite3.copied",
        RRClass::IN())
    {
        startUpdateZone("example.org.", true);
        string columns[ADD_COLUMN_COUNT];
        for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
            columns[ADD_NAME] = TEST_RECORDS[i][0];
            columns[ADD_REV_NAME] = Name(columns[ADD_NAME]).reverse().toText();
            columns[ADD_TYPE] = TEST_RECORDS[i][1];
            columns[ADD_TTL] = TEST_RECORDS[i][2];
            columns[ADD_SIGTYPE] = TEST_RECORDS[i][3];
            columns[ADD_RDATA] = TEST_RECORDS[i][4];

            addRecordToZone(columns);
        }
        commitUpdateZone();
    }
};

// The following two lines instantiate test cases with concrete accessor
// classes to be tested.
typedef ::testing::Types<MockAccessor, TestSQLite3Accessor> TestAccessorTypes;
TYPED_TEST_CASE(DatabaseClientTest, TestAccessorTypes);

836
837
838
839
840
// In some cases the entire test fixture is for the mock accessor only.
// We use the usual TEST_F for them with the corresponding specialized class
// to make the code simpler.
typedef DatabaseClientTest<MockAccessor> MockDatabaseClientTest;

841
842
843
TYPED_TEST(DatabaseClientTest, zoneNotFound) {
    DataSourceClient::FindResult zone(
        this->client_->findZone(Name("example.com")));
844
845
846
    EXPECT_EQ(result::NOTFOUND, zone.code);
}

847
848
849
TYPED_TEST(DatabaseClientTest, exactZone) {
    DataSourceClient::FindResult zone(
        this->client_->findZone(Name("example.org")));
850
    EXPECT_EQ(result::SUCCESS, zone.code);
851
    this->checkZoneFinder(zone);
852
853
}

854
855
TYPED_TEST(DatabaseClientTest, superZone) {
    DataSourceClient::FindResult zone(this->client_->findZone(Name(
856
857
        "sub.example.org")));
    EXPECT_EQ(result::PARTIALMATCH, zone.code);
858
    this->checkZoneFinder(zone);
859
860
}

861
862
// This test doesn't depend on derived accessor class, so we use TEST().
TEST(GenericDatabaseClientTest, noAccessorException) {
Jelte Jansen's avatar
Jelte Jansen committed
863
864
    // We need a dummy variable here; some compiler would regard it a mere
    // declaration instead of an instantiation and make the test fail.
865
866
    EXPECT_THROW(DatabaseClient dummy(RRClass::IN(),
                                      shared_ptr<DatabaseAccessor>()),
867
868
869
                 isc::InvalidParameter);
}

870
// If the zone doesn't exist, exception is thrown
871
872
873
TYPED_TEST(DatabaseClientTest, noZoneIterator) {
    EXPECT_THROW(this->client_->getIterator(Name("example.com")),
                 DataSourceError);
874
875
876
877
}

// If the zone doesn't exist and iteration is not implemented, it still throws
// the exception it doesn't exist
878
TEST(GenericDatabaseClientTest, noZoneNotImplementedIterator) {
879
880
881
882
    EXPECT_THROW(DatabaseClient(RRClass::IN(),
                                boost::shared_ptr<DatabaseAccessor>(
                                    new NopAccessor())).getIterator(
                                        Name("example.com")),
883
884
885
                 DataSourceError);
}

886
TEST(GenericDatabaseClientTest, notImplementedIterator) {
887
    EXPECT_THROW(DatabaseClient(RRClass::IN(), shared_ptr<DatabaseAccessor>(
888
        new NopAccessor())).getIterator(Name("example.org")),
889
890
891
892
                 isc::NotImplemented);
}

// Pretend a bug in the connection and pass NULL as the context
893
// Should not crash, but gracefully throw.  Works for the mock accessor only.
894
895
TEST_F(MockDatabaseClientTest, nullIteratorContext) {
    EXPECT_THROW(this->client_->getIterator(Name("null.example.org")),
896
897
898
                 isc::Unexpected);
}

899
900
// It doesn't crash or anything if the zone is completely empty.
// Works for the mock accessor only.
901
TEST_F(MockDatabaseClientTest, emptyIterator) {
902
    ZoneIteratorPtr it(this->client_->getIterator(Name("empty.example.org")));
903
904
905
906
907
    EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
    // This is past the end, it should throw
    EXPECT_THROW(it->getNextRRset(), isc::Unexpected);
}

908
909
910
// Iterate through a zone
TYPED_TEST(DatabaseClientTest, iterator) {
    ZoneIteratorPtr it(this->client_->getIterator(Name("example.org")));
911
912
    ConstRRsetPtr rrset(it->getNextRRset());
    ASSERT_NE(ConstRRsetPtr(), rrset);
913
914
915
916
917
918

    // The rest of the checks work only for the mock accessor.
    if (!this->is_mock_) {
        return;
    }

919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
    EXPECT_EQ(Name("example.org"), rrset->getName());
    EXPECT_EQ(RRClass::IN(), rrset->getClass());
    EXPECT_EQ(RRType::SOA(), rrset->getType());
    EXPECT_EQ(RRTTL(300), rrset->getTTL());
    RdataIteratorPtr rit(rrset->getRdataIterator());
    ASSERT_FALSE(rit->isLast());
    rit->next();
    EXPECT_TRUE(rit->isLast());

    rrset = it->getNextRRset();
    ASSERT_NE(ConstRRsetPtr(), rrset);
    EXPECT_EQ(Name("x.example.org"), rrset->getName());
    EXPECT_EQ(RRClass::IN(), rrset->getClass());
    EXPECT_EQ(RRType::A(), rrset->getType());
    EXPECT_EQ(RRTTL(300), rrset->getTTL());
    rit = rrset->getRdataIterator();
    ASSERT_FALSE(rit->isLast());
    EXPECT_EQ("192.0.2.1", rit->getCurrent().toText());
    rit->next();
    ASSERT_FALSE(rit->isLast());
    EXPECT_EQ("192.0.2.2", rit->getCurrent().toText());
    rit->next();
    EXPECT_TRUE(rit->isLast());

    rrset = it->getNextRRset();
    ASSERT_NE(ConstRRsetPtr(), rrset);
    EXPECT_EQ(Name("x.example.org"), rrset->getName());
    EXPECT_EQ(RRClass::IN(), rrset->getClass());
    EXPECT_EQ(RRType::AAAA(), rrset->getType());
    EXPECT_EQ(RRTTL(300), rrset->getTTL());
    EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
    rit = rrset->getRdataIterator();
    ASSERT_FALSE(rit->isLast());
    EXPECT_EQ("2001:db8::1", rit->getCurrent().toText());
    rit->next();
    ASSERT_FALSE(rit->isLast());
    EXPECT_EQ("2001:db8::2", rit->getCurrent().toText());
    rit->next();
    EXPECT_TRUE(rit->isLast());
}

// This has inconsistent TTL in the set (the rest, like nonsense in
961
962
// the data is handled in rdata itself).  Works for the mock accessor only.
TEST_F(MockDatabaseClientTest, badIterator) {
963
    // It should not throw, but get the lowest one of them
964
    ZoneIteratorPtr it(this->client_->getIterator(Name("bad.example.org")));
965
    EXPECT_EQ(it->getNextRRset()->getTTL(), isc::dns::RRTTL(300));
966
967
}

968
969
970
971
972
973
974
975
// checks if the given rrset matches the
// given name, class, type and rdatas
void
checkRRset(isc::dns::ConstRRsetPtr rrset,
           const isc::dns::Name& name,
           const isc::dns::RRClass& rrclass,
           const isc::dns::RRType& rrtype,
           const isc::dns::RRTTL& rrttl,
976
           const std::vector<std::string>& rdatas) {
977
978
979
980
981
982
983
984
985
986
    isc::dns::RRsetPtr expected_rrset(
        new isc::dns::RRset(name, rrclass, rrtype, rrttl));
    for (unsigned int i = 0; i < rdatas.size(); ++i) {
        expected_rrset->addRdata(
            isc::dns::rdata::createRdata(rrtype, rrclass,
                                         rdatas[i]));
    }
    isc::testutils::rrsetCheck(expected_rrset, rrset);
}

987
void
988
doFindTest(ZoneFinder& finder,
989
990
991
           const isc::dns::Name& name,
           const isc::dns::RRType& type,
           const isc::dns::RRType& expected_type,
992
           const isc::dns::RRTTL expected_ttl,
993
           ZoneFinder::Result expected_result,
994
           const std::vector<std::string>& expected_rdatas,
995
           const std::vector<std::string>& expected_sig_rdatas,
996
997
           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
998
{
999
    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
1000
    ZoneFinder::FindResult result =
1001
        finder.find(name, type, NULL, options);
1002
    ASSERT_EQ(expected_result, result.code) << name << " " << type;
1003
    if (!expected_rdatas.empty() && result.rrset) {
1004
        checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
1005
                   name, finder.getClass(), expected_type, expected_ttl,
1006
                   expected_rdatas);
1007

1008
        if (!expected_sig_rdatas.empty() && result.rrset->getRRsig()) {
1009
            checkRRset(result.rrset->getRRsig(), expected_name != Name(".") ?
1010
                       expected_name : name, finder.getClass(),
1011
1012
                       isc::dns::RRType::RRSIG(), expected_ttl,
                       expected_sig_rdatas);
1013
        } else if (expected_sig_rdatas.empty()) {
1014
            EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset->getRRsig());
1015
1016
        } else {
            ADD_FAILURE() << "Missing RRSIG";
1017
        }
1018
    } else if (expected_rdatas.empty()) {
1019
        EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset);
1020
1021
    } else {
        ADD_FAILURE() << "Missing result";
1022
1023
1024
    }
}

1025
1026
TYPED_TEST(DatabaseClientTest, find) {
    shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
1027

1028
1029
1030
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
1031
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1032
1033
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1034

1035
1036
1037
1038
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_rdatas_.push_back("192.0.2.2");
1039
    doFindTest(*finder, isc::dns::Name("www2.example.org."),
1040
1041
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1042

1043
1044
1045
1046
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_rdatas_.push_back("2001:db8::2");
1047
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1048
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1049
               this->rrttl_,
1050
               ZoneFinder::SUCCESS,
1051
               this->expected_rdatas_, this->expected_sig_rdatas_);
1052

1053
1054
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1055
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1056
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
1057
               this->rrttl_,
1058
               ZoneFinder::NXRRSET,
1059
               this->expected_rdatas_, this->expected_sig_rdatas_);
1060

1061
1062
1063
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
1064
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
1065
1066
1067
1068
1069
1070
1071
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
1072
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
1073
               isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
1074
1075
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1076

1077
1078
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1079
    doFindTest(*finder, isc::dns::Name("doesnotexist.example.org."),
1080
1081
1082
1083
1084
1085
1086
1087
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
1088
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1089
1090
1091
1092
1093
1094
1095
1096
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_rdatas_.push_back("2001:db8::2");
    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1097
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1098
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1099
1100
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1101

1102
1103
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1104
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1105
1106
1107
1108
1109
1110
1111
1112
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
               ZoneFinder::NXRRSET, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1113
    doFindTest(*finder, isc::dns::Name("signedcname1.example.org."),
1114
1115
1116
1117
1118
1119
1120
1121
1122
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
1123
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1124
1125
1126
1127
1128
1129
1130
1131
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::2");
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1132
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1133
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1134
1135
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1136

1137
1138
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1139
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1140
1141
1142
1143
1144
1145
1146
1147
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
               ZoneFinder::NXRRSET, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1148
    doFindTest(*finder, isc::dns::Name("signedcname2.example.org."),
1149
1150
1151
1152
1153
1154
1155
1156
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1157
    doFindTest(*finder, isc::dns::Name("acnamesig1.example.org."),
1158
1159
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1160

1161
1162
1163
1164
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1165
    doFindTest(*finder, isc::dns::Name("acnamesig2.example.org."),
1166
1167
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1168

1169
1170
1171
1172
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1173
    doFindTest(*finder, isc::dns::Name("acnamesig3.example.org."),
1174
1175
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
Jelte Jansen's avatar
Jelte Jansen committed
1176

1177
1178
1179
1180
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_rdatas_.push_back("192.0.2.2");