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

15
16
#include <boost/foreach.hpp>

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

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

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

30
31
#include <testutils/dnsmessage_test.h>

32
#include <map>
33
34
35
36

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

namespace {

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    // Something for wildcards
    {"*.wild.example.org.", "A", "3600", "", "192.0.2.5"},
166
    {"*.wild.example.org.", "RRSIG", "3600", "A", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
167
168
    {"*.wild.example.org.", "NSEC", "3600", "", "cancel.here.wild.example.org. A NSEC RRSIG"},
    {"*.wild.example.org.", "RRSIG", "3600", "", "NSEC 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
169
170
171
172
173
174
175
176
177
    {"cancel.here.wild.example.org.", "AAAA", "3600", "", "2001:db8::5"},
    {"delegatedwild.example.org.", "NS", "3600", "", "ns.example.com."},
    {"*.delegatedwild.example.org.", "A", "3600", "", "192.0.2.5"},
    {"wild.*.foo.example.org.", "A", "3600", "", "192.0.2.5"},
    {"wild.*.foo.*.bar.example.org.", "A", "3600", "", "192.0.2.5"},

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

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

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

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

JINMEI Tatuya's avatar
JINMEI Tatuya committed
205
206
207
208
209
210
    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() {}
211
212
    virtual void addRecordToZone(const string (&)[ADD_COLUMN_COUNT]) {}
    virtual void deleteRecordInZone(const string (&)[DEL_PARAM_COUNT]) {}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
213

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

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

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

230
231
232
private:
    const std::string database_name_;

233
234
};

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

247
public:
JINMEI Tatuya's avatar
JINMEI Tatuya committed
248
    MockAccessor() : rollbacked_(false) {
249
250
251
        readonly_records_ = &readonly_records_master_;
        update_records_ = &update_records_master_;
        empty_records_ = &empty_records_master_;
252
253
        fillData();
    }
254
255
256
257
258
259
260
261
262
263

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

264
private:
265
266
267
    class MockNameIteratorContext : public IteratorContext {
    public:
        MockNameIteratorContext(const MockAccessor& mock_accessor, int zone_id,
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
268
                                const std::string& name, bool subdomains) :
269
            searched_name_(name), cur_record_(0)
270
        {
271
            // 'hardcoded' names to trigger exceptions
272
            // On these names some exceptions are thrown, to test the robustness
273
            // of the find() method.
274
275
276
277
278
279
280
281
            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();
            }

282
283
284
            cur_record_ = 0;
            const Domains& cur_records = mock_accessor.getMockRecords(zone_id);
            if (cur_records.count(name) > 0) {
285
286
                    // we're not aiming for efficiency in this test, simply
                    // copy the relevant vector from records
287
288
289
290
291
292
293
294
295
296
297
298
                    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
299
                    }
300
                }
301
302
            } else {
                cur_name.clear();
303
304
305
            }
        }

306
        virtual bool getNext(std::string (&columns)[COLUMN_COUNT]) {
307
308
309
310
311
312
313
314
315
            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()) {
316
                for (size_t i = 0; i < COLUMN_COUNT; ++i) {
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
                    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;
    };

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

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

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    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() {
465
466
467
468
469
470
471
        // 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");
        }

472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
        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]);
        }
    }

520
521
522
523
524
525
526
    //
    // Helper methods to keep track of some update related activities
    //
    bool isRollbacked() const {
        return (rollbacked_);
    }

527
    const string* getLastAdded() const {
528
529
530
531
532
533
534
535
        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_);
    }

536
private:
537
538
    // The following member variables are storage and/or update work space
    // of the test zone.  The "master"s are the real objects that contain
539
    // the data, and they are shared among all accessors cloned from
540
541
542
543
544
545
546
547
548
549
550
551
    // 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_;

552
    // used as temporary storage during the building of the fake data
553

554
555
556
    // used as temporary storage after searchForRecord() and during
    // getNextRecord() calls, as well as during the building of the
    // fake data
557
558
559
    std::vector< std::vector<std::string> > cur_name_;

    // The columns that were most recently added via addRecordToZone()
560
    string columns_lastadded_[ADD_COLUMN_COUNT];
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576

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

578
579
580
    // Adds one record to the current name in the database
    // The actual data will not be added to 'records' until
    // addCurName() is called
581
582
    void addRecord(const std::string& type,
                   const std::string& ttl,
583
584
585
586
                   const std::string& sigtype,
                   const std::string& rdata) {
        std::vector<std::string> columns;
        columns.push_back(type);
587
        columns.push_back(ttl);
588
589
        columns.push_back(sigtype);
        columns.push_back(rdata);
590
        cur_name_.push_back(columns);
591
592
    }

593
    // Adds all records we just built with calls to addRecords
594
    // to the actual fake database. This will clear cur_name_,
595
    // so we can immediately start adding new records.
596
    void addCurName(const std::string& name) {
597
        ASSERT_EQ(0, readonly_records_->count(name));
598
599
        // Append the name to all of them
        for (std::vector<std::vector<std::string> >::iterator
600
             i(cur_name_.begin()); i != cur_name_.end(); ++ i) {
601
602
            i->push_back(name);
        }
603
604
        (*readonly_records_)[name] = cur_name_;
        cur_name_.clear();
605
606
    }

607
608
609
610
611
612
613
614
615
616
    // 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.
617
    void fillData() {
618
619
620
621
622
623
624
625
626
627
628
        const char* prev_name = NULL;
        for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
            if (prev_name != NULL &&
                strcmp(prev_name, TEST_RECORDS[i][0]) != 0) {
                addCurName(prev_name);
            }
            prev_name = TEST_RECORDS[i][0];
            addRecord(TEST_RECORDS[i][1], TEST_RECORDS[i][2],
                      TEST_RECORDS[i][3], TEST_RECORDS[i][4]);
        }
        addCurName(prev_name);
629
    }
630
631
};

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

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

645
646
647
648
// This test fixture is templated so that we can share (most of) the test
// cases with different types of data sources.  Note that in test cases
// we need to use 'this' to refer to member variables of the test class.
template <typename ACCESSOR_TYPE>
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
685
        current_accessor_ = new ACCESSOR_TYPE();
        is_mock_ = (dynamic_cast<MockAccessor*>(current_accessor_) != NULL);
686
        client_.reset(new DatabaseClient(qclass_,
687
                                         shared_ptr<ACCESSOR_TYPE>(
688
                                             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
702
703
        if (is_mock_) {
            EXPECT_EQ(READONLY_ZONE_ID, finder->zone_id());
        }
704
        EXPECT_EQ(current_accessor_, &finder->getAccessor());
705
    }
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
706
707

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

        return (finder);
    }

719
    // Helper methods for update tests
720
721
722
723
724
725
726
727
    bool isRollbacked(bool expected = false) const {
        if (is_mock_) {
            const MockAccessor& mock_accessor =
                dynamic_cast<const MockAccessor&>(*update_accessor_);
            return (mock_accessor.isRollbacked());
        } else {
            return (expected);
        }
728
729
730
    }

    void checkLastAdded(const char* const expected[]) const {
731
732
733
734
735
736
737
        if (is_mock_) {
            const MockAccessor* mock_accessor =
                dynamic_cast<const MockAccessor*>(current_accessor_);
            for (int i = 0; i < DatabaseAccessor::ADD_COLUMN_COUNT; ++i) {
                EXPECT_EQ(expected[i],
                          mock_accessor->getLatestClone()->getLastAdded()[i]);
            }
738
739
740
741
        }
    }

    void setUpdateAccessor() {
742
743
744
745
746
        if (is_mock_) {
            const MockAccessor* mock_accessor =
                dynamic_cast<const MockAccessor*>(current_accessor_);
            update_accessor_ = mock_accessor->getLatestClone();
        }
747
748
    }

749
750
751
752
    // Some tests only work for MockAccessor.  We remember whether our accessor
    // is of that type.
    bool is_mock_;

753
    // Will be deleted by client_, just keep the current value for comparison.
754
    ACCESSOR_TYPE* current_accessor_;
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
    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_;
772
    shared_ptr<const DatabaseAccessor> update_accessor_;
773
774
775

    // placeholders
    const std::vector<std::string> empty_rdatas_; // for NXRRSET/NXDOMAIN
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
776
777
    std::vector<std::string> expected_rdatas_;
    std::vector<std::string> expected_sig_rdatas_;
778
779
};

780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
class TestSQLite3Accessor : public SQLite3Accessor {
public:
    TestSQLite3Accessor() : SQLite3Accessor(
        TEST_DATA_BUILDDIR "/rwtest.sqlite3.copied",
        RRClass::IN())
    {
        startUpdateZone("example.org.", true);
        string columns[ADD_COLUMN_COUNT];
        for (int i = 0; TEST_RECORDS[i][0] != NULL; ++i) {
            columns[ADD_NAME] = TEST_RECORDS[i][0];
            columns[ADD_REV_NAME] = Name(columns[ADD_NAME]).reverse().toText();
            columns[ADD_TYPE] = TEST_RECORDS[i][1];
            columns[ADD_TTL] = TEST_RECORDS[i][2];
            columns[ADD_SIGTYPE] = TEST_RECORDS[i][3];
            columns[ADD_RDATA] = TEST_RECORDS[i][4];

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

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

807
808
809
810
811
// In some cases the entire test fixture is for the mock accessor only.
// We use the usual TEST_F for them with the corresponding specialized class
// to make the code simpler.
typedef DatabaseClientTest<MockAccessor> MockDatabaseClientTest;

812
813
814
TYPED_TEST(DatabaseClientTest, zoneNotFound) {
    DataSourceClient::FindResult zone(
        this->client_->findZone(Name("example.com")));
815
816
817
    EXPECT_EQ(result::NOTFOUND, zone.code);
}

818
819
820
TYPED_TEST(DatabaseClientTest, exactZone) {
    DataSourceClient::FindResult zone(
        this->client_->findZone(Name("example.org")));
821
    EXPECT_EQ(result::SUCCESS, zone.code);
822
    this->checkZoneFinder(zone);
823
824
}

825
826
TYPED_TEST(DatabaseClientTest, superZone) {
    DataSourceClient::FindResult zone(this->client_->findZone(Name(
827
828
        "sub.example.org")));
    EXPECT_EQ(result::PARTIALMATCH, zone.code);
829
    this->checkZoneFinder(zone);
830
831
}

832
833
// This test doesn't depend on derived accessor class, so we use TEST().
TEST(GenericDatabaseClientTest, noAccessorException) {
Jelte Jansen's avatar
Jelte Jansen committed
834
835
    // We need a dummy variable here; some compiler would regard it a mere
    // declaration instead of an instantiation and make the test fail.
836
837
    EXPECT_THROW(DatabaseClient dummy(RRClass::IN(),
                                      shared_ptr<DatabaseAccessor>()),
838
839
840
                 isc::InvalidParameter);
}

841
// If the zone doesn't exist, exception is thrown
842
843
844
TYPED_TEST(DatabaseClientTest, noZoneIterator) {
    EXPECT_THROW(this->client_->getIterator(Name("example.com")),
                 DataSourceError);
845
846
847
848
}

// If the zone doesn't exist and iteration is not implemented, it still throws
// the exception it doesn't exist
849
TEST(GenericDatabaseClientTest, noZoneNotImplementedIterator) {
850
851
852
853
    EXPECT_THROW(DatabaseClient(RRClass::IN(),
                                boost::shared_ptr<DatabaseAccessor>(
                                    new NopAccessor())).getIterator(
                                        Name("example.com")),
854
855
856
                 DataSourceError);
}

857
TEST(GenericDatabaseClientTest, notImplementedIterator) {
858
    EXPECT_THROW(DatabaseClient(RRClass::IN(), shared_ptr<DatabaseAccessor>(
859
        new NopAccessor())).getIterator(Name("example.org")),
860
861
862
863
                 isc::NotImplemented);
}

// Pretend a bug in the connection and pass NULL as the context
864
// Should not crash, but gracefully throw.  Works for the mock accessor only.
865
866
TEST_F(MockDatabaseClientTest, nullIteratorContext) {
    EXPECT_THROW(this->client_->getIterator(Name("null.example.org")),
867
868
869
                 isc::Unexpected);
}

870
871
// It doesn't crash or anything if the zone is completely empty.
// Works for the mock accessor only.
872
TEST_F(MockDatabaseClientTest, emptyIterator) {
873
    ZoneIteratorPtr it(this->client_->getIterator(Name("empty.example.org")));
874
875
876
877
878
    EXPECT_EQ(ConstRRsetPtr(), it->getNextRRset());
    // This is past the end, it should throw
    EXPECT_THROW(it->getNextRRset(), isc::Unexpected);
}

879
880
881
// Iterate through a zone
TYPED_TEST(DatabaseClientTest, iterator) {
    ZoneIteratorPtr it(this->client_->getIterator(Name("example.org")));
882
883
    ConstRRsetPtr rrset(it->getNextRRset());
    ASSERT_NE(ConstRRsetPtr(), rrset);
884
885
886
887
888
889

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

890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
    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
932
933
// the data is handled in rdata itself).  Works for the mock accessor only.
TEST_F(MockDatabaseClientTest, badIterator) {
934
    // It should not throw, but get the lowest one of them
935
    ZoneIteratorPtr it(this->client_->getIterator(Name("bad.example.org")));
936
    EXPECT_EQ(it->getNextRRset()->getTTL(), isc::dns::RRTTL(300));
937
938
}

939
940
941
942
943
944
945
946
// 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,
947
           const std::vector<std::string>& rdatas) {
948
949
950
951
952
953
954
955
956
957
    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);
}

958
void
959
doFindTest(ZoneFinder& finder,
960
961
962
           const isc::dns::Name& name,
           const isc::dns::RRType& type,
           const isc::dns::RRType& expected_type,
963
           const isc::dns::RRTTL expected_ttl,
964
           ZoneFinder::Result expected_result,
965
           const std::vector<std::string>& expected_rdatas,
966
           const std::vector<std::string>& expected_sig_rdatas,
967
968
           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
969
{
970
    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
971
    ZoneFinder::FindResult result =
972
        finder.find(name, type, NULL, options);
973
    ASSERT_EQ(expected_result, result.code) << name << " " << type;
974
    if (!expected_rdatas.empty() && result.rrset) {
975
        checkRRset(result.rrset, expected_name != Name(".") ? expected_name :
976
                   name, finder.getClass(), expected_type, expected_ttl,
977
                   expected_rdatas);
978

979
        if (!expected_sig_rdatas.empty() && result.rrset->getRRsig()) {
980
            checkRRset(result.rrset->getRRsig(), expected_name != Name(".") ?
981
                       expected_name : name, finder.getClass(),
982
983
                       isc::dns::RRType::RRSIG(), expected_ttl,
                       expected_sig_rdatas);
984
        } else if (expected_sig_rdatas.empty()) {
985
            EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset->getRRsig());
986
987
        } else {
            ADD_FAILURE() << "Missing RRSIG";
988
        }
989
    } else if (expected_rdatas.empty()) {
990
        EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset);
991
992
    } else {
        ADD_FAILURE() << "Missing result";
993
994
995
    }
}

996
997
TYPED_TEST(DatabaseClientTest, find) {
    shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
998

999
1000
1001
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
1002
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1003
1004
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1005

1006
1007
1008
1009
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_rdatas_.push_back("192.0.2.2");
1010
    doFindTest(*finder, isc::dns::Name("www2.example.org."),
1011
1012
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1013

1014
1015
1016
1017
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_rdatas_.push_back("2001:db8::2");
1018
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1019
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1020
               this->rrttl_,
1021
               ZoneFinder::SUCCESS,
1022
               this->expected_rdatas_, this->expected_sig_rdatas_);
1023

1024
1025
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1026
    doFindTest(*finder, isc::dns::Name("www.example.org."),
1027
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
1028
               this->rrttl_,
1029
               ZoneFinder::NXRRSET,
1030
               this->expected_rdatas_, this->expected_sig_rdatas_);
1031

1032
1033
1034
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
1035
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
1036
1037
1038
1039
1040
1041
1042
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
1043
    doFindTest(*finder, isc::dns::Name("cname.example.org."),
1044
               isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
1045
1046
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1047

1048
1049
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1050
    doFindTest(*finder, isc::dns::Name("doesnotexist.example.org."),
1051
1052
1053
1054
1055
1056
1057
1058
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::NXDOMAIN,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
1059
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1060
1061
1062
1063
1064
1065
1066
1067
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_rdatas_.push_back("2001:db8::2");
    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1068
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1069
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1070
1071
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1072

1073
1074
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1075
    doFindTest(*finder, isc::dns::Name("signed1.example.org."),
1076
1077
1078
1079
1080
1081
1082
1083
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
               ZoneFinder::NXRRSET, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1084
    doFindTest(*finder, isc::dns::Name("signedcname1.example.org."),
1085
1086
1087
1088
1089
1090
1091
1092
1093
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
1094
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1095
1096
1097
1098
1099
1100
1101
1102
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("2001:db8::2");
    this->expected_rdatas_.push_back("2001:db8::1");
    this->expected_sig_rdatas_.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1103
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1104
               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
1105
1106
               this->rrttl_, ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1107

1108
1109
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
1110
    doFindTest(*finder, isc::dns::Name("signed2.example.org."),
1111
1112
1113
1114
1115
1116
1117
1118
               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(), this->rrttl_,
               ZoneFinder::NXRRSET, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("www.example.org.");
    this->expected_sig_rdatas_.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1119
    doFindTest(*finder, isc::dns::Name("signedcname2.example.org."),
1120
1121
1122
1123
1124
1125
1126
1127
               this->qtype_, isc::dns::RRType::CNAME(), this->rrttl_,
               ZoneFinder::CNAME, this->expected_rdatas_,
               this->expected_sig_rdatas_);

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

1132
1133
1134
1135
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1136
    doFindTest(*finder, isc::dns::Name("acnamesig2.example.org."),
1137
1138
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
1139

1140
1141
1142
1143
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_sig_rdatas_.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
1144
    doFindTest(*finder, isc::dns::Name("acnamesig3.example.org."),
1145
1146
               this->qtype_, this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
               this->expected_rdatas_, this->expected_sig_rdatas_);
Jelte Jansen's avatar
Jelte Jansen committed
1147

1148
1149
1150
1151
    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_rdatas_.push_back("192.0.2.2");
1152
    doFindTest(*finder, isc::dns::Name("ttldiff1.example.org."),
1153
1154
1155
1156
1157
1158
1159
1160
               this->qtype_, this->qtype_, isc::dns::RRTTL(360),
               ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);

    this->expected_rdatas_.clear();
    this->expected_sig_rdatas_.clear();
    this->expected_rdatas_.push_back("192.0.2.1");
    this->expected_rdatas_.push_back("192.0.2.2");
1161
    doFindTest(*finder, isc::dns::Name("ttldiff2.example.org."),
1162
1163
1164
               this->qtype_, this->qtype_, isc::dns::RRTTL(360),
               ZoneFinder::SUCCESS, this->expected_rdatas_,
               this->expected_sig_rdatas_);
1165
1166

    EXPECT_THROW(finder->find(isc::dns::Name("badcname1.example.org."),
1167
                                              this->qtype_,
1168
1169
1170
                                              NULL, ZoneFinder::FIND_DEFAULT),
                 DataSourceError);
    EXPECT_THROW(finder->find(isc::dns::Name("badcname2.example.org."),