memory_datasrc_unittest.cc 98.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Copyright (C) 2010  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
#include "faked_nsec3.h"
16

17
18
#include <exceptions/exceptions.h>

19
#include <dns/masterload.h>
20
#include <dns/name.h>
21
#include <dns/nsec3hash.h>
22
23
#include <dns/rdata.h>
#include <dns/rdataclass.h>
24
#include <dns/rrclass.h>
chenzhengzhang's avatar
chenzhengzhang committed
25
#include <dns/rrsetlist.h>
Michal Vaner's avatar
Michal Vaner committed
26
#include <dns/rrttl.h>
Michal Vaner's avatar
Michal Vaner committed
27
#include <dns/masterload.h>
28

29
#include <datasrc/client.h>
30
#include <datasrc/memory_datasrc.h>
31
32
#include <datasrc/data_source.h>
#include <datasrc/iterator.h>
33

34
35
#include "test_client.h"

36
37
#include <testutils/dnsmessage_test.h>

38
39
#include <gtest/gtest.h>

40
41
42
43
44
45
46
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>

#include <sstream>
#include <vector>

47
using namespace std;
48
using namespace isc::dns;
49
using namespace isc::dns::rdata;
50
using namespace isc::datasrc;
51
using namespace isc::testutils;
52
using boost::shared_ptr;
53
using namespace isc::datasrc::test;
54
55

namespace {
56
57
58
// Commonly used result codes (Who should write the prefix all the time)
using result::SUCCESS;
using result::EXIST;
59

60
class InMemoryClientTest : public ::testing::Test {
61
protected:
62
    InMemoryClientTest() : rrclass(RRClass::IN())
63
    {}
64
    RRClass rrclass;
65
    InMemoryClient memory_client;
66
67
};

68
TEST_F(InMemoryClientTest, add_find_Zone) {
69
70
    // test add zone
    // Bogus zone (NULL)
71
    EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
72
                 isc::InvalidParameter);
73
74

    // add zones with different names one by one
75
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
76
77
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("a")))));
78
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
79
80
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("b")))));
81
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
82
83
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("c")))));
84
    // add zones with the same name suffix
85
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
86
87
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("x.d.e.f")))));
88
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
89
90
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("o.w.y.d.e.f")))));
91
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
92
93
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("p.w.y.d.e.f")))));
94
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
95
96
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("q.w.y.d.e.f")))));
97
    // add super zone and its subzone
98
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
99
100
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("g.h")))));
101
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
102
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
103
                                               Name("i.g.h")))));
104
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
105
106
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("z.d.e.f")))));
107
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(
108
109
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("j.z.d.e.f")))));
110
111

    // different zone class isn't allowed.
112
    EXPECT_EQ(result::EXIST, memory_client.addZone(
113
114
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("q.w.y.d.e.f")))));
115
116

    // names are compared in a case insensitive manner.
117
    EXPECT_EQ(result::EXIST, memory_client.addZone(
118
119
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("Q.W.Y.d.E.f")))));
120
121

    // test find zone
122
    EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
123
    EXPECT_EQ(Name("a"),
124
              memory_client.findZone(Name("a")).zone_finder->getOrigin());
125
126

    EXPECT_EQ(result::SUCCESS,
127
              memory_client.findZone(Name("j.z.d.e.f")).code);
128
    EXPECT_EQ(Name("j.z.d.e.f"),
129
130
              memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
                  getOrigin());
131
132

    // NOTFOUND
133
    EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
134
    EXPECT_EQ(ConstZoneFinderPtr(),
135
              memory_client.findZone(Name("d.e.f")).zone_finder);
136
137

    EXPECT_EQ(result::NOTFOUND,
138
              memory_client.findZone(Name("w.y.d.e.f")).code);
139
    EXPECT_EQ(ConstZoneFinderPtr(),
140
              memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
141
142
143
144

    // there's no exact match.  the result should be the longest match,
    // and the code should be PARTIALMATCH.
    EXPECT_EQ(result::PARTIALMATCH,
145
              memory_client.findZone(Name("j.g.h")).code);
146
    EXPECT_EQ(Name("g.h"),
147
              memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
148
149

    EXPECT_EQ(result::PARTIALMATCH,
150
              memory_client.findZone(Name("z.i.g.h")).code);
151
    EXPECT_EQ(Name("i.g.h"),
152
153
              memory_client.findZone(Name("z.i.g.h")).zone_finder->
                  getOrigin());
154
}
155

156
157
158
159
160
161
162
163
164
165
166
167
168
169
TEST_F(InMemoryClientTest, iterator) {
    // Just some preparations of data
    boost::shared_ptr<InMemoryZoneFinder>
        zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
    RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
                                  RRTTL(300)));
    aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
    RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
                                  RRTTL(300)));
    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
    RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
                                  RRTTL(300)));
    subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
170
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
171
172
    // First, the zone is not there, so it should throw
    EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
173
174
    // This zone is not there either, even when there's a zone containing this
    EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
175
176
177
178
179
180
181
182
    // Now, an empty zone
    ZoneIteratorPtr iterator(memory_client.getIterator(Name("a")));
    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
    // It throws Unexpected when we are past the end
    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
    EXPECT_EQ(result::SUCCESS, zone->add(aRRsetA));
    EXPECT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
    EXPECT_EQ(result::SUCCESS, zone->add(subRRsetA));
183
184
185
186
187
188
189

    // Check it with full zone.
    vector<ConstRRsetPtr> expected_rrsets;
    expected_rrsets.push_back(aRRsetA);
    expected_rrsets.push_back(aRRsetAAAA);
    expected_rrsets.push_back(subRRsetA);

190
    iterator = memory_client.getIterator(Name("a"));
191
    vector<ConstRRsetPtr> actual_rrsets;
192
193
    ConstRRsetPtr actual;
    while ((actual = iterator->getNextRRset()) != NULL) {
194
195
196
197
198
199
        actual_rrsets.push_back(actual);
    }

    rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
                actual_rrsets.begin(), actual_rrsets.end());

200
201
}

202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
TEST_F(InMemoryClientTest, iterator_separate_rrs) {
    // Exactly the same tests as for iterator, but now with separate_rrs = true
    // For the one that returns actual data, the AAAA should now be split up
    boost::shared_ptr<InMemoryZoneFinder>
        zone(new InMemoryZoneFinder(RRClass::IN(), Name("a")));
    RRsetPtr aRRsetA(new RRset(Name("a"), RRClass::IN(), RRType::A(),
                                  RRTTL(300)));
    aRRsetA->addRdata(rdata::in::A("192.0.2.1"));
    RRsetPtr aRRsetAAAA(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
                                  RRTTL(300)));
    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::1"));
    aRRsetAAAA->addRdata(rdata::in::AAAA("2001:db8::2"));
    RRsetPtr aRRsetAAAA_r1(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
                                  RRTTL(300)));
    aRRsetAAAA_r1->addRdata(rdata::in::AAAA("2001:db8::1"));
    RRsetPtr aRRsetAAAA_r2(new RRset(Name("a"), RRClass::IN(), RRType::AAAA(),
                                  RRTTL(300)));
    aRRsetAAAA_r2->addRdata(rdata::in::AAAA("2001:db8::2"));

    RRsetPtr subRRsetA(new RRset(Name("sub.x.a"), RRClass::IN(), RRType::A(),
                                  RRTTL(300)));
    subRRsetA->addRdata(rdata::in::A("192.0.2.2"));
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));

    // First, the zone is not there, so it should throw
    EXPECT_THROW(memory_client.getIterator(Name("b"), true), DataSourceError);
    // This zone is not there either, even when there's a zone containing this
    EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
    // Now, an empty zone
    ZoneIteratorPtr iterator(memory_client.getIterator(Name("a"), true));
    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
    // It throws Unexpected when we are past the end
    EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);

    ASSERT_EQ(result::SUCCESS, zone->add(aRRsetA));
    ASSERT_EQ(result::SUCCESS, zone->add(aRRsetAAAA));
    ASSERT_EQ(result::SUCCESS, zone->add(subRRsetA));
    // Check it with full zone, one by one.
    // It should be in ascending order in case of InMemory data source
    // (isn't guaranteed in general)
    iterator = memory_client.getIterator(Name("a"), true);
    EXPECT_EQ(aRRsetA->toText(), iterator->getNextRRset()->toText());
    EXPECT_EQ(aRRsetAAAA_r1->toText(), iterator->getNextRRset()->toText());
    EXPECT_EQ(aRRsetAAAA_r2->toText(), iterator->getNextRRset()->toText());
    EXPECT_EQ(subRRsetA->toText(), iterator->getNextRRset()->toText());
    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
}

250
251
252
TEST_F(InMemoryClientTest, getZoneCount) {
    EXPECT_EQ(0, memory_client.getZoneCount());
    memory_client.addZone(
253
254
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.com"))));
255
    EXPECT_EQ(1, memory_client.getZoneCount());
256
257

    // duplicate add.  counter shouldn't change
258
    memory_client.addZone(
259
260
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.com"))));
261
    EXPECT_EQ(1, memory_client.getZoneCount());
262
263

    // add one more
264
    memory_client.addZone(
265
266
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.org"))));
267
    EXPECT_EQ(2, memory_client.getZoneCount());
268
}
269

270
TEST_F(InMemoryClientTest, startUpdateZone) {
271
    EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
272
                 isc::NotImplemented);
273
274
}

275
276
277
278
279
280
281
282
283
284
285
286
287
288
// Commonly used RRSIG data
const char* const rrsig_a_txt =
    "example.org. 300 IN RRSIG A 5 3 3600 20000101000000 20000201000000 12345 "
    "example.org. FAKEFAKEFAKE\n";
const char* const rrsig_ns_txt =
    "example.org. 300 IN RRSIG NS 5 3 3600 20000101000000 20000201000000 "
    "54321 example.org. FAKEFAKEFAKEFAKE\n";
// This RRset has two RRSIGs
const char* const rrsig_aaaa_txt =
    "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
    "12345 example.org. FAKEFAKEFAKE\n"
    "ns.example.org. 300 IN RRSIG AAAA 5 3 3600 20000101000000 20000201000000 "
    "54321 example.org. FAKEFAKEFAKEFAKE\n";

289
// A helper callback of masterLoad() used in InMemoryZoneFinderTest.
290
291
292
293
294
295
void
setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
    *(*it) = rrset;
    ++it;
}

296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
// Some faked NSEC3 hash values commonly used in tests and the faked NSEC3Hash
// object.
//
// For apex (example.org)
const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
// For ns1.example.org
const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
// For w.example.org
const char* const w_hash = "01UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
// For x.y.w.example.org (lower-cased)
const char* const xyw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
// For zzz.example.org.
const char* const zzz_hash = "R53BQ7CC2UVMUBFU5OCMM6PERS9TK9EN";

// A simple faked NSEC3 hash calculator with a dedicated creator for it.
//
// This is used in some NSEC3-related tests below.
class TestNSEC3HashCreator : public NSEC3HashCreator {
    class TestNSEC3Hash : public NSEC3Hash {
    private:
        typedef map<Name, string> NSEC3HashMap;
        typedef NSEC3HashMap::value_type NSEC3HashPair;
319
        NSEC3HashMap map_;
320
321
322
    public:
        TestNSEC3Hash() {
            // Build pre-defined hash
323
324
325
326
327
            map_[Name("example.org")] = apex_hash;
            map_[Name("www.example.org")] = "2S9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
            map_[Name("xxx.example.org")] = "Q09MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
            map_[Name("yyy.example.org")] = "0A9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
            map_[Name("x.y.w.example.org")] =
328
                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
329
330
331
332
            map_[Name("y.w.example.org")] = "K8UDEMVP1J2F7EG6JEBPS17VP3N8I58H";
            map_[Name("w.example.org")] = w_hash;
            map_[Name("zzz.example.org")] = zzz_hash;
            map_[Name("smallest.example.org")] =
333
                "00000000000000000000000000000000";
334
            map_[Name("largest.example.org")] =
335
336
337
                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
        }
        virtual string calculate(const Name& name) const {
338
339
            const NSEC3HashMap::const_iterator found = map_.find(name);
            if (found != map_.end()) {
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
                return (found->second);
            }
            isc_throw(isc::Unexpected, "unexpected name for NSEC3 test: "
                      << name);
        }
        virtual bool match(const generic::NSEC3PARAM&) const {
            return (true);
        }
        virtual bool match(const generic::NSEC3&) const {
            return (true);
        }
    };

public:
    virtual NSEC3Hash* create(const generic::NSEC3PARAM&) const {
        return (new TestNSEC3Hash);
    }
    virtual NSEC3Hash* create(const generic::NSEC3&) const {
        return (new TestNSEC3Hash);
    }
};

362
363
/// \brief Test fixture for the InMemoryZoneFinder class
class InMemoryZoneFinderTest : public ::testing::Test {
364
365
366
367
368
369
    // A straightforward pair of textual RR(set) and a RRsetPtr variable
    // to store the RRset.  Used to build test data below.
    struct RRsetData {
        const char* const text; // textual representation of an RRset
        RRsetPtr* rrset;
    };
370
371
372
373
374
375
protected:
    // The following sub tests are shared by multiple test cases, changing
    // the zone's DNSSEC status (unsigned, NSEC-signed or NSEC3-signed).
    // expected_flags is set to either RESULT_NSEC_SIGNED or
    // RESULT_NSEC3_SIGNED when it's NSEC/NSEC3 signed respectively and
    // find() is expected to set the corresponding flags.
376
377
    // find_options should be set to FIND_DNSSEC for NSEC-signed case when
    // NSEC is expected to be returned.
378
    void findCheck(ZoneFinder::FindResultFlags expected_flags =
379
380
381
                   ZoneFinder::RESULT_DEFAULT,
                   ZoneFinder::FindOptions find_options =
                   ZoneFinder::FIND_DEFAULT);
382
383
384
    void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
                        ZoneFinder::RESULT_DEFAULT);
    void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
385
386
387
                       ZoneFinder::RESULT_DEFAULT,
                       ZoneFinder::FindOptions find_options =
                       ZoneFinder::FIND_DEFAULT);
388
    void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
389
390
391
                               ZoneFinder::RESULT_DEFAULT,
                               ZoneFinder::FindOptions find_options =
                               ZoneFinder::FIND_DEFAULT);
392
393
394
395
    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                          ZoneFinder::RESULT_DEFAULT);
    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                            ZoneFinder::RESULT_DEFAULT);
396
    void findNSECENTCheck(const Name& ent_name,
397
                          ConstRRsetPtr expected_nsec,
398
399
                          ZoneFinder::FindResultFlags expected_flags =
                          ZoneFinder::RESULT_DEFAULT);
400

401
public:
402
    InMemoryZoneFinderTest() :
403
404
        class_(RRClass::IN()),
        origin_("example.org"),
405
        zone_finder_(class_, origin_)
Michal Vaner's avatar
Michal Vaner committed
406
    {
407
408
409
        // Build test RRsets.  Below, we construct an RRset for
        // each textual RR(s) of zone_data, and assign it to the corresponding
        // rr_xxx.
410
411
        // Note that this contains an out-of-zone RR, and due to the
        // validation check of masterLoad() used below, we cannot add SOA.
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
        const RRsetData zone_data[] = {
            {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
            {"example.org. 300 IN A 192.0.2.1", &rr_a_},
            {"ns.example.org. 300 IN A 192.0.2.2", &rr_ns_a_},
            {"ns.example.org. 300 IN AAAA 2001:db8::2", &rr_ns_aaaa_},
            {"cname.example.org. 300 IN CNAME canonical.example.org",
             &rr_cname_},
            {"cname.example.org. 300 IN A 192.0.2.3", &rr_cname_a_},
            {"dname.example.org. 300 IN DNAME target.example.org.",
             &rr_dname_},
            {"dname.example.org. 300 IN A 192.0.2.39", &rr_dname_a_},
            {"dname.example.org. 300 IN NS ns.dname.example.org.",
             &rr_dname_ns_},
            {"example.org. 300 IN DNAME example.com.", &rr_dname_apex_},
            {"child.example.org. 300 IN NS ns.child.example.org.",
             &rr_child_ns_},
428
429
            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
             &rr_child_ds_},
430
431
432
433
434
435
436
437
            {"ns.child.example.org. 300 IN A 192.0.2.153",
             &rr_child_glue_},
            {"grand.child.example.org. 300 IN NS ns.grand.child.example.org.",
             &rr_grandchild_ns_},
            {"ns.grand.child.example.org. 300 IN AAAA 2001:db8::253",
             &rr_grandchild_glue_},
            {"dname.child.example.org. 300 IN DNAME example.com.",
             &rr_child_dname_},
438
            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
439
            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
440
441
            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
             &rr_cnamewild_},
442
            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
443
444
445
446
447
448
            {"wild.*.foo.example.org. 300 IN A 192.0.2.1", &rr_emptywild_},
            {"wild.*.foo.*.bar.example.org. 300 IN A 192.0.2.1",
             &rr_nested_emptywild_},
            {"*.nswild.example.org. 300 IN NS nswild.example.", &rr_nswild_},
            {"*.dnamewild.example.org. 300 IN DNAME dnamewild.example.",
             &rr_dnamewild_},
449
            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
450
            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
451
452
            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
             &rr_not_wild_another_},
453
454
455
            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
             &rr_nsec3_},
456
457
458
459
460
461
462
463
464
465
466
467
            {"example.org. 300 IN NSEC wild.*.foo.example.org. "
             "NS SOA RRSIG NSEC DNSKEY", &rr_nsec_},
            // Together with the apex NSEC, these next NSECs make a complete
            // chain in the case of the zone for the emptyNonterminal tests
            // (We may want to clean up this generator code and/or masterLoad
            // so that we can prepare conflicting datasets better)
            {"wild.*.foo.example.org. 3600 IN NSEC ns.example.org. "
             "A RRSIG NSEC", &rr_ent_nsec2_},
            {"ns.example.org. 3600 IN NSEC foo.wild.example.org. A RRSIG NSEC",
             &rr_ent_nsec3_},
            {"foo.wild.example.org. 3600 IN NSEC example.org. A RRSIG NSEC",
             &rr_ent_nsec4_},
468
            // And these are NSECs used in different tests
469
470
            {"ns.example.org. 300 IN NSEC *.nswild.example.org. A AAAA NSEC",
             &rr_ns_nsec_},
471
472
            {"*.wild.example.org. 300 IN NSEC foo.wild.example.org. A NSEC",
             &rr_wild_nsec_},
473
            {NULL, NULL}
474
475
476
477
478
479
480
481
482
483
        };

        stringstream zone_data_stream;
        vector<RRsetPtr*> rrsets;
        for (unsigned int i = 0; zone_data[i].text != NULL; ++i) {
            zone_data_stream << zone_data[i].text << "\n";
            rrsets.push_back(zone_data[i].rrset);
        }

        masterLoad(zone_data_stream, Name::ROOT_NAME(), class_,
484
                   boost::bind(setRRset, _1, rrsets.begin()));
Michal Vaner's avatar
Michal Vaner committed
485
    }
486

487
    ~InMemoryZoneFinderTest() {
488
489
490
491
        // Make sure we reset the hash creator to the default
        setNSEC3HashCreator(NULL);
    }

492
    // Some data to test with
493
    const RRClass class_;
494
    const Name origin_;
495
    // The zone finder to torture by tests
496
    InMemoryZoneFinder zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
497

498
499
500
    // Placeholder for storing RRsets to be checked with rrsetsCheck()
    vector<ConstRRsetPtr> actual_rrsets_;

Michal Vaner's avatar
Michal Vaner committed
501
502
503
    /*
     * Some RRsets to put inside the zone.
     */
504
    RRsetPtr
Michal Vaner's avatar
Michal Vaner committed
505
506
507
508
509
510
511
512
513
        // Out of zone RRset
        rr_out_,
        // NS of example.org
        rr_ns_,
        // A of ns.example.org
        rr_ns_a_,
        // AAAA of ns.example.org
        rr_ns_aaaa_,
        // A of example.org
514
        rr_a_;
515
    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
516
    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
517
    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
518
519
520
521
    RRsetPtr rr_dname_a_; // for mixed DNAME + A case
    RRsetPtr rr_dname_ns_; // for mixed DNAME + NS case
    RRsetPtr rr_dname_apex_; // for mixed DNAME + NS case in the apex
    RRsetPtr rr_child_ns_; // NS of a child domain (for delegation)
522
    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
523
524
525
526
    RRsetPtr rr_child_glue_; // glue RR of the child domain
    RRsetPtr rr_grandchild_ns_; // NS below a zone cut (unusual)
    RRsetPtr rr_grandchild_glue_; // glue RR below a deeper zone cut
    RRsetPtr rr_child_dname_; // A DNAME under NS
527
528
    RRsetPtr rr_wild_;        // Wildcard record
    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
529
530
531
    RRsetPtr rr_emptywild_;
    RRsetPtr rr_nested_emptywild_;
    RRsetPtr rr_nswild_, rr_dnamewild_;
532
    RRsetPtr rr_child_wild_;
533
    RRsetPtr rr_under_wild_;
534
    RRsetPtr rr_not_wild_;
535
    RRsetPtr rr_not_wild_another_;
536
    RRsetPtr rr_nsec3_;
537
    RRsetPtr rr_nsec_;
538
539
540
    RRsetPtr rr_ent_nsec2_;
    RRsetPtr rr_ent_nsec3_;
    RRsetPtr rr_ent_nsec4_;
541
    RRsetPtr rr_ns_nsec_;
542
    RRsetPtr rr_wild_nsec_;
Michal Vaner's avatar
Michal Vaner committed
543

544
545
546
547
548
549
    // A faked NSEC3 hash calculator for convenience.
    // Tests that need to use the faked hashed values should call
    // setNSEC3HashCreator() with a pointer to this variable at the beginning
    // of the test (at least before adding any NSEC3/NSEC3PARAM RR).
    TestNSEC3HashCreator nsec3_hash_creator_;

Michal Vaner's avatar
Michal Vaner committed
550
    /**
551
     * \brief Test one find query to the zone finder.
Michal Vaner's avatar
Michal Vaner committed
552
     *
553
     * Asks a query to the zone finder and checks it does not throw and returns
Michal Vaner's avatar
Michal Vaner committed
554
555
556
557
558
559
     * expected results. It returns nothing, it just signals failures
     * to GTEST.
     *
     * \param name The name to ask for.
     * \param rrtype The RRType to ask of.
     * \param result The expected code of the result.
Michal Vaner's avatar
Michal Vaner committed
560
561
     * \param check_answer Should a check against equality of the answer be
     *     done?
Michal Vaner's avatar
Michal Vaner committed
562
     * \param answer The expected rrset, if any should be returned.
563
564
     * \param expected_flags The expected result flags returned via find().
     *     These can be tested using isWildcard() etc.
565
566
     * \param zone_finder Check different InMemoryZoneFinder object than
     *     zone_finder_ (if NULL, uses zone_finder_)
567
568
569
570
     * \param check_wild_answer Checks that the answer has the same RRs, type
     *     class and TTL as the eqxpected answer and that the name corresponds
     *     to the one searched. It is meant for checking answers for wildcard
     *     queries.
Michal Vaner's avatar
Michal Vaner committed
571
     */
572
573
    void findTest(const Name& name, const RRType& rrtype,
                  ZoneFinder::Result result,
574
575
                  bool check_answer = true,
                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
576
577
                  ZoneFinder::FindResultFlags expected_flags =
                  ZoneFinder::RESULT_DEFAULT,
578
                  InMemoryZoneFinder* zone_finder = NULL,
579
                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
580
                  bool check_wild_answer = false)
Michal Vaner's avatar
Michal Vaner committed
581
    {
582
583
        SCOPED_TRACE("findTest for " + name.toText() + "/" + rrtype.toText());

584
585
        if (zone_finder == NULL) {
            zone_finder = &zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
586
        }
587
588
        const ConstRRsetPtr answer_sig = answer ? answer->getRRsig() :
            RRsetPtr(); // note we use the same type as of retval of getRRsig()
Michal Vaner's avatar
Michal Vaner committed
589
590
591
        // The whole block is inside, because we need to check the result and
        // we can't assign to FindResult
        EXPECT_NO_THROW({
592
593
                ZoneFinderContextPtr find_result(zone_finder->find(
                                                     name, rrtype, options));
594
                // Check it returns correct answers
595
                EXPECT_EQ(result, find_result->code);
596
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
597
                          find_result->isWildcard());
598
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
599
                          != 0, find_result->isNSECSigned());
600
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
601
                          != 0, find_result->isNSEC3Signed());
602
                if (check_answer) {
603
                    if (!answer) {
604
                        ASSERT_FALSE(find_result->rrset);
605
                    } else {
606
607
                        ASSERT_TRUE(find_result->rrset);
                        rrsetCheck(answer, find_result->rrset);
608
                        if (answer_sig) {
609
                            ASSERT_TRUE(find_result->rrset->getRRsig());
610
                            rrsetCheck(answer_sig,
611
                                       find_result->rrset->getRRsig());
612
                        }
613
                    }
614
                } else if (check_wild_answer) {
615
                    ASSERT_NE(ConstRRsetPtr(), answer) <<
616
                        "Wrong test, don't check for wild names if you expect "
617
                        "empty answer";
618
                    ASSERT_NE(ConstRRsetPtr(), find_result->rrset) <<
619
                        "No answer found";
620
621
622
623
624
                    // Build the expected answer using the given name and
                    // other parameter of the base wildcard RRset.
                    RRsetPtr wildanswer(new RRset(name, answer->getClass(),
                                                  answer->getType(),
                                                  answer->getTTL()));
625
                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
626
627
                    for (; !expectedIt->isLast(); expectedIt->next()) {
                        wildanswer->addRdata(expectedIt->getCurrent());
628
                    }
629
                    rrsetCheck(wildanswer, find_result->rrset);
630
631
632

                    // Same for the RRSIG, if any.
                    if (answer_sig) {
633
                        ASSERT_TRUE(find_result->rrset->getRRsig());
634
635
636
637
638
639
640
641
642
643

                        RRsetPtr wildsig(new RRset(name,
                                                   answer_sig->getClass(),
                                                   RRType::RRSIG(),
                                                   answer_sig->getTTL()));
                        RdataIteratorPtr expectedIt(
                            answer_sig->getRdataIterator());
                        for (; !expectedIt->isLast(); expectedIt->next()) {
                            wildsig->addRdata(expectedIt->getCurrent());
                        }
644
                        rrsetCheck(wildsig, find_result->rrset->getRRsig());
645
                    }
646
647
                }
            });
Michal Vaner's avatar
Michal Vaner committed
648
    }
649
650
651
    /**
     * \brief Calls the findAll on the finder and checks the result.
     */
652
653
    void findAllTest(const Name& name, ZoneFinder::Result result,
                     const vector<ConstRRsetPtr>& expected_rrsets,
654
655
                     ZoneFinder::FindResultFlags expected_flags =
                     ZoneFinder::RESULT_DEFAULT,
656
657
658
659
                     InMemoryZoneFinder* finder = NULL,
                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
                     ZoneFinder::FindOptions options =
                     ZoneFinder::FIND_DEFAULT)
660
661
662
663
664
    {
        if (finder == NULL) {
            finder = &zone_finder_;
        }
        std::vector<ConstRRsetPtr> target;
665
666
667
        ZoneFinderContextPtr find_result(finder->findAll(name, target,
                                                         options));
        EXPECT_EQ(result, find_result->code);
668
        if (!rrset_result) {
669
            EXPECT_FALSE(find_result->rrset);
670
        } else {
671
672
            ASSERT_TRUE(find_result->rrset);
            rrsetCheck(rrset_result, find_result->rrset);
673
674
        }
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
675
                  find_result->isWildcard());
676
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
677
                  != 0, find_result->isNSECSigned());
678
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
679
                  != 0, find_result->isNSEC3Signed());
680
681
        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
                    target.begin(), target.end());
682
    }
683
684
685
};

/**
686
 * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
687
 *
688
 * Takes the created zone finder and checks its properties they are the same
689
690
 * as passed parameters.
 */
691
TEST_F(InMemoryZoneFinderTest, constructor) {
692
693
    ASSERT_EQ(class_, zone_finder_.getClass());
    ASSERT_EQ(origin_, zone_finder_.getOrigin());
694
}
Michal Vaner's avatar
Michal Vaner committed
695
696
697
698
699
700
/**
 * \brief Test adding.
 *
 * We test that it throws at the correct moments and the correct exceptions.
 * And we test the return value.
 */
701
TEST_F(InMemoryZoneFinderTest, add) {
Michal Vaner's avatar
Michal Vaner committed
702
    // This one does not belong to this zone
703
    EXPECT_THROW(zone_finder_.add(rr_out_), OutOfZone);
Michal Vaner's avatar
Michal Vaner committed
704
    // Test null pointer
705
    EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
706
                 InMemoryZoneFinder::NullRRset);
Michal Vaner's avatar
Michal Vaner committed
707
708

    // Now put all the data we have there. It should throw nothing
709
710
711
712
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_a_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_aaaa_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
Michal Vaner's avatar
Michal Vaner committed
713
714

    // Try putting there something twice, it should be rejected
715
716
    EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(EXIST, zone_finder_.add(rr_ns_a_)));
Michal Vaner's avatar
Michal Vaner committed
717
718
}

719
TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
720
    rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
721
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
722
723
}

724
TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
725
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
726
    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
727
728
}

729
TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
730
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
731
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
732
733
}

734
TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
735
736
    // CNAME and RRSIG can coexist
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
737
738
739
740
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
                              "3600 20000101000000 20000201000000 12345 "
                              "example.org. FAKEFAKEFAKE")));
741
742

    // Same for NSEC
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname.example.org. 300 IN NSEC "
                              "dname.example.org. CNAME RRSIG NSEC")));

    // Same as above, but adding NSEC first.
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname2.example.org. 300 IN NSEC "
                              "dname.example.org. CNAME RRSIG NSEC")));
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname2.example.org. 300 IN CNAME c.example.")));

    // If there's another type of RRset with NSEC, it should still fail.
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname3.example.org. 300 IN A 192.0.2.1")));
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname3.example.org. 300 IN NSEC "
                              "dname.example.org. CNAME RRSIG NSEC")));
    EXPECT_THROW(zone_finder_.add(textToRRset("cname3.example.org. 300 "
                                              "IN CNAME c.example.")),
                 InMemoryZoneFinder::AddError);
763
764
}

765
TEST_F(InMemoryZoneFinderTest, findCNAME) {
766
    // install CNAME RR
767
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
768
769

    // Find A RR of the same.  Should match the CNAME
770
771
    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
             rr_cname_);
772
773

    // Find the CNAME itself.  Should result in normal SUCCESS
774
    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
775
             rr_cname_);
776
777
}

778
TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
779
780
781
    // There's nothing special when we find a CNAME under a zone cut
    // (with FIND_GLUE_OK).  The behavior is different from BIND 9,
    // so we test this case explicitly.
782
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
783
784
    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
785
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
786
    findTest(Name("cname.child.example.org"), RRType::AAAA(),
787
788
             ZoneFinder::CNAME, true, rr_cname_under_cut_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
789
790
}

791
792
793
// Two DNAMEs at single domain are disallowed by RFC 2672, section 3)
// Having a CNAME there is disallowed too, but it is tested by
// addOtherThenCNAME and addCNAMEThenOther.
794
TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
795
    rr_dname_->addRdata(generic::DNAME("target2.example.org."));
796
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
797
798
799
800
801
802
}

/*
 * These two tests ensure that we can't have DNAME and NS at the same
 * node with the exception of the apex of zone (forbidden by RFC 2672)
 */
803
TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
804
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
805
    EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
806
807
}

808
TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
809
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
810
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
811
812
813
}

// It is allowed to have NS and DNAME at apex
814
TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
815
816
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
Michal 'vorner' Vaner's avatar
Michal 'vorner' Vaner committed
817
818
819

    // The NS should be possible to be found, below should be DNAME, not
    // delegation
820
821
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
    findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
822
             rr_dname_apex_);
823
824
}

825
TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
826
827
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
828
829
830
831
832
833
}

// TODO: Test (and implement) adding data under DNAME. That is forbidden by
// 2672 as well.

// Search under a DNAME record. It should return the DNAME
834
TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
835
836
837
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
             true, rr_dname_);
838
839
840
841
}

// Search at the domain with DNAME. It should act as DNAME isn't there, DNAME
// influences only the data below (see RFC 2672, section 3)
842
TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
843
844
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
845

846
    const Name dname_name(rr_dname_->getName());
847
848
849
850
    findTest(dname_name, RRType::A(), ZoneFinder::SUCCESS, true, rr_dname_a_);
    findTest(dname_name, RRType::DNAME(), ZoneFinder::SUCCESS, true,
             rr_dname_);
    findTest(dname_name, RRType::TXT(), ZoneFinder::NXRRSET, true);
851
852
}

853
854
// Try searching something that is both under NS and DNAME, without and with
// GLUE_OK mode (it should stop at the NS and DNAME respectively).
855
TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
856
857
    zone_finder_.add(rr_child_ns_);
    zone_finder_.add(rr_child_dname_);
858
859
860

    Name lowName("below.dname.child.example.org.");

861
862
    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
863
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
864
865
}

866
// Test adding child zones and zone cut handling
867
TEST_F(InMemoryZoneFinderTest, delegationNS) {
868
    // add in-zone data
869
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
870
871

    // install a zone cut
872
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
873
874

    // below the zone cut
875
876
    findTest(Name("www.child.example.org"), RRType::A(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
877
878

    // at the zone cut
879
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
880
             true, rr_child_ns_);
881
    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
882
             true, rr_child_ns_);
883

884
885
    // finding NS for the apex (origin) node.  This must not be confused
    // with delegation due to the existence of an NS RR.
886
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
887
888

    // unusual case of "nested delegation": the highest cut should be used.
889
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
890
    findTest(Name("www.grand.child.example.org"), RRType::A(),
891
892
             // note: !rr_grandchild_ns_
             ZoneFinder::DELEGATION, true, rr_child_ns_);
893
894
}

895
896
897
898
899
900
901
TEST_F(InMemoryZoneFinderTest, delegationWithDS) {
    // Similar setup to the previous one, but with DS RR at the delegation
    // point.
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_));
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ds_));

902
    // Normal types of query should result in delegation, but DS query
903
    // should be considered in-zone (but only exactly at the delegation point).
904
905
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
906
907
    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
             true, rr_child_ds_);
908
909
    findTest(Name("grand.child.example.org"), RRType::DS(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
910
911
912
913
914

    // There's nothing special for DS query at the zone apex.  It would
    // normally result in NXRRSET.
    findTest(Name("example.org"), RRType::DS(), ZoneFinder::NXRRSET,
             true, ConstRRsetPtr());
915
916
}

917
TEST_F(InMemoryZoneFinderTest, findAny) {
918
919
920
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_a_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
chenzhengzhang's avatar
chenzhengzhang committed
921

922
923
    vector<ConstRRsetPtr> expected_sets;

chenzhengzhang's avatar
chenzhengzhang committed
924
    // origin
925
926
927
    expected_sets.push_back(rr_a_);
    expected_sets.push_back(rr_ns_);
    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
928
929

    // out zone name
930
931
    EXPECT_THROW(findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
                             vector<ConstRRsetPtr>()),
932
                 OutOfZone);
933

934
935
936
    expected_sets.clear();
    expected_sets.push_back(rr_child_glue_);
    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
937
938

    // add zone cut
939
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
chenzhengzhang's avatar
chenzhengzhang committed
940
941

    // zone cut
JINMEI Tatuya's avatar