memory_datasrc_unittest.cc 65.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
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
public:
287
    InMemoryZoneFinderTest() :
288
289
        class_(RRClass::IN()),
        origin_("example.org"),
290
        zone_finder_(class_, origin_)
Michal Vaner's avatar
Michal Vaner committed
291
    {
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
        // 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_},
311
312
            {"child.example.org. 300 IN DS 12345 5 1 DEADBEEF",
             &rr_child_ds_},
313
314
315
316
317
318
319
320
            {"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_},
321
            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
322
            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
323
            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
324
325
326
327
328
329
            {"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_},
330
            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
331
            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
332
333
            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
             &rr_not_wild_another_},
334
            {NULL, NULL}
335
336
337
338
339
340
341
342
343
344
        };

        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_,
345
                   boost::bind(setRRset, _1, rrsets.begin()));
Michal Vaner's avatar
Michal Vaner committed
346
    }
347
    // Some data to test with
348
    const RRClass class_;
349
    const Name origin_;
350
    // The zone finder to torture by tests
351
    InMemoryZoneFinder zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
352

353
354
355
    // Placeholder for storing RRsets to be checked with rrsetsCheck()
    vector<ConstRRsetPtr> actual_rrsets_;

Michal Vaner's avatar
Michal Vaner committed
356
357
358
    /*
     * Some RRsets to put inside the zone.
     */
359
    RRsetPtr
Michal Vaner's avatar
Michal Vaner committed
360
361
362
363
364
365
366
367
368
        // 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
369
        rr_a_;
370
    RRsetPtr rr_cname_;         // CNAME in example.org (RDATA will be added)
371
    RRsetPtr rr_cname_a_; // for mixed CNAME + A case
372
    RRsetPtr rr_dname_;         // DNAME in example.org (RDATA will be added)
373
374
375
376
    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)
377
    RRsetPtr rr_child_ds_; // DS of a child domain (for delegation, auth data)
378
379
380
381
    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
382
383
384
385
    RRsetPtr rr_wild_;
    RRsetPtr rr_emptywild_;
    RRsetPtr rr_nested_emptywild_;
    RRsetPtr rr_nswild_, rr_dnamewild_;
386
    RRsetPtr rr_child_wild_;
387
    RRsetPtr rr_under_wild_;
388
    RRsetPtr rr_not_wild_;
389
    RRsetPtr rr_not_wild_another_;
Michal Vaner's avatar
Michal Vaner committed
390
391

    /**
392
     * \brief Test one find query to the zone finder.
Michal Vaner's avatar
Michal Vaner committed
393
     *
394
     * Asks a query to the zone finder and checks it does not throw and returns
Michal Vaner's avatar
Michal Vaner committed
395
396
397
398
399
400
     * 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
401
402
     * \param check_answer Should a check against equality of the answer be
     *     done?
Michal Vaner's avatar
Michal Vaner committed
403
     * \param answer The expected rrset, if any should be returned.
404
405
     * \param zone_finder Check different InMemoryZoneFinder object than
     *     zone_finder_ (if NULL, uses zone_finder_)
406
407
408
409
     * \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
410
     */
411
412
    void findTest(const Name& name, const RRType& rrtype,
                  ZoneFinder::Result result,
413
414
                  bool check_answer = true,
                  const ConstRRsetPtr& answer = ConstRRsetPtr(),
415
                  InMemoryZoneFinder* zone_finder = NULL,
416
                  ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT,
417
                  bool check_wild_answer = false)
Michal Vaner's avatar
Michal Vaner committed
418
    {
419
420
        if (zone_finder == NULL) {
            zone_finder = &zone_finder_;
Michal Vaner's avatar
Michal Vaner committed
421
        }
Michal Vaner's avatar
Michal Vaner committed
422
423
424
        // The whole block is inside, because we need to check the result and
        // we can't assign to FindResult
        EXPECT_NO_THROW({
425
426
                ZoneFinder::FindResult find_result(zone_finder->find(
                                                       name, rrtype,
427
                                                       options));
428
429
430
431
                // Check it returns correct answers
                EXPECT_EQ(result, find_result.code);
                if (check_answer) {
                    EXPECT_EQ(answer, find_result.rrset);
432
                } else if (check_wild_answer) {
433
                    ASSERT_NE(ConstRRsetPtr(), answer) <<
434
                        "Wrong test, don't check for wild names if you expect "
435
436
437
                        "empty answer";
                    ASSERT_NE(ConstRRsetPtr(), find_result.rrset) <<
                        "No answer found";
438
                    RdataIteratorPtr expectedIt(answer->getRdataIterator());
439
440
441
                    RdataIteratorPtr actualIt(
                        find_result.rrset->getRdataIterator());
                    while (!expectedIt->isLast() && !actualIt->isLast()) {
442
                        EXPECT_EQ(0, expectedIt->getCurrent().compare(
443
                            actualIt->getCurrent())) << "The RRs differ ('" <<
444
                            expectedIt->getCurrent().toText() << "', '" <<
445
                            actualIt->getCurrent().toText() << "')";
446
                        expectedIt->next();
447
                        actualIt->next();
448
449
450
                    }
                    EXPECT_TRUE(expectedIt->isLast()) <<
                        "Result has less RRs than expected";
451
                    EXPECT_TRUE(actualIt->isLast()) <<
452
                        "Result has more RRs than expected";
453
454
                    EXPECT_EQ(answer->getClass(),
                        find_result.rrset->getClass());
455
456
457
458
459
                    EXPECT_EQ(answer->getType(),
                        find_result.rrset->getType());
                    EXPECT_EQ(answer->getTTL(),
                        find_result.rrset->getTTL());
                    EXPECT_EQ(name, find_result.rrset->getName());
460
461
                }
            });
Michal Vaner's avatar
Michal Vaner committed
462
    }
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
    /**
     * \brief Calls the findAll on the finder and checks the result.
     */
    std::vector<ConstRRsetPtr> findAllTest(const Name& name,
                                           ZoneFinder::Result result,
                                           size_t expected_size,
                                           InMemoryZoneFinder* finder = NULL,
                                           const ConstRRsetPtr &rrset_result =
                                           ConstRRsetPtr(),
                                           ZoneFinder::FindOptions options =
                                           ZoneFinder::FIND_DEFAULT)
    {
        if (finder == NULL) {
            finder = &zone_finder_;
        }
        std::vector<ConstRRsetPtr> target;
        ZoneFinder::FindResult findResult(finder->findAll(name, target,
                                                          options));
        EXPECT_EQ(result, findResult.code);
        EXPECT_EQ(rrset_result, findResult.rrset);
        BOOST_FOREACH(const ConstRRsetPtr& rrset, target) {
            EXPECT_EQ(name, rrset->getName());
        }
        EXPECT_EQ(expected_size, target.size());
        return (target);
    }
489
    // Internal part of the cancelWildcard test that is multiple times
490
    void doCancelWildcardTest();
491
492
493
494
495
496
497
498
499
500
501
502

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

505
506
507
508
509
510
511
512
/**
 * \brief Check that findPreviousName throws as it should now.
 */
TEST_F(InMemoryZoneFinderTest, findPreviousName) {
    EXPECT_THROW(zone_finder_.findPreviousName(Name("www.example.org")),
                 isc::NotImplemented);
}

513
/**
514
 * \brief Test InMemoryZoneFinder::InMemoryZoneFinder constructor.
515
 *
516
 * Takes the created zone finder and checks its properties they are the same
517
518
 * as passed parameters.
 */
519
TEST_F(InMemoryZoneFinderTest, constructor) {
520
521
    ASSERT_EQ(class_, zone_finder_.getClass());
    ASSERT_EQ(origin_, zone_finder_.getOrigin());
522
}
Michal Vaner's avatar
Michal Vaner committed
523
524
525
526
527
528
/**
 * \brief Test adding.
 *
 * We test that it throws at the correct moments and the correct exceptions.
 * And we test the return value.
 */
529
TEST_F(InMemoryZoneFinderTest, add) {
Michal Vaner's avatar
Michal Vaner committed
530
    // This one does not belong to this zone
531
    EXPECT_THROW(zone_finder_.add(rr_out_), InMemoryZoneFinder::OutOfZone);
Michal Vaner's avatar
Michal Vaner committed
532
    // Test null pointer
533
    EXPECT_THROW(zone_finder_.add(ConstRRsetPtr()),
534
                 InMemoryZoneFinder::NullRRset);
Michal Vaner's avatar
Michal Vaner committed
535
536

    // Now put all the data we have there. It should throw nothing
537
538
539
540
    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
541
542

    // Try putting there something twice, it should be rejected
543
544
    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
545
546
}

547
TEST_F(InMemoryZoneFinderTest, addMultipleCNAMEs) {
548
    rr_cname_->addRdata(generic::CNAME("canonical2.example.org."));
549
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
550
551
}

552
TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
553
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
554
    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
555
556
}

557
TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
558
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
559
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
560
561
}

562
TEST_F(InMemoryZoneFinderTest, addCNAMEAndDNSSECRecords) {
563
564
    // CNAME and RRSIG can coexist
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
565
566
567
568
    EXPECT_EQ(SUCCESS, zone_finder_.add(
                  textToRRset("cname.example.org. 300 IN RRSIG CNAME 5 3 "
                              "3600 20000101000000 20000201000000 12345 "
                              "example.org. FAKEFAKEFAKE")));
569
570

    // Same for NSEC
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    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);
591
592
}

593
TEST_F(InMemoryZoneFinderTest, findCNAME) {
594
    // install CNAME RR
595
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
596
597

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

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

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

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

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

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

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

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

653
TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
654
655
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
656
657
658
659
660
661
}

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

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

674
    const Name dname_name(rr_dname_->getName());
675
676
677
678
    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);
679
680
}

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

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

689
690
    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
691
             NULL, ZoneFinder::FIND_GLUE_OK);
692
693
}

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

    // install a zone cut
700
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
701
702

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

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

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

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

723
724
725
726
727
728
729
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_));

730
731
732
733
    // 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_);
734
735
    findTest(Name("child.example.org"), RRType::DS(), ZoneFinder::SUCCESS,
             true, rr_child_ds_);
736
737
738
739
740

    // 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());
741
742
}

743
TEST_F(InMemoryZoneFinderTest, findAny) {
744
745
746
    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
747
748

    // origin
749
750
751
752
753
754
    std::vector<ConstRRsetPtr> rrsets(findAllTest(origin_, ZoneFinder::SUCCESS,
                                                  2));
    EXPECT_FALSE(rrsets.end() == std::find(rrsets.begin(), rrsets.end(),
                                           rr_a_));
    EXPECT_FALSE(rrsets.end() == std::find(rrsets.begin(), rrsets.end(),
                                           rr_ns_));
chenzhengzhang's avatar
chenzhengzhang committed
755
756

    // out zone name
757
758
759
760
761
    findAllTest(Name("example.com"), ZoneFinder::NXDOMAIN, 0);

    rrsets = findAllTest(rr_child_glue_->getName(), ZoneFinder::SUCCESS, 1);
    EXPECT_FALSE(rrsets.end() == std::find(rrsets.begin(), rrsets.end(),
                                           rr_child_glue_));
chenzhengzhang's avatar
chenzhengzhang committed
762
763
764
765
766

    // TODO: test NXRRSET case after rbtree non-terminal logic has
    // been implemented

    // 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
771
    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION, 0, NULL,
                rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
772
773

    // glue for this zone cut
774
775
    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION, 0, NULL,
                rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
776
777
}

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

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


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

    // glue OK + NXRRSET case
799
    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
800
             true, ConstRRsetPtr(), NULL, ZoneFinder::FIND_GLUE_OK);
801
802

    // glue OK + NXDOMAIN case
803
    findTest(Name("www.child.example.org"), RRType::A(),
804
             ZoneFinder::DELEGATION, true, rr_child_ns_, NULL,
805
             ZoneFinder::FIND_GLUE_OK);
806
807

    // nested cut case.  The glue should be found.
808
    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
809
             ZoneFinder::SUCCESS,
810
             true, rr_grandchild_glue_, NULL, ZoneFinder::FIND_GLUE_OK);
811
812
813
814

    // 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(),
815
             ZoneFinder::DELEGATION, true, rr_child_ns_, NULL,
816
             ZoneFinder::FIND_GLUE_OK);
817
818
}

Michal Vaner's avatar
Michal Vaner committed
819
820
821
822
823
824
825
/**
 * \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.
 */
826
TEST_F(InMemoryZoneFinderTest, find) {
Michal Vaner's avatar
Michal Vaner committed
827
828
    // Fill some data inside
    // Now put all the data we have there. It should throw nothing
829
830
831
832
    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
833
834

    // These two should be successful
835
836
837
    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
838
839

    // These domain exist but don't have the provided RRType
840
841
    findTest(origin_, RRType::AAAA(), ZoneFinder::NXRRSET);
    findTest(rr_ns_a_->getName(), RRType::NS(), ZoneFinder::NXRRSET);
Michal Vaner's avatar
Michal Vaner committed
842
843

    // These domains don't exist (and one is out of the zone)
844
845
    findTest(Name("nothere.example.org"), RRType::A(), ZoneFinder::NXDOMAIN);
    findTest(Name("example.net"), RRType::A(), ZoneFinder::NXDOMAIN);
Michal Vaner's avatar
Michal Vaner committed
846
847
}

848
TEST_F(InMemoryZoneFinderTest, emptyNode) {
849
850
851
852
853
854
    /*
     * The backend RBTree for this test should look like as follows:
     *          example.org
     *               |
     *              baz (empty; easy case)
     *            /  |  \
JINMEI Tatuya's avatar
JINMEI Tatuya committed
855
     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
856
857
858
859
860
861
862
     *              bbb
     *             /
     *           aaa
     */

    // Construct the test zone
    const char* const names[] = {
863
        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
864
865
        "bbb.baz.example.org.", NULL};
    for (int i = 0; names[i] != NULL; ++i) {
866
867
        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
                                          " 300 IN A 192.0.2.1");
868
        EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
869
870
871
872
    }

    // empty node matching, easy case: the node for 'baz' exists with
    // no data.
873
    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET);
874
875
876

    // empty node matching, a trickier case: the node for 'foo' is part of
    // "x.foo", which should be considered an empty node.
877
    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
878
879
880
881
882
883

    // "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.
884
    findTest(Name("org"), RRType::A(), ZoneFinder::NXDOMAIN);
885
886
}

887
TEST_F(InMemoryZoneFinderTest, load) {
Michal Vaner's avatar
Michal Vaner committed
888
    // Put some data inside the zone
889
    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
Michal Vaner's avatar
Michal Vaner committed
890
    // Loading with different origin should fail
891
892
    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
                 MasterLoadError);
Michal Vaner's avatar
Michal Vaner committed
893
    // See the original data is still there, survived the exception
894
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
Michal Vaner's avatar
Michal Vaner committed
895
    // Create correct zone
896
    InMemoryZoneFinder rootzone(class_, Name("."));
Michal Vaner's avatar
Michal Vaner committed
897
    // Try putting something inside
Michal Vaner's avatar
Michal Vaner committed
898
    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
Michal Vaner's avatar
Michal Vaner committed
899
900
901
902
    // Load the zone. It should overwrite/remove the above RRset
    EXPECT_NO_THROW(rootzone.load(TEST_DATA_DIR "/root.zone"));

    // Now see there are some rrsets (we don't look inside, though)
903
    findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
904
             ConstRRsetPtr(), &rootzone);
905
    findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
906
             ConstRRsetPtr(), &rootzone);
907
    findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
908
             false, ConstRRsetPtr(), &rootzone);
Michal Vaner's avatar
Michal Vaner committed
909
    // But this should no longer be here
910
    findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
911