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

// $Id$

17 18
#include <config.h>

19 20 21 22 23 24
#include <gtest/gtest.h>

#include <dns/buffer.h>
#include <dns/name.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
25
#include <dns/opcode.h>
26
#include <dns/rcode.h>
27 28 29
#include <dns/rrclass.h>
#include <dns/rrtype.h>

30
#include <cc/data.h>
31
#include <cc/session.h>
32

33
#include <xfr/xfrout_client.h>
34

35
#include <auth/auth_srv.h>
36
#include <auth/asio_link.h>
37 38 39 40 41

#include <dns/tests/unittest_util.h>

using isc::UnitTestUtil;
using namespace std;
42
using namespace isc::cc;
43
using namespace isc::dns;
44
using namespace isc::data;
45
using namespace isc::xfr;
46
using namespace asio_link;
47
using namespace statistics;
48 49

namespace {
50
const char* const CONFIG_TESTDB =
51
    "{\"database_file\": \"" TEST_DATA_DIR "/example.sqlite3\"}";
52 53
// The following file must be non existent and must be non"creatable" (see
// the sqlite3 test).
54
const char* const BADCONFIG_TESTDB =
55
    "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
56
const char* const DEFAULT_REMOTE_ADDRESS = "192.0.2.1";
57

58
class AuthSrvTest : public ::testing::Test {
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
private:
    class MockXfroutClient : public AbstractXfroutClient {
    public:
        MockXfroutClient() :
            is_connected_(false), connect_ok_(true), send_ok_(true),
            disconnect_ok_(true)
        {}
        virtual void connect();
        virtual void disconnect();
        virtual int sendXfroutRequestInfo(int tcp_sock, const void* msg_data,
                                          uint16_t msg_len);
        bool isConnected() const { return (is_connected_); }
        void disableConnect() { connect_ok_ = false; }
        void disableDisconnect() { disconnect_ok_ = false; }
        void enableDisconnect() { disconnect_ok_ = true; }
        void disableSend() { send_ok_ = false; }
    private:
        bool is_connected_;
        bool connect_ok_;
        bool send_ok_;
        bool disconnect_ok_;
    };
81 82 83 84 85

    class MockSession : public AbstractSession {
    public:
        MockSession() :
            // by default we return a simple "success" message.
86
            msg_(Element::fromJSON("{\"result\": [0, \"SUCCESS\"]}")),
87
            send_ok_(true), receive_ok_(true)
88 89 90
        {}
        virtual void establish(const char* socket_file);
        virtual void disconnect();
91
        virtual int group_sendmsg(ConstElementPtr msg, string group,
92
                                  string instance, string to);
93 94
        virtual bool group_recvmsg(ConstElementPtr& envelope,
                                   ConstElementPtr& msg,
95
                                   bool nonblock, int seq);
96 97 98
        virtual void subscribe(string group, string instance);
        virtual void unsubscribe(string group, string instance);
        virtual void startRead(boost::function<void()> read_callback);
99 100
        virtual int reply(ConstElementPtr envelope, ConstElementPtr newmsg);
        virtual bool hasQueuedMsgs() const;
101
        virtual void setTimeout(size_t) {}
102
        virtual size_t getTimeout() const { return 0; };
103

104
        void setMessage(ConstElementPtr msg) { msg_ = msg; }
105 106
        void disableSend() { send_ok_ = false; }
        void disableReceive() { receive_ok_ = false; }
107

108
        ConstElementPtr sent_msg;
109
        string msg_destination;
110
    private:
111
        ConstElementPtr msg_;
112 113
        bool send_ok_;
        bool receive_ok_;
114 115
    };

116
protected:
117
    AuthSrvTest() : server(true, xfrout),
118
                    request_message(Message::RENDER),
119
                    parse_message(Message::PARSE), default_qid(0x1035),
120
                    opcode(Opcode::QUERY()), qname("www.example.com"),
121
                    qclass(RRClass::IN()), qtype(RRType::A()),
122
                    io_message(NULL), endpoint(NULL), request_obuffer(0),
123
                    request_renderer(request_obuffer),
124 125
                    response_obuffer(0), response_renderer(response_obuffer),
                    counter(counter_verbose)
126
    {
127
        server.setXfrinSession(&notify_session);
128
        server.setStatsSession(&stats_session);
129
    }
130 131
    ~AuthSrvTest() {
        delete io_message;
132
        delete endpoint;
133
    }
134
    MockSession notify_session;
135
    MockSession stats_session;
136
    MockXfroutClient xfrout;
137 138 139
    AuthSrv server;
    Message request_message;
    Message parse_message;
140 141 142 143 144
    const qid_t default_qid;
    const Opcode opcode;
    const Name qname;
    const RRClass qclass;
    const RRType qtype;
145 146
    IOMessage* io_message;
    const IOEndpoint* endpoint;
147 148 149 150 151
    OutputBuffer request_obuffer;
    MessageRenderer request_renderer;
    OutputBuffer response_obuffer;
    MessageRenderer response_renderer;
    vector<uint8_t> data;
152 153 154 155 156 157
    // for Counter unittest
    // TODO: consider where to put Counter
    // AuthSrvTest is now includes a test for Counter
    // In future make a test class CounterTest
    bool counter_verbose;
    Counter counter;
158

JINMEI Tatuya's avatar
JINMEI Tatuya committed
159
    void createDataFromFile(const char* const datafile, int protocol);
160 161 162 163 164 165
    void createRequestMessage(const Opcode& opcode, const Name& request_name,
                              const RRClass& rrclass, const RRType& rrtype);
    void createRequestPacket(const Opcode& opcode, const Name& request_name,
                             const RRClass& rrclass, const RRType& rrtype,
                             int protocol);
    void createRequestPacket(int protocol);
166 167
};

168
void
169
AuthSrvTest::MockSession::establish(const char*) {}
170 171

void
172
AuthSrvTest::MockSession::disconnect() {}
173

174
void
175
AuthSrvTest::MockSession::subscribe(string, string)
176 177 178
{}

void
179
AuthSrvTest::MockSession::unsubscribe(string, string)
180 181 182
{}

void
183
AuthSrvTest::MockSession::startRead(boost::function<void()>)
184 185 186
{}

int
187
AuthSrvTest::MockSession::reply(ConstElementPtr, ConstElementPtr) {
188 189 190 191
    return (-1);
}

bool
192
AuthSrvTest::MockSession::hasQueuedMsgs() const {
193 194 195
    return (false);
}

196
int
197
AuthSrvTest::MockSession::group_sendmsg(ConstElementPtr msg, string group,
198
                                        string, string)
199
{
200 201 202
    if (!send_ok_) {
        isc_throw(XfroutError, "mock session send is disabled for test");
    }
203 204 205

    sent_msg = msg;
    msg_destination = group;
206 207 208 209
    return (0);
}

bool
210 211
AuthSrvTest::MockSession::group_recvmsg(ConstElementPtr&,
                                        ConstElementPtr& msg, bool, int)
212
{
213 214 215 216
    if (!receive_ok_) {
        isc_throw(XfroutError, "mock session receive is disabled for test");
    }

217 218 219 220
    msg = msg_;
    return (true);
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
void
AuthSrvTest::MockXfroutClient::connect() {
    if (!connect_ok_) {
        isc_throw(XfroutError, "xfrout connection disabled for test");
    }
    is_connected_ = true;
}

void
AuthSrvTest::MockXfroutClient::disconnect() {
    if (!disconnect_ok_) {
        isc_throw(XfroutError,
                  "closing xfrout connection is disabled for test");
    }
    is_connected_ = false;
}

int
239 240 241
AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(const int,
                                                     const void*,
                                                     const uint16_t)
242 243
{
    if (!send_ok_) {
244
        isc_throw(XfroutError, "xfrout connection send is disabled for test");
245 246 247 248
    }
    return (0);
}

249

250 251 252 253 254 255 256 257 258 259 260 261
// These are flags to indicate whether the corresponding flag bit of the
// DNS header is to be set in the test cases.  (Note that the flag values
// is irrelevant to their wire-format values)
const unsigned int QR_FLAG = 0x1;
const unsigned int AA_FLAG = 0x2;
const unsigned int TC_FLAG = 0x4;
const unsigned int RD_FLAG = 0x8;
const unsigned int RA_FLAG = 0x10;
const unsigned int AD_FLAG = 0x20;
const unsigned int CD_FLAG = 0x40;

void
JINMEI Tatuya's avatar
JINMEI Tatuya committed
262 263 264
AuthSrvTest::createDataFromFile(const char* const datafile,
                                const int protocol = IPPROTO_UDP)
{
265
    delete io_message;
266 267
    data.clear();

268
    delete endpoint;
269 270
    endpoint = IOEndpoint::create(protocol,
                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
271
    UnitTestUtil::readWireData(datafile, data);
272
    io_message = new IOMessage(&data[0], data.size(),
273 274 275
                               protocol == IPPROTO_UDP ?
                               IOSocket::getDummyUDPSocket() :
                               IOSocket::getDummyTCPSocket(), *endpoint);
276 277
}

278
void
279 280 281 282
AuthSrvTest::createRequestMessage(const Opcode& opcode,
                                  const Name& request_name,
                                  const RRClass& rrclass,
                                  const RRType& rrtype)
283
{
284
    request_message.clear(Message::RENDER);
285
    request_message.setOpcode(opcode);
286
    request_message.setRcode(Rcode::NOERROR());
JINMEI Tatuya's avatar
JINMEI Tatuya committed
287
    request_message.setQid(default_qid);
288
    request_message.addQuestion(Question(request_name, rrclass, rrtype));
289 290 291 292 293 294 295 296 297 298 299 300 301 302
}

void
AuthSrvTest::createRequestPacket(const Opcode& opcode,
                                 const Name& request_name,
                                 const RRClass& rrclass, const RRType& rrtype,
                                 const int protocol = IPPROTO_UDP)
{
    createRequestMessage(opcode, request_name, rrclass, rrtype);
    createRequestPacket(protocol);
}

void
AuthSrvTest::createRequestPacket(const int protocol = IPPROTO_UDP) {
303 304 305
    request_message.toWire(request_renderer);

    delete io_message;
306 307
    endpoint = IOEndpoint::create(protocol,
                                  IOAddress(DEFAULT_REMOTE_ADDRESS), 5300);
308 309
    io_message = new IOMessage(request_renderer.getData(),
                               request_renderer.getLength(),
310 311 312
                               protocol == IPPROTO_UDP ?
                               IOSocket::getDummyUDPSocket() :
                               IOSocket::getDummyTCPSocket(), *endpoint);
313 314
}

315 316 317 318 319 320 321 322 323 324
void
headerCheck(const Message& message, const qid_t qid, const Rcode& rcode,
            const uint16_t opcodeval, const unsigned int flags,
            const unsigned int qdcount,
            const unsigned int ancount, const unsigned int nscount,
            const unsigned int arcount)
{
    EXPECT_EQ(qid, message.getQid());
    EXPECT_EQ(rcode, message.getRcode());
    EXPECT_EQ(opcodeval, message.getOpcode().getCode());
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
    EXPECT_EQ((flags & QR_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_QR));
    EXPECT_EQ((flags & AA_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_AA));
    EXPECT_EQ((flags & TC_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_TC));
    EXPECT_EQ((flags & RA_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_RA));
    EXPECT_EQ((flags & RD_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_RD));
    EXPECT_EQ((flags & AD_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_AD));
    EXPECT_EQ((flags & CD_FLAG) != 0,
              message.getHeaderFlag(Message::HEADERFLAG_CD));

    EXPECT_EQ(qdcount, message.getRRCount(Message::SECTION_QUESTION));
    EXPECT_EQ(ancount, message.getRRCount(Message::SECTION_ANSWER));
    EXPECT_EQ(nscount, message.getRRCount(Message::SECTION_AUTHORITY));
    EXPECT_EQ(arcount, message.getRRCount(Message::SECTION_ADDITIONAL));
344 345 346 347
}

// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
348
    for (unsigned int i = 0; i < 16; ++i) {
349
        // set Opcode to 'i', which iterators over all possible codes except
350 351 352
        // the standard query and notify
        if (i == Opcode::QUERY().getCode() ||
            i == Opcode::NOTIFY().getCode()) {
Han Feng's avatar
Han Feng committed
353
            continue;
354
        }
355
        createDataFromFile("simplequery_fromWire.wire");
356 357 358
        data[2] = ((i << 3) & 0xff);

        parse_message.clear(Message::PARSE);
359 360
        EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                          response_renderer));
361 362 363
        headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
                    0, 0, 0, 0);
    }
364
}
365

366 367 368 369 370 371 372 373 374
// Simple API check
TEST_F(AuthSrvTest, verbose) {
    EXPECT_FALSE(server.getVerbose());
    server.setVerbose(true);
    EXPECT_TRUE(server.getVerbose());
    server.setVerbose(false);
    EXPECT_FALSE(server.getVerbose());
}

375 376
// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
377
    createDataFromFile("multiquestion_fromWire.wire");
378 379
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
380
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
381 382 383 384 385 386 387 388 389 390 391 392
                QR_FLAG, 2, 0, 0, 0);

    QuestionIterator qit = parse_message.beginQuestion();
    EXPECT_EQ(Name("example.com"), (*qit)->getName());
    EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
    EXPECT_EQ(RRType::A(), (*qit)->getType());
    ++qit;
    EXPECT_EQ(Name("example.com"), (*qit)->getName());
    EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
    EXPECT_EQ(RRType::AAAA(), (*qit)->getType());
    ++qit;
    EXPECT_TRUE(qit == parse_message.endQuestion());
393 394
}

395 396 397
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
398
    createDataFromFile("shortmessage_fromWire");
399 400
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
401 402 403 404 405 406
}

// Response messages.  Must be silently dropped, whether it's a valid response
// or malformed or could otherwise cause a protocol error.
TEST_F(AuthSrvTest, response) {
    // A valid (although unusual) response
407
    createDataFromFile("simpleresponse_fromWire.wire");
408 409
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
410 411 412

    // A response with a broken question section.  must be dropped rather than
    // returning FORMERR.
413
    createDataFromFile("shortresponse_fromWire");
414 415
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
416 417

    // A response to iquery.  must be dropped rather than returning NOTIMP.
418
    createDataFromFile("iqueryresponse_fromWire.wire");
419 420
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
421 422 423 424
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
425
    createDataFromFile("shortquestion_fromWire");
426 427
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
428 429 430 431 432
    // Since the query's question is broken, the question section of the
    // response should be empty.
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                QR_FLAG, 0, 0, 0, 0);
}
433

434 435
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
436
    createDataFromFile("shortanswer_fromWire.wire");
437 438
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
439 440 441

    // This is a bogus query, but question section is valid.  So the response
    // should copy the question section.
442 443 444
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                QR_FLAG, 1, 0, 0, 0);

445 446 447 448 449 450
    QuestionIterator qit = parse_message.beginQuestion();
    EXPECT_EQ(Name("example.com"), (*qit)->getName());
    EXPECT_EQ(RRClass::IN(), (*qit)->getClass());
    EXPECT_EQ(RRType::A(), (*qit)->getType());
    ++qit;
    EXPECT_TRUE(qit == parse_message.endQuestion());
451 452
}

453 454
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
455
    createDataFromFile("queryBadEDNS_fromWire.wire");
456 457
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
458

459 460
    // The response must have an EDNS OPT RR in the additional section, but
    // it will be added automatically at the render time.
461 462 463 464
    // Note that the DNSSEC DO bit is cleared even if this bit in the query
    // is set.  This is a limitation of the current implementation.
    headerCheck(parse_message, default_qid, Rcode::BADVERS(), opcode.getCode(),
                QR_FLAG, 1, 0, 0, 1);
465 466 467 468 469 470 471
    EXPECT_FALSE(parse_message.getEDNS()); // EDNS isn't added at this point

    parse_message.clear(Message::PARSE);
    InputBuffer ib(response_renderer.getData(), response_renderer.getLength());
    parse_message.fromWire(ib);
    EXPECT_EQ(Rcode::BADVERS(), parse_message.getRcode());
    EXPECT_TRUE(parse_message.getEDNS());
472
    EXPECT_FALSE(parse_message.getEDNS()->getDNSSECAwareness());
473 474
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
475 476
TEST_F(AuthSrvTest, AXFROverUDP) {
    // AXFR over UDP is invalid and should result in FORMERR.
477 478
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_UDP);
479 480
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
JINMEI Tatuya's avatar
JINMEI Tatuya committed
481 482 483 484
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                QR_FLAG, 1, 0, 0, 0);
}

485 486
TEST_F(AuthSrvTest, AXFRSuccess) {
    EXPECT_FALSE(xfrout.isConnected());
487 488
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
489 490
    // On success, the AXFR query has been passed to a separate process,
    // so we shouldn't have to respond.
491 492
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
493
    EXPECT_TRUE(xfrout.isConnected());
494 495 496 497 498
}

TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
499 500
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
501 502 503 504 505 506 507 508 509 510
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, AXFRSendFail) {
    // first send a valid query, making the connection with the xfr process
    // open.
511 512
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
513
    server.processMessage(*io_message, parse_message, response_renderer);
514
    EXPECT_TRUE(xfrout.isConnected());
515 516 517 518

    xfrout.disableSend();
    parse_message.clear(Message::PARSE);
    response_renderer.clear();
519 520
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
521 522 523 524 525 526 527 528 529 530 531 532 533 534
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);

    // The connection should have been closed due to the send failure.
    EXPECT_FALSE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, AXFRDisconnectFail) {
    // In our usage disconnect() shouldn't fail.  So we'll see the exception
    // should it be thrown.
    xfrout.disableSend();
    xfrout.disableDisconnect();
535 536
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
537 538 539 540 541 542 543 544 545
    EXPECT_THROW(server.processMessage(*io_message, parse_message,
                                       response_renderer),
                 XfroutError);
    EXPECT_TRUE(xfrout.isConnected());
    // XXX: we need to re-enable disconnect.  otherwise an exception would be
    // thrown via the destructor of the server.
    xfrout.enableDisconnect();
}

546 547 548
TEST_F(AuthSrvTest, notify) {
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
549
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
550
    createRequestPacket(IPPROTO_UDP);
551 552
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
553 554 555

    // An internal command message should have been created and sent to an
    // external module.  Check them.
556
    EXPECT_EQ("Zonemgr", notify_session.msg_destination);
557 558
    EXPECT_EQ("notify",
              notify_session.sent_msg->get("command")->get(0)->stringValue());
559 560
    ConstElementPtr notify_args =
        notify_session.sent_msg->get("command")->get(1);
561 562 563
    EXPECT_EQ("example.com.", notify_args->get("zone_name")->stringValue());
    EXPECT_EQ(DEFAULT_REMOTE_ADDRESS,
              notify_args->get("master")->stringValue());
564
    EXPECT_EQ("IN", notify_args->get("zone_class")->stringValue());
565 566

    // On success, the server should return a response to the notify.
567 568 569
    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);

570
    // The question must be identical to that of the received notify
571 572 573 574 575 576
    ConstQuestionPtr question = *parse_message.beginQuestion();
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
}

577 578 579 580
TEST_F(AuthSrvTest, notifyForCHClass) {
    // Same as the previous test, but for the CH RRClass.
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::CH(),
                        RRType::SOA());
581
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
582
    createRequestPacket(IPPROTO_UDP);
583 584
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
585 586 587

    // Other conditions should be the same, so simply confirm the RR class is
    // set correctly.
588 589
    ConstElementPtr notify_args =
        notify_session.sent_msg->get("command")->get(1);
590
    EXPECT_EQ("CH", notify_args->get("zone_class")->stringValue());
591 592
}

593 594 595
TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
596
    request_message.setRcode(Rcode::NOERROR());
597
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
598 599 600
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
    createRequestPacket(IPPROTO_UDP);
601 602
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
603 604 605 606 607 608 609 610 611 612
    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                Opcode::NOTIFY().getCode(), QR_FLAG, 0, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyMultiQuestions) {
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
    // add one more SOA question
    request_message.addQuestion(Question(Name("example.com"), RRClass::IN(),
                                         RRType::SOA()));
613
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
614
    createRequestPacket(IPPROTO_UDP);
615 616
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
617 618 619 620 621 622 623
    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                Opcode::NOTIFY().getCode(), QR_FLAG, 2, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyNonSOAQuestion) {
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::NS());
624
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
625
    createRequestPacket(IPPROTO_UDP);
626 627
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
628 629 630 631 632 633 634 635
    headerCheck(parse_message, default_qid, Rcode::FORMERR(),
                Opcode::NOTIFY().getCode(), QR_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithoutAA) {
    // implicitly leave the AA bit off.  our implementation will accept it.
    createRequestPacket(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
636 637
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
638 639 640 641 642 643 644
    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
}

TEST_F(AuthSrvTest, notifyWithErrorRcode) {
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
645
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
646 647
    request_message.setRcode(Rcode::SERVFAIL());
    createRequestPacket(IPPROTO_UDP);
648 649
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
650 651
    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);
Han Feng's avatar
Han Feng committed
652 653
}

654
TEST_F(AuthSrvTest, notifyWithoutSession) {
655
    server.setXfrinSession(NULL);
656 657 658

    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
659
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
660 661 662 663 664 665 666 667 668 669 670 671 672
    createRequestPacket(IPPROTO_UDP);

    // we simply ignore the notify and let it be resent if an internal error
    // happens.
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
}

TEST_F(AuthSrvTest, notifySendFail) {
    notify_session.disableSend();

    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
673
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
674
    createRequestPacket(IPPROTO_UDP);
675

676 677 678 679 680 681 682 683 684
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
}

TEST_F(AuthSrvTest, notifyReceiveFail) {
    notify_session.disableReceive();

    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
685
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
686 687 688 689 690 691
    createRequestPacket(IPPROTO_UDP);
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
}

TEST_F(AuthSrvTest, notifyWithBogusSessionMessage) {
692
    notify_session.setMessage(Element::fromJSON("{\"foo\": 1}"));
693 694 695

    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
696
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
697 698 699 700 701 702 703
    createRequestPacket(IPPROTO_UDP);
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
}

TEST_F(AuthSrvTest, notifyWithSessionMessageError) {
    notify_session.setMessage(
704
        Element::fromJSON("{\"result\": [1, \"FAIL\"]}"));
705 706 707

    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
708
    request_message.setHeaderFlag(Message::HEADERFLAG_AA);
709 710 711 712 713
    createRequestPacket(IPPROTO_UDP);
    EXPECT_FALSE(server.processMessage(*io_message, parse_message,
                                       response_renderer));
}

714
void
715 716 717
updateConfig(AuthSrv* server, const char* const dbfile,
             const bool expect_success)
{
718
    ConstElementPtr config_answer =
719
        server->updateConfig(Element::fromJSON(dbfile));
720 721 722
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

723
    ConstElementPtr result = config_answer->get("result");
724
    EXPECT_EQ(Element::list, result->getType());
725
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
726 727 728 729
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
730
    updateConfig(&server, CONFIG_TESTDB, true);
731 732 733 734

    // query for existent data in the installed data source.  The resulting
    // response should have the AA flag on, and have an RR in each answer
    // and authority section.
735
    createDataFromFile("examplequery_fromWire.wire");
736 737
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
738 739 740 741 742
    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
743
    updateConfig(&server, CONFIG_TESTDB, true);
744 745 746 747 748

    // This query will hit a corrupted entry of the data source (the zoneload
    // tool and the data source itself naively accept it).  This will result
    // in a SERVFAIL response, and the answer and authority sections should
    // be empty.
749
    createDataFromFile("badExampleQuery_fromWire.wire");
750 751
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
752 753
    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(),
                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
754
}
755 756 757 758 759 760 761 762 763

TEST_F(AuthSrvTest, updateConfigFail) {
    // First, load a valid data source.
    updateConfig(&server, CONFIG_TESTDB, true);

    // Next, try to update it with a non-existent one.  This should fail.
    updateConfig(&server, BADCONFIG_TESTDB, false);

    // The original data source should still exist.
764
    createDataFromFile("examplequery_fromWire.wire");
765 766
    EXPECT_TRUE(server.processMessage(*io_message, parse_message,
                                      response_renderer));
767 768 769
    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
JINMEI Tatuya's avatar
JINMEI Tatuya committed
770 771 772 773 774 775 776 777 778 779

TEST_F(AuthSrvTest, cacheSlots) {
    // simple check for the get/set operations
    server.setCacheSlots(10);    // 10 = arbitrary choice
    EXPECT_EQ(10, server.getCacheSlots());

    // 0 is a valid size
    server.setCacheSlots(0);
    EXPECT_EQ(00, server.getCacheSlots());
}
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827

TEST_F(AuthSrvTest, statsCallback) {
    // getStatsCallback() test
    // expect returning a valid function
    asio_link::IntervalTimer::Callback cbFunc;
    cbFunc = server.getStatsCallback();
    EXPECT_FALSE(cbFunc.empty());
}

TEST_F(AuthSrvTest, sendStatsWithoutSession) {
    // to cover the code path in case the stats session is not set
    // expect to put an error message
    server.setStatsSession(NULL);
    bool verbose = server.getVerbose();
    server.setVerbose(true);
    server.getStatsCallback()();
    server.setVerbose(verbose);
}

//
// statistics::Counter unittest

TEST_F(AuthSrvTest, counter_incUDP) {
    counter.inc(Counter::COUNTER_UDP);
}

TEST_F(AuthSrvTest, counter_incTCP) {
    counter.inc(Counter::COUNTER_TCP);
}

TEST_F(AuthSrvTest, counter_incUnknown) {
    EXPECT_THROW(counter.inc(Counter::COUNTER_TYPES), std::out_of_range);
}

TEST_F(AuthSrvTest, counter_getCallback) {
    // getCallback() test
    // expect returning a valid function
    asio_link::IntervalTimer::Callback cbFunc;
    cbFunc = counter.getCallback();
    EXPECT_FALSE(cbFunc.empty());
}

TEST_F(AuthSrvTest, counter_sendStatsWithSession) {
    // Test the function to send statistics information to b10-stats
    // expect to run without throwing any exception
    counter.setStatsSession(&stats_session);
    counter.getCallback()();
}
828
}