static_unittest.cc 16.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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.

#include <stdint.h>
#include <string>
#include <vector>

19
#include <config.h>
20

21
22
23
24
25
26
27
28
29
#include <gtest/gtest.h>

#include <dns/name.h>
#include <dns/message.h>
#include <dns/rdata.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rdataclass.h>
#include <dns/rrsetlist.h>
30
#include <cc/data.h>
31

Evan Hunt's avatar
Evan Hunt committed
32
33
34
#include <datasrc/query.h>
#include <datasrc/data_source.h>
#include <datasrc/static_datasrc.h>
35
36
37
38

using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
Evan Hunt's avatar
Evan Hunt committed
39
using namespace isc::datasrc;
40
41
42
43

namespace {
class StaticDataSourceTest : public ::testing::Test {
protected:
44
    StaticDataSourceTest() : version_name("version.bind"),
45
46
47
                             authors_name("authors.bind"),
                             nomatch_name("example.com"),
                             rrclass(RRClass::CH()), rrtype(RRType::TXT()),
48
                             rrttl(RRTTL(0)), find_flags(0), matched_rdata(0)
49
    {
50
51
        // version.bind is answered with package name+version
        // (defined as PACKAGE_STRING in config.h)
52
        version_data.push_back(PACKAGE_STRING);
53

54
        // NOTE: in addition, the order of the following items matter.
55
        authors_data.push_back("Chen Zhengzhang");
56
        authors_data.push_back("Dmitriy Volodin");
57
        authors_data.push_back("Evan Hunt");
58
        authors_data.push_back("Haidong Wang");
59
        authors_data.push_back("Haikuo Zhang");
60
61
        authors_data.push_back("Han Feng");
        authors_data.push_back("Jelte Jansen");
62
63
        authors_data.push_back("Jeremy C. Reed");
        authors_data.push_back("Xie Jiagui");
64
65
66
67
        authors_data.push_back("Jin Jian");
        authors_data.push_back("JINMEI Tatuya");
        authors_data.push_back("Kazunori Fujiwara");
        authors_data.push_back("Michael Graff");
68
        authors_data.push_back("Michal Vaner");
69
70
        authors_data.push_back("Naoki Kambe");
        authors_data.push_back("Shane Kerr");
71
72
        authors_data.push_back("Shen Tingting");
        authors_data.push_back("Stephen Morris");
73
        authors_data.push_back("Yoshitaka Aharen");
74
75
76
77
        authors_data.push_back("Zhang Likun");

        version_ns_data.push_back("version.bind.");
        authors_ns_data.push_back("authors.bind.");
JINMEI Tatuya's avatar
JINMEI Tatuya committed
78
79
80
81
82

        version_soa_data.push_back("version.bind. hostmaster.version.bind. "
                                   "0 28800 7200 604800 86400");
        authors_soa_data.push_back("authors.bind. hostmaster.authors.bind. "
                                   "0 28800 7200 604800 86400");
83
84
85
86
87
88
89
    }
    StaticDataSrc data_source;
    const Name version_name;
    const Name authors_name;
    const Name nomatch_name;
    const RRClass rrclass;
    RRType rrtype;              // we allow this to be modified in the test
90
    RRTTL rrttl;
91
92
93
    RRsetList result_sets;
    uint32_t find_flags;
    unsigned matched_rdata;
94
95
96
    vector<RRType> types;
    vector<RRTTL> ttls;
    vector<const vector<string>* > answers;
97
98
99
100
    vector<string> version_data;
    vector<string> authors_data;
    vector<string> version_ns_data;
    vector<string> authors_ns_data;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
101
102
    vector<string> version_soa_data;
    vector<string> authors_soa_data;
103
104
105
106
107
};

void
checkRRset(ConstRRsetPtr rrset, const Name& expected_name,
           const RRClass& expected_class, const RRType& expected_type,
108
           const RRTTL& rrttl, const vector<string>& expected_data)
109
110
111
112
{
    EXPECT_EQ(expected_name, rrset->getName());
    EXPECT_EQ(expected_class, rrset->getClass());
    EXPECT_EQ(expected_type, rrset->getType());
113
    EXPECT_EQ(rrttl, rrset->getTTL());
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

    RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
    vector<string>::const_iterator data_it = expected_data.begin();
    for (; data_it != expected_data.end(); ++data_it) {
        EXPECT_FALSE(rdata_iterator->isLast());
        if (rdata_iterator->isLast()) {
            // buggy case, should stop here
            break;
        }
        EXPECT_EQ(0, (rdata_iterator->getCurrent()).compare(
                      *createRdata(expected_type,
                                   expected_class,
                                   *data_it)));
        rdata_iterator->next();
    }

    EXPECT_TRUE(rdata_iterator->isLast());
}

133
134
135
136
void
checkFind(const DataSrc& data_source,
          const Name& qname, const Name* zone_name,
          const RRClass& qclass, const RRClass& expected_class,
137
138
139
          const RRType& qtype, const vector<RRTTL>& expected_ttls,
          const uint32_t expected_flags, const vector<RRType>& expected_types,
          const vector<const vector<string>* >& expected_answers)
140
141
142
{
    RRsetList result_sets;
    uint32_t find_flags;
143
144
    unsigned int rrset_matched = 0;
    unsigned int rrset_count = 0;
145
146
147
148
149

    EXPECT_EQ(DataSrc::SUCCESS,
              data_source.findRRset(qname, qclass, qtype, result_sets,
                                    find_flags, zone_name));
    EXPECT_EQ(expected_flags, find_flags);
150

151
152
153
154
155
156
157
    if ((find_flags & (DataSrc::NO_SUCH_ZONE | DataSrc::NAME_NOT_FOUND |
                       DataSrc::TYPE_NOT_FOUND)) != 0) {
        EXPECT_TRUE(result_sets.begin() == result_sets.end());
        return;
    }

    RRsetList::iterator it = result_sets.begin();
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    for (; it != result_sets.end(); ++it) {
        vector<RRType>::const_iterator found_type =
            find(expected_types.begin(), expected_types.end(),
                 (*it)->getType());
        // there should be a match
        EXPECT_TRUE(found_type != expected_types.end());
        if (found_type != expected_types.end()) {
            unsigned int index = distance(expected_types.begin(), found_type);
            checkRRset(*it, qname, expected_class, (*it)->getType(),
                       expected_ttls[index], *expected_answers[index]);
            ++rrset_matched;
        }
        ++rrset_count;
    }
    EXPECT_EQ(expected_types.size(), rrset_count);
    EXPECT_EQ(expected_types.size(), rrset_matched);
}

void
checkFind(const DataSrc& data_source,
          const Name& qname, const Name* zone_name,
          const RRClass& qclass, const RRClass& expected_class,
          const RRType& qtype,  // == expected RRType
          const RRTTL& expected_ttl, const uint32_t expected_flags,
          const vector<string>& expected_answers)
{
    vector<RRType> types;
    vector<RRTTL> ttls;
    vector<const vector<string>* > answers;

    types.push_back(qtype);
    ttls.push_back(expected_ttl);
    answers.push_back(&expected_answers);

    checkFind(data_source, qname, zone_name, qclass, expected_class, qtype,
              ttls, expected_flags, types, answers);
194
195
}

196
197
198
199
200
201
202
203
204
TEST_F(StaticDataSourceTest, init) {
    EXPECT_EQ(DataSrc::SUCCESS, data_source.init());
}

TEST_F(StaticDataSourceTest, close) {
    EXPECT_EQ(DataSrc::SUCCESS, data_source.init());
}

TEST_F(StaticDataSourceTest, findClosestEnclosureForVersion) {
Evan Hunt's avatar
Evan Hunt committed
205
206
207
208
    DataSrcMatch match(version_name, rrclass);
    data_source.findClosestEnclosure(match);
    EXPECT_EQ(version_name, *match.getEnclosingZone());
    EXPECT_EQ(&data_source, match.getDataSource());
209
210
}

211
212
// Class Any query should result in the same answer.
TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionClassAny) {
Evan Hunt's avatar
Evan Hunt committed
213
214
215
216
    DataSrcMatch match(version_name, RRClass::ANY());
    data_source.findClosestEnclosure(match);
    EXPECT_EQ(version_name, *match.getEnclosingZone());
    EXPECT_EQ(&data_source, match.getDataSource());
217
218
219
220
}

// If class doesn't match the lookup should fail.
TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionClassMismatch) {
Evan Hunt's avatar
Evan Hunt committed
221
222
    DataSrcMatch match(version_name, RRClass::IN());
    data_source.findClosestEnclosure(match);
223
224
    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
225
226
}

227
TEST_F(StaticDataSourceTest, findClosestEnclosureForVersionPartial) {
Evan Hunt's avatar
Evan Hunt committed
228
229
230
231
    DataSrcMatch match(Name("foo").concatenate(version_name), rrclass);
    data_source.findClosestEnclosure(match);
    EXPECT_EQ(version_name, *match.getEnclosingZone());
    EXPECT_EQ(&data_source, match.getDataSource());
232
233
234
}

TEST_F(StaticDataSourceTest, findClosestEnclosureForAuthors) {
Evan Hunt's avatar
Evan Hunt committed
235
236
237
238
    DataSrcMatch match(authors_name, rrclass);
    data_source.findClosestEnclosure(match);
    EXPECT_EQ(authors_name, *match.getEnclosingZone());
    EXPECT_EQ(&data_source, match.getDataSource());
239
240
241
}

TEST_F(StaticDataSourceTest, findClosestEnclosureForAuthorsPartial) {
Evan Hunt's avatar
Evan Hunt committed
242
243
244
245
    DataSrcMatch match(Name("foo").concatenate(authors_name), rrclass);
    data_source.findClosestEnclosure(match);
    EXPECT_EQ(authors_name, *match.getEnclosingZone());
    EXPECT_EQ(&data_source, match.getDataSource());
246
247
248
}

TEST_F(StaticDataSourceTest, findClosestEnclosureNoMatch) {
Evan Hunt's avatar
Evan Hunt committed
249
250
    DataSrcMatch match(nomatch_name, rrclass);
    data_source.findClosestEnclosure(match);
251
252
    EXPECT_EQ(static_cast<void*>(NULL), match.getEnclosingZone());
    EXPECT_EQ(static_cast<void*>(NULL), match.getDataSource());
253
254
255
}

TEST_F(StaticDataSourceTest, findRRsetVersionTXT) {
256
257
258
259
    checkFind(data_source, version_name, NULL, rrclass, rrclass,
              rrtype, rrttl, 0, version_data);
    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
              rrtype, rrttl, 0, version_data);
260
261
262
263
}

TEST_F(StaticDataSourceTest, findRRsetVersionNS) {
    rrtype = RRType::NS();
264
265
266
267
    checkFind(data_source, version_name, NULL, rrclass, rrclass,
              rrtype, rrttl, 0, version_ns_data);
    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
              rrtype, rrttl, 0, version_ns_data);
268
269
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
270
271
TEST_F(StaticDataSourceTest, findRRsetVersionSOA) {
    rrtype = RRType::SOA();
272

JINMEI Tatuya's avatar
JINMEI Tatuya committed
273
    checkFind(data_source, version_name, NULL, rrclass, rrclass,
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
              rrtype, rrttl, 0, version_soa_data);
    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
              rrtype, rrttl, 0, version_soa_data);
}

TEST_F(StaticDataSourceTest, findRRsetVersionANY) {
    rrtype = RRType::ANY();
    
    types.push_back(RRType::TXT());
    types.push_back(RRType::NS());
    types.push_back(RRType::SOA());
    ttls.push_back(rrttl);
    ttls.push_back(rrttl);
    ttls.push_back(rrttl);
    answers.push_back(&version_data);
    answers.push_back(&version_ns_data);
    answers.push_back(&version_soa_data);

    checkFind(data_source, version_name, NULL, rrclass, rrclass, rrtype, ttls,
              0, types, answers);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
294
    checkFind(data_source, version_name, &version_name, rrclass, rrclass,
295
              rrtype, ttls, 0, types, answers);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
296
297
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
298
TEST_F(StaticDataSourceTest, findRRsetAuthorsTXT) {
299
300
301
302
    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
              rrtype, rrttl, 0, authors_data);
    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
              rrtype, rrttl, 0, authors_data);
303
304
305
306
}

TEST_F(StaticDataSourceTest, findRRsetAuthorsNS) {
    rrtype = RRType::NS();
307
308
309
310
311
312
    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
              rrtype, rrttl, 0, authors_ns_data);
    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
              rrtype, rrttl, 0, authors_ns_data);
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
313
314
315
TEST_F(StaticDataSourceTest, findRRsetAuthorsSOA) {
    rrtype = RRType::SOA();
    checkFind(data_source, authors_name, NULL, rrclass, rrclass,
316
              rrtype, rrttl, 0, authors_soa_data);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
317
    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
318
              rrtype, rrttl, 0, authors_soa_data);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
319
320
}

321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
TEST_F(StaticDataSourceTest, findRRsetAuthorsANY) {
    rrtype = RRType::ANY();
    
    types.push_back(RRType::TXT());
    types.push_back(RRType::NS());
    types.push_back(RRType::SOA());
    ttls.push_back(rrttl);
    ttls.push_back(rrttl);
    ttls.push_back(rrttl);
    answers.push_back(&authors_data);
    answers.push_back(&authors_ns_data);
    answers.push_back(&authors_soa_data);

    checkFind(data_source, authors_name, NULL, rrclass, rrclass, rrtype, ttls,
              0, types, answers);
    checkFind(data_source, authors_name, &authors_name, rrclass, rrclass,
              rrtype, ttls, 0, types, answers);
}
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
// Class ANY lookup should result in the same answer.
TEST_F(StaticDataSourceTest, findRRsetVersionClassAny) {
    checkFind(data_source, version_name, NULL, RRClass::ANY(), rrclass,
              rrtype, rrttl, 0, version_data);
    checkFind(data_source, version_name, &version_name, RRClass::ANY(), rrclass,
              rrtype, rrttl, 0, version_data);
}

// If the class doesn't match, it should simply fail.
TEST_F(StaticDataSourceTest, findRRsetVersionClassMismatch) {
    EXPECT_EQ(DataSrc::ERROR,
              data_source.findRRset(version_name, RRClass::IN(), rrtype,
                                    result_sets, find_flags, &version_name));
}

TEST_F(StaticDataSourceTest, findRRsetOutOfZone) {
    // If the qname doesn't match any of the static zones, the result should
    // be "no such zone", regardless of whether the zone is explicitly
    // specified.  Other "expected" result parameters will be ignored.
    checkFind(data_source, nomatch_name, NULL, rrclass, rrclass,
              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
    checkFind(data_source, nomatch_name, &version_name, rrclass, rrclass,
              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
    checkFind(data_source, nomatch_name, &authors_name, rrclass, rrclass,
              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
}

// If a zone name is given but doesn't match any of the static zones,
// the result should be "no such zone"
TEST_F(StaticDataSourceTest, findRRsetZoneMismatch) {
    const Name& short_zonename(Name("bind"));
    checkFind(data_source, version_name, &short_zonename, rrclass, rrclass,
              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
    checkFind(data_source, authors_name, &short_zonename, rrclass, rrclass,
              rrtype, rrttl, DataSrc::NO_SUCH_ZONE, authors_ns_data);
}

// Zone matches, but name doesn't exist in the zone
TEST_F(StaticDataSourceTest, findRRsetNoName) {
    checkFind(data_source, Name("foo").concatenate(version_name), NULL, rrclass,
              rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND, authors_ns_data);
    checkFind(data_source, Name("foo").concatenate(version_name), &version_name,
              rrclass, rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND,
              authors_ns_data);
    checkFind(data_source, Name("foo").concatenate(authors_name), NULL, rrclass,
              rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND, authors_ns_data);
    checkFind(data_source, Name("foo").concatenate(authors_name), &authors_name,
              rrclass, rrclass, rrtype, rrttl, DataSrc::NAME_NOT_FOUND,
              authors_ns_data);
}

// Zone matches and qname exists, but type doesn't exist for the name.
TEST_F(StaticDataSourceTest, findRRsetNoType) {
    const RRType& nomatch_type = RRType::A();

    checkFind(data_source, version_name, NULL, rrclass,
              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
              authors_ns_data);
    checkFind(data_source, version_name, &version_name, rrclass,
              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
              authors_ns_data);
    checkFind(data_source, authors_name, NULL, rrclass,
              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
              authors_ns_data);
    checkFind(data_source, authors_name, &authors_name, rrclass,
              rrclass, nomatch_type, rrttl, DataSrc::TYPE_NOT_FOUND,
              authors_ns_data);
}

// Simple tests for "unsupported" tests.
TEST_F(StaticDataSourceTest, notImplemented) {
    Name target_name(version_name);
    EXPECT_EQ(DataSrc::NOT_IMPLEMENTED,
              data_source.findPreviousName(version_name, target_name,
                                           &version_name));

    string target_hash;
    EXPECT_EQ(DataSrc::NOT_IMPLEMENTED,
              data_source.findCoveringNSEC3(version_name, target_hash,
                                            result_sets));
419
420
421
}

}