auth_srv_unittest.cc 23.5 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 25 26 27
#include <gtest/gtest.h>

#include <dns/buffer.h>
#include <dns/name.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>

28
#include <cc/data.h>
29
#include <cc/session.h>
30

31 32
#include <xfr/xfrout_client.h>

33
#include <auth/auth_srv.h>
34
#include <auth/asio_link.h>
35 36 37 38 39

#include <dns/tests/unittest_util.h>

using isc::UnitTestUtil;
using namespace std;
40
using namespace isc::cc;
41
using namespace isc::dns;
42
using namespace isc::data;
43
using namespace isc::xfr;
44
using namespace asio_link;
45 46

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

54
class AuthSrvTest : public ::testing::Test {
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
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_;
    };
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94

    class MockSession : public AbstractSession {
    public:
        MockSession() :
            // by default we return a simple "success" message.
            msg_(Element::createFromString("{\"result\": [0, \"SUCCESS\"]}"))
        {}
        virtual void establish(const char* socket_file);
        virtual void disconnect();
        virtual int group_sendmsg(ElementPtr msg, string group,
                                  string instance, string to);
        virtual bool group_recvmsg(ElementPtr& envelope, ElementPtr& msg,
                                   bool nonblock, int seq);
        void setMessage(ElementPtr msg) { msg_ = msg; }
    private:
        ElementPtr msg_;
    };

95
protected:
96 97
    AuthSrvTest() : server(notify_session, xfrout),
                    request_message(Message::RENDER),
98
                    parse_message(Message::PARSE), default_qid(0x1035),
99
                    opcode(Opcode(Opcode::QUERY())), qname("www.example.com"),
100
                    qclass(RRClass::IN()), qtype(RRType::A()),
101
                    io_message(NULL), endpoint(NULL), request_obuffer(0),
102
                    request_renderer(request_obuffer),
103 104
                    response_obuffer(0), response_renderer(response_obuffer)
    {}
105 106
    ~AuthSrvTest() {
        delete io_message;
107
        delete endpoint;
108
    }
109
    MockSession notify_session;
110
    MockXfroutClient xfrout;
111 112 113
    AuthSrv server;
    Message request_message;
    Message parse_message;
114 115 116 117 118
    const qid_t default_qid;
    const Opcode opcode;
    const Name qname;
    const RRClass qclass;
    const RRType qtype;
119 120
    IOMessage* io_message;
    const IOEndpoint* endpoint;
121 122 123 124 125
    OutputBuffer request_obuffer;
    MessageRenderer request_renderer;
    OutputBuffer response_obuffer;
    MessageRenderer response_renderer;
    vector<uint8_t> data;
126

JINMEI Tatuya's avatar
JINMEI Tatuya committed
127
    void createDataFromFile(const char* const datafile, int protocol);
128 129 130 131 132 133
    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);
134 135
};

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
void
AuthSrvTest::MockSession::establish(const char* socket_file UNUSED_PARAM) {
}

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

int
AuthSrvTest::MockSession::group_sendmsg(ElementPtr msg UNUSED_PARAM,
                                        string group UNUSED_PARAM,
                                        string instance UNUSED_PARAM,
                                        string to UNUSED_PARAM)
{
    return (0);
}

bool
AuthSrvTest::MockSession::group_recvmsg(ElementPtr& envelope UNUSED_PARAM,
                                        ElementPtr& msg,
                                        bool nonblock UNUSED_PARAM,
                                        int seq UNUSED_PARAM)
{
    msg = msg_;
    return (true);
}

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
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
AuthSrvTest::MockXfroutClient::sendXfroutRequestInfo(
    const int tcp_sock UNUSED_PARAM,
    const void* msg_data UNUSED_PARAM,
    const uint16_t msg_len UNUSED_PARAM)
{
    if (!send_ok_) {
        isc_throw(XfroutError, "xfrout connection send for test");
    }
    return (0);
}

192

193 194 195 196 197 198 199 200 201 202 203 204
// 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
205 206 207
AuthSrvTest::createDataFromFile(const char* const datafile,
                                const int protocol = IPPROTO_UDP)
{
208
    delete io_message;
209 210
    data.clear();

211
    delete endpoint;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
212
    endpoint = IOEndpoint::create(protocol, IOAddress("192.0.2.1"), 5300);
213
    UnitTestUtil::readWireData(datafile, data);
214
    io_message = new IOMessage(&data[0], data.size(),
215 216 217
                               protocol == IPPROTO_UDP ?
                               IOSocket::getDummyUDPSocket() :
                               IOSocket::getDummyTCPSocket(), *endpoint);
218 219
}

220
void
221 222 223 224
AuthSrvTest::createRequestMessage(const Opcode& opcode,
                                  const Name& request_name,
                                  const RRClass& rrclass,
                                  const RRType& rrtype)
225
{
226
    request_message.clear(Message::RENDER);
227
    request_message.setOpcode(opcode);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
228
    request_message.setQid(default_qid);
229
    request_message.addQuestion(Question(request_name, rrclass, rrtype));
230 231 232 233 234 235 236 237 238 239 240 241 242 243
}

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) {
244 245 246
    request_message.toWire(request_renderer);

    delete io_message;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
247
    endpoint = IOEndpoint::create(protocol, IOAddress("192.0.2.1"), 5300);
248 249
    io_message = new IOMessage(request_renderer.getData(),
                               request_renderer.getLength(),
250 251 252
                               protocol == IPPROTO_UDP ?
                               IOSocket::getDummyUDPSocket() :
                               IOSocket::getDummyTCPSocket(), *endpoint);
253 254
}

255 256 257 258 259 260 261 262 263 264
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());
265 266 267 268 269 270 271
    EXPECT_EQ((flags & QR_FLAG) != 0, message.getHeaderFlag(MessageFlag::QR()));
    EXPECT_EQ((flags & AA_FLAG) != 0, message.getHeaderFlag(MessageFlag::AA()));
    EXPECT_EQ((flags & TC_FLAG) != 0, message.getHeaderFlag(MessageFlag::TC()));
    EXPECT_EQ((flags & RA_FLAG) != 0, message.getHeaderFlag(MessageFlag::RA()));
    EXPECT_EQ((flags & RD_FLAG) != 0, message.getHeaderFlag(MessageFlag::RD()));
    EXPECT_EQ((flags & AD_FLAG) != 0, message.getHeaderFlag(MessageFlag::AD()));
    EXPECT_EQ((flags & CD_FLAG) != 0, message.getHeaderFlag(MessageFlag::CD()));
272 273 274 275 276 277 278 279 280 281 282

    EXPECT_EQ(qdcount, message.getRRCount(Section::QUESTION()));
    EXPECT_EQ(ancount, message.getRRCount(Section::ANSWER()));
    EXPECT_EQ(nscount, message.getRRCount(Section::AUTHORITY()));
    EXPECT_EQ(arcount, message.getRRCount(Section::ADDITIONAL()));
}

// Unsupported requests.  Should result in NOTIMP.
TEST_F(AuthSrvTest, unsupportedRequest) {
    for (unsigned int i = 1; i < 16; ++i) {
        // set Opcode to 'i', which iterators over all possible codes except
Han Feng's avatar
Han Feng committed
283
        // the standard query (0) and notify(4)
284
        if (i == Opcode::NOTIFY().getCode()) {
Han Feng's avatar
Han Feng committed
285
            continue;
286
        }
287
        createDataFromFile("simplequery_fromWire");
288 289 290
        data[2] = ((i << 3) & 0xff);

        parse_message.clear(Message::PARSE);
291 292
        EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                              response_renderer));
293 294 295
        headerCheck(parse_message, default_qid, Rcode::NOTIMP(), i, QR_FLAG,
                    0, 0, 0, 0);
    }
296
}
297

298 299 300 301 302 303 304 305 306
// 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());
}

307 308
// Multiple questions.  Should result in FORMERR.
TEST_F(AuthSrvTest, multiQuestion) {
309
    createDataFromFile("multiquestion_fromWire");
310 311
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
312
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
313 314 315 316 317 318 319 320 321 322 323 324
                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());
325 326
}

327 328 329
// Incoming data doesn't even contain the complete header.  Must be silently
// dropped.
TEST_F(AuthSrvTest, shortMessage) {
330
    createDataFromFile("shortmessage_fromWire");
331 332
    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
                                           response_renderer));
333 334 335 336 337 338
}

// 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
339
    createDataFromFile("simpleresponse_fromWire");
340 341
    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
                                           response_renderer));
342 343 344

    // A response with a broken question section.  must be dropped rather than
    // returning FORMERR.
345
    createDataFromFile("shortresponse_fromWire");
346 347
    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
                                           response_renderer));
348 349

    // A response to iquery.  must be dropped rather than returning NOTIMP.
350
    createDataFromFile("iqueryresponse_fromWire");
351 352
    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
                                           response_renderer));
353 354 355 356
}

// Query with a broken question
TEST_F(AuthSrvTest, shortQuestion) {
357
    createDataFromFile("shortquestion_fromWire");
358 359
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
360 361 362 363 364
    // 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);
}
365

366 367
// Query with a broken answer section
TEST_F(AuthSrvTest, shortAnswer) {
368
    createDataFromFile("shortanswer_fromWire");
369 370
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
371 372 373

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

377 378 379 380 381 382
    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());
383 384
}

385 386
// Query with unsupported version of EDNS.
TEST_F(AuthSrvTest, ednsBadVers) {
387
    createDataFromFile("queryBadEDNS_fromWire");
388 389
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
390 391 392 393 394 395 396 397 398 399

    // The response must have an EDNS OPT RR in the additional section.
    // 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);
    EXPECT_EQ(4096, parse_message.getUDPSize());
    EXPECT_FALSE(parse_message.isDNSSECSupported());
}

JINMEI Tatuya's avatar
JINMEI Tatuya committed
400 401
TEST_F(AuthSrvTest, AXFROverUDP) {
    // AXFR over UDP is invalid and should result in FORMERR.
402 403
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_UDP);
JINMEI Tatuya's avatar
JINMEI Tatuya committed
404 405 406 407 408 409
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
    headerCheck(parse_message, default_qid, Rcode::FORMERR(), opcode.getCode(),
                QR_FLAG, 1, 0, 0, 0);
}

410 411
TEST_F(AuthSrvTest, AXFRSuccess) {
    EXPECT_FALSE(xfrout.isConnected());
412 413
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
414 415 416 417 418 419 420 421 422 423
    // On success, the AXFR query has been passed to a separate process,
    // so we shouldn't have to respond.
    EXPECT_EQ(false, server.processMessage(*io_message, parse_message,
                                           response_renderer));
    EXPECT_TRUE(xfrout.isConnected());
}

TEST_F(AuthSrvTest, AXFRConnectFail) {
    EXPECT_FALSE(xfrout.isConnected()); // check prerequisite
    xfrout.disableConnect();
424 425
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
426 427 428 429 430 431 432 433 434 435
    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.
436 437
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
438 439 440 441 442 443
    server.processMessage(*io_message, parse_message, response_renderer);
    EXPECT_TRUE(xfrout.isConnected());

    xfrout.disableSend();
    parse_message.clear(Message::PARSE);
    response_renderer.clear();
444 445
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
446 447 448 449 450 451 452 453 454 455 456 457 458 459
    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();
460 461
    createRequestPacket(opcode, Name("example.com"), RRClass::IN(),
                        RRType::AXFR(), IPPROTO_TCP);
462 463 464 465 466 467 468 469 470
    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();
}

471 472 473 474 475
TEST_F(AuthSrvTest, notify) {
    createRequestMessage(Opcode::NOTIFY(), Name("example.com"), RRClass::IN(),
                        RRType::SOA());
    createRequestPacket(IPPROTO_UDP);
    request_message.setHeaderFlag(MessageFlag::AA());
476
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
                                          response_renderer));
    headerCheck(parse_message, default_qid, Rcode::NOERROR(),
                Opcode::NOTIFY().getCode(), QR_FLAG | AA_FLAG, 1, 0, 0, 0);

    // The question must be identical of the notify
    ConstQuestionPtr question = *parse_message.beginQuestion();
    EXPECT_EQ(Name("example.com"), question->getName());
    EXPECT_EQ(RRClass::IN(), question->getClass());
    EXPECT_EQ(RRType::SOA(), question->getType());
}

TEST_F(AuthSrvTest, notifyEmptyQuestion) {
    request_message.clear(Message::RENDER);
    request_message.setOpcode(Opcode::NOTIFY());
    request_message.setHeaderFlag(MessageFlag::AA());
    request_message.setQid(default_qid);
    request_message.toWire(request_renderer);
    createRequestPacket(IPPROTO_UDP);
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
    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()));
    request_message.setHeaderFlag(MessageFlag::AA());
    createRequestPacket(IPPROTO_UDP);
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
    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());
    request_message.setHeaderFlag(MessageFlag::AA());
    createRequestPacket(IPPROTO_UDP);
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
    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());
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
    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());
    request_message.setHeaderFlag(MessageFlag::AA());
    request_message.setRcode(Rcode::SERVFAIL());
    createRequestPacket(IPPROTO_UDP);
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
544 545
    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
546 547
}

548
void
549 550 551
updateConfig(AuthSrv* server, const char* const dbfile,
             const bool expect_success)
{
552 553 554 555 556 557 558
    const ElementPtr config_answer =
        server->updateConfig(Element::createFromString(dbfile));
    EXPECT_EQ(Element::map, config_answer->getType());
    EXPECT_TRUE(config_answer->contains("result"));

    const ElementPtr result = config_answer->get("result");
    EXPECT_EQ(Element::list, result->getType());
559
    EXPECT_EQ(expect_success ? 0 : 1, result->get(0)->intValue());
560 561 562 563
}

// Install a Sqlite3 data source with testing data.
TEST_F(AuthSrvTest, updateConfig) {
564
    updateConfig(&server, CONFIG_TESTDB, true);
565 566 567 568

    // 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.
569
    createDataFromFile("examplequery_fromWire");
570 571
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
572 573 574 575 576
    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}

TEST_F(AuthSrvTest, datasourceFail) {
577
    updateConfig(&server, CONFIG_TESTDB, true);
578 579 580 581 582

    // 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.
583
    createDataFromFile("badExampleQuery_fromWire");
584 585
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
586 587 588
    headerCheck(parse_message, default_qid, Rcode::SERVFAIL(), opcode.getCode(),
                QR_FLAG, 1, 0, 0, 0);
}
589 590 591 592 593 594 595 596 597

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.
598
    createDataFromFile("examplequery_fromWire");
599 600
    EXPECT_EQ(true, server.processMessage(*io_message, parse_message,
                                          response_renderer));
601 602 603
    headerCheck(parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
}
604
}