memory_datasrc_unittest.cc 71.2 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
26
#include <dns/rdata.h>
#include <dns/rdataclass.h>
27
#include <dns/rrclass.h>
chenzhengzhang's avatar
chenzhengzhang committed
28
#include <dns/rrsetlist.h>
Michal Vaner's avatar
Michal Vaner committed
29
#include <dns/rrttl.h>
Michal Vaner's avatar
Michal Vaner committed
30
#include <dns/masterload.h>
31
32

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

36
37
#include <testutils/dnsmessage_test.h>

38
39
#include <gtest/gtest.h>

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

278
279
/// \brief Test fixture for the InMemoryZoneFinder class
class InMemoryZoneFinderTest : public ::testing::Test {
280
281
282
283
284
285
    // 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;
    };
286
287
288
289
290
291
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.
292
293
294
295
296
297
298
299
    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);
300
301
302
303
    void anyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                          ZoneFinder::RESULT_DEFAULT);
    void emptyWildcardCheck(ZoneFinder::FindResultFlags expected_flags =
                            ZoneFinder::RESULT_DEFAULT);
304

305
public:
306
    InMemoryZoneFinderTest() :
307
308
        class_(RRClass::IN()),
        origin_("example.org"),
309
        zone_finder_(class_, origin_)
Michal Vaner's avatar
Michal Vaner committed
310
    {
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
        // 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_},
330
331
            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
             &rr_child_ds_},
332
333
334
335
336
337
338
339
            {"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_},
340
            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
341
            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
342
343
            {"*.cnamewild.example.org. 300 IN CNAME canonial.example.org.",
             &rr_cnamewild_},
344
            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
345
346
347
348
349
350
            {"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_},
351
            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
352
            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
353
354
            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
             &rr_not_wild_another_},
355
356
357
            {"0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. 300 IN "
             "NSEC3 1 1 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG",
             &rr_nsec3_},
358
            {NULL, NULL}
359
360
361
362
363
364
365
366
367
368
        };

        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_,
369
                   boost::bind(setRRset, _1, rrsets.begin()));
Michal Vaner's avatar
Michal Vaner committed
370
    }
371
    // Some data to test with
372
    const RRClass class_;
373
    const Name origin_;
374
    // The zone finder to torture by tests
375
    InMemoryZoneFinder zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
376

377
378
379
    // Placeholder for storing RRsets to be checked with rrsetsCheck()
    vector<ConstRRsetPtr> actual_rrsets_;

Michal Vaner's avatar
Michal Vaner committed
380
381
382
    /*
     * Some RRsets to put inside the zone.
     */
383
    RRsetPtr
Michal Vaner's avatar
Michal Vaner committed
384
385
386
387
388
389
390
391
392
        // 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
393
        rr_a_;
394
    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
395
    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
396
    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
397
398
399
400
    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)
401
    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
402
403
404
405
    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
406
407
    RRsetPtr rr_wild_;        // Wildcard record
    RRsetPtr rr_cnamewild_;     // CNAME at a wildcard
408
409
410
    RRsetPtr rr_emptywild_;
    RRsetPtr rr_nested_emptywild_;
    RRsetPtr rr_nswild_, rr_dnamewild_;
411
    RRsetPtr rr_child_wild_;
412
    RRsetPtr rr_under_wild_;
413
    RRsetPtr rr_not_wild_;
414
    RRsetPtr rr_not_wild_another_;
415
    RRsetPtr rr_nsec3_;
Michal Vaner's avatar
Michal Vaner committed
416
417

    /**
418
     * \brief Test one find query to the zone finder.
Michal Vaner's avatar
Michal Vaner committed
419
     *
420
     * Asks a query to the zone finder and checks it does not throw and returns
Michal Vaner's avatar
Michal Vaner committed
421
422
423
424
425
426
     * 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
427
428
     * \param check_answer Should a check against equality of the answer be
     *     done?
Michal Vaner's avatar
Michal Vaner committed
429
     * \param answer The expected rrset, if any should be returned.
430
431
     * \param expected_flags The expected result flags returned via find().
     *     These can be tested using isWildcard() etc.
432
433
     * \param zone_finder Check different InMemoryZoneFinder object than
     *     zone_finder_ (if NULL, uses zone_finder_)
434
435
436
437
     * \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
438
     */
439
440
    void findTest(const Name& name, const RRType& rrtype,
                  ZoneFinder::Result result,
441
442
                  bool check_answer = true,
                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
443
444
                  ZoneFinder::FindResultFlags expected_flags =
                  ZoneFinder::RESULT_DEFAULT,
445
                  InMemoryZoneFinder* zone_finder = NULL,
446
                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
447
                  bool check_wild_answer = false)
Michal Vaner's avatar
Michal Vaner committed
448
    {
449
450
        if (zone_finder == NULL) {
            zone_finder = &zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
451
        }
Michal Vaner's avatar
Michal Vaner committed
452
453
454
        // The whole block is inside, because we need to check the result and
        // we can't assign to FindResult
        EXPECT_NO_THROW({
455
                ZoneFinder::FindResult find_result(zone_finder->find(
456
                                                       name, rrtype, options));
457
458
                // Check it returns correct answers
                EXPECT_EQ(result, find_result.code);
459
460
461
462
463
464
                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());
465
                if (check_answer) {
466
467
468
469
470
471
                    if (!answer) {
                        ASSERT_FALSE(find_result.rrset);
                    } else {
                        ASSERT_TRUE(find_result.rrset);
                        rrsetCheck(answer, find_result.rrset);
                    }
472
                } else if (check_wild_answer) {
473
                    ASSERT_NE(ConstRRsetPtr(), answer) <<
474
                        "Wrong test, don't check for wild names if you expect "
475
476
477
                        "empty answer";
                    ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
                        "No answer found";
478
479
480
481
482
                    // 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()));
483
                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
484
485
                    for (; !expectedIt->isLast(); expectedIt->next()) {
                        wildanswer->addRdata(expectedIt->getCurrent());
486
                    }
487
                    rrsetCheck(wildanswer, find_result.rrset);
488
489
                }
            });
Michal Vaner's avatar
Michal Vaner committed
490
    }
491
492
493
    /**
     * \brief Calls the findAll on the finder and checks the result.
     */
494
495
    void findAllTest(const Name& name, ZoneFinder::Result result,
                     const vector<ConstRRsetPtr>& expected_rrsets,
496
497
                     ZoneFinder::FindResultFlags expected_flags =
                     ZoneFinder::RESULT_DEFAULT,
498
499
500
501
                     InMemoryZoneFinder* finder = NULL,
                     const ConstRRsetPtr &rrset_result = ConstRRsetPtr(),
                     ZoneFinder::FindOptions options =
                     ZoneFinder::FIND_DEFAULT)
502
503
504
505
506
    {
        if (finder == NULL) {
            finder = &zone_finder_;
        }
        std::vector<ConstRRsetPtr> target;
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
        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());
522
523
        rrsetsCheck(expected_rrsets.begin(), expected_rrsets.end(),
                    target.begin(), target.end());
524
    }
525
526
527
528
529
530
531
532
533
534
535
536

    ConstRRsetPtr textToRRset(const string& text_rrset,
                              const RRClass& rrclass = RRClass::IN()) const
    {
        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);
    }
537
538
};

539
540
541
542
543
544
545
546
/**
 * \brief Check that findPreviousName throws as it should now.
 */
TEST_F(InMemoryZoneFinderTest, findPreviousName) {
    EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
                 isc::NotImplemented);
}

547
/**
548
 * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
549
 *
550
 * Takes the created zone finder and checks its properties they are the same
551
552
 * as passed parameters.
 */
553
TEST_F(InMemoryZoneFinderTest, constructor) {
554
555
    ASSERT_EQ(class_, zone_finder_.getClass());
    ASSERT_EQ(origin_, zone_finder_.getOrigin());
556
}
Michal Vaner's avatar
Michal Vaner committed
557
558
559
560
561
562
/**
 * \brief Test adding.
 *
 * We test that it throws at the correct moments and the correct exceptions.
 * And we test the return value.
 */
563
TEST_F(InMemoryZoneFinderTest, add) {
Michal Vaner's avatar
Michal Vaner committed
564
    // This one does not belong to this zone
565
    EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
Michal Vaner's avatar
Michal Vaner committed
566
    // Test null pointer
567
    EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
568
                 InMemoryZoneFinder::NullRRset);
Michal Vaner's avatar
Michal Vaner committed
569
570

    // Now put all the data we have there. It should throw nothing
571
572
573
574
    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
575
576

    // Try putting there something twice, it should be rejected
577
578
    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
579
580
}

581
TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
582
    rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
583
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
584
585
}

586
TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
587
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
588
    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
589
590
}

591
TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
592
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
593
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
594
595
}

596
TEST_F(InMemoryZoneFinderTest, findCNAME) {
597
    // install CNAME RR
598
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
599
600

    // Find A RR of the same.  Should match the CNAME
601
602
    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
             rr_cname_);
603
604

    // Find the CNAME itself.  Should result in normal SUCCESS
605
    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
606
             rr_cname_);
607
608
}

609
TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
610
611
612
    // 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.
613
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
614
615
    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
616
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
617
    findTest(Name("cname.child.example.org"), RRType::AAAA(),
618
619
             ZoneFinder::CNAME, true, rr_cname_under_cut_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
620
621
}

622
623
624
// 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.
625
TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
626
    rr_dname_->addRdata(generic::DNAME("target2.example.org."));
627
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
628
629
630
631
632
633
}

/*
 * 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)
 */
634
TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
635
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
636
    EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
637
638
}

639
TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
640
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
641
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
642
643
644
}

// It is allowed to have NS and DNAME at apex
645
TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
646
647
    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
648
649
650

    // The NS should be possible to be found, below should be DNAME, not
    // delegation
651
652
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
    findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
653
             rr_dname_apex_);
654
655
}

656
TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
657
658
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
659
660
661
662
663
664
}

// 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
665
TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
666
667
668
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
             true, rr_dname_);
669
670
671
672
}

// 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)
673
TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
674
675
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
676

677
    const Name dname_name(rr_dname_->getName());
678
679
680
681
    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);
682
683
}

684
685
// 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).
686
TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
687
688
    zone_finder_.add(rr_child_ns_);
    zone_finder_.add(rr_child_dname_);
689
690
691

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

692
693
    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
694
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
695
696
}

697
// Test adding child zones and zone cut handling
698
TEST_F(InMemoryZoneFinderTest, delegationNS) {
699
    // add in-zone data
700
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
701
702

    // install a zone cut
703
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
704
705

    // below the zone cut
706
707
    findTest(Name("www.child.example.org"), RRType::A(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
708
709

    // at the zone cut
710
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
711
             true, rr_child_ns_);
712
    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
713
             true, rr_child_ns_);
714

715
716
    // finding NS for the apex (origin) node.  This must not be confused
    // with delegation due to the existence of an NS RR.
717
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
718
719

    // unusual case of "nested delegation": the highest cut should be used.
720
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
721
    findTest(Name("www.grand.child.example.org"), RRType::A(),
722
723
             // note: !rr_grandchild_ns_
             ZoneFinder::DELEGATION, true, rr_child_ns_);
724
725
}

726
727
728
729
730
731
732
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_));

733
734
735
736
    // Normal types of query should result in delegation, but DS query
    // should be considered in-zone.
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
737
738
    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
             true, rr_child_ds_);
739
740
741
742
743

    // 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());
744
745
}

746
TEST_F(InMemoryZoneFinderTest, findAny) {
747
748
749
    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
750

751
752
    vector<ConstRRsetPtr> expected_sets;

chenzhengzhang's avatar
chenzhengzhang committed
753
    // origin
754
755
756
    expected_sets.push_back(rr_a_);
    expected_sets.push_back(rr_ns_);
    findAllTest(origin_, ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
757
758

    // out zone name
759
760
    findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN,
                vector<ConstRRsetPtr>());
761

762
763
764
    expected_sets.clear();
    expected_sets.push_back(rr_child_glue_);
    findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, expected_sets);
chenzhengzhang's avatar
chenzhengzhang committed
765
766

    // add zone cut
767
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
chenzhengzhang's avatar
chenzhengzhang committed
768
769

    // zone cut
770
    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION,
771
772
                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
                NULL, rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
773
774

    // glue for this zone cut
775
    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION,
776
777
                vector<ConstRRsetPtr>(), ZoneFinder::RESULT_DEFAULT,
                NULL, rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
778
779
}

780
TEST_F(InMemoryZoneFinderTest, glue) {
781
782
    // install zone data:
    // a zone cut
783
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
784
    // glue for this cut
785
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
786
    // a nested zone cut (unusual)
787
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
788
    // glue under the deeper zone cut
789
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
790
791

    // by default glue is hidden due to the zone cut
792
793
    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
794
795
796


    // If we do it in the "glue OK" mode, we should find the exact match.
797
    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::SUCCESS, true,
798
799
             rr_child_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
800
801

    // glue OK + NXRRSET case
802
    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
803
804
             true, ConstRRsetPtr(), ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
805
806

    // glue OK + NXDOMAIN case
807
    findTest(Name("www.child.example.org"), RRType::A(),
808
809
             ZoneFinder::DELEGATION, true, rr_child_ns_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
810
811

    // nested cut case.  The glue should be found.
812
    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
813
             ZoneFinder::SUCCESS,
814
815
             true, rr_grandchild_glue_, ZoneFinder::RESULT_DEFAULT, NULL,
             ZoneFinder::FIND_GLUE_OK);
816
817
818
819

    // 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(),
820
821
             ZoneFinder::DELEGATION, true, rr_child_ns_,
             ZoneFinder::RESULT_DEFAULT, NULL, ZoneFinder::FIND_GLUE_OK);
822
823
}

Michal Vaner's avatar
Michal Vaner committed
824
825
826
827
828
829
830
/**
 * \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.
 */
831
832
void
InMemoryZoneFinderTest::findCheck(ZoneFinder::FindResultFlags expected_flags) {
Michal Vaner's avatar
Michal Vaner committed
833
834
    // Fill some data inside
    // Now put all the data we have there. It should throw nothing
835
836
837
838
    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_)));
839
840
841
    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
    }
Michal Vaner's avatar
Michal Vaner committed
842
843

    // These two should be successful
844
845
846
    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
847
848

    // These domain exist but don't have the provided RRType
849
850
851
852
    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
853
854

    // These domains don't exist (and one is out of the zone)
855
856
857
858
    findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN,
             true, ConstRRsetPtr(), expected_flags);
    findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN, true,
             ConstRRsetPtr(), expected_flags);
Michal Vaner's avatar
Michal Vaner committed
859
860
}

861
862
863
864
865
866
867
868
869
870
871
872
TEST_F(InMemoryZoneFinderTest, find) {
    findCheck();
}

TEST_F(InMemoryZoneFinderTest, findNSEC3) {
    findCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
}

void
InMemoryZoneFinderTest::emptyNodeCheck(
    ZoneFinder::FindResultFlags expected_flags)
{
873
874
875
876
877
878
    /*
     * The backend RBTree for this test should look like as follows:
     *          example.org
     *               |
     *              baz (empty; easy case)
     *            /  |  \
JINMEI Tatuya's avatar
JINMEI Tatuya committed
879
     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
880
881
882
883
884
885
886
     *              bbb
     *             /
     *           aaa
     */

    // Construct the test zone
    const char* const names[] = {
887
        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
888
889
        "bbb.baz.example.org.", NULL};
    for (int i = 0; names[i] != NULL; ++i) {
890
891
        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
                                          " 300 IN A 192.0.2.1");
892
        EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
893
    }
894
895
896
    if ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0) {
        EXPECT_EQ(SUCCESS, zone_finder_.add(rr_nsec3_));
    }
897
898
899

    // empty node matching, easy case: the node for 'baz' exists with
    // no data.
900
901
    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
             ConstRRsetPtr(), expected_flags);
902
903
904

    // empty node matching, a trickier case: the node for 'foo' is part of
    // "x.foo", which should be considered an empty node.
905
906
    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET, true,
             ConstRRsetPtr(), expected_flags);
907
908
909
910
911
912

    // "org" is contained in "example.org", but it shouldn't be treated as
    // NXRRSET because it's out of zone.
    // Note: basically we don't expect such a query to be performed (the common
    // operation is to identify the best matching zone first then perform
    // search it), but we shouldn't be confused even in the unexpected case.
913
914
915
916
917
918
919
920
921
922
    findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN, true,
             ConstRRsetPtr(), expected_flags);
}

TEST_F(InMemoryZoneFinderTest, emptyNode) {
    emptyNodeCheck();
}

TEST_F(InMemoryZoneFinderTest, emptyNodeNSEC3) {
    emptyNodeCheck(ZoneFinder::RESULT_NSEC3_SIGNED);
923
924
}

925
TEST_F(InMemoryZoneFinderTest, load) {
Michal Vaner's avatar
Michal Vaner committed
926
    // Put some data inside the zone
927
    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
Michal Vaner's avatar
Michal Vaner committed
928
    // Loading with different origin should fail
929
930
    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
                 MasterLoadError);
Michal Vaner's avatar
Michal Vaner committed
931
    // See the original data is still there, survived the exception