recursive_query_unittest_3.cc 22.8 KB
Newer Older
Dima Volodin's avatar
Dima Volodin committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Copyright (C) 2011  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 <algorithm>
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>

#include <gtest/gtest.h>
#include <boost/bind.hpp>

#include <asio.hpp>

#include <util/buffer.h>
#include <util/io_utilities.h>

#include <dns/question.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/opcode.h>
#include <dns/name.h>
#include <dns/rcode.h>
#include <dns/rrtype.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>
#include <dns/rdata.h>

#include <util/io_utilities.h>
#include <asiodns/dns_service.h>
#include <asiodns/io_fetch.h>
#include <asiolink/io_address.h>
#include <asiolink/io_endpoint.h>
#include <asiolink/io_service.h>
#include <resolve/recursive_query.h>
#include <resolve/resolver_interface.h>

using namespace asio;
using namespace asio::ip;
using namespace isc::asiolink;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::util;
using namespace isc::resolve;
using namespace std;

/// RecursiveQuery Test - 3
///
/// The second part of the RecursiveQuery unit tests, this attempts to get the
/// RecursiveQuery object to follow a set of EDNS-induced errors, causing the
/// resolver to follow the fallback logic.
///
/// - Send EDNS question over UDP - get FORMERR
/// - Send EDNS question over TCP - get FORMERR
/// - Send non-EDNS question over UDP - get RESPONSE
///
/// By using the "test_server_" element of RecursiveQuery, all queries are
/// directed to one or other of the "servers" in the RecursiveQueryTest3 class.

Jelte Jansen's avatar
Jelte Jansen committed
72
73
74
75
namespace {
const char* const TEST_ADDRESS3 = "127.0.0.1"; ///< Servers are on this address
const uint16_t TEST_PORT3 = 5303;              ///< ... and this port
const size_t BUFFER_SIZE = 1024;               ///< For all buffers
Dima Volodin's avatar
Dima Volodin committed
76

Jelte Jansen's avatar
Jelte Jansen committed
77
78
const char* const DUMMY_ADDR3 = "1.2.3.4";     ///< address to return as A
} // end anonymous namespace
Dima Volodin's avatar
Dima Volodin committed
79

Jelte Jansen's avatar
Jelte Jansen committed
80
81
namespace isc {
namespace asiodns {
Dima Volodin's avatar
Dima Volodin committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104

class MockResolver3 : public isc::resolve::ResolverInterface {
public:
    virtual void resolve(const QuestionPtr& question,
                 const ResolverInterface::CallbackPtr& callback) {
    }

    virtual ~MockResolver3() {}
};



/// \brief Test fixture for the RecursiveQuery Test
class RecursiveQueryTest3 : public virtual ::testing::Test
{
public:

    /// \brief Status of query
    ///
    /// Set before the query and then by each "server" when responding.
    enum QueryStatus {
        NONE = 0,                   ///< Default
        EDNS_UDP = 1,               ///< EDNS query over UDP
105
        NON_EDNS_UDP = 2,           ///< Non-EDNS query over UDP
Dima Volodin's avatar
Dima Volodin committed
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
        COMPLETE = 6                ///< Query is complete
    };

    // Common stuff
    IOService       service_;                   ///< Service to run everything
    DNSService      dns_service_;               ///< Resolver is part of "server"
    QuestionPtr     question_;                  ///< What to ask
    QueryStatus     last_;                      ///< What was the last state
    QueryStatus     expected_;                  ///< Expected next state
    OutputBufferPtr question_buffer_;           ///< Question we expect to receive
    boost::shared_ptr<MockResolver3> resolver_;  ///< Mock resolver
    isc::nsas::NameserverAddressStore* nsas_;   ///< Nameserver address store
    isc::cache::ResolverCache cache_;           ///< Resolver cache

    // Data for TCP Server
    size_t          tcp_cumulative_;            ///< Cumulative TCP data received
    tcp::endpoint   tcp_endpoint_;              ///< Endpoint for TCP receives
    size_t          tcp_length_;                ///< Expected length value
    uint8_t         tcp_receive_buffer_[BUFFER_SIZE];   ///< Receive buffer for TCP I/O
    OutputBufferPtr tcp_send_buffer_;           ///< Send buffer for TCP I/O
    tcp::socket     tcp_socket_;                ///< Socket used by TCP server

    /// Data for UDP
    udp::endpoint   udp_remote_;                ///< Endpoint for UDP receives
    size_t          udp_length_;                ///< Expected length value
    uint8_t         udp_receive_buffer_[BUFFER_SIZE];   ///< Receive buffer for UDP I/O
    OutputBufferPtr udp_send_buffer_;           ///< Send buffer for UDP I/O
    udp::socket     udp_socket_;                ///< Socket used by UDP server

135
136
137
138
    /// Some of the tests cause an 'active' running query to be created, but
    /// don't complete the framework that makes that query delete itself.
    /// This member can be used to store it so that it is deleted automatically
    /// when the test is finished.
139
    AbstractRunningQuery* running_query_;
Jelte Jansen's avatar
Jelte Jansen committed
140

Dima Volodin's avatar
Dima Volodin committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
    /// \brief Constructor
    RecursiveQueryTest3() :
        service_(),
        dns_service_(service_, NULL, NULL, NULL),
        question_(new Question(Name("ednsfallback"),
                  RRClass::IN(), RRType::A())),
        last_(NONE),
        expected_(NONE),
        question_buffer_(new OutputBuffer(BUFFER_SIZE)),
        resolver_(new MockResolver3()),
        nsas_(new isc::nsas::NameserverAddressStore(resolver_)),
        tcp_cumulative_(0),
        tcp_endpoint_(asio::ip::address::from_string(TEST_ADDRESS3),
                      TEST_PORT3),
        tcp_length_(0),
        tcp_receive_buffer_(),
        tcp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
        tcp_socket_(service_.get_io_service()),
        udp_remote_(),
        udp_length_(0),
        udp_receive_buffer_(),
        udp_send_buffer_(new OutputBuffer(BUFFER_SIZE)),
Jelte Jansen's avatar
Jelte Jansen committed
163
164
        udp_socket_(service_.get_io_service(), udp::v4()),
        running_query_(NULL)
Dima Volodin's avatar
Dima Volodin committed
165
166
167
    {
    }

Jelte Jansen's avatar
Jelte Jansen committed
168
169
170
171
172
173
174
175
176
177
    ~RecursiveQueryTest3() {
        delete nsas_;
        // It would delete itself, but after the io_service_, which could
        // segfailt in case there were unhandled requests
        resolver_.reset();
        // In a similar note, we wait until the resolver has been cleaned up
        // until deleting and active test running_query_
        delete running_query_;
    }

Dima Volodin's avatar
Dima Volodin committed
178
179
180
181
182
183
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
232
233
234
235
236
237
238
239
240
241
242
243
244
    /// \brief Set Common Message Bits
    ///
    /// Sets up the common bits of a response message returned by the handlers.
    ///
    /// \param message Message buffer in RENDER mode.
    /// \param qid QID to set the message to
    void setCommonMessage(isc::dns::Message& message, uint16_t qid) {
        message.setQid(qid);
        message.setHeaderFlag(Message::HEADERFLAG_QR);
        message.setOpcode(Opcode::QUERY());
        message.setHeaderFlag(Message::HEADERFLAG_AA);
        message.addQuestion(*question_);
    }

    /// \brief Set FORMERR answer
    ///
    /// \param message Message to update with FORMERR status
    void setFORMERR(isc::dns::Message& message) {
        message.setRcode(Rcode::FORMERR());
    }

    /// \brief Set Answer
    ///
    /// \param message Message to update with FORMERR status
    void setAnswer(isc::dns::Message& message) {
        // Give a response
        RRsetPtr answer(new RRset(Name("ednsfallback."), RRClass::IN(),
                        RRType::A(), RRTTL(300)));
        answer->addRdata(createRdata(RRType::A(), RRClass::IN(), DUMMY_ADDR3));
        message.addRRset(Message::SECTION_ANSWER, answer);
        message.setRcode(Rcode::NOERROR());
    }

    /// \brief UDP Receive Handler
    ///
    /// This is invoked when a message is received over UDP from the
    /// RecursiveQuery object under test.  It formats an answer and sends it
    /// asynchronously, with the UdpSendHandler method being specified as the
    /// completion handler.
    ///
    /// \param ec ASIO error code, completion code of asynchronous I/O issued
    ///        by the "server" to receive data.
    /// \param length Amount of data received.
    void udpReceiveHandler(error_code ec = error_code(), size_t length = 0) {
        // Expected state should be one greater than the last state.
        EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
        last_ = expected_;

        Message query(Message::PARSE);

        // The QID in the incoming data is random so set it to 0 for the
        // data comparison check. (It is set to 0 in the buffer containing
        // the expected data.)
        // And check that question we received is what was expected.
        checkReceivedPacket(udp_receive_buffer_, length, query);

        // The message returned depends on what state we are in.  Set up
        // common stuff first: bits not mentioned are set to 0.
        Message message(Message::RENDER);
        setCommonMessage(message, query.getQid());

        // Set up state-dependent bits:
        switch (expected_) {
        case EDNS_UDP:
            EXPECT_TRUE(query.getEDNS());
            // Return FORMERROR
            setFORMERR(message);
245
            expected_ = NON_EDNS_UDP;
Dima Volodin's avatar
Dima Volodin committed
246
247
248
            break;

        case NON_EDNS_UDP:
Dima Volodin's avatar
Dima Volodin committed
249
            EXPECT_FALSE(query.getEDNS());
Dima Volodin's avatar
Dima Volodin committed
250
251
252
253
254
255
256
257
258
259
260
            // Return the answer to the question.
            setAnswer(message);
            expected_ = COMPLETE;
            break;

         default:
            FAIL() << "UdpReceiveHandler called with unknown state";
        }

        // Convert to wire format
        udp_send_buffer_->clear();
261
262
        MessageRenderer renderer;
        renderer.setBuffer(udp_send_buffer_.get());
Dima Volodin's avatar
Dima Volodin committed
263
        message.toWire(renderer);
264
        renderer.setBuffer(NULL);
Dima Volodin's avatar
Dima Volodin committed
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
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

        // Return a message back to the IOFetch object (after setting the
        // expected length of data for the check in the send handler).
        udp_length_ = udp_send_buffer_->getLength();
        udp_socket_.async_send_to(asio::buffer(udp_send_buffer_->getData(),
                                               udp_send_buffer_->getLength()),
                                  udp_remote_,
                              boost::bind(&RecursiveQueryTest3::udpSendHandler,
                                              this, _1, _2));
    }

    /// \brief UDP Send Handler
    ///
    /// Called when a send operation of the UDP server (i.e. a response
    /// being sent to the RecursiveQuery) has completed, this re-issues
    /// a read call.
    ///
    /// \param ec Completion error code of the send.
    /// \param length Actual number of bytes sent.
    void udpSendHandler(error_code ec = error_code(), size_t length = 0) {
        // Check send was OK
        EXPECT_EQ(0, ec.value());
        EXPECT_EQ(udp_length_, length);

        // Reissue the receive call to await the next message.
        udp_socket_.async_receive_from(
            asio::buffer(udp_receive_buffer_, sizeof(udp_receive_buffer_)),
            udp_remote_,
            boost::bind(&RecursiveQueryTest3::udpReceiveHandler,
                        this, _1, _2));
    }

    /// \brief Completion Handler for Accepting TCP Data
    ///
    /// Called when the remote system connects to the "TCP server".  It issues
    /// an asynchronous read on the socket to read data.
    ///
    /// \param socket Socket on which data will be received
    /// \param ec Boost error code, value should be zero.
    void tcpAcceptHandler(error_code ec = error_code(), size_t length = 0) {
        // Expect that the accept completed without a problem.
        EXPECT_EQ(0, ec.value());

        // Initiate a read on the socket, indicating that nothing has yet been
        // received.
        tcp_cumulative_ = 0;
        tcp_socket_.async_receive(
            asio::buffer(tcp_receive_buffer_, sizeof(tcp_receive_buffer_)),
            boost::bind(&RecursiveQueryTest3::tcpReceiveHandler, this, _1, _2));
    }

    /// \brief Completion Handler for Receiving TCP Data
    ///
    /// Reads data from the RecursiveQuery object and loops, reissuing reads,
    /// until all the message has been read.  It then returns an appropriate
    /// response.
    ///
    /// \param socket Socket to use to send the answer
    /// \param ec ASIO error code, completion code of asynchronous I/O issued
    ///        by the "server" to receive data.
    /// \param length Amount of data received.
    void tcpReceiveHandler(error_code ec = error_code(), size_t length = 0) {
        // Expect that the receive completed without a problem.
        EXPECT_EQ(0, ec.value());

        // Have we received all the data?  We know this by checking if the two-
        // byte length count in the message is equal to the data received.
        tcp_cumulative_ += length;
        bool complete = false;
        if (tcp_cumulative_ > 2) {
            uint16_t dns_length = readUint16(tcp_receive_buffer_);
            complete = ((dns_length + 2) == tcp_cumulative_);
        }

        if (!complete) {
            // Not complete yet, issue another read.
            tcp_socket_.async_receive(
                asio::buffer(tcp_receive_buffer_ + tcp_cumulative_,
                             sizeof(tcp_receive_buffer_) - tcp_cumulative_),
                boost::bind(&RecursiveQueryTest3::tcpReceiveHandler,
                            this, _1, _2));
            return;
        }

        // Have received a TCP message.  Expected state should be one greater
        // than the last state.
        EXPECT_EQ(static_cast<int>(expected_), static_cast<int>(last_) + 1);
        last_ = expected_;

        Message query(Message::PARSE);

        // Check that question we received is what was expected.  Note that we
        // have to ignore the two-byte header in order to parse the message.
        checkReceivedPacket(tcp_receive_buffer_ + 2, length - 2, query);

        // Return a message back.  This is a referral to example.org, which
        // should result in another query over UDP.  Note the setting of the
        // QID in the returned message with what was in the received message.
        Message message(Message::RENDER);
        setCommonMessage(message, query.getQid());

        // Set up state-dependent bits:
        switch (expected_) {
368
        default:
Dima Volodin's avatar
Dima Volodin committed
369
370
371
372
373
374
375
            FAIL() << "TcpReceiveHandler called with unknown state";
        }


        // Convert to wire format
        // Use a temporary buffer for the dns wire data (we copy it
        // to the 'real' buffer below)
376
        MessageRenderer renderer;
Dima Volodin's avatar
Dima Volodin committed
377
378
379
380
381
382
383
384
385
386
387
388
389
        message.toWire(renderer);

        // Also, take this opportunity to clear the accumulated read count in
        // readiness for the next read. (If any - at present, there is only
        // one read in the test, although extensions to this test suite could
        // change that.)
        tcp_cumulative_ = 0;

        // Unless we go through a callback loop we cannot simply use
        // async_send() multiple times, so we cannot send the size first
        // followed by the actual data. We copy them to a new buffer
        // first
        tcp_send_buffer_->clear();
390
391
        tcp_send_buffer_->writeUint16(renderer.getLength());
        tcp_send_buffer_->writeData(renderer.getData(), renderer.getLength());
Dima Volodin's avatar
Dima Volodin committed
392
393
        tcp_socket_.async_send(asio::buffer(tcp_send_buffer_->getData(),
                                            tcp_send_buffer_->getLength()),
394
395
396
397
                               boost::bind(
                                   &RecursiveQueryTest3::tcpSendHandler,
                                   this,
                                   tcp_send_buffer_->getLength(), _1, _2));
Dima Volodin's avatar
Dima Volodin committed
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
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
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
    }

    /// \brief Completion Handler for Sending TCP data
    ///
    /// Called when the asynchronous send of data back to the RecursiveQuery
    /// by the TCP "server" in this class has completed.  (This send has to
    /// be asynchronous because control needs to return to the caller in order
    /// for the IOService "run()" method to be called to run the handlers.)
    ///
    /// \param expected_length Number of bytes that were expected to have been
    /// sent.
    /// \param ec Boost error code, value should be zero.
    /// \param length Number of bytes sent.
    void tcpSendHandler(size_t expected_length = 0,
                        error_code ec = error_code(),
                        size_t length = 0)
    {
        EXPECT_EQ(0, ec.value());       // Expect no error
        EXPECT_EQ(expected_length, length);    // And that amount sent is as
                                               // expected
    }

    /// \brief Check Received Packet
    ///
    /// Checks the packet received from the RecursiveQuery object to ensure
    /// that the question is what is expected.
    ///
    /// \param data Start of data.  This is the start of the received buffer in
    ///        the case of UDP data, and an offset into the buffer past the
    ///        count field for TCP data.
    /// \param length Length of data.
    /// \return The QID of the message
    void checkReceivedPacket(uint8_t* data, size_t length, Message& message) {

        // Decode the received buffer.
        InputBuffer buffer(data, length);
        message.fromWire(buffer);

        // Check the packet.
        EXPECT_FALSE(message.getHeaderFlag(Message::HEADERFLAG_QR));

        Question question = **(message.beginQuestion());
        EXPECT_TRUE(question == *question_);
    }
};

/// \brief Resolver Callback Object
///
/// Holds the success and failure callback methods for the resolver
class ResolverCallback3 : public isc::resolve::ResolverInterface::Callback {
public:
    /// \brief Constructor
    ResolverCallback3(IOService& service) :
        service_(service), run_(false), status_(false)
    {}

    /// \brief Destructor
    virtual ~ResolverCallback3()
    {}

    /// \brief Resolver Callback Success
    ///
    /// Called if the resolver detects that the call has succeeded.
    ///
    /// \param response Answer to the question.
    virtual void success(const isc::dns::MessagePtr response) {
        // There should be one RR each  in the question and answer sections,
        // and two RRs in each of the the authority and additional sections.
        EXPECT_EQ(1, response->getRRCount(Message::SECTION_QUESTION));
        EXPECT_EQ(1, response->getRRCount(Message::SECTION_ANSWER));

        // Check the answer - that the RRset is there...
        EXPECT_TRUE(response->hasRRset(Message::SECTION_ANSWER,
                                       RRsetPtr(new RRset(Name("ednsfallback."),
                                                RRClass::IN(),
                                                RRType::A(),
                                                RRTTL(300)))));
        const RRsetIterator rrset_i = response->beginSection(Message::SECTION_ANSWER);

        // ... get iterator into the Rdata of this RRset and point to first
        // element...
        const RdataIteratorPtr rdata_i = (*rrset_i)->getRdataIterator();
        rdata_i->first();

        // ... and check it is what we expect.
        EXPECT_EQ(string(DUMMY_ADDR3), rdata_i->getCurrent().toText());

        // Flag completion
        run_ = true;
        status_ = true;

        service_.stop();    // Cause run() to exit.
    }

    /// \brief Resolver Failure Completion
    ///
    /// Called if the resolver detects that the resolution has failed.
    virtual void failure() {
        FAIL() << "Resolver reported completion failure";

        // Flag completion
        run_ = true;
        status_ = false;

        service_.stop();    // Cause run() to exit.
    }

    /// \brief Return status of "run" flag
    bool getRun() const {
        return (run_);
    }

    /// \brief Return "status" flag
    bool getStatus() const {
        return (status_);
    }

private:
    IOService&      service_;       ///< Service handling the run queue
    bool            run_;           ///< Set true when completion handler run
    bool            status_;        ///< Set true for success, false on error
};

// Sets up the UDP and TCP "servers", then tries a resolution.

TEST_F(RecursiveQueryTest3, Resolve) {
    // Set up the UDP server and issue the first read.  The endpoint from which
    // the query is sent is put in udp_endpoint_ when the read completes, which
Dima Volodin's avatar
Dima Volodin committed
526
527
    // is referenced in the callback as the place to which the response is
    // sent.
Dima Volodin's avatar
Dima Volodin committed
528
529
530
531
532
533
    udp_socket_.set_option(socket_base::reuse_address(true));
    udp_socket_.bind(udp::endpoint(address::from_string(TEST_ADDRESS3),
                                   TEST_PORT3));
    udp_socket_.async_receive_from(asio::buffer(udp_receive_buffer_,
                                                sizeof(udp_receive_buffer_)),
                                   udp_remote_,
Dima Volodin's avatar
Dima Volodin committed
534
                           boost::bind(&RecursiveQueryTest3::udpReceiveHandler,
Dima Volodin's avatar
Dima Volodin committed
535
536
537
538
539
540
541
542
543
544
                                               this, _1, _2));

    // Set up the TCP server and issue the accept.  Acceptance will cause the
    // read to be issued.
    tcp::acceptor acceptor(service_.get_io_service(),
                           tcp::endpoint(tcp::v4(), TEST_PORT3));
    acceptor.async_accept(tcp_socket_,
                          boost::bind(&RecursiveQueryTest3::tcpAcceptHandler,
                                      this, _1, 0));

Dima Volodin's avatar
Dima Volodin committed
545
546
    // Set up the RecursiveQuery object. We will also test that it correctly
    // records RTT times by setting up a RTT recorder object as well.
Dima Volodin's avatar
Dima Volodin committed
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
    std::vector<std::pair<std::string, uint16_t> > upstream;         // Empty
    std::vector<std::pair<std::string, uint16_t> > upstream_root;    // Empty
    RecursiveQuery query(dns_service_, *nsas_, cache_,
                         upstream, upstream_root);
    query.setTestServer(TEST_ADDRESS3, TEST_PORT3);

    boost::shared_ptr<RttRecorder> recorder(new RttRecorder());
    query.setRttRecorder(recorder);

    // Set up callback to receive notification that the query has completed.
    isc::resolve::ResolverInterface::CallbackPtr
        resolver_callback(new ResolverCallback3(service_));

    // Kick off the resolution process.
    expected_ = EDNS_UDP;
Jelte Jansen's avatar
Jelte Jansen committed
562
    running_query_ = query.resolve(question_, resolver_callback);
Dima Volodin's avatar
Dima Volodin committed
563
564
565
566
567
    service_.run();

    // Check what ran. (We have to cast the callback to ResolverCallback3 as we
    // lost the information on the derived class when we used a
    // ResolverInterface::CallbackPtr to store a pointer to it.)
Dima Volodin's avatar
Dima Volodin committed
568
569
    ResolverCallback3* rc
                    = static_cast<ResolverCallback3*>(resolver_callback.get());
Dima Volodin's avatar
Dima Volodin committed
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
    EXPECT_TRUE(rc->getRun());
    EXPECT_TRUE(rc->getStatus());

    // Finally, check that all the RTTs were "reasonable" (defined here as
    // being below 2 seconds).  This is an explicit check to test that the
    // variables in the RTT calculation are at least being initialized; if they
    // weren't, we would expect some absurdly high answers.
    vector<uint32_t> rtt = recorder->getRtt();
    EXPECT_GT(rtt.size(), 0);
    for (int i = 0; i < rtt.size(); ++i) {
        EXPECT_LT(rtt[i], 2000);
    }
}

} // namespace asiodns
} // namespace isc