memory_datasrc_unittest.cc 87.9 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
16
17
18
#include <sstream>
#include <vector>

#include <boost/bind.hpp>
19
#include <boost/foreach.hpp>
20

21
22
#include <exceptions/exceptions.h>

23
#include <dns/masterload.h>
24
#include <dns/name.h>
25
#include <dns/nsec3hash.h>
26
27
#include <dns/rdata.h>
#include <dns/rdataclass.h>
28
#include <dns/rrclass.h>
chenzhengzhang's avatar
chenzhengzhang committed
29
#include <dns/rrsetlist.h>
Michal Vaner's avatar
Michal Vaner committed
30
#include <dns/rrttl.h>
Michal Vaner's avatar
Michal Vaner committed
31
#include <dns/masterload.h>
32
33

#include <datasrc/memory_datasrc.h>
34
35
#include <datasrc/data_source.h>
#include <datasrc/iterator.h>
36

37
38
#include <testutils/dnsmessage_test.h>

39
40
#include <gtest/gtest.h>

41
using namespace std;
42
using namespace isc::dns;
43
using namespace isc::dns::rdata;
44
using namespace isc::datasrc;
45
using namespace isc::testutils;
46
47

namespace {
48
49
50
// Commonly used result codes (Who should write the prefix all the time)
using result::SUCCESS;
using result::EXIST;
51

52
class InMemoryClientTest : public ::testing::Test {
53
protected:
54
    InMemoryClientTest() : rrclass(RRClass::IN())
55
    {}
56
    RRClass rrclass;
57
    InMemoryClient memory_client;
58
59
};

60
TEST_F(InMemoryClientTest, add_find_Zone) {
61
62
    // test add zone
    // Bogus zone (NULL)
63
    EXPECT_THROW(memory_client.addZone(ZoneFinderPtr()),
64
                 isc::InvalidParameter);
65
66

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

    // different zone class isn't allowed.
104
    EXPECT_EQ(result::EXIST, memory_client.addZone(
105
106
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
                                                       Name("q.w.y.d.e.f")))));
107
108

    // names are compared in a case insensitive manner.
109
    EXPECT_EQ(result::EXIST, memory_client.addZone(
110
111
                  ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
                                                       Name("Q.W.Y.d.E.f")))));
112
113

    // test find zone
114
    EXPECT_EQ(result::SUCCESS, memory_client.findZone(Name("a")).code);
115
    EXPECT_EQ(Name("a"),
116
              memory_client.findZone(Name("a")).zone_finder->getOrigin());
117
118

    EXPECT_EQ(result::SUCCESS,
119
              memory_client.findZone(Name("j.z.d.e.f")).code);
120
    EXPECT_EQ(Name("j.z.d.e.f"),
121
122
              memory_client.findZone(Name("j.z.d.e.f")).zone_finder->
                  getOrigin());
123
124

    // NOTFOUND
125
    EXPECT_EQ(result::NOTFOUND, memory_client.findZone(Name("d.e.f")).code);
126
    EXPECT_EQ(ConstZoneFinderPtr(),
127
              memory_client.findZone(Name("d.e.f")).zone_finder);
128
129

    EXPECT_EQ(result::NOTFOUND,
130
              memory_client.findZone(Name("w.y.d.e.f")).code);
131
    EXPECT_EQ(ConstZoneFinderPtr(),
132
              memory_client.findZone(Name("w.y.d.e.f")).zone_finder);
133
134
135
136

    // there's no exact match.  the result should be the longest match,
    // and the code should be PARTIALMATCH.
    EXPECT_EQ(result::PARTIALMATCH,
137
              memory_client.findZone(Name("j.g.h")).code);
138
    EXPECT_EQ(Name("g.h"),
139
              memory_client.findZone(Name("g.h")).zone_finder->getOrigin());
140
141

    EXPECT_EQ(result::PARTIALMATCH,
142
              memory_client.findZone(Name("z.i.g.h")).code);
143
    EXPECT_EQ(Name("i.g.h"),
144
145
              memory_client.findZone(Name("z.i.g.h")).zone_finder->
                  getOrigin());
146
}
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
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"));
162
    EXPECT_EQ(result::SUCCESS, memory_client.addZone(zone));
163
164
    // First, the zone is not there, so it should throw
    EXPECT_THROW(memory_client.getIterator(Name("b")), DataSourceError);
165
166
    // This zone is not there either, even when there's a zone containing this
    EXPECT_THROW(memory_client.getIterator(Name("x.a")), DataSourceError);
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
    // 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));
    // 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"));
    EXPECT_EQ(aRRsetA, iterator->getNextRRset());
    EXPECT_EQ(aRRsetAAAA, iterator->getNextRRset());
    EXPECT_EQ(subRRsetA, iterator->getNextRRset());
    EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
}

185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
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
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());
}

233
234
235
TEST_F(InMemoryClientTest, getZoneCount) {
    EXPECT_EQ(0, memory_client.getZoneCount());
    memory_client.addZone(
236
237
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.com"))));
238
    EXPECT_EQ(1, memory_client.getZoneCount());
239
240

    // duplicate add.  counter shouldn't change
241
    memory_client.addZone(
242
243
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.com"))));
244
    EXPECT_EQ(1, memory_client.getZoneCount());
245
246

    // add one more
247
    memory_client.addZone(
248
249
                  ZoneFinderPtr(new InMemoryZoneFinder(rrclass,
                                                       Name("example.org"))));
250
    EXPECT_EQ(2, memory_client.getZoneCount());
251
}
252

253
TEST_F(InMemoryClientTest, startUpdateZone) {
254
    EXPECT_THROW(memory_client.getUpdater(Name("example.org"), false),
255
                 isc::NotImplemented);
256
257
}

258
259
260
261
262
263
264
265
266
267
268
269
270
271
// 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";

272
// A helper callback of masterLoad() used in InMemoryZoneFinderTest.
273
274
275
276
277
278
void
setRRset(RRsetPtr rrset, vector<RRsetPtr*>::iterator& it) {
    *(*it) = rrset;
    ++it;
}

279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
ConstRRsetPtr
textToRRset(const string& text_rrset, const RRClass& rrclass = RRClass::IN()) {
    stringstream ss(text_rrset);
    RRsetPtr rrset;
    vector<RRsetPtr*> rrsets;
    rrsets.push_back(&rrset);
    masterLoad(ss, Name::ROOT_NAME(), rrclass,
               boost::bind(setRRset, _1, rrsets.begin()));
    return (rrset);
}

// 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;
313
        NSEC3HashMap map_;
314
315
316
    public:
        TestNSEC3Hash() {
            // Build pre-defined hash
317
318
319
320
321
            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")] =
322
                "2VPTU5TIMAMQTTGL4LUU9KG21E0AOR3S";
323
324
325
326
            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")] =
327
                "00000000000000000000000000000000";
328
            map_[Name("largest.example.org")] =
329
330
331
                "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU";
        }
        virtual string calculate(const Name& name) const {
332
333
            const NSEC3HashMap::const_iterator found = map_.find(name);
            if (found != map_.end()) {
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
                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);
    }
};

356
357
/// \brief Test fixture for the InMemoryZoneFinder class
class InMemoryZoneFinderTest : public ::testing::Test {
358
359
360
361
362
363
    // 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;
    };
364
365
366
367
368
369
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.
370
371
372
373
374
375
376
377
    void findCheck(ZoneFinder::FindResultFlags expected_flags =
                   ZoneFinder::RESULT_DEFAULT);
    void emptyNodeCheck(ZoneFinder::FindResultFlags expected_flags =
                        ZoneFinder::RESULT_DEFAULT);
    void wildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                       ZoneFinder::RESULT_DEFAULT);
    void doCancelWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                               ZoneFinder::RESULT_DEFAULT);
378
379
380
381
    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                          ZoneFinder::RESULT_DEFAULT);
    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                            ZoneFinder::RESULT_DEFAULT);
382

383
public:
384
    InMemoryZoneFinderTest() :
385
386
        class_(RRClass::IN()),
        origin_("example.org"),
387
        zone_finder_(class_, origin_)
Michal Vaner's avatar
Michal Vaner committed
388
    {
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
        // Build test RRsets.  Below, we construct an RRset for
        // each textual RR(s) of zone_data, and assign it to the corresponding
        // rr_xxx.
        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_},
408
409
            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
             &rr_child_ds_},
410
411
412
413
414
415
416
417
            {"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_},
418
            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
419
            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
420
421
            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
             &rr_cnamewild_},
422
            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
423
424
425
426
427
428
            {"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_},
429
            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
430
            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
431
432
            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
             &rr_not_wild_another_},
433
434
435
            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
             &rr_nsec3_},
436
            {NULL, NULL}
437
438
439
440
441
442
443
444
445
446
        };

        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_,
447
                   boost::bind(setRRset, _1, rrsets.begin()));
Michal Vaner's avatar
Michal Vaner committed
448
    }
449

450
    ~InMemoryZoneFinderTest() {
451
452
453
454
        // Make sure we reset the hash creator to the default
        setNSEC3HashCreator(NULL);
    }

455
    // Some data to test with
456
    const RRClass class_;
457
    const Name origin_;
458
    // The zone finder to torture by tests
459
    InMemoryZoneFinder zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
460

461
462
463
    // Placeholder for storing RRsets to be checked with rrsetsCheck()
    vector<ConstRRsetPtr> actual_rrsets_;

Michal Vaner's avatar
Michal Vaner committed
464
465
466
    /*
     * Some RRsets to put inside the zone.
     */
467
    RRsetPtr
Michal Vaner's avatar
Michal Vaner committed
468
469
470
471
472
473
474
475
476
        // 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
477
        rr_a_;
478
    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
479
    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
480
    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
481
482
483
484
    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)
485
    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
486
487
488
489
    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
490
491
    RRsetPtr rr_wild_;        // Wildcard record
    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
492
493
494
    RRsetPtr rr_emptywild_;
    RRsetPtr rr_nested_emptywild_;
    RRsetPtr rr_nswild_, rr_dnamewild_;
495
    RRsetPtr rr_child_wild_;
496
    RRsetPtr rr_under_wild_;
497
    RRsetPtr rr_not_wild_;
498
    RRsetPtr rr_not_wild_another_;
499
    RRsetPtr rr_nsec3_;
Michal Vaner's avatar
Michal Vaner committed
500

501
502
503
504
505
506
    // 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
507
    /**
508
     * \brief Test one find query to the zone finder.
Michal Vaner's avatar
Michal Vaner committed
509
     *
510
     * Asks a query to the zone finder and checks it does not throw and returns
Michal Vaner's avatar
Michal Vaner committed
511
512
513
514
515
516
     * 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
517
518
     * \param check_answer Should a check against equality of the answer be
     *     done?
Michal Vaner's avatar
Michal Vaner committed
519
     * \param answer The expected rrset, if any should be returned.
520
521
     * \param expected_flags The expected result flags returned via find().
     *     These can be tested using isWildcard() etc.
522
523
     * \param zone_finder Check different InMemoryZoneFinder object than
     *     zone_finder_ (if NULL, uses zone_finder_)
524
525
526
527
     * \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
528
     */
529
530
    void findTest(const Name& name, const RRType& rrtype,
                  ZoneFinder::Result result,
531
532
                  bool check_answer = true,
                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
533
534
                  ZoneFinder::FindResultFlags expected_flags =
                  ZoneFinder::RESULT_DEFAULT,
535
                  InMemoryZoneFinder* zone_finder = NULL,
536
                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
537
                  bool check_wild_answer = false)
Michal Vaner's avatar
Michal Vaner committed
538
    {
539
540
        if (zone_finder == NULL) {
            zone_finder = &zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
541
        }
542
543
        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
544
545
546
        // The whole block is inside, because we need to check the result and
        // we can't assign to FindResult
        EXPECT_NO_THROW({
547
                ZoneFinder::FindResult find_result(zone_finder->find(
548
                                                       name, rrtype, options));
549
550
                // Check it returns correct answers
                EXPECT_EQ(result, find_result.code);
551
552
553
554
555
556
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
                          find_result.isWildcard());
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
                          != 0, find_result.isNSECSigned());
                EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
                          != 0, find_result.isNSEC3Signed());
557
                if (check_answer) {
558
559
560
561
562
                    if (!answer) {
                        ASSERT_FALSE(find_result.rrset);
                    } else {
                        ASSERT_TRUE(find_result.rrset);
                        rrsetCheck(answer, find_result.rrset);
563
564
565
566
567
                        if (answer_sig) {
                            ASSERT_TRUE(find_result.rrset->getRRsig());
                            rrsetCheck(answer_sig,
                                       find_result.rrset->getRRsig());
                        }
568
                    }
569
                } else if (check_wild_answer) {
570
                    ASSERT_NE(ConstRRsetPtr(), answer) <<
571
                        "Wrong test, don't check for wild names if you expect "
572
573
574
                        "empty answer";
                    ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
                        "No answer found";
575
576
577
578
579
                    // 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()));
580
                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
581
582
                    for (; !expectedIt->isLast(); expectedIt->next()) {
                        wildanswer->addRdata(expectedIt->getCurrent());
583
                    }
584
                    rrsetCheck(wildanswer, find_result.rrset);
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

                    // Same for the RRSIG, if any.
                    if (answer_sig) {
                        ASSERT_TRUE(find_result.rrset->getRRsig());

                        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());
                        }
                        rrsetCheck(wildsig, find_result.rrset->getRRsig());
                    }
601
602
                }
            });
Michal Vaner's avatar
Michal Vaner committed
603
    }
604
605
606
    /**
     * \brief Calls the findAll on the finder and checks the result.
     */
607
608
    void findAllTest(const Name& name, ZoneFinder::Result result,
                     const vector<ConstRRsetPtr>& expected_rrsets,
609
610
                     ZoneFinder::FindResultFlags expected_flags =
                     ZoneFinder::RESULT_DEFAULT,
611
612
613
614
                     InMemoryZoneFinder* finder = NULL,
                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
                     ZoneFinder::FindOptions options =
                     ZoneFinder::FIND_DEFAULT)
615
616
617
618
619
    {
        if (finder == NULL) {
            finder = &zone_finder_;
        }
        std::vector<ConstRRsetPtr> target;
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
        ZoneFinder::FindResult find_result(finder->findAll(name, target,
                                                           options));
        EXPECT_EQ(result, find_result.code);
        if (!rrset_result) {
            EXPECT_FALSE(find_result.rrset);
        } else {
            ASSERT_TRUE(find_result.rrset);
            rrsetCheck(rrset_result, find_result.rrset);
        }
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
                  find_result.isWildcard());
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED)
                  != 0, find_result.isNSECSigned());
        EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED)
                  != 0, find_result.isNSEC3Signed());
635
636
        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
                    target.begin(), target.end());
637
    }
638
639
};

640
641
642
643
644
645
646
647
/**
 * \brief Check that findPreviousName throws as it should now.
 */
TEST_F(InMemoryZoneFinderTest, findPreviousName) {
    EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
                 isc::NotImplemented);
}

648
/**
649
 * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
650
 *
651
 * Takes the created zone finder and checks its properties they are the same
652
653
 * as passed parameters.
 */
654
TEST_F(InMemoryZoneFinderTest, constructor) {
655
656
    ASSERT_EQ(class_, zone_finder_.getClass());
    ASSERT_EQ(origin_, zone_finder_.getOrigin());
657
}
Michal Vaner's avatar
Michal Vaner committed
658
659
660
661
662
663
/**
 * \brief Test adding.
 *
 * We test that it throws at the correct moments and the correct exceptions.
 * And we test the return value.
 */
664
TEST_F(InMemoryZoneFinderTest, add) {
Michal Vaner's avatar
Michal Vaner committed
665
    // This one does not belong to this zone
666
    EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
Michal Vaner's avatar
Michal Vaner committed
667
    // Test null pointer
668
    EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
669
                 InMemoryZoneFinder::NullRRset);
Michal Vaner's avatar
Michal Vaner committed
670
671

    // Now put all the data we have there. It should throw nothing
672
673
674
675
    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
676
677

    // Try putting there something twice, it should be rejected
678
679
    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
680
681
}

682
TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
683
    rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
684
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
685
686
}

687
TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
688
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
689
    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
690
691
}

692
TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
693
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
694
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
695
696
}

697
TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
698
699
    // CNAME and RRSIG can coexist
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
700
701
702
703
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
                              "3600 20000101000000 20000201000000 12345 "
                              "example.org. FAKEFAKEFAKE")));
704
705

    // Same for NSEC
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
    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);
726
727
}

728
TEST_F(InMemoryZoneFinderTest, findCNAME) {
729
    // install CNAME RR
730
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
731
732

    // Find A RR of the same.  Should match the CNAME
733
734
    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
             rr_cname_);
735
736

    // Find the CNAME itself.  Should result in normal SUCCESS
737
    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
738
             rr_cname_);
739
740
}

741
TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
742
743
744
    // 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.
745
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
746
747
    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
748
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
749
    findTest(Name("cname.child.example.org"), RRType::AAAA(),
750
751
             ZoneFinder::CNAME, true, rr_cname_under_cut_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
752
753
}

754
755
756
// 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.
757
TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
758
    rr_dname_->addRdata(generic::DNAME("target2.example.org."));
759
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
760
761
762
763
764
765
}

/*
 * 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)
 */
766
TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
767
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
768
    EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
769
770
}

771
TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
772
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
773
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
774
775
776
}

// It is allowed to have NS and DNAME at apex
777
TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
778
779
    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
780
781
782

    // The NS should be possible to be found, below should be DNAME, not
    // delegation
783
784
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
    findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
785
             rr_dname_apex_);
786
787
}

788
TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
789
790
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
791
792
793
794
795
796
}

// 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
797
TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
798
799
800
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
             true, rr_dname_);
801
802
803
804
}

// 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)
805
TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
806
807
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
808

809
    const Name dname_name(rr_dname_->getName());
810
811
812
813
    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);
814
815
}

816
817
// 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).
818
TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
819
820
    zone_finder_.add(rr_child_ns_);
    zone_finder_.add(rr_child_dname_);
821
822
823

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

824
825
    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
826
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
827
828
}

829
// Test adding child zones and zone cut handling
830
TEST_F(InMemoryZoneFinderTest, delegationNS) {
831
    // add in-zone data
832
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
833
834

    // install a zone cut
835
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
836
837

    // below the zone cut
838
839
    findTest(Name("www.child.example.org"), RRType::A(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
840
841

    // at the zone cut
842
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
843
             true, rr_child_ns_);
844
    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
845
             true, rr_child_ns_);
846

847
848
    // finding NS for the apex (origin) node.  This must not be confused
    // with delegation due to the existence of an NS RR.
849
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
850
851

    // unusual case of "nested delegation": the highest cut should be used.
852
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
853
    findTest(Name("www.grand.child.example.org"), RRType::A(),
854
855
             // note: !rr_grandchild_ns_
             ZoneFinder::DELEGATION, true, rr_child_ns_);
856
857
}

858
859
860
861
862
863
864
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_));

865
    // Normal types of query should result in delegation, but DS query
866
    // should be considered in-zone (but only exactly at the delegation point).
867
868
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
869
870
    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
             true, rr_child_ds_);
871
872
    findTest(Name("grand.child.example.org"), RRType::DS(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
873
874
875
876
877

    // 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());
878
879
}

880
TEST_F(InMemoryZoneFinderTest, findAny) {
881
882
883
    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
884

885
886
    vector<ConstRRsetPtr> expected_sets;

chenzhengzhang's avatar
chenzhengzhang committed
887
    // origin
888
889
890
    expected_sets.push_back(rr_a_);
    expected_sets.push_back(rr_ns_);
    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
891
892

    // out zone name
893
894
    findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
                vector<ConstRRsetPtr>());
895

896
897
898
    expected_sets.clear();
    expected_sets.push_back(rr_child_glue_);
    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
899
900

    // add zone cut
901
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
chenzhengzhang's avatar
chenzhengzhang committed
902
903

    // zone cut
904
    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
905
906
                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
                NULL, rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
907
908

    // glue for this zone cut
909
    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
910
911
                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
                NULL, rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
912
913
}

914
TEST_F(InMemoryZoneFinderTest, glue) {
915
916
    // install zone data:
    // a zone cut
917
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
918
    // glue for this cut
919
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
920
    // a nested zone cut (unusual)
921
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
922
    // glue under the deeper zone cut
923
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
924
925

    // by default glue is hidden due to the zone cut
926
927
    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
928
929
930


    // If we do it in the "glue OK" mode, we should find the exact match.
931
    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
932
933
             rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
934
935

    // glue OK + NXRRSET case
936
    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
937
938
             true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
939
940

    // glue OK + NXDOMAIN case
941
    findTest(Name("www.child.example.org"), RRType::A(),
942
943
             ZoneFinder::DELEGATION, true, rr_child_ns_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
944
945

    // nested cut case.  The glue should be found.
946
    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
947
             ZoneFinder::SUCCESS,
948
949
             true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
950
951
952
953

    // A non-existent name in nested cut.  This should result in delegation
    // at the highest zone cut.
    findTest(Name("www.grand.child.example.org"), RRType::TXT(),
954
955
             ZoneFinder::DELEGATION, true, rr_child_ns_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
956
957
}

Michal Vaner's avatar
Michal Vaner committed
958
959
960
961
962
963
964
/**
 * \brief Test searching.
 *
 * Check it finds or does not find correctly and does not throw exceptions.
 * \todo This doesn't do any kind of CNAME and so on. If it isn't
 *     directly there, it just tells it doesn't exist.
 */
965
966
void
InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags) {
Michal Vaner's avatar
Michal Vaner committed
967
968
    // Fill some data inside
    // Now put all the data we have there. It should throw nothing
969
970
971
972
    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_)));
973
974
975
    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
    }
Michal Vaner's avatar
Michal Vaner committed
976
977

    // These two should be successful
978
979
980
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
    findTest(rr_ns_a_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
             rr_ns_a_);
Michal Vaner's avatar
Michal Vaner committed
981
982

    // These domain exist but don't have the provided RRType
983
984
985
986
    findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET, true,
             ConstRRsetPtr(), expected_flags);
    findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET, true,
             ConstRRsetPtr(), expected_flags);
Michal Vaner's avatar
Michal Vaner committed
987
988

    // These domains don't exist (and one is out of the zone)
989
990
991
992
    findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN,
             true, ConstRRsetPtr(), expected_flags);
    findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN