memory_datasrc_unittest.cc 52.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
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
311
312
313
314
315
316
317
318
        // 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_},
            {"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_},
319
            {"example.com. 300 IN A 192.0.2.10", &rr_out_},
320
            {"*.wild.example.org. 300 IN A 192.0.2.1", &rr_wild_},
321
            {"foo.wild.example.org. 300 IN A 192.0.2.3", &rr_under_wild_},
322
323
324
325
326
327
            {"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_},
328
            {"*.child.example.org. 300 IN A 192.0.2.1", &rr_child_wild_},
329
            {"bar.foo.wild.example.org. 300 IN A 192.0.2.2", &rr_not_wild_},
330
331
            {"baz.foo.wild.example.org. 300 IN A 192.0.2.3",
             &rr_not_wild_another_},
332
            {NULL, NULL}
333
334
335
336
337
338
339
340
341
342
        };

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

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

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

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

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

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

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

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

    // Try putting there something twice, it should be rejected
540
541
    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
542
543
}

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

549
TEST_F(InMemoryZoneFinderTest, addCNAMEThenOther) {
550
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
551
    EXPECT_THROW(zone_finder_.add(rr_cname_a_), InMemoryZoneFinder::AddError);
552
553
}

554
TEST_F(InMemoryZoneFinderTest, addOtherThenCNAME) {
555
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_a_));
556
    EXPECT_THROW(zone_finder_.add(rr_cname_), InMemoryZoneFinder::AddError);
557
558
}

559
TEST_F(InMemoryZoneFinderTest, findCNAME) {
560
    // install CNAME RR
561
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_));
562
563

    // Find A RR of the same.  Should match the CNAME
564
565
    findTest(rr_cname_->getName(), RRType::NS(), ZoneFinder::CNAME, true,
             rr_cname_);
566
567

    // Find the CNAME itself.  Should result in normal SUCCESS
568
    findTest(rr_cname_->getName(), RRType::CNAME(), ZoneFinder::SUCCESS, true,
569
             rr_cname_);
570
571
}

572
TEST_F(InMemoryZoneFinderTest, findCNAMEUnderZoneCut) {
573
574
575
    // 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.
576
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_));
577
578
    ConstRRsetPtr rr_cname_under_cut_ = textToRRset(
        "cname.child.example.org. 300 IN CNAME target.child.example.org.");
579
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_cname_under_cut_));
580
    findTest(Name("cname.child.example.org"), RRType::AAAA(),
581
             ZoneFinder::CNAME, true, rr_cname_under_cut_, NULL,
582
             ZoneFinder::FIND_GLUE_OK);
583
584
}

585
586
587
// 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.
588
TEST_F(InMemoryZoneFinderTest, addMultipleDNAMEs) {
589
    rr_dname_->addRdata(generic::DNAME("target2.example.org."));
590
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
591
592
593
594
595
596
}

/*
 * 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)
 */
597
TEST_F(InMemoryZoneFinderTest, addDNAMEThenNS) {
598
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
599
    EXPECT_THROW(zone_finder_.add(rr_dname_ns_), InMemoryZoneFinder::AddError);
600
601
}

602
TEST_F(InMemoryZoneFinderTest, addNSThenDNAME) {
603
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_ns_)));
604
    EXPECT_THROW(zone_finder_.add(rr_dname_), InMemoryZoneFinder::AddError);
605
606
607
}

// It is allowed to have NS and DNAME at apex
608
TEST_F(InMemoryZoneFinderTest, DNAMEAndNSAtApex) {
609
610
    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
611
612
613

    // The NS should be possible to be found, below should be DNAME, not
    // delegation
614
615
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
    findTest(rr_child_ns_->getName(), RRType::A(), ZoneFinder::DNAME, true,
616
             rr_dname_apex_);
617
618
}

619
TEST_F(InMemoryZoneFinderTest, NSAndDNAMEAtApex) {
620
621
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_apex_)));
622
623
624
625
626
627
}

// 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
628
TEST_F(InMemoryZoneFinderTest, findBelowDNAME) {
629
630
631
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    findTest(Name("below.dname.example.org"), RRType::A(), ZoneFinder::DNAME,
             true, rr_dname_);
632
633
634
635
}

// 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)
636
TEST_F(InMemoryZoneFinderTest, findAtDNAME) {
637
638
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_)));
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_dname_a_)));
639

640
    const Name dname_name(rr_dname_->getName());
641
642
643
644
    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);
645
646
}

647
648
// 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).
649
TEST_F(InMemoryZoneFinderTest, DNAMEUnderNS) {
650
651
    zone_finder_.add(rr_child_ns_);
    zone_finder_.add(rr_child_dname_);
652
653
654

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

655
656
    findTest(lowName, RRType::A(), ZoneFinder::DELEGATION, true, rr_child_ns_);
    findTest(lowName, RRType::A(), ZoneFinder::DNAME, true, rr_child_dname_,
657
             NULL, ZoneFinder::FIND_GLUE_OK);
658
659
}

660
// Test adding child zones and zone cut handling
661
TEST_F(InMemoryZoneFinderTest, delegationNS) {
662
    // add in-zone data
663
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_ns_)));
664
665

    // install a zone cut
666
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
667
668

    // below the zone cut
669
670
    findTest(Name("www.child.example.org"), RRType::A(),
             ZoneFinder::DELEGATION, true, rr_child_ns_);
671
672

    // at the zone cut
673
    findTest(Name("child.example.org"), RRType::A(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
674
             true, rr_child_ns_);
675
    findTest(Name("child.example.org"), RRType::NS(), ZoneFinder::DELEGATION,
JINMEI Tatuya's avatar
JINMEI Tatuya committed
676
             true, rr_child_ns_);
677

678
679
    // finding NS for the apex (origin) node.  This must not be confused
    // with delegation due to the existence of an NS RR.
680
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
681
682

    // unusual case of "nested delegation": the highest cut should be used.
683
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
684
    findTest(Name("www.grand.child.example.org"), RRType::A(),
685
686
             // note: !rr_grandchild_ns_
             ZoneFinder::DELEGATION, true, rr_child_ns_);
687
688
}

689
TEST_F(InMemoryZoneFinderTest, findAny) {
690
691
692
    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
693
694

    // origin
695
696
697
698
699
700
    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
701
702

    // out zone name
703
704
705
706
707
    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
708
709
710
711
712

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

    // add zone cut
713
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
chenzhengzhang's avatar
chenzhengzhang committed
714
715

    // zone cut
716
717
    findAllTest(rr_child_ns_->getName(), ZoneFinder::DELEGATION, 0, NULL,
                rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
718
719

    // glue for this zone cut
720
721
    findAllTest(rr_child_glue_->getName(),ZoneFinder::DELEGATION, 0, NULL,
                rr_child_ns_);
chenzhengzhang's avatar
chenzhengzhang committed
722
723
}

724
TEST_F(InMemoryZoneFinderTest, glue) {
725
726
    // install zone data:
    // a zone cut
727
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_ns_)));
728
    // glue for this cut
729
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_child_glue_)));
730
    // a nested zone cut (unusual)
731
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_ns_)));
732
    // glue under the deeper zone cut
733
    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_finder_.add(rr_grandchild_glue_)));
734
735

    // by default glue is hidden due to the zone cut
736
737
    findTest(rr_child_glue_->getName(), RRType::A(), ZoneFinder::DELEGATION,
             true, rr_child_ns_);
738
739
740


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

    // glue OK + NXRRSET case
745
    findTest(rr_child_glue_->getName(), RRType::AAAA(), ZoneFinder::NXRRSET,
746
             true, ConstRRsetPtr(), NULL, ZoneFinder::FIND_GLUE_OK);
747
748

    // glue OK + NXDOMAIN case
749
    findTest(Name("www.child.example.org"), RRType::A(),
750
             ZoneFinder::DELEGATION, true, rr_child_ns_, NULL,
751
             ZoneFinder::FIND_GLUE_OK);
752
753

    // nested cut case.  The glue should be found.
754
    findTest(rr_grandchild_glue_->getName(), RRType::AAAA(),
755
             ZoneFinder::SUCCESS,
756
             true, rr_grandchild_glue_, NULL, ZoneFinder::FIND_GLUE_OK);
757
758
759
760

    // 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(),
761
             ZoneFinder::DELEGATION, true, rr_child_ns_, NULL,
762
             ZoneFinder::FIND_GLUE_OK);
763
764
}

Michal Vaner's avatar
Michal Vaner committed
765
766
767
768
769
770
771
/**
 * \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.
 */
772
TEST_F(InMemoryZoneFinderTest, find) {
Michal Vaner's avatar
Michal Vaner committed
773
774
    // Fill some data inside
    // Now put all the data we have there. It should throw nothing
775
776
777
778
    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
779
780

    // These two should be successful
781
782
783
    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
784
785

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

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

794
TEST_F(InMemoryZoneFinderTest, emptyNode) {
795
796
797
798
799
800
    /*
     * The backend RBTree for this test should look like as follows:
     *          example.org
     *               |
     *              baz (empty; easy case)
     *            /  |  \
JINMEI Tatuya's avatar
JINMEI Tatuya committed
801
     *          bar  |  x.foo ('foo' part is empty; a bit trickier)
802
803
804
805
806
807
808
     *              bbb
     *             /
     *           aaa
     */

    // Construct the test zone
    const char* const names[] = {
809
        "bar.example.org.", "x.foo.example.org.", "aaa.baz.example.org.",
810
811
        "bbb.baz.example.org.", NULL};
    for (int i = 0; names[i] != NULL; ++i) {
812
813
        ConstRRsetPtr rrset = textToRRset(string(names[i]) +
                                          " 300 IN A 192.0.2.1");
814
        EXPECT_EQ(SUCCESS, zone_finder_.add(rrset));
815
816
817
818
    }

    // empty node matching, easy case: the node for 'baz' exists with
    // no data.
819
    findTest(Name("baz.example.org"), RRType::A(), ZoneFinder::NXRRSET);
820
821
822

    // empty node matching, a trickier case: the node for 'foo' is part of
    // "x.foo", which should be considered an empty node.
823
    findTest(Name("foo.example.org"), RRType::A(), ZoneFinder::NXRRSET);
824
825
826
827
828
829

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

833
TEST_F(InMemoryZoneFinderTest, load) {
Michal Vaner's avatar
Michal Vaner committed
834
    // Put some data inside the zone
835
    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, zone_finder_.add(rr_ns_)));
Michal Vaner's avatar
Michal Vaner committed
836
    // Loading with different origin should fail
837
838
    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/root.zone"),
                 MasterLoadError);
Michal Vaner's avatar
Michal Vaner committed
839
    // See the original data is still there, survived the exception
840
    findTest(origin_, RRType::NS(), ZoneFinder::SUCCESS, true, rr_ns_);
Michal Vaner's avatar
Michal Vaner committed
841
    // Create correct zone
842
    InMemoryZoneFinder rootzone(class_, Name("."));
Michal Vaner's avatar
Michal Vaner committed
843
    // Try putting something inside
Michal Vaner's avatar
Michal Vaner committed
844
    EXPECT_NO_THROW(EXPECT_EQ(result::SUCCESS, rootzone.add(rr_ns_aaaa_)));
Michal Vaner's avatar
Michal Vaner committed
845
846
847
848
    // 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)
849
    findTest(Name("."), RRType::SOA(), ZoneFinder::SUCCESS, false,
850
             ConstRRsetPtr(), &rootzone);
851
    findTest(Name("."), RRType::NS(), ZoneFinder::SUCCESS, false,
852
             ConstRRsetPtr(), &rootzone);
853
    findTest(Name("a.root-servers.net."), RRType::A(), ZoneFinder::SUCCESS,
854
             false, ConstRRsetPtr(), &rootzone);
Michal Vaner's avatar
Michal Vaner committed
855
    // But this should no longer be here
856
    findTest(rr_ns_a_->getName(), RRType::AAAA(), ZoneFinder::NXDOMAIN, true,
857
             ConstRRsetPtr(), &rootzone);
858
859

    // Try loading zone that is wrong in a different way
860
    EXPECT_THROW(zone_finder_.load(TEST_DATA_DIR "/duplicate_rrset.zone"),
861
        MasterLoadError);
Michal Vaner's avatar
Michal Vaner committed
862
863
}

864
865
866
867
/*
 * Test that puts a (simple) wildcard into the zone and checks we can
 * correctly find the data.
 */
868
TEST_F(InMemoryZoneFinderTest, wildcard) {
869
870
871
872
873
874
875
    /*
     *            example.org.
     *                 |
     *                wild (not *.wild, should have wild mark)
     *                 |
     *                 *
     */
876
    EXPECT_EQ(SUCCESS, zone_finder_.add(rr_wild_));
877

878
879
    // Search at the parent. The parent will not have the A, but it will
    // be in the wildcard (so check the wildcard isn't matched at the parent)
880
881
    {
        SCOPED_TRACE("Search at parrent");
882
        findTest(Name("wild.example.org"), RRType::A(), ZoneFinder::NXRRSET);
883
884
    }

885
    // Search the original name of wildcard
886
887
    {
        SCOPED_TRACE("Search directly at *");
888
889
        findTest(Name("*.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
                 true, rr_wild_);
890
891
892
893
    }
    // Search "created" name.
    {
        SCOPED_TRACE("Search at created child");
894
        findTest(Name("a.wild.example.org"), RRType::A(), ZoneFinder::SUCCESS,
895
                 false, rr_wild_, NULL, ZoneFinder::FIND_DEFAULT, true);
896
897
898
899
900
    }

    // Search another created name, this time little bit lower
    {
        SCOPED_TRACE("Search at created grand-child");
901
        findTest(Name("a.b.wild.example.org"), RRType::A(),
902
                 ZoneFinder::SUCCESS, false, rr_wild_, NULL,
903
                 ZoneFinder::FIND_DEFAULT, true);