nameserver_address_store_unittest.cc 21.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

15
/// \brief Nameserver Address Store Tests
16
///
17
/// This file contains tests for the nameserver address store as a whole.
18

19 20
#include <config.h>

21 22 23 24
#include <algorithm>
#include <cassert>
#include <string.h>
#include <vector>
Michal Vaner's avatar
Michal Vaner committed
25 26

#include <boost/foreach.hpp>
27 28 29
#include <boost/lexical_cast.hpp>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
30

31 32 33 34 35 36
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrset.h>
#include <dns/rrttl.h>

#include "../address_request_callback.h"
Michal Vaner's avatar
Michal Vaner committed
37 38
#include "../nameserver_address_store.h"
#include "../nameserver_entry.h"
39
#include "../nsas_entry_compare.h"
Michal Vaner's avatar
Michal Vaner committed
40
#include "../zone_entry.h"
41 42
#include "nsas_test.h"

Michal Vaner's avatar
Michal Vaner committed
43
using namespace isc::dns;
44
using namespace isc::util;
Michal Vaner's avatar
Michal Vaner committed
45
using namespace std;
Michal Vaner's avatar
Michal Vaner committed
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60
namespace isc {
namespace nsas {


/// \brief NSAS Store
///
/// This is a subclass of the NameserverAddressStore class, with methods to
/// access the internal members to check that the deleter objects are working.
class DerivedNsas : public NameserverAddressStore {
public:
    /// \brief Constructor
    ///
    /// \param hashsize Size of the zone hash table
    /// \param lrusize Size of the zone hash table
61
    DerivedNsas(boost::shared_ptr<TestResolver> resolver, uint32_t hashsize,
Michal Vaner's avatar
Michal Vaner committed
62
        uint32_t lrusize) :
63 64
        NameserverAddressStore(resolver, hashsize, lrusize),
        resolver_(resolver)
65 66 67 68 69 70
    {}

    /// \brief Virtual Destructor
    virtual ~DerivedNsas()
    {}

71 72 73
    /// \brief Add Nameserver Entry to hash and LRU tables
    ///
    /// \param entry Nameserver Entry to add.
74 75
    void AddNameserverEntry(boost::shared_ptr<NameserverEntry>& entry) {
        HashKey h = entry->hashKey();
76 77
        nameserver_hash_->add(entry, h);
        nameserver_lru_->add(entry);
78 79
    }

80 81 82
    /// \brief Add Zone Entry to hash and LRU tables
    ///
    /// \param entry Zone Entry to add.
83 84
    void AddZoneEntry(boost::shared_ptr<ZoneEntry>& entry) {
        HashKey h = entry->hashKey();
85 86
        zone_hash_->add(entry, h);
        zone_lru_->add(entry);
87
    }
88 89 90 91 92 93 94 95 96 97 98

    /// \brief Wrap the common lookup
    ///
    /// Calls the lookup and provides the authority section if it is asked
    /// for by the resolver.
    ///
    /// \param name Name of zone for which an address is required
    /// \param class_code Class of the zone
    /// \param authority Pointer to authority section RRset to which NS
    ///        records will be added.
    /// \param callback Callback object used to pass result back to caller
99
    void lookupAndAnswer(const string& name, const RRClass& class_code,
100 101
                         RRsetPtr authority,
                         boost::shared_ptr<AddressRequestCallback> callback)
102
    {
103
        // Note how many requests are in the resolver's queue
104
        size_t size(resolver_->requests.size());
105 106

        // Lookup the name.  This should generate a request for NS records.
107 108
        NameserverAddressStore::lookup(name, class_code, callback, ANY_OK);
        if (size < resolver_->requests.size()) {
109 110 111

            // It asked something, the only thing it can ask is the NS list.
            // Once answered, drop the request so no-one else sees it
112 113
            resolver_->provideNS(size, authority);
            resolver_->requests.erase(resolver_->requests.begin() + size);
114

115
        } else {
116 117 118 119

            // The test resolver's requests queue has not increased in size,
            // so the lookup did not generate a request.
            ADD_FAILURE() << "Lookup did not generate a request for NS records";
120 121
        }
    }
122

123
private:
124 125 126
    boost::shared_ptr<TestResolver> resolver_; 
                                ///< Resolver used to answer generated requests
};                                              
127 128 129 130



/// \brief Text Fixture Class
131
class NameserverAddressStoreTest : public TestWithRdata {
132 133
protected:

134
    /// \brief Constructor
Michal Vaner's avatar
Michal Vaner committed
135 136
    NameserverAddressStoreTest() :
        authority_(new RRset(Name("example.net."), RRClass::IN(), RRType::NS(),
137 138
            RRTTL(128))),
        empty_authority_(new RRset(Name("example.net."), RRClass::IN(),
139 140
            RRType::NS(), RRTTL(128))),
        resolver_(new TestResolver)
141
    {
142 143
        // Initialize a set of nameserver and zone objects.  For convenience,
        // these are stored in vectors.
144
        for (int i = 1; i <= 9; ++i) {
145 146 147 148
            std::string name = "nameserver" + boost::lexical_cast<std::string>(
                i);
            nameservers_.push_back(boost::shared_ptr<NameserverEntry>(
                new NameserverEntry(name, RRClass(40 + i))));
149 150
        }

151 152
        // Some zones. They will not use the tables in this test, so it can be
        // empty
153 154
        for (int i = 1; i <= 9; ++i) {
            std::string name = "zone" + boost::lexical_cast<std::string>(i);
155
            zones_.push_back(boost::shared_ptr<ZoneEntry>(new ZoneEntry(
156
                resolver_.get(), name, RRClass(40 + i),
157 158
                boost::shared_ptr<HashTable<NameserverEntry> >(),
                boost::shared_ptr<LruList<NameserverEntry> >())));
159
        }
Michal Vaner's avatar
Michal Vaner committed
160 161

        // A nameserver serving data
162 163
        authority_->addRdata(ConstRdataPtr(new rdata::generic::NS(Name(
            "ns.example.com."))));
Michal Vaner's avatar
Michal Vaner committed
164 165 166

        // This is reused because of convenience, clear it just in case
        NSASCallback::results.clear();
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
    /// \brief Internal callback object
    ///
    /// Callback object.  It just records whether the success() or
    /// unreachable() methods were called and if success, a copy of the
    /// Nameserver object. (The data is held in a static object that will
    /// outlive the lifetime of the callback object.)
    struct NSASCallback : public AddressRequestCallback {
        typedef pair<bool, NameserverAddress> Result;
        static vector<Result> results;

        virtual void success(const NameserverAddress& address) {
            results.push_back(Result(true, address));
        }
        virtual void unreachable() {
            results.push_back(Result(false, NameserverAddress()));
        }
    };

    /// \brief Return pointer to callback object
    boost::shared_ptr<AddressRequestCallback> getCallback() {
        return (boost::shared_ptr<AddressRequestCallback>(new NSASCallback));
    }

    // Member variables

194 195 196
    // Vector of pointers to nameserver and zone entries.
    std::vector<boost::shared_ptr<NameserverEntry> > nameservers_;
    std::vector<boost::shared_ptr<ZoneEntry> >       zones_;
Michal Vaner's avatar
Michal Vaner committed
197

198 199 200
    // Authority sections used in the tests
    RRsetPtr authority_;
    RRsetPtr empty_authority_;
Michal Vaner's avatar
Michal Vaner committed
201

202
    // ... and the resolver
203
    boost::shared_ptr<TestResolver> resolver_;
204 205
};

206
/// Definition of the static results object
Michal Vaner's avatar
Michal Vaner committed
207 208 209
vector<NameserverAddressStoreTest::NSASCallback::Result>
    NameserverAddressStoreTest::NSASCallback::results;

210 211 212

/// \brief Remove Zone Entry from Hash Table
///
213 214
/// Check that when an entry reaches the top of the zone LRU list, it is removed
/// from the hash table as well.
215 216
TEST_F(NameserverAddressStoreTest, ZoneDeletionCheck) {

217 218
    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone
    // and nameserver tables).
219
    DerivedNsas nsas(resolver_, 2, 2);
220

221 222 223
    // Add six entries to the tables.  After addition the reference count of
    // each element should be 3 - one for the entry in the zones_ vector, and
    // one each for the entries in the LRU list and hash table.
224 225 226 227 228 229
    for (int i = 1; i <= 6; ++i) {
        EXPECT_EQ(1, zones_[i].use_count());
        nsas.AddZoneEntry(zones_[i]);
        EXPECT_EQ(3, zones_[i].use_count());
    }

230 231 232
    // Adding another entry should cause the first one to drop off the LRU list,
    // which should also trigger the deletion of the entry from the hash table.
    //  This should reduce its use count to 1.
233 234 235 236 237 238 239 240 241 242
    EXPECT_EQ(1, zones_[7].use_count());
    nsas.AddZoneEntry(zones_[7]);
    EXPECT_EQ(3, zones_[7].use_count());

    EXPECT_EQ(1, zones_[1].use_count());
}


/// \brief Remove Entry from Hash Table
///
243 244
/// Check that when an entry reaches the top of the LRU list, it is removed from
/// the hash table as well.
245 246
TEST_F(NameserverAddressStoreTest, NameserverDeletionCheck) {

247 248
    // Create a NSAS with a hash size of three and a LRU size of 9 (both zone
    // and nameserver tables).
249
    DerivedNsas nsas(resolver_, 2, 2);
250

251 252 253
    // Add six entries to the tables.  After addition the reference count of
    // each element should be 3 - one for the entry in the nameservers_ vector,
    // and one each for the entries in the LRU list and hash table.
254 255 256 257 258 259
    for (int i = 1; i <= 6; ++i) {
        EXPECT_EQ(1, nameservers_[i].use_count());
        nsas.AddNameserverEntry(nameservers_[i]);
        EXPECT_EQ(3, nameservers_[i].use_count());
    }

260 261 262
    // Adding another entry should cause the first one to drop off the LRU list,
    // which should also trigger the deletion of the entry from the hash table.
    // This should reduce its use count to 1.
263 264 265 266 267 268 269
    EXPECT_EQ(1, nameservers_[7].use_count());
    nsas.AddNameserverEntry(nameservers_[7]);
    EXPECT_EQ(3, nameservers_[7].use_count());

    EXPECT_EQ(1, nameservers_[1].use_count());
}

270 271 272
/// \brief Try lookup on empty store.
///
/// Check if it asks correct questions and it keeps correct internal state.
Michal Vaner's avatar
Michal Vaner committed
273
TEST_F(NameserverAddressStoreTest, emptyLookup) {
274
    DerivedNsas nsas(resolver_, 10, 10);
275

Michal Vaner's avatar
Michal Vaner committed
276
    // Ask it a question
277 278
    nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
        getCallback());
279

280
    // It should ask for IP addresses for ns.example.com.
281
    EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
Michal Vaner's avatar
Michal Vaner committed
282 283

    // Ask another question for the same zone
284
    nsas.lookup("example.net.", RRClass::IN(), getCallback());
285

Michal Vaner's avatar
Michal Vaner committed
286
    // It should ask no more questions now
287
    EXPECT_EQ(2, resolver_->requests.size());
Michal Vaner's avatar
Michal Vaner committed
288 289 290

    // Ask another question with different zone but the same nameserver
    authority_->setName(Name("example.com."));
291 292
    nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_,
        getCallback());
293

Michal Vaner's avatar
Michal Vaner committed
294
    // It still should ask nothing
295
    EXPECT_EQ(2, resolver_->requests.size());
Michal Vaner's avatar
Michal Vaner committed
296 297 298

    // We provide IP address of one nameserver, it should generate all the
    // results
299 300
    EXPECT_NO_THROW(resolver_->answer(0, Name("ns.example.com."), RRType::A(),
        rdata::in::A("192.0.2.1")));
Michal Vaner's avatar
Michal Vaner committed
301 302 303
    EXPECT_EQ(3, NSASCallback::results.size());
    BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) {
        EXPECT_TRUE(result.first);
304
        EXPECT_EQ("192.0.2.1", result.second.getAddress().toText());
Michal Vaner's avatar
Michal Vaner committed
305 306 307
    }
}

308 309 310
/// \brief Try looking up a zone that does not have any nameservers.
///
/// It should not ask anything and say it is unreachable right away.
311
TEST_F(NameserverAddressStoreTest, zoneWithoutNameservers) {
312
    DerivedNsas nsas(resolver_, 10, 10);
313

314
    // Ask it a question
315 316
    nsas.lookupAndAnswer("example.net.", RRClass::IN(), empty_authority_,
        getCallback());
317

318
    // There should be no questions, because there's nothing to ask
319
    EXPECT_EQ(0, resolver_->requests.size());
320

Michal Vaner's avatar
Michal Vaner committed
321
    // And there should be one "unreachable" answer for the query
322 323 324 325
    ASSERT_EQ(1, NSASCallback::results.size());
    EXPECT_FALSE(NSASCallback::results[0].first);
}

326 327 328 329 330
/// \brief Try looking up a zone that has only an unreachable nameserver.
///
/// It should be unreachable. Furthermore, subsequent questions for that zone
/// or other zone with the same nameserver should be unreachable right away,
/// without further asking.
Michal Vaner's avatar
Michal Vaner committed
331
TEST_F(NameserverAddressStoreTest, unreachableNS) {
332
    DerivedNsas nsas(resolver_, 10, 10);
333

Michal Vaner's avatar
Michal Vaner committed
334
    // Ask it a question
335 336
    nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
        getCallback());
337

Michal Vaner's avatar
Michal Vaner committed
338
    // It should ask for IP addresses for example.com.
339
    EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
Michal Vaner's avatar
Michal Vaner committed
340 341 342

    // Ask another question with different zone but the same nameserver
    authority_->setName(Name("example.com."));
343 344
    nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_,
        getCallback());
345

Michal Vaner's avatar
Michal Vaner committed
346
    // It should ask nothing more now
347
    EXPECT_EQ(2, resolver_->requests.size());
Michal Vaner's avatar
Michal Vaner committed
348 349

    // We say there are no addresses
350 351
    resolver_->requests[0].second->failure();
    resolver_->requests[1].second->failure();
Michal Vaner's avatar
Michal Vaner committed
352 353 354

    // We should have 2 answers now
    EXPECT_EQ(2, NSASCallback::results.size());
355

Michal Vaner's avatar
Michal Vaner committed
356 357
    // When we ask one same and one other zone with the same nameserver,
    // it should generate no questions and answer right away
358
    nsas.lookup("example.net.", RRClass::IN(), getCallback());
359
    authority_->setName(Name("example.org."));
360 361
    nsas.lookupAndAnswer("example.org.", RRClass::IN(), authority_,
        getCallback());
362

Michal Vaner's avatar
Michal Vaner committed
363 364 365 366 367 368 369
    // There should be 4 negative answers now
    EXPECT_EQ(4, NSASCallback::results.size());
    BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) {
        EXPECT_FALSE(result.first);
    }
}

370 371 372 373
/// \short Try to stress it little bit by having multiple zones and nameservers.
///
/// Does some asking, on a set of zones that share some nameservers, with
/// slower answering, evicting data, etc.
374
TEST_F(NameserverAddressStoreTest, CombinedTest) {
375

376 377
    // Create small caches, so we get some evictions
    DerivedNsas nsas(resolver_, 1, 1);
378

379 380 381
    // Ask for example.net. It has single nameserver out of the zone
    nsas.lookupAndAnswer("example.net.", RRClass::IN(), authority_,
        getCallback());
382

383 384 385
    // It should ask for the nameserver IP addresses
    EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), 0, 1));
    EXPECT_EQ(0, NSASCallback::results.size());
386

387 388 389 390
    // But we do not answer it right away. We create a new zone and
    // let this nameserver entry get out.
    rrns_->addRdata(rdata::generic::NS("example.cz"));
    nsas.lookupAndAnswer(EXAMPLE_CO_UK, RRClass::IN(), rrns_, getCallback());
391

392 393 394 395 396 397 398 399 400 401
    // It really should ask something, one of the nameservers
    // (or both)
    ASSERT_GT(resolver_->requests.size(), 2);
    Name name(resolver_->requests[2].first->getName());
    EXPECT_TRUE(name == Name("example.fr") || name == Name("example.de") ||
        name == Name("example.cz"));
    EXPECT_NO_THROW(resolver_->asksIPs(name, 2, 3));
    EXPECT_EQ(0, NSASCallback::results.size());

    // This should still be in the hash table, so try it asks no more questions
402
    size_t request_count(resolver_->requests.size());
403 404 405 406 407 408 409
    nsas.lookup("example.net.", RRClass::IN(), getCallback());
    EXPECT_EQ(request_count, resolver_->requests.size());
    EXPECT_EQ(0, NSASCallback::results.size());

    // We respond to one of the 3 nameservers
    EXPECT_NO_THROW(resolver_->answer(2, name, RRType::A(),
        rdata::in::A("192.0.2.1")));
410

411 412 413
    // That should trigger one answer
    EXPECT_EQ(1, NSASCallback::results.size());
    EXPECT_TRUE(NSASCallback::results[0].first);
414 415
    EXPECT_EQ("192.0.2.1",
        NSASCallback::results[0].second.getAddress().toText());
416 417
    EXPECT_NO_THROW(resolver_->answer(3, name, RRType::AAAA(),
        rdata::in::AAAA("2001:bd8::1")));
418

419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    // And there should be yet another query
    ASSERT_GT(resolver_->requests.size(), 4);
    EXPECT_NE(name, resolver_->requests[4].first->getName());
    Name another_name = resolver_->requests[4].first->getName();
    EXPECT_TRUE(another_name == Name("example.fr") ||
        another_name == Name("example.de") ||
        another_name == Name("example.cz"));
    request_count = resolver_->requests.size();

    // But when ask for a different zone with the first nameserver, it should
    // ask again, as it is evicted already
    authority_->setName(Name("example.com."));
    nsas.lookupAndAnswer("example.com.", RRClass::IN(), authority_,
        getCallback());
    EXPECT_EQ(request_count + 2, resolver_->requests.size());
    EXPECT_NO_THROW(resolver_->asksIPs(Name("ns.example.com."), request_count,
        request_count + 1));
436 437 438

    // Now, we answer both queries for the same address and three (one for the
    // original, one for this one) more answers should arrive
439 440 441 442 443 444 445 446
    NSASCallback::results.clear();
    EXPECT_NO_THROW(resolver_->answer(0, Name("ns.example.com."), RRType::A(),
        rdata::in::A("192.0.2.2")));
    EXPECT_NO_THROW(resolver_->answer(request_count, Name("ns.example.com."),
        RRType::A(), rdata::in::A("192.0.2.2")));
    EXPECT_EQ(3, NSASCallback::results.size());
    BOOST_FOREACH(const NSASCallback::Result& result, NSASCallback::results) {
        EXPECT_TRUE(result.first);
447
        EXPECT_EQ("192.0.2.2", result.second.getAddress().toText());
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
// Check that we can update the RTT associated with nameservers successfully.
// Also checks that we can't set the RTT to zero (which would cause problems
// with selection algorithm).
TEST_F(NameserverAddressStoreTest, updateRTT) {

    // Initialization.
    string  zone_name = "example.net.";
    string  ns_name = "ns.example.com."; 
    vector<string> address;
    address.push_back("192.0.2.1");
    address.push_back("192.0.2.2");

    uint32_t HIGH_RTT = 10000;  // 1E4; When squared, the result fits in 32 bits

    DerivedNsas nsas(resolver_, 103, 107);   // Arbitrary cache sizes

    // Ensure that location holding the addresses returned is empty.  We'll
    // be using this throughout the tests.  As the full name is a bit of a
    // mouthful, set up an alias.
    vector<NameserverAddressStoreTest::NSASCallback::Result>& results =
        NameserverAddressStoreTest::NSASCallback::results;
    results.clear();

    // Initialize the test resolver with the answer for the A record query
    // for ns.example.com (the nameserver set for example.net in the class
    // initialization).  We'll set two addresses.
    Name ns_example_com(ns_name);
478
    isc::dns::RRsetPtr ns_address = boost::shared_ptr<RRset>(new RRset(
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 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
        ns_example_com, RRClass::IN(), RRType::A(), RRTTL(300)));
    BOOST_FOREACH(string addr, address) {
        ns_address->addRdata(rdata::in::A(addr));
    }

    // All set.  Ask for example.net.
    boost::shared_ptr<AddressRequestCallback> callback = getCallback();
    nsas.lookupAndAnswer(zone_name, RRClass::IN(), authority_, getCallback());

    // This should generate two requests - one for A and one for AAAA.
    EXPECT_EQ(2, resolver_->requests.size());

    // Provide an answer that has two A records.  This should generate one
    // result.
    EXPECT_NO_THROW(resolver_->answer(0, ns_address));
    EXPECT_EQ(1, results.size());

    // We expect the lookup to be successful.  Check that the address is one of
    // the two we've set and that the RTT associated with this nameserver is
    // non-zero.
    EXPECT_EQ(true, results[0].first);
    vector<string>::iterator addr1 = find(address.begin(), address.end(),
                                     results[0].second.getAddress().toText());
    EXPECT_TRUE(addr1 != address.end());

    // The RTT we got should be non-zero and less than the high value we are
    // using for the test.
    uint32_t rtt1 = results[0].second.getAddressEntry().getRTT();
    EXPECT_NE(0, rtt1);
    EXPECT_LT(rtt1, HIGH_RTT);

    // Update the address with a very high RTT.  Owning to the way the NSAS is
    // written, we can update the RTT but cannot read the new value back from
    // the new object.  
    results[0].second.updateRTT(HIGH_RTT);

    // Get another nameserver.  As the probability of returning a particular
    // address is proporational to 1/t^2, we should get the second address
    // since the first now has a larger RTT.  However, this is not guaranteed
    // - this is a probability (albeit small) of getting the first again. We'll
    // allow three chances of getting the "wrong" address before we declare
    // an error.
    int attempt = 0;
    vector<string>::iterator addr2 = addr1;
    for (attempt = 0; (attempt < 3) && (*addr1 == *addr2); ++attempt) {
        results.clear();
        nsas.lookup(zone_name, RRClass::IN(), 
                             getCallback(), ANY_OK);
        addr2 = find(address.begin(), address.end(),
                     results[0].second.getAddress().toText());
    }
    EXPECT_LT(attempt, 3);

    // Ensure that the RTT is non-zero.
    // obtained earlier.
    uint32_t rtt2 = results[0].second.getAddressEntry().getRTT();
    EXPECT_NE(0, rtt2);

    // The test has shown that the code can return the two nameservers.  Now
    // try to set the RTT for the last one returned to zero.  As there is a
    // smoothing effect in the calculations which damps out an abrupt change
    // in the RTT, the underlying RTT will not be set to zero immediately.  So
    // loop a large number of times, each time setting it to zero.
    //
    // Between each setting of the RTT, we have to retrieve the nameserver from
    // the NSAS again.  This means that we _could_ occasionally get the address
    // of the one whose RTT we have raised to HIGH_RTT.  We overcome this by
    // looping a _very_ large number of times.  Ultimately the RTT of both
    // addresses should decay to a small value.
    for (int i = 0; i < 2000; ++i) {   // 1000 times for each nameserver
        results.clear();
        nsas.lookup(zone_name, RRClass::IN(), getCallback(), ANY_OK);
        EXPECT_EQ(1, results.size());
        uint32_t rtt3 = results[0].second.getAddressEntry().getRTT();
        EXPECT_NE(0, rtt3);
        results[0].second.updateRTT(0);
    }
}


559 560
} // namespace nsas
} // namespace isc