database_unittest.cc 83.7 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

29
30
#include <testutils/dnsmessage_test.h>

31
#include <map>
32
33
34
35

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

namespace {

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

44
/*
45
 * An accessor with minimum implementation, keeping the original
46
 * "NotImplemented" methods.
47
 */
48
class NopAccessor : public DatabaseAccessor {
49
public:
50
51
    NopAccessor() : database_name_("mock_database")
    { }
52

53
54
    virtual std::pair<bool, int> getZone(const std::string& name) const {
        if (name == "example.org.") {
55
            return (std::pair<bool, int>(true, READONLY_ZONE_ID));
56
        } else if (name == "null.example.org.") {
57
            return (std::pair<bool, int>(true, 13));
58
        } else if (name == "empty.example.org.") {
59
            return (std::pair<bool, int>(true, 0));
60
        } else if (name == "bad.example.org.") {
61
            return (std::pair<bool, int>(true, -1));
62
63
64
65
        } else {
            return (std::pair<bool, int>(false, 0));
        }
    }
66

67
68
69
    virtual shared_ptr<DatabaseAccessor> clone() {
        return (shared_ptr<DatabaseAccessor>()); // bogus data, but unused
    }
70

JINMEI Tatuya's avatar
JINMEI Tatuya committed
71
72
73
74
75
76
    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() {}
77
78
    virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
    virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
79

80
81
82
83
    virtual const std::string& getDBName() const {
        return (database_name_);
    }

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
84
85
86
    virtual IteratorContextPtr getRecords(const std::string&, int, bool)
        const
        {
87
88
        isc_throw(isc::NotImplemented,
                  "This database datasource can't be iterated");
89
    }
90
91
92
93

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

96
97
98
private:
    const std::string database_name_;

99
100
};

101
/*
102
 * A virtual database accessor that pretends it contains single zone --
103
104
105
106
107
 * example.org.
 *
 * It has the same getZone method as NopConnection, but it provides
 * implementation of the optional functionality.
 */
108
class MockAccessor : public NopAccessor {
109
110
111
112
    // Type of mock database "row"s
    typedef std::map<std::string, std::vector< std::vector<std::string> > >
        Domains;

113
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
114
    MockAccessor() : rollbacked_(false) {
115
116
117
        readonly_records_ = &readonly_records_master_;
        update_records_ = &update_records_master_;
        empty_records_ = &empty_records_master_;
118
119
        fillData();
    }
120
121
122
123
124
125
126
127
128
129

    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);
    }

130
private:
131
132
133
    class MockNameIteratorContext : public IteratorContext {
    public:
        MockNameIteratorContext(const MockAccessor& mock_accessor, int zone_id,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
134
                                const std::string& name, bool subdomains) :
135
            searched_name_(name), cur_record_(0)
136
        {
137
            // 'hardcoded' names to trigger exceptions
138
            // On these names some exceptions are thrown, to test the robustness
139
            // of the find() method.
140
141
142
143
144
145
146
147
            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();
            }

148
149
150
            cur_record_ = 0;
            const Domains& cur_records = mock_accessor.getMockRecords(zone_id);
            if (cur_records.count(name) > 0) {
151
152
                    // we're not aiming for efficiency in this test, simply
                    // copy the relevant vector from records
153
154
155
156
157
158
159
160
161
162
163
164
                    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
165
                    }
166
                }
167
168
            } else {
                cur_name.clear();
169
170
171
            }
        }

172
        virtual bool getNext(std::string (&columns)[COLUMN_COUNT]) {
173
174
175
176
177
178
179
180
181
            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()) {
182
                for (size_t i = 0; i < COLUMN_COUNT; ++i) {
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
                    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;
    };

198
199
200
201
202
203
204
    class MockIteratorContext : public IteratorContext {
    private:
        int step;
    public:
        MockIteratorContext() :
            step(0)
        { }
205
        virtual bool getNext(string (&data)[COLUMN_COUNT]) {
206
207
            switch (step ++) {
                case 0:
208
209
210
211
                    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. "
212
213
214
                        "1234 3600 1800 2419200 7200";
                    return (true);
                case 1:
215
216
217
218
                    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";
219
220
                    return (true);
                case 2:
221
222
223
224
                    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";
225
226
                    return (true);
                case 3:
227
228
229
230
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::1";
231
232
                    return (true);
                case 4:
233
234
235
236
                    data[DatabaseAccessor::NAME_COLUMN] = "x.example.org";
                    data[DatabaseAccessor::TYPE_COLUMN] = "AAAA";
                    data[DatabaseAccessor::TTL_COLUMN] = "300";
                    data[DatabaseAccessor::RDATA_COLUMN] = "2001:db8::2";
237
238
239
240
241
242
243
244
245
246
247
                    return (true);
                default:
                    ADD_FAILURE() <<
                        "Request past the end of iterator context";
                case 5:
                    return (false);
            }
        }
    };
    class EmptyIteratorContext : public IteratorContext {
    public:
248
        virtual bool getNext(string(&)[COLUMN_COUNT]) {
249
250
251
252
253
254
255
256
257
258
            return (false);
        }
    };
    class BadIteratorContext : public IteratorContext {
    private:
        int step;
    public:
        BadIteratorContext() :
            step(0)
        { }
259
        virtual bool getNext(string (&data)[COLUMN_COUNT]) {
260
261
            switch (step ++) {
                case 0:
262
263
264
265
                    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";
266
267
                    return (true);
                case 1:
268
269
270
271
                    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";
272
273
274
275
276
277
278
279
280
281
                    return (true);
                default:
                    ADD_FAILURE() <<
                        "Request past the end of iterator context";
                case 2:
                    return (false);
            }
        }
    };
public:
282
    virtual IteratorContextPtr getAllRecords(int id) const {
283
        if (id == READONLY_ZONE_ID) {
284
285
286
287
288
289
290
291
292
293
294
            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");
        }
    }
295

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
296
297
298
    virtual IteratorContextPtr getRecords(const std::string& name, int id,
                                          bool subdomains) const
    {
299
300
301
302
        if (id == READONLY_ZONE_ID || id == WRITABLE_ZONE_ID) {
            return (IteratorContextPtr(
                        new MockNameIteratorContext(*this, id, name,
                                                    subdomains)));
303
304
305
306
307
        } else {
            isc_throw(isc::Unexpected, "Unknown zone ID");
        }
    }

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    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() {
331
332
333
334
335
336
337
        // 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");
        }

338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
        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]);
        }
    }

386
387
388
389
390
391
392
    //
    // Helper methods to keep track of some update related activities
    //
    bool isRollbacked() const {
        return (rollbacked_);
    }

393
    const string* getLastAdded() const {
394
395
396
397
398
399
400
401
        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_);
    }

402
private:
403
404
    // The following member variables are storage and/or update work space
    // of the test zone.  The "master"s are the real objects that contain
405
    // the data, and they are shared among all accessors cloned from
406
407
408
409
410
411
412
413
414
415
416
417
    // 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_;

418
    // used as temporary storage during the building of the fake data
419

420
421
422
    // used as temporary storage after searchForRecord() and during
    // getNextRecord() calls, as well as during the building of the
    // fake data
423
424
425
    std::vector< std::vector<std::string> > cur_name_;

    // The columns that were most recently added via addRecordToZone()
426
    string columns_lastadded_[ADD_COLUMN_COUNT];
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442

    // 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_);
    }
443

444
445
446
    // Adds one record to the current name in the database
    // The actual data will not be added to 'records' until
    // addCurName() is called
447
448
    void addRecord(const std::string& type,
                   const std::string& ttl,
449
450
451
452
                   const std::string& sigtype,
                   const std::string& rdata) {
        std::vector<std::string> columns;
        columns.push_back(type);
453
        columns.push_back(ttl);
454
455
        columns.push_back(sigtype);
        columns.push_back(rdata);
456
        cur_name_.push_back(columns);
457
458
    }

459
    // Adds all records we just built with calls to addRecords
460
    // to the actual fake database. This will clear cur_name_,
461
    // so we can immediately start adding new records.
462
    void addCurName(const std::string& name) {
463
        ASSERT_EQ(0, readonly_records_->count(name));
464
465
        // Append the name to all of them
        for (std::vector<std::vector<std::string> >::iterator
466
             i(cur_name_.begin()); i != cur_name_.end(); ++ i) {
467
468
            i->push_back(name);
        }
469
470
        (*readonly_records_)[name] = cur_name_;
        cur_name_.clear();
471
472
    }

473
474
475
476
477
478
479
480
481
482
    // 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.
483
    void fillData() {
484
        // some plain data
485
486
487
488
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("AAAA", "3600", "", "2001:db8::1");
        addRecord("AAAA", "3600", "", "2001:db8::2");
        addCurName("www.example.org.");
489

490
491
492
493
494
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("AAAA", "3600", "", "2001:db8::1");
        addRecord("A", "3600", "", "192.0.2.2");
        addCurName("www2.example.org.");

495
496
497
        addRecord("CNAME", "3600", "", "www.example.org.");
        addCurName("cname.example.org.");

498
499
500
        // some DNSSEC-'signed' data
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
Jelte Jansen's avatar
Jelte Jansen committed
501
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
502
503
504
505
        addRecord("AAAA", "3600", "", "2001:db8::1");
        addRecord("AAAA", "3600", "", "2001:db8::2");
        addRecord("RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("signed1.example.org.");
506
507
508
        addRecord("CNAME", "3600", "", "www.example.org.");
        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("signedcname1.example.org.");
Jelte Jansen's avatar
Jelte Jansen committed
509
510
511
512
513
514
        // 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.)
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("acnamesig1.example.org.");
515
516
517
518
519

        // let's pretend we have a database that is not careful
        // about the order in which it returns data
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("AAAA", "3600", "", "2001:db8::2");
Jelte Jansen's avatar
Jelte Jansen committed
520
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
521
522
523
524
525
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("AAAA", "3600", "", "2001:db8::1");
        addCurName("signed2.example.org.");
        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
526
527
        addRecord("CNAME", "3600", "", "www.example.org.");
        addCurName("signedcname2.example.org.");
528

Jelte Jansen's avatar
Jelte Jansen committed
529
530
531
532
533
534
535
536
537
538
        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("acnamesig2.example.org.");

        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("acnamesig3.example.org.");

539
540
541
542
543
544
545
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("A", "360", "", "192.0.2.2");
        addCurName("ttldiff1.example.org.");
        addRecord("A", "360", "", "192.0.2.1");
        addRecord("A", "3600", "", "192.0.2.2");
        addCurName("ttldiff2.example.org.");

546
547
548
        // also add some intentionally bad data
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("CNAME", "3600", "", "www.example.org.");
549
550
551
552
553
554
555
556
557
558
        addCurName("badcname1.example.org.");

        addRecord("CNAME", "3600", "", "www.example.org.");
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("badcname2.example.org.");

        addRecord("CNAME", "3600", "", "www.example.org.");
        addRecord("CNAME", "3600", "", "www.example2.org.");
        addCurName("badcname3.example.org.");

Jelte Jansen's avatar
Jelte Jansen committed
559
560
        addRecord("A", "3600", "", "bad");
        addCurName("badrdata.example.org.");
561

Jelte Jansen's avatar
Jelte Jansen committed
562
563
        addRecord("BAD_TYPE", "3600", "", "192.0.2.1");
        addCurName("badtype.example.org.");
564

Jelte Jansen's avatar
Jelte Jansen committed
565
566
        addRecord("A", "badttl", "", "192.0.2.1");
        addCurName("badttl.example.org.");
567
568
569
570
571
572
573
574

        addRecord("A", "badttl", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("badsig.example.org.");

        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
        addCurName("badsigtype.example.org.");
575
576
577
578

        // Data for testing delegation (with NS and DNAME)
        addRecord("NS", "3600", "", "ns.example.com.");
        addRecord("NS", "3600", "", "ns.delegation.example.org.");
579
580
        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
581
582
583
        addCurName("delegation.example.org.");
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("ns.delegation.example.org.");
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
584
585
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("deep.below.delegation.example.org.");
586
587
588

        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("DNAME", "3600", "", "dname.example.com.");
589
590
        addRecord("RRSIG", "3600", "", "DNAME 5 3 3600 20000101000000 "
                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
591
592
593
594
        addCurName("dname.example.org.");
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("below.dname.example.org.");

595
596
597
598
599
600
601
602
        // Broken NS
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("NS", "3600", "", "ns.example.com.");
        addCurName("brokenns1.example.org.");
        addRecord("NS", "3600", "", "ns.example.com.");
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("brokenns2.example.org.");

603
604
605
606
        // Now double DNAME, to test failure mode
        addRecord("DNAME", "3600", "", "dname1.example.com.");
        addRecord("DNAME", "3600", "", "dname2.example.com.");
        addCurName("baddname.example.org.");
607
608
609
610
611

        // Put some data into apex (including NS) so we can check our NS
        // doesn't break anything
        addRecord("NS", "3600", "", "ns.example.com.");
        addRecord("A", "3600", "", "192.0.2.1");
612
613
        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
614
        addCurName("example.org.");
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
615

616
617
618
        // This is because of empty domain test
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("a.b.example.org.");
619
620
621
622
623
624

        // Something for wildcards
        addRecord("A", "3600", "", "192.0.2.5");
        addCurName("*.wild.example.org.");
        addRecord("AAAA", "3600", "", "2001:db8::5");
        addCurName("cancel.here.wild.example.org.");
625
626
627
628
629
630
631
632
        addRecord("NS", "3600", "", "ns.example.com.");
        addCurName("delegatedwild.example.org.");
        addRecord("A", "3600", "", "192.0.2.5");
        addCurName("*.delegatedwild.example.org.");
        addRecord("A", "3600", "", "192.0.2.5");
        addCurName("wild.*.foo.example.org.");
        addRecord("A", "3600", "", "192.0.2.5");
        addCurName("wild.*.foo.*.bar.example.org.");
633
    }
634
635
};

636
637
// This tests the default getRecords behaviour, throwing NotImplemented
TEST(DatabaseConnectionTest, getRecords) {
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
638
    EXPECT_THROW(NopAccessor().getRecords(".", 1, false),
639
640
641
                 isc::NotImplemented);
}

642
643
// This tests the default getAllRecords behaviour, throwing NotImplemented
TEST(DatabaseConnectionTest, getAllRecords) {
644
    // The parameters don't matter
645
    EXPECT_THROW(NopAccessor().getAllRecords(1),
646
647
648
                 isc::NotImplemented);
}

649
650
class DatabaseClientTest : public ::testing::Test {
public:
651
652
653
654
    DatabaseClientTest() : zname_("example.org"), qname_("www.example.org"),
                           qclass_(RRClass::IN()), qtype_(RRType::A()),
                           rrttl_(3600)
    {
655
        createClient();
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676

        // 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"));
677
    }
678

679
680
681
682
683
    /*
     * We initialize the client from a function, so we can call it multiple
     * times per test.
     */
    void createClient() {
684
        current_accessor_ = new MockAccessor();
685
        client_.reset(new DatabaseClient(qclass_,
686
687
                                         shared_ptr<DatabaseAccessor>(
                                             current_accessor_)));
688
    }
689

690
691
    /**
     * Check the zone finder is a valid one and references the zone ID and
692
     * database available here.
693
694
695
696
697
698
699
     */
    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";
700
        EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
701
        EXPECT_EQ(current_accessor_, &finder->getAccessor());
702
    }
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
703
704

    shared_ptr<DatabaseClient::Finder> getFinder() {
705
        DataSourceClient::FindResult zone(client_->findZone(zname_));
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
706
707
708
        EXPECT_EQ(result::SUCCESS, zone.code);
        shared_ptr<DatabaseClient::Finder> finder(
            dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
709
        EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
710
711
712
713

        return (finder);
    }

714
715
716
717
718
719
    // Helper methods for update tests
    bool isRollbacked() const {
        return (update_accessor_->isRollbacked());
    }

    void checkLastAdded(const char* const expected[]) const {
720
721
722
        for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
            EXPECT_EQ(expected[i],
                      current_accessor_->getLatestClone()->getLastAdded()[i]);
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
        }
    }

    void setUpdateAccessor() {
        update_accessor_ = current_accessor_->getLatestClone();
    }

    // Will be deleted by client_, just keep the current value for comparison.
    MockAccessor* current_accessor_;
    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_;
    shared_ptr<const MockAccessor> update_accessor_;

    // placeholders
    const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
753
754
    std::vector<std::string> expected_rdatas_;
    std::vector<std::string> expected_sig_rdatas_;
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
};

TEST_F(DatabaseClientTest, zoneNotFound) {
    DataSourceClient::FindResult zone(client_->findZone(Name("example.com")));
    EXPECT_EQ(result::NOTFOUND, zone.code);
}

TEST_F(DatabaseClientTest, exactZone) {
    DataSourceClient::FindResult zone(client_->findZone(Name("example.org")));
    EXPECT_EQ(result::SUCCESS, zone.code);
    checkZoneFinder(zone);
}

TEST_F(DatabaseClientTest, superZone) {
    DataSourceClient::FindResult zone(client_->findZone(Name(
        "sub.example.org")));
    EXPECT_EQ(result::PARTIALMATCH, zone.code);
    checkZoneFinder(zone);
}

775
TEST_F(DatabaseClientTest, noAccessorException) {
Jelte Jansen's avatar
Jelte Jansen committed
776
777
    // We need a dummy variable here; some compiler would regard it a mere
    // declaration instead of an instantiation and make the test fail.
778
779
    EXPECT_THROW(DatabaseClient dummy(RRClass::IN(),
                                      shared_ptr<DatabaseAccessor>()),
780
781
782
                 isc::InvalidParameter);
}

783
784
785
786
787
788
789
790
// If the zone doesn't exist, exception is thrown
TEST_F(DatabaseClientTest, noZoneIterator) {
    EXPECT_THROW(client_->getIterator(Name("example.com")), DataSourceError);
}

// If the zone doesn't exist and iteration is not implemented, it still throws
// the exception it doesn't exist
TEST_F(DatabaseClientTest, noZoneNotImplementedIterator) {
791
792
793
794
    EXPECT_THROW(DatabaseClient(RRClass::IN(),
                                boost::shared_ptr<DatabaseAccessor>(
                                    new NopAccessor())).getIterator(
                                        Name("example.com")),
795
796
797
798
                 DataSourceError);
}

TEST_F(DatabaseClientTest, notImplementedIterator) {
799
    EXPECT_THROW(DatabaseClient(RRClass::IN(), shared_ptr<DatabaseAccessor>(
800
        new NopAccessor())).getIterator(Name("example.org")),
801
802
803
804
805
806
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
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
                 isc::NotImplemented);
}

// Pretend a bug in the connection and pass NULL as the context
// Should not crash, but gracefully throw
TEST_F(DatabaseClientTest, nullIteratorContext) {
    EXPECT_THROW(client_->getIterator(Name("null.example.org")),
                 isc::Unexpected);
}

// It doesn't crash or anything if the zone is completely empty
TEST_F(DatabaseClientTest, emptyIterator) {
    ZoneIteratorPtr it(client_->getIterator(Name("empty.example.org")));
    EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
    // This is past the end, it should throw
    EXPECT_THROW(it->getNextRRset(), isc::Unexpected);
}

// Iterate trough a zone
TEST_F(DatabaseClientTest, iterator) {
    ZoneIteratorPtr it(client_->getIterator(Name("example.org")));
    ConstRRsetPtr rrset(it->getNextRRset());
    ASSERT_NE(ConstRRsetPtr(), rrset);
    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
// the data is handled in rdata itself).
TEST_F(DatabaseClientTest, badIterator) {
868
    // It should not throw, but get the lowest one of them
869
    ZoneIteratorPtr it(client_->getIterator(Name("bad.example.org")));
870
    EXPECT_EQ(it->getNextRRset()->getTTL(), isc::dns::RRTTL(300));
871
872
}

873
874
875
876
877
878
879
880
// 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,
881
           const std::vector<std::string>& rdatas) {
882
883
884
885
886
887
888
889
890
891
    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);
}

892
void
893
doFindTest(ZoneFinder& finder,
894
895
896
           const isc::dns::Name& name,
           const isc::dns::RRType& type,
           const isc::dns::RRType& expected_type,
897
           const isc::dns::RRTTL expected_ttl,
898
           ZoneFinder::Result expected_result,
899
           const std::vector<std::string>& expected_rdatas,
900
           const std::vector<std::string>& expected_sig_rdatas,
901
902
           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
903
{
904
    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
905
    ZoneFinder::FindResult result =
906
        finder.find(name, type, NULL, options);
907
    ASSERT_EQ(expected_result, result.code) << name << " " << type;
908
    if (!expected_rdatas.empty()) {
909
        checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
910
                   name, finder.getClass(), expected_type, expected_ttl,
911
                   expected_rdatas);
912

913
        if (!expected_sig_rdatas.empty()) {
914
            checkRRset(result.rrset->getRRsig(), expected_name != Name(".") ?
915
                       expected_name : name, finder.getClass(),
916
917
                       isc::dns::RRType::RRSIG(), expected_ttl,
                       expected_sig_rdatas);
918
919
920
921
922
923
924
925
        } else {
            EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset->getRRsig());
        }
    } else {
        EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset);
    }
}

926
TEST_F(DatabaseClientTest, find) {
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
927
    shared_ptr<DatabaseClient::Finder> finder(getFinder());
928

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
929
930
931
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
932
    doFindTest(*finder, isc::dns::Name("www.example.org."),
933
               isc::dns::RRType::A(), isc::dns::RRType::A(),
934
               isc::dns::RRTTL(3600),
935
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
936
               expected_rdatas_, expected_sig_rdatas_);
937

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
938
939
940
941
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
    expected_rdatas_.push_back("192.0.2.2");
942
    doFindTest(*finder, isc::dns::Name("www2.example.org."),
943
944
               isc::dns::RRType::A(), isc::dns::RRType::A(),
               isc::dns::RRTTL(3600),
945
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
946
               expected_rdatas_, expected_sig_rdatas_);
947

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
948
949
950
951
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("2001:db8::1");
    expected_rdatas_.push_back("2001:db8::2");
952
    doFindTest(*finder, isc::dns::Name("www.example.org."),
953
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
954
               isc::dns::RRTTL(3600),
955
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
956
               expected_rdatas_, expected_sig_rdatas_);
957

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
958
959
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
960
    doFindTest(*finder, isc::dns::Name("www.example.org."),
961
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
962
               isc::dns::RRTTL(3600),
963
               ZoneFinder::NXRRSET,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
964
               expected_rdatas_, expected_sig_rdatas_);
965

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
966
967
968
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("www.example.org.");
969
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
970
               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
971
               isc::dns::RRTTL(3600),
972
               ZoneFinder::CNAME,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
973
               expected_rdatas_, expected_sig_rdatas_);
974

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
975
976
977
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("www.example.org.");
978
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
979
980
               isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
               isc::dns::RRTTL(3600),
981
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
982
               expected_rdatas_, expected_sig_rdatas_);
983

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
984
985
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
986
    doFindTest(*finder, isc::dns::Name("doesnotexist.example.org."),
987
               isc::dns::RRType::A(), isc::dns::RRType::A(),
988
               isc::dns::RRTTL(3600),
989
               ZoneFinder::NXDOMAIN,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
990
               expected_rdatas_, expected_sig_rdatas_);
991

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
992
993
994
995
996
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
997
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
998
               isc::dns::RRType::A(), isc::dns::RRType::A(),
999
               isc::dns::RRTTL(3600),
1000
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1001
               expected_rdatas_, expected_sig_rdatas_);
1002

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1003
1004
1005
1006
1007
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("2001:db8::1");
    expected_rdatas_.push_back("2001:db8::2");
    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1008
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1009
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1010
               isc::dns::RRTTL(3600),
1011
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1012
               expected_rdatas_, expected_sig_rdatas_);
1013

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1014
1015
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
1016
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1017
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
1018
               isc::dns::RRTTL(3600),
1019
               ZoneFinder::NXRRSET,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1020
               expected_rdatas_, expected_sig_rdatas_);
1021

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1022
1023
1024
1025
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("www.example.org.");
    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1026
    doFindTest(*finder, isc::dns::Name("signedcname1.example.org."),
1027
               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
1028
               isc::dns::RRTTL(3600),
1029
               ZoneFinder::CNAME,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1030
               expected_rdatas_, expected_sig_rdatas_);
1031

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1032
1033
1034
1035
1036
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
1037
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1038
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1039
               isc::dns::RRTTL(3600),
1040
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1041
               expected_rdatas_, expected_sig_rdatas_);
1042

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1043
1044
1045
1046
1047
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("2001:db8::2");
    expected_rdatas_.push_back("2001:db8::1");
    expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1048
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1049
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1050
               isc::dns::RRTTL(3600),
1051
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1052
               expected_rdatas_, expected_sig_rdatas_);
1053

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1054
1055
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
1056
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1057
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
1058
               isc::dns::RRTTL(3600),
1059
               ZoneFinder::NXRRSET,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1060
               expected_rdatas_, expected_sig_rdatas_);
1061

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1062
1063
1064
1065
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("www.example.org.");
    expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1066
    doFindTest(*finder, isc::dns::Name("signedcname2.example.org."),
1067
               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
1068
               isc::dns::RRTTL(3600),
1069
               ZoneFinder::CNAME,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1070
               expected_rdatas_, expected_sig_rdatas_);
1071

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1072
1073
1074
1075
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1076
    doFindTest(*finder, isc::dns::Name("acnamesig1.example.org."),
Jelte Jansen's avatar
Jelte Jansen committed
1077
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1078
               isc::dns::RRTTL(3600),
1079
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1080
               expected_rdatas_, expected_sig_rdatas_);
1081

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1082
1083
1084
1085
    expected_rdatas_.clear();
    expected_sig_rdatas_.clear();
    expected_rdatas_.push_back("192.0.2.1");
    expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1086
    doFindTest(*finder, isc::dns::Name("acnamesig2.example.org."),
Jelte Jansen's avatar
Jelte Jansen committed
1087
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1088
               isc::dns::RRTTL(3600),
1089
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1090
               expected_rdatas_, expected_sig_rdatas_);
1091

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1092
1093
1094
1095