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

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

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

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

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

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

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

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

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

499
500
501
        // 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
502
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
503
504
505
506
        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.");
507
508
509
        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
510
511
512
513
514
515
        // 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.");
516
517
518
519
520

        // 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
521
        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
522
523
524
525
526
        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");
527
528
        addRecord("CNAME", "3600", "", "www.example.org.");
        addCurName("signedcname2.example.org.");
529

Jelte Jansen's avatar
Jelte Jansen committed
530
531
532
533
534
535
536
537
538
539
        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.");

540
541
542
543
544
545
546
        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.");

547
548
549
        // also add some intentionally bad data
        addRecord("A", "3600", "", "192.0.2.1");
        addRecord("CNAME", "3600", "", "www.example.org.");
550
551
552
553
554
555
556
557
558
559
        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
560
561
        addRecord("A", "3600", "", "bad");
        addCurName("badrdata.example.org.");
562

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

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

        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.");
576
577
578
579

        // Data for testing delegation (with NS and DNAME)
        addRecord("NS", "3600", "", "ns.example.com.");
        addRecord("NS", "3600", "", "ns.delegation.example.org.");
580
581
        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
582
583
584
        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
585
586
        addRecord("A", "3600", "", "192.0.2.1");
        addCurName("deep.below.delegation.example.org.");
587
588
589

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

596
597
598
599
600
601
602
603
        // 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.");

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

        // 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");
613
614
        addRecord("RRSIG", "3600", "", "NS 5 3 3600 20000101000000 "
                  "20000201000000 12345 example.org. FAKEFAKEFAKE");
615
        addCurName("example.org.");
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
616

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

        // 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.");
626
627
628
629
630
631
632
633
        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.");
634
    }
635
636
};

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

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

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

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

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

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

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

        return (finder);
    }

715
716
717
718
719
720
721
    // Helper methods for update tests
    //bool isRollbacked(bool expected = false) const {
    bool isRollbacked() const {
        return (update_accessor_->isRollbacked());
    }

    void checkLastAdded(const char* const expected[]) const {
722
723
724
        for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
            EXPECT_EQ(expected[i],
                      current_accessor_->getLatestClone()->getLastAdded()[i]);
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
753
754
        }
    }

    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
755
756
    std::vector<std::string> expected_rdatas_;
    std::vector<std::string> expected_sig_rdatas_;
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
};

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

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

785
786
787
788
789
790
791
792
// 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) {
793
794
795
796
    EXPECT_THROW(DatabaseClient(RRClass::IN(),
                                boost::shared_ptr<DatabaseAccessor>(
                                    new NopAccessor())).getIterator(
                                        Name("example.com")),
797
798
799
800
                 DataSourceError);
}

TEST_F(DatabaseClientTest, notImplementedIterator) {
801
    EXPECT_THROW(DatabaseClient(RRClass::IN(), shared_ptr<DatabaseAccessor>(
802
        new NopAccessor())).getIterator(Name("example.org")),
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
868
869
                 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) {
870
    // It should not throw, but get the lowest one of them
871
    ZoneIteratorPtr it(client_->getIterator(Name("bad.example.org")));
872
    EXPECT_EQ(it->getNextRRset()->getTTL(), isc::dns::RRTTL(300));
873
874
}

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

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

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

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

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

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

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

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

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

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

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

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
994
995
996
997
998
    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");
999
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1000
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1001
               isc::dns::RRTTL(3600),
1002
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1003
               expected_rdatas_, expected_sig_rdatas_);
1004

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1005
1006
1007
1008
1009
    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");
1010
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1011
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1012
               isc::dns::RRTTL(3600),
1013
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1014
               expected_rdatas_, expected_sig_rdatas_);
1015

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

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1024
1025
1026
1027
    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");
1028
    doFindTest(*finder, isc::dns::Name("signedcname1.example.org."),
1029
               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
1030
               isc::dns::RRTTL(3600),
1031
               ZoneFinder::CNAME,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1032
               expected_rdatas_, expected_sig_rdatas_);
1033

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1034
1035
1036
1037
1038
    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");
1039
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1040
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1041
               isc::dns::RRTTL(3600),
1042
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1043
               expected_rdatas_, expected_sig_rdatas_);
1044

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1045
1046
1047
1048
1049
    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");
1050
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1051
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1052
               isc::dns::RRTTL(3600),
1053
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1054
               expected_rdatas_, expected_sig_rdatas_);
1055

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

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1064
1065
1066
1067
    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");
1068
    doFindTest(*finder, isc::dns::Name("signedcname2.example.org."),
1069
               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
1070
               isc::dns::RRTTL(3600),
1071
               ZoneFinder::CNAME,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1072
               expected_rdatas_, expected_sig_rdatas_);
1073

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1074
1075
1076
1077
    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");
1078
    doFindTest(*finder, isc::dns::Name("acnamesig1.example.org."),
Jelte Jansen's avatar
Jelte Jansen committed
1079
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1080
               isc::dns::RRTTL(3600),
1081
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1082
               expected_rdatas_, expected_sig_rdatas_);
1083

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1084
1085
1086
1087
    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");
1088
    doFindTest(*finder, isc::dns::Name("acnamesig2.example.org."),
Jelte Jansen's avatar
Jelte Jansen committed
1089
               isc::dns::RRType::A(), isc::dns::RRType::A(),
1090
               isc::dns::RRTTL(3600),
1091
               ZoneFinder::SUCCESS,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1092
               expected_rdatas_, expected_sig_rdatas_);
1093

Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
1094
1095
1096
1097
    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");
1098