// 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$ #include #include #include #include #include "../asiolink.h" #include "../zone_entry.h" #include "../nameserver_entry.h" #include "../address_request_callback.h" #include "../nsas_entry_compare.h" #include "../hash_deleter.h" #include "nsas_test.h" using namespace isc::nsas; using namespace asiolink; using namespace std; using namespace boost; using namespace isc::dns; namespace { /// \brief Inherited version with access into its internals for tests class InheritedZoneEntry : public ZoneEntry { public: InheritedZoneEntry(shared_ptr resolver, const std::string& name, const RRClass& class_code, shared_ptr > nameserver_table, shared_ptr > nameserver_lru) : ZoneEntry(resolver, name, class_code, nameserver_table, nameserver_lru) { } NameserverVector& nameservers() { return nameservers_; } }; /// \brief Test Fixture Class class ZoneEntryTest : public TestWithRdata { protected: /// \brief Constructor ZoneEntryTest() : nameserver_table_(new HashTable( new NsasEntryCompare)), nameserver_lru_(new LruList( (3 * nameserver_table_->tableSize()), new HashDeleter(*nameserver_table_))), resolver_(new TestResolver), callback_(new Callback) { } /// \brief Tables of nameservers to pass into zone entry constructor shared_ptr > nameserver_table_; shared_ptr > nameserver_lru_; /// \brief The resolver shared_ptr resolver_; /** * \short A callback we use into the zone. * * It counts failures and stores successufll results. */ struct Callback : public AddressRequestCallback { Callback() : unreachable_count_(0) {} size_t unreachable_count_; vector successes_; virtual void unreachable() { unreachable_count_ ++; } virtual void success(const IOAddress& address) { successes_.push_back(address); } }; shared_ptr callback_; // Empty callback to pass to nameserver entry, to do injection of them struct NseCallback : public NameserverEntry::Callback { virtual void operator()(shared_ptr) { } }; shared_ptr nseCallback() { return (shared_ptr(new NseCallback)); } /** * \short Function returning a new zone. * * Convenience funcion, just creating a new zone, to shorten the code. */ shared_ptr getZone() { return (shared_ptr(new InheritedZoneEntry( resolver_, EXAMPLE_CO_UK, RRClass::IN(), nameserver_table_, nameserver_lru_))); } /** * \short Creates and injects a NameserverEntry * * This is used by few tests checking it works when the nameserver * hash table already contains the NameserverEntry. This function * creates one and puts it into the hash table. */ shared_ptr injectEntry() { shared_ptr nse(new NameserverEntry(ns_name_.toText(), RRClass::IN())); nameserver_table_->add(nse, HashKey(ns_name_.toText(), RRClass::IN())); EXPECT_EQ(Fetchable::NOT_ASKED, nse->getState()); return (nse); } /** * \short Common part of few tests. * * All the tests NameserverEntryReady, NameserverEntryNotAsked, * NameserverEntryInProgress, NameserverEntryExpired, * NameserverEntryUnreachable check that it does not break * when the nameserver hash table already contains the nameserver * in one of the Fetchable::State. * * All the tests prepare the NameserverEntry and then call this * to see if the zone really works. This asks and checks if it * asks for the IP addresses or not and if it succeeds or fails. * * \param answer Should it ask for IP addresses of the nameserver? * If not, it expects it already asked during the preparation * (therefore the request count in resolver is 2). * \param success_count How many callbacks to the zone should * succeed. * \param failure_count How many callbacks to the zone should * fail. */ void checkInjected(bool answer, size_t success_count = 1, size_t failure_count = 0) { // Create the zone and check it acts correctly shared_ptr zone(getZone()); resolver_->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS()), rr_single_); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(2, resolver_->requests.size()); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 0, 1)); if (answer) { EXPECT_NO_THROW(resolver_->answer(0, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"))); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"))); } // Check the answers EXPECT_EQ(Fetchable::READY, zone->getState()); EXPECT_EQ(failure_count, callback_->unreachable_count_); EXPECT_EQ(success_count, callback_->successes_.size()); for (size_t i = 0; i < callback_->successes_.size(); ++ i) { EXPECT_TRUE(IOAddress("192.0.2.1").equal( callback_->successes_[i]) || IOAddress("2001:db8::1").equal( callback_->successes_[i])); } } }; /// Tests of the default constructor TEST_F(ZoneEntryTest, DefaultConstructor) { // Default constructor should not create any RRsets InheritedZoneEntry alpha(resolver_, EXAMPLE_CO_UK, RRClass::IN(), nameserver_table_, nameserver_lru_); EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName()); EXPECT_EQ(RRClass::IN(), alpha.getClass()); EXPECT_TRUE(alpha.nameservers().empty()); } /** * \short Test with no nameservers. * * When we create a zone that does not have any nameservers, * it should return failures right away (eg. no queries to nameservers * should be generated anywhere and the failure should be provided). */ TEST_F(ZoneEntryTest, CallbackNoNS) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); // feed it with a callback zone->addCallback(callback_, ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); // Give it the (empty) nameserver list EXPECT_NO_THROW(resolver_->provideNS(0, rr_empty_)); // It should tell us it is unreachable. EXPECT_TRUE(callback_->successes_.empty()); EXPECT_EQ(1, callback_->unreachable_count_); } /** * \short Test how the zone behaves when the list of nameserves change. * * We use TTL of 0, so it asks every time for new list of nameservers. * This allows us to pass a different list each time. * * So, this implicitly tests that it behaves correctly with 0 TTL as well, * it means that it answers even with 0 TTL and that it answers only * one query (or, all queries queued at that time). * * We change the list twice, to see it can ask for another nameserver and * then to see if it can return to the previous (already cached) nameserver. */ TEST_F(ZoneEntryTest, ChangedNS) { // Make it zero TTL, so it expires right away rr_single_->setTTL(RRTTL(0)); shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); // Feed it with callback zone->addCallback(callback_, ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); EXPECT_NO_THROW(resolver_->provideNS(0, rr_single_)); // It should not be answered yet, it should ask for the IP addresses // (trough the NameserverEntry there) EXPECT_TRUE(callback_->successes_.empty()); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 1, 2)); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"))); ASSERT_EQ(1, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0])); EXPECT_NO_THROW(resolver_->answer(2, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"))); EXPECT_EQ(1, callback_->successes_.size()); // It should request the NSs again, as TTL is 0 zone->addCallback(callback_, ANY_OK); EXPECT_EQ(4, resolver_->requests.size()); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); Name different_name("ns.example.com"); // Create a different answer RRsetPtr different_ns(new RRset(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS(), RRTTL(0))); different_ns->addRdata(rdata::generic::NS(different_name)); EXPECT_NO_THROW(resolver_->provideNS(3, different_ns)); // It should become ready and ask for the new nameserver addresses EXPECT_EQ(Fetchable::READY, zone->getState()); // Answer one of the IP addresses, we should get an address now EXPECT_TRUE(resolver_->asksIPs(different_name, 4, 5)); EXPECT_NO_THROW(resolver_->answer(4, different_name, RRType::A(), rdata::in::A("192.0.2.2"))); ASSERT_EQ(2, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.2").equal(callback_->successes_[1])); // And now, switch back, as it timed out again zone->addCallback(callback_, ANY_OK); EXPECT_EQ(7, resolver_->requests.size()); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); // When we answer with the original, it should still be cached and // we should get the answer EXPECT_NO_THROW(resolver_->provideNS(0, rr_single_)); EXPECT_EQ(7, resolver_->requests.size()); EXPECT_EQ(Fetchable::READY, zone->getState()); ASSERT_EQ(3, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0])); } /** * \short Check it works when everything is answered. * * This test emulates a situation when all queries for NS rrsets and * IP addresses (of the NameserverEntry objects inside) are answered * positively. All the callbacks should be called and answer to them * provided. */ TEST_F(ZoneEntryTest, CallbacksAnswered) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); // Feed it with a callback zone->addCallback(callback_, ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); EXPECT_NO_THROW(resolver_->provideNS(0, rr_single_)); // It should not be answered yet, its NameserverEntry should ask for the // IP addresses EXPECT_TRUE(callback_->successes_.empty()); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 1, 2)); // We should be READY, as it marks we have nameservers // (not that they are ready) EXPECT_EQ(Fetchable::READY, zone->getState()); // Give two more callbacks, with different address families zone->addCallback(callback_, V4_ONLY); zone->addCallback(callback_, V6_ONLY); // Nothing more is asked EXPECT_EQ(3, resolver_->requests.size()); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"))); // Two are answered (ANY and V4) ASSERT_EQ(2, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0])); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[1])); // None are rejected EXPECT_EQ(0, callback_->unreachable_count_); // Answer the IPv6 one as well EXPECT_NO_THROW(resolver_->answer(2, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"))); // This should answer the third callback EXPECT_EQ(0, callback_->unreachable_count_); ASSERT_EQ(3, callback_->successes_.size()); EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[2])); // It should think it is ready EXPECT_EQ(Fetchable::READY, zone->getState()); // When we ask something more, it should be answered right away zone->addCallback(callback_, V4_ONLY); EXPECT_EQ(3, resolver_->requests.size()); ASSERT_EQ(4, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[3])); EXPECT_EQ(0, callback_->unreachable_count_); } /** * \short Test zone reachable only on IPv4. * * This test simulates a zone with its nameservers reachable only * over IPv4. It means we answer the NS query, the A query, but * we generate a failure for AAAA. * * The callbacks asking for any address and IPv4 address should be * called successfully, while the ones asking for IPv6 addresses should * fail. */ TEST_F(ZoneEntryTest, CallbacksAOnly) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); EXPECT_NO_THROW(resolver_->provideNS(0, rr_single_)); // It should not be answered yet, it should ask for the IP addresses EXPECT_TRUE(callback_->successes_.empty()); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 1, 2)); EXPECT_EQ(Fetchable::READY, zone->getState()); // Give two more callbacks, with different address families zone->addCallback(callback_, V4_ONLY); zone->addCallback(callback_, V6_ONLY); ASSERT_GE(resolver_->requests.size(), 3); // We tell its NameserverEntry we can't get IPv6 address resolver_->requests[2].second->failure(); // One should be rejected (V6_ONLY one), but two still stay EXPECT_EQ(0, callback_->successes_.size()); EXPECT_EQ(1, callback_->unreachable_count_); // Answer the A one and see it answers what can be answered EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"))); ASSERT_EQ(2, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0])); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[1])); EXPECT_EQ(1, callback_->unreachable_count_); // Everything arriwed, so we are ready EXPECT_EQ(Fetchable::READY, zone->getState()); // Try asking something more and see it asks no more zone->addCallback(callback_, V4_ONLY); EXPECT_EQ(3, resolver_->requests.size()); ASSERT_EQ(3, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[2])); EXPECT_EQ(1, callback_->unreachable_count_); zone->addCallback(callback_, V6_ONLY); EXPECT_EQ(3, resolver_->requests.size()); EXPECT_EQ(3, callback_->successes_.size()); EXPECT_EQ(2, callback_->unreachable_count_); } /** * \short Test with unreachable and v6-reachable nameserver. * * In this test we have a zone with two nameservers. The first one of them * is unreachable, it will not have any addresses. We check that the ZoneEntry * is patient and asks and waits for the second one and then returns the * (successful) answers to us. */ TEST_F(ZoneEntryTest, CallbackTwoNS) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); zone->addCallback(callback_, V4_ONLY); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); EXPECT_NO_THROW(resolver_->provideNS(0, rrns_)); EXPECT_EQ(Fetchable::READY, zone->getState()); // It asks a question (we do not know which nameserver) shared_ptr name; ASSERT_NO_THROW(name.reset(new Name((*resolver_)[1]->getName()))); ASSERT_TRUE(resolver_->asksIPs(*name, 1, 2)); resolver_->requests[1].second->failure(); // Nothing should be answered or failed yet, there's second one EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_EQ(0, callback_->successes_.size()); ASSERT_TRUE(resolver_->asksIPs((*resolver_)[3]->getName(), 3, 4)); // Fail the second one resolver_->requests[3].second->failure(); // The callback should be failed now, as there is no chance of getting // v4 address EXPECT_EQ(1, callback_->unreachable_count_); EXPECT_EQ(0, callback_->successes_.size()); // And question for v6 or any should still wait while v4 should be failed // right away zone->addCallback(callback_, V6_ONLY); EXPECT_EQ(1, callback_->unreachable_count_); EXPECT_EQ(0, callback_->successes_.size()); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(1, callback_->unreachable_count_); EXPECT_EQ(0, callback_->successes_.size()); zone->addCallback(callback_, V4_ONLY); EXPECT_EQ(2, callback_->unreachable_count_); EXPECT_EQ(0, callback_->successes_.size()); // Answer the IPv6 one EXPECT_NO_THROW(resolver_->answer(2, (*resolver_)[2]->getName(), RRType::AAAA(), rdata::in::AAAA("2001:db8::1"))); // Ready, as we have at last some address EXPECT_EQ(Fetchable::READY, zone->getState()); // The other callbacks should be answered now EXPECT_EQ(2, callback_->unreachable_count_); ASSERT_EQ(2, callback_->successes_.size()); EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[0])); EXPECT_TRUE(IOAddress("2001:db8::1").equal(callback_->successes_[1])); } /** * \short This test checks it works with answers from cache. * * The resolver might provide the answer by calling the callback both sometime * later or directly from its resolve method, causing recursion back inside * the ZoneEntry. This test checks it works even in the second case (eg. that * the ZoneEntry is able to handle callback called directly from the * resolve). Tries checking both positive and negative answers. */ TEST_F(ZoneEntryTest, DirectAnswer) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); // One unsuccessfull attempt, nameservers fail resolver_->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS()), shared_ptr()); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(0, callback_->successes_.size()); EXPECT_EQ(1, callback_->unreachable_count_); EXPECT_EQ(0, resolver_->requests.size()); EXPECT_EQ(Fetchable::UNREACHABLE, zone->getState()); // Successfull attempt now zone = getZone(); // First, fill the answers to all the questions it should ask EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); resolver_->addPresetAnswer(Question(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS()), rr_single_); Name ns_name("ns.example.net"); rrv4_->setName(ns_name); resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(), RRType::A()), rrv4_); rrv6_->setName(ns_name); resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(), RRType::AAAA()), rrv6_); // Reset the results callback_->unreachable_count_ = 0; // Ask for the IP address zone->addCallback(callback_, ANY_OK); // It should be answered right away, positively EXPECT_EQ(1, callback_->successes_.size()); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_EQ(0, resolver_->requests.size()); EXPECT_EQ(Fetchable::READY, zone->getState()); // Reset the results callback_->successes_.clear(); // Now, pretend we do not have IP addresses resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(), RRType::A()), shared_ptr()); resolver_->addPresetAnswer(Question(ns_name, RRClass::IN(), RRType::AAAA()), shared_ptr()); // Get another zone and ask it again. It should fail. // Clean the table first, though, so it does not find the old nameserver nameserver_table_->remove(HashKey(ns_name.toText(), RRClass::IN())); zone = getZone(); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(0, callback_->successes_.size()); EXPECT_EQ(1, callback_->unreachable_count_); EXPECT_EQ(0, resolver_->requests.size()); // It should be ready, but have no IP addresses on the nameservers EXPECT_EQ(Fetchable::READY, zone->getState()); } /** * \short Test it works with timeouting NameserverEntries. * * In this test we have a zone with nameserver addresses at TTL 0. * So, the NameserverEntry expires each time the ZoneEntry tries to get * its addresses and must ask it again. */ TEST_F(ZoneEntryTest, AddressTimeout) { shared_ptr zone(getZone()); EXPECT_EQ(Fetchable::NOT_ASKED, zone->getState()); zone->addCallback(callback_, ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, zone->getState()); EXPECT_NO_THROW(resolver_->provideNS(0, rr_single_)); // It should not be answered yet, it should ask for the IP addresses EXPECT_TRUE(callback_->successes_.empty()); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 1, 2)); // We should be READY, as it marks we have nameservers // (not that they are ready) EXPECT_EQ(Fetchable::READY, zone->getState()); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"), 0)); // It answers, not rejects ASSERT_EQ(1, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[0])); EXPECT_EQ(0, callback_->unreachable_count_); // As well with IPv6 EXPECT_NO_THROW(resolver_->answer(2, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"), 0)); EXPECT_EQ(1, callback_->successes_.size()); EXPECT_EQ(Fetchable::READY, zone->getState()); // When we ask for another one, it should ask for the addresses again zone->addCallback(callback_, ANY_OK); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 3, 4)); EXPECT_EQ(0, callback_->unreachable_count_); EXPECT_EQ(1, callback_->successes_.size()); EXPECT_NO_THROW(resolver_->answer(3, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"), 0)); EXPECT_EQ(0, callback_->unreachable_count_); ASSERT_EQ(2, callback_->successes_.size()); EXPECT_TRUE(IOAddress("192.0.2.1").equal(callback_->successes_[1])); } /** * \short Injection tests. * * These tests check the ZoneEntry does not break when the nameserver hash * table already contains a NameserverEntry in some given state. Each test * for a different state. */ //@{ /// \short Test how the zone reacts to a nameserver entry in ready state TEST_F(ZoneEntryTest, NameserverEntryReady) { // Inject the entry shared_ptr nse(injectEntry()); // Fill it with data nse->askIP(resolver_, nseCallback(), ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, nse->getState()); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 0, 1)); EXPECT_NO_THROW(resolver_->answer(0, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"))); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"))); EXPECT_EQ(Fetchable::READY, nse->getState()); checkInjected(false); } /// \short Test how the zone reacts to a nameserver in not asked state TEST_F(ZoneEntryTest, NameserverEntryNotAsked) { // Inject the entry injectEntry(); // We do not need it, nothing to modify on it checkInjected(true); } /// \short What if the zone finds a nameserver in progress? TEST_F(ZoneEntryTest, NameserverEntryInProgress) { // Prepare the nameserver entry shared_ptr nse(injectEntry()); nse->askIP(resolver_, nseCallback(), ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, nse->getState()); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 0, 1)); checkInjected(true); } /// \short Check Zone's reaction to found expired nameserver TEST_F(ZoneEntryTest, NameserverEntryExpired) { shared_ptr nse(injectEntry()); nse->askIP(resolver_, nseCallback(), ANY_OK); EXPECT_EQ(Fetchable::IN_PROGRESS, nse->getState()); EXPECT_TRUE(resolver_->asksIPs(ns_name_, 0, 1)); EXPECT_NO_THROW(resolver_->answer(0, ns_name_, RRType::A(), rdata::in::A("192.0.2.1"), 0)); EXPECT_NO_THROW(resolver_->answer(1, ns_name_, RRType::AAAA(), rdata::in::AAAA("2001:db8::1"), 0)); EXPECT_EQ(Fetchable::READY, nse->getState()); NameserverEntry::AddressVector addresses; EXPECT_EQ(Fetchable::EXPIRED, nse->getAddresses(addresses)); EXPECT_EQ(Fetchable::EXPIRED, nse->getState()); resolver_->requests.clear(); checkInjected(true); } /// \short Check how it reacts to an unreachable zone already in the table TEST_F(ZoneEntryTest, NameserverEntryUnreachable) { shared_ptr nse(injectEntry()); nse->askIP(resolver_, nseCallback(), ANY_OK); ASSERT_EQ(2, resolver_->requests.size()); resolver_->requests[0].second->failure(); resolver_->requests[1].second->failure(); EXPECT_EQ(Fetchable::UNREACHABLE, nse->getState()); checkInjected(false, 0, 1); } //@} } // namespace