Browse Source

Some tests for ZoneEntry

Does not link, more tests needed.

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac408@3634 e5f2f494-b856-4b98-b285-d166d9295462
Michal Vaner 14 years ago
parent
commit
acdf418345

+ 4 - 3
src/lib/nsas/nameserver_address_store.h

@@ -83,7 +83,7 @@ public:
     /// value of 2003 is the first prime number over 2000, and by implication,
     /// value of 2003 is the first prime number over 2000, and by implication,
     /// there is an assumption that there will be more nameservers than zones
     /// there is an assumption that there will be more nameservers than zones
     /// in the store.
     /// in the store.
-    NameserverAddressStore(ResolverInterface& resolver,
+    NameserverAddressStore(boost::shared_ptr<ResolverInterface> resolver,
         uint32_t zonehashsize = 1009, uint32_t nshashsize = 3001);
         uint32_t zonehashsize = 1009, uint32_t nshashsize = 3001);
 
 
     /// \brief Destructor
     /// \brief Destructor
@@ -92,6 +92,7 @@ public:
     virtual ~NameserverAddressStore()
     virtual ~NameserverAddressStore()
     {}
     {}
 
 
+    // TODO Drop zone and class code, they can be found out from the authority
     /// \brief Lookup Address for a Zone
     /// \brief Lookup Address for a Zone
     ///
     ///
     /// Looks up the address of a nameserver in the zone.
     /// Looks up the address of a nameserver in the zone.
@@ -107,7 +108,7 @@ public:
     /// \param request Which address is requested.
     /// \param request Which address is requested.
     void lookup(const std::string& zone, uint16_t class_code,
     void lookup(const std::string& zone, uint16_t class_code,
         const isc::dns::AbstractRRset& authority,
         const isc::dns::AbstractRRset& authority,
-        const std::vector<isc::dns::AbstractRRset>& additional,
+        const std::vector<const isc::dns::AbstractRRset*>& additional,
         boost::shared_ptr<AddressRequestCallback> callback, AddressRequest
         boost::shared_ptr<AddressRequestCallback> callback, AddressRequest
         request = ANY_OK);
         request = ANY_OK);
 
 
@@ -132,7 +133,7 @@ protected:
     LruList<NameserverEntry>    nameserver_lru_;
     LruList<NameserverEntry>    nameserver_lru_;
     //}@
     //}@
 private:
 private:
-    ResolverInterface& resolver_;
+    boost::shared_ptr<ResolverInterface> resolver_;
 };
 };
 
 
 } // namespace nsas
 } // namespace nsas

+ 4 - 4
src/lib/nsas/nameserver_entry.cc

@@ -432,18 +432,18 @@ class NameserverEntry::ResolverCallback : public ResolverInterface::Callback {
 };
 };
 
 
 void
 void
-NameserverEntry::askIP(ResolverInterface& resolver, const RRType& type,
-    AddressFamily family, shared_ptr<NameserverEntry> self)
+NameserverEntry::askIP(shared_ptr<ResolverInterface> resolver,
+    const RRType& type, AddressFamily family, shared_ptr<NameserverEntry> self)
 {
 {
     QuestionPtr question(new Question(Name(getName()), RRClass(getClass()),
     QuestionPtr question(new Question(Name(getName()), RRClass(getClass()),
          type));
          type));
     shared_ptr<ResolverCallback> callback(new ResolverCallback(self, family,
     shared_ptr<ResolverCallback> callback(new ResolverCallback(self, family,
          type));
          type));
-    resolver.resolve(question, callback);
+    resolver->resolve(question, callback);
 }
 }
 
 
 void
 void
-NameserverEntry::askIP(ResolverInterface& resolver,
+NameserverEntry::askIP(shared_ptr<ResolverInterface> resolver,
     shared_ptr<Callback> callback, AddressFamily family,
     shared_ptr<Callback> callback, AddressFamily family,
     shared_ptr<NameserverEntry> self)
     shared_ptr<NameserverEntry> self)
 {
 {

+ 3 - 2
src/lib/nsas/nameserver_entry.h

@@ -224,7 +224,7 @@ public:
      *     even when there are addresses, if there are no addresses for this
      *     even when there are addresses, if there are no addresses for this
      *     family.
      *     family.
      */
      */
-    void askIP(ResolverInterface& resolver,
+    void askIP(boost::shared_ptr<ResolverInterface> resolver,
         boost::shared_ptr<Callback> callback, AddressFamily family,
         boost::shared_ptr<Callback> callback, AddressFamily family,
         boost::shared_ptr<NameserverEntry> self);
         boost::shared_ptr<NameserverEntry> self);
     //@}
     //@}
@@ -248,7 +248,8 @@ private:
         CallbackPair;
         CallbackPair;
     std::vector<CallbackPair> callbacks_;
     std::vector<CallbackPair> callbacks_;
     /// \short Private version that does the actual asking of one address type
     /// \short Private version that does the actual asking of one address type
-    void askIP(ResolverInterface&, const isc::dns::RRType&, AddressFamily,
+    void askIP(boost::shared_ptr<ResolverInterface> resolver,
+        const isc::dns::RRType&, AddressFamily,
         boost::shared_ptr<NameserverEntry>);
         boost::shared_ptr<NameserverEntry>);
 };
 };
 
 

+ 1 - 1
src/lib/nsas/tests/Makefile.am

@@ -28,7 +28,7 @@ run_unittests_SOURCES += nameserver_address_unittest.cc
 run_unittests_SOURCES += nameserver_entry_unittest.cc
 run_unittests_SOURCES += nameserver_entry_unittest.cc
 run_unittests_SOURCES += nsas_entry_compare_unittest.cc
 run_unittests_SOURCES += nsas_entry_compare_unittest.cc
 run_unittests_SOURCES += nsas_test.h
 run_unittests_SOURCES += nsas_test.h
-#run_unittests_SOURCES += zone_entry_unittest.cc
+run_unittests_SOURCES += zone_entry_unittest.cc
 run_unittests_SOURCES += fetchable_unittest.cc
 run_unittests_SOURCES += fetchable_unittest.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)

+ 15 - 75
src/lib/nsas/tests/nameserver_entry_unittest.cc

@@ -37,77 +37,18 @@
 
 
 #include "nsas_test.h"
 #include "nsas_test.h"
 
 
+using namespace isc::nsas;
 using namespace asiolink;
 using namespace asiolink;
 using namespace std;
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace rdata;
 using namespace rdata;
 using namespace boost;
 using namespace boost;
 
 
-namespace isc {
-namespace nsas {
-
-// String constants.  These should end in a dot.
-static const std::string EXAMPLE_CO_UK("example.co.uk.");
-static const std::string EXAMPLE_NET("example.net.");
-static const std::string MIXED_EXAMPLE_CO_UK("EXAmple.co.uk.");
+namespace {
 
 
 /// \brief Test Fixture Class
 /// \brief Test Fixture Class
-class NameserverEntryTest : public ::testing::Test {
+class NameserverEntryTest : public TestWithRdata {
 protected:
 protected:
-
-    /// \brief Constructor
-    ///
-    /// Initializes the RRsets used in the tests.  The RRsets themselves have to
-    /// be initialized with the basic data on their construction. The Rdata for
-    /// them is added in SetUp().
-    NameserverEntryTest() :
-        rrv4_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::A(), RRTTL(1200)),
-        rrcase_(Name(MIXED_EXAMPLE_CO_UK), RRClass::IN(), RRType::A(),
-            RRTTL(1200)),
-        rrch_(Name(EXAMPLE_CO_UK), RRClass::CH(), RRType::A(), RRTTL(1200)),
-        rrns_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS(), RRTTL(1200)),
-        rrv6_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::AAAA(), RRTTL(900)),
-        rrnet_(Name(EXAMPLE_NET), RRClass::IN(), RRType::A(), RRTTL(600))
-    {}
-
-    /// \brief Add Rdata to RRsets
-    ///
-    /// The data are added as const pointers to avoid the stricter type checking
-    /// applied by the Rdata code.  There is no need for it in these tests.
-    virtual void SetUp() {
-
-        // A records
-        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("1.2.3.4")));
-        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("5.6.7.8")));
-        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("9.10.11.12")));
-
-        // A records
-        rrcase_.addRdata(ConstRdataPtr(new RdataTest<A>("13.14.15.16")));
-
-        // No idea what Chaosnet address look like other than they are 16 bits
-        // The fact that they are type A is probably also incorrect.
-        rrch_.addRdata(ConstRdataPtr(new RdataTest<A>("1324")));
-
-        // NS records take a single name
-        rrns_.addRdata(ConstRdataPtr(new RdataTest<NS>("example.fr")));
-        rrns_.addRdata(ConstRdataPtr(new RdataTest<NS>("example.de")));
-
-        // AAAA records
-        rrv6_.addRdata(ConstRdataPtr(new RdataTest<AAAA>("2001::1002")));
-        rrv6_.addRdata(ConstRdataPtr(new RdataTest<AAAA>("dead:beef:feed::")));
-
-        // A record for example.net
-        rrnet_.addRdata(ConstRdataPtr(new RdataTest<A>("17.18.18.20")));
-    }
-
-    /// \brief Data for the tests
-    BasicRRset rrv4_;           ///< Standard RRSet - IN, A, lowercase name
-    BasicRRset rrcase_;         ///< Mixed-case name
-    BasicRRset rrch_;           ///< Non-IN RRset (Chaos in this case)
-    BasicRRset rrns_;           ///< NS RRset
-    BasicRRset rrv6_;           ///< Standard RRset, IN, AAAA, lowercase name
-    BasicRRset rrnet_;          ///< example.net A RRset
-
     /// \short Just a really stupid callback counting times called
     /// \short Just a really stupid callback counting times called
     struct Callback : public NameserverEntry::Callback {
     struct Callback : public NameserverEntry::Callback {
         size_t count;
         size_t count;
@@ -471,25 +412,25 @@ TEST_F(NameserverEntryTest, IPCallbacks) {
     shared_ptr<NameserverEntry> entry(new NameserverEntry(EXAMPLE_CO_UK,
     shared_ptr<NameserverEntry> entry(new NameserverEntry(EXAMPLE_CO_UK,
         RRClass::IN().getCode()));
         RRClass::IN().getCode()));
     shared_ptr<Callback> callback(new Callback);
     shared_ptr<Callback> callback(new Callback);
-    TestResolver resolver;
+    shared_ptr<TestResolver> resolver(new TestResolver);
 
 
     entry->askIP(resolver, callback, ANY_OK, entry);
     entry->askIP(resolver, callback, ANY_OK, entry);
     // Ensure it becomes IN_PROGRESS
     // Ensure it becomes IN_PROGRESS
     EXPECT_EQ(Fetchable::IN_PROGRESS, entry->getState());
     EXPECT_EQ(Fetchable::IN_PROGRESS, entry->getState());
     // Now, there should be two queries in the resolver
     // Now, there should be two queries in the resolver
-    ASSERT_EQ(2, resolver.requests.size());
-    resolver.asksIPs(Name(EXAMPLE_CO_UK), 0, 1);
+    ASSERT_EQ(2, resolver->requests.size());
+    resolver->asksIPs(Name(EXAMPLE_CO_UK), 0, 1);
 
 
     // Another one might ask
     // Another one might ask
     entry->askIP(resolver, callback, V4_ONLY, entry);
     entry->askIP(resolver, callback, V4_ONLY, entry);
     // There should still be only two queries in the resolver
     // There should still be only two queries in the resolver
-    ASSERT_EQ(2, resolver.requests.size());
+    ASSERT_EQ(2, resolver->requests.size());
 
 
     // Another one, with need of IPv6 address
     // Another one, with need of IPv6 address
     entry->askIP(resolver, callback, V6_ONLY, entry);
     entry->askIP(resolver, callback, V6_ONLY, entry);
 
 
     // Answer one and see that the callbacks are called
     // Answer one and see that the callbacks are called
-    resolver.answer(0, Name(EXAMPLE_CO_UK), RRType::A(),
+    resolver->answer(0, Name(EXAMPLE_CO_UK), RRType::A(),
         rdata::in::A("192.0.2.1"));
         rdata::in::A("192.0.2.1"));
 
 
     // Both callbacks that want IPv4 should be called by now
     // Both callbacks that want IPv4 should be called by now
@@ -501,7 +442,7 @@ TEST_F(NameserverEntryTest, IPCallbacks) {
     EXPECT_EQ(1, addresses.size());
     EXPECT_EQ(1, addresses.size());
     // Answer IPv6 address
     // Answer IPv6 address
     // It is with zero TTL, so it should expire right away
     // It is with zero TTL, so it should expire right away
-    resolver.answer(1, Name(EXAMPLE_CO_UK), RRType::AAAA(),
+    resolver->answer(1, Name(EXAMPLE_CO_UK), RRType::AAAA(),
         rdata::in::AAAA("2001:db8::1"), 0);
         rdata::in::AAAA("2001:db8::1"), 0);
     // The other callback should appear
     // The other callback should appear
     EXPECT_EQ(3, callback->count);
     EXPECT_EQ(3, callback->count);
@@ -520,19 +461,19 @@ TEST_F(NameserverEntryTest, IPCallbacksUnreachable) {
     shared_ptr<NameserverEntry> entry(new NameserverEntry(EXAMPLE_CO_UK,
     shared_ptr<NameserverEntry> entry(new NameserverEntry(EXAMPLE_CO_UK,
         RRClass::IN().getCode()));
         RRClass::IN().getCode()));
     shared_ptr<Callback> callback(new Callback);
     shared_ptr<Callback> callback(new Callback);
-    TestResolver resolver;
+    shared_ptr<TestResolver> resolver(new TestResolver);
 
 
     // Ask for its IP
     // Ask for its IP
     entry->askIP(resolver, callback, ANY_OK, entry);
     entry->askIP(resolver, callback, ANY_OK, entry);
     // Check it asks the resolver
     // Check it asks the resolver
-    ASSERT_EQ(2, resolver.requests.size());
-    resolver.asksIPs(Name(EXAMPLE_CO_UK), 0, 1);
-    resolver.requests[0].second->failure();
+    ASSERT_EQ(2, resolver->requests.size());
+    resolver->asksIPs(Name(EXAMPLE_CO_UK), 0, 1);
+    resolver->requests[0].second->failure();
     // It should still wait for the second one
     // It should still wait for the second one
     EXPECT_EQ(0, callback->count);
     EXPECT_EQ(0, callback->count);
     EXPECT_EQ(Fetchable::IN_PROGRESS, entry->getState());
     EXPECT_EQ(Fetchable::IN_PROGRESS, entry->getState());
     // It should call the callback now and be unrechable
     // It should call the callback now and be unrechable
-    resolver.requests[1].second->failure();
+    resolver->requests[1].second->failure();
     EXPECT_EQ(1, callback->count);
     EXPECT_EQ(1, callback->count);
     EXPECT_EQ(Fetchable::UNREACHABLE, entry->getState());
     EXPECT_EQ(Fetchable::UNREACHABLE, entry->getState());
     NameserverEntry::AddressVector addresses;
     NameserverEntry::AddressVector addresses;
@@ -540,5 +481,4 @@ TEST_F(NameserverEntryTest, IPCallbacksUnreachable) {
     EXPECT_EQ(0, addresses.size());
     EXPECT_EQ(0, addresses.size());
 }
 }
 
 
-}   // namespace nsas
-}   // namespace isc
+}   // namespace

+ 70 - 0
src/lib/nsas/tests/nsas_test.h

@@ -276,6 +276,76 @@ class TestResolver : public isc::nsas::ResolverInterface {
         }
         }
 };
 };
 
 
+// String constants.  These should end in a dot.
+static const std::string EXAMPLE_CO_UK("example.co.uk.");
+static const std::string EXAMPLE_NET("example.net.");
+static const std::string MIXED_EXAMPLE_CO_UK("EXAmple.co.uk.");
+
+class TestWithRdata : public ::testing::Test {
+protected:
+    /// \brief Constructor
+    ///
+    /// Initializes the RRsets used in the tests.  The RRsets themselves have to
+    /// be initialized with the basic data on their construction. The Rdata for
+    /// them is added in SetUp().
+    TestWithRdata() :
+        rrv4_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::A(), RRTTL(1200)),
+        rrcase_(Name(MIXED_EXAMPLE_CO_UK), RRClass::IN(), RRType::A(),
+            RRTTL(1200)),
+        rrch_(Name(EXAMPLE_CO_UK), RRClass::CH(), RRType::A(), RRTTL(1200)),
+        rrns_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS(), RRTTL(1200)),
+        rr_single_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS(), RRTTL(0)),
+        rr_empty_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::NS(),
+            RRTTL(600)),
+        rrv6_(Name(EXAMPLE_CO_UK), RRClass::IN(), RRType::AAAA(), RRTTL(900)),
+        rrnet_(Name(EXAMPLE_NET), RRClass::IN(), RRType::A(), RRTTL(600))
+    {}
+
+    /// \brief Add Rdata to RRsets
+    ///
+    /// The data are added as const pointers to avoid the stricter type checking
+    /// applied by the Rdata code.  There is no need for it in these tests.
+    virtual void SetUp() {
+
+        // A records
+        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("1.2.3.4")));
+        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("5.6.7.8")));
+        rrv4_.addRdata(ConstRdataPtr(new RdataTest<A>("9.10.11.12")));
+
+        // A records
+        rrcase_.addRdata(ConstRdataPtr(new RdataTest<A>("13.14.15.16")));
+
+        // No idea what Chaosnet address look like other than they are 16 bits
+        // The fact that they are type A is probably also incorrect.
+        rrch_.addRdata(ConstRdataPtr(new RdataTest<A>("1324")));
+
+        // NS records take a single name
+        rrns_.addRdata(ConstRdataPtr(new RdataTest<NS>("example.fr")));
+        rrns_.addRdata(ConstRdataPtr(new RdataTest<NS>("example.de")));
+
+        // Single NS record with 0 TTL
+        rr_single_.addRdata(ConstRdataPtr(new RdataTest<NS>(
+            "ns.example.net.")));
+
+        // AAAA records
+        rrv6_.addRdata(ConstRdataPtr(new RdataTest<AAAA>("2001::1002")));
+        rrv6_.addRdata(ConstRdataPtr(new RdataTest<AAAA>("dead:beef:feed::")));
+
+        // A record for example.net
+        rrnet_.addRdata(ConstRdataPtr(new RdataTest<A>("17.18.18.20")));
+    }
+
+    /// \brief Data for the tests
+    BasicRRset rrv4_;           ///< Standard RRSet - IN, A, lowercase name
+    BasicRRset rrcase_;         ///< Mixed-case name
+    BasicRRset rrch_;           ///< Non-IN RRset (Chaos in this case)
+    BasicRRset rrns_;           ///< NS RRset
+    BasicRRset rr_single_;      ///< NS RRset with single NS
+    BasicRRset rr_empty_;       ///< NS RRset without any nameservers
+    BasicRRset rrv6_;           ///< Standard RRset, IN, AAAA, lowercase name
+    BasicRRset rrnet_;          ///< example.net A RRset
+};
+
 } // Empty namespace
 } // Empty namespace
 
 
 #endif // __NSAS_TEST_H
 #endif // __NSAS_TEST_H

+ 80 - 126
src/lib/nsas/tests/zone_entry_unittest.cc

@@ -16,7 +16,6 @@
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 #include <boost/shared_ptr.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/thread.hpp>
 
 
 #include <dns/rrclass.h>
 #include <dns/rrclass.h>
 
 
@@ -24,156 +23,111 @@
 #include "../zone_entry.h"
 #include "../zone_entry.h"
 #include "../nameserver_entry.h"
 #include "../nameserver_entry.h"
 #include "../address_request_callback.h"
 #include "../address_request_callback.h"
+#include "../nsas_entry_compare.h"
+#include "../hash_deleter.h"
 
 
 #include "nsas_test.h"
 #include "nsas_test.h"
 
 
+using namespace isc::nsas;
 using namespace asiolink;
 using namespace asiolink;
 using namespace std;
 using namespace std;
 using namespace boost;
 using namespace boost;
 using namespace isc::dns;
 using namespace isc::dns;
 
 
-namespace isc {
-namespace nsas {
-
-// String constants.  These should end in a dot.
-static const std::string EXAMPLE_CO_UK("example.co.uk.");
-static const std::string EXAMPLE_NET("example.net.");
+namespace {
 
 
 /// \brief Test Fixture Class
 /// \brief Test Fixture Class
-class ZoneEntryTest : public ::testing::Test {
+class ZoneEntryTest : public TestWithRdata {
 protected:
 protected:
+    /// \brief Constructor
+    ZoneEntryTest() :
+        nameservers_hash_(new NsasEntryCompare<NameserverEntry>),
+        nameservers_lru_((3 * nameservers_hash_.tableSize()),
+            new HashDeleter<NameserverEntry>(nameservers_hash_)),
+        resolver_(new TestResolver),
+        callback_(new Callback)
+    { }
+    /// \brief Tables of nameservers to pass into zone entry constructor
+    HashTable<NameserverEntry> nameservers_hash_;
+    LruList<NameserverEntry> nameservers_lru_;
+    shared_ptr<TestResolver> resolver_;
+
+    struct Callback : public AddressRequestCallback {
+        Callback() : unreachable_count_(0) {}
+        size_t unreachable_count_;
+        vector<IOAddress> successes_;
+        virtual void unreachable() { unreachable_count_ ++; }
+        virtual void success(const IOAddress& address) {
+            successes_.push_back(address);
+        }
+    };
+    shared_ptr<Callback> callback_;
+};
 
 
+/// \brief Inherited version with access into its internals for tests
+class InheritedZoneEntry : public ZoneEntry {
+    public:
+        InheritedZoneEntry(shared_ptr<ResolverInterface> resolver,
+            const isc::dns::AbstractRRset& authority,
+            const std::vector<const isc::dns::AbstractRRset*>& additional,
+            HashTable<NameserverEntry>& nameservers,
+            LruList<NameserverEntry>& nameserver_lru) :
+            ZoneEntry(resolver, authority, additional, nameservers,
+                nameserver_lru)
+        { }
+        InheritedZoneEntry(shared_ptr<ResolverInterface> resolver,
+            const std::string& name, uint16_t class_code) :
+            ZoneEntry(resolver, name, class_code)
+        { }
+        NameserverVector& nameservers() { return nameservers_; }
 };
 };
 
 
 /// Tests of the default constructor
 /// Tests of the default constructor
 TEST_F(ZoneEntryTest, DefaultConstructor) {
 TEST_F(ZoneEntryTest, DefaultConstructor) {
 
 
     // Default constructor should not create any RRsets
     // Default constructor should not create any RRsets
-    ZoneEntry alpha(EXAMPLE_CO_UK, RRClass::IN().getCode());
+    InheritedZoneEntry alpha(resolver_, EXAMPLE_CO_UK,
+        RRClass::IN().getCode());
     EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName());
     EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName());
     EXPECT_EQ(RRClass::IN().getCode(), alpha.getClass());
     EXPECT_EQ(RRClass::IN().getCode(), alpha.getClass());
+    EXPECT_TRUE(alpha.nameservers().empty());
 }
 }
 
 
-namespace {
-// Just something that can be created and passed
-class Callback : public AddressRequestCallback {
-    public:
-        void success(const asiolink::IOAddress&) { };
-        void unreachable() { };
-};
-}
-
-TEST_F(ZoneEntryTest, Callbacks) {
-    const size_t count(3);
-    shared_ptr<AddressRequestCallback> callbacks[count];
-
-    ZoneEntry zone(EXAMPLE_CO_UK, RRClass::IN().getCode());
-    EXPECT_FALSE(zone.hasCallbacks());
-    for (size_t i(0); i < count; ++ i) {
-        zone.addCallback(callbacks[i] = shared_ptr<AddressRequestCallback>(
-            new Callback));
-    }
-    for (size_t i(0); i < count; ++ i) {
-        ASSERT_TRUE(zone.hasCallbacks());
-        EXPECT_EQ(callbacks[i], zone.popCallback());
-    }
-    EXPECT_FALSE(zone.hasCallbacks());
-}
-
-TEST_F(ZoneEntryTest, NameserverIterators) {
-    ZoneEntry zone(EXAMPLE_CO_UK, RRClass::IN().getCode());
-    shared_ptr<NameserverEntry> nse(new NameserverEntry(EXAMPLE_CO_UK,
-        RRClass::IN().getCode()));
-    // The iterator can't be printed, so we can't use EQ
-    const ZoneEntry& zone_const(zone);
-    EXPECT_TRUE(zone.begin() == zone.end());
-    EXPECT_TRUE(zone_const.begin() == zone_const.end());
-    zone.nameserverAdd(nse);
-    EXPECT_FALSE(zone.begin() == zone.end());
-    EXPECT_FALSE(zone_const.begin() == zone_const.end());
-    EXPECT_TRUE(*zone.begin() == nse);
-    EXPECT_TRUE(*zone_const.begin() == nse);
-    EXPECT_TRUE(zone.begin() + 1 == zone.end());
-    EXPECT_TRUE(zone_const.begin() + 1 == zone_const.end());
-}
-
-void lockAndWait(ZoneEntry* zone, barrier* when) {
-    ZoneEntry::Lock lock(zone->getLock());
-    when->wait();
+/// Tests of constructor from referral data
+TEST_F(ZoneEntryTest, ReferralConstructor) {
+    InheritedZoneEntry alpha(resolver_, rr_single_,
+        vector<const AbstractRRset*>(), nameservers_hash_, nameservers_lru_);
+    // It should load the name and class from the referral info
+    EXPECT_EQ(EXAMPLE_CO_UK, alpha.getName());
+    EXPECT_EQ(RRClass::IN().getCode(), alpha.getClass());
+    EXPECT_EQ(1, alpha.nameservers().size());
+    EXPECT_EQ("ns.example.net.", alpha.nameservers()[0]->getName());
+    // TODO Test with some additional data once NameserverEntry supports them?
 }
 }
 
 
-void lockAndKeep(ZoneEntry* zone, bool* locked_self, bool* locked_other,
-    barrier* when)
-{
-    // Wait for go signal
-    when->wait();
-    // Lock
-    ZoneEntry::Lock lock(zone->getLock());
-    *locked_self = true;
-    // Wait for the start of the other thread
-    when->wait();
-    // Make sure the other thread gets a chance to run
-    for (int i(0); i < 100; ++ i) {
-        this_thread::yield();
-        EXPECT_FALSE(*locked_other);
-    }
-    *locked_self = false;
+TEST_F(ZoneEntryTest, CallbackNoNS) {
+    shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
+        rr_empty_, vector<const AbstractRRset*>(), nameservers_hash_,
+        nameservers_lru_));
+    // It should accept the callback
+    EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
+    // And tell imediatelly that it is unreachable (when it has no nameservers)
+    EXPECT_TRUE(callback_->successes_.empty());
+    EXPECT_EQ(1, callback_->unreachable_count_);
 }
 }
 
 
-TEST_F(ZoneEntryTest, Lock) {
-    // Create some testing data
-    ZoneEntry z1(EXAMPLE_CO_UK, RRClass::IN().getCode());
-    ZoneEntry z2(EXAMPLE_NET, RRClass::IN().getCode());
-    shared_ptr<NameserverEntry> ns1(new NameserverEntry(EXAMPLE_CO_UK,
-        RRClass::IN().getCode()));
-    shared_ptr<NameserverEntry> ns2(new NameserverEntry(EXAMPLE_NET,
-        RRClass::IN().getCode()));
-    z1.nameserverAdd(ns1);
-    z2.nameserverAdd(ns2);
-
-    barrier both(2);
-
-    // This tries that both can lock right now.
-    // FIXME If they can't it will deadlock. Any idea how to do it better?
-    thread t1(lockAndWait, &z1, &both);
-    thread t2(lockAndWait, &z2, &both);
-    t1.join();
-    t2.join();
-
-    z1.nameserverAdd(ns2);
-    z2.nameserverAdd(ns1);
-    // Now check that they can't both lock at the same time.
-    barrier both_second(2);
-    bool l1(false), l2(false);
-    thread t3(lockAndKeep, &z1, &l1, &l2, &both);
-    // Let this one run into the lock, not the other
-    both.wait();
-    thread t4(lockAndKeep, &z2, &l2, &l1, &both_second);
-    // Let it start the loop
-    both.wait();
-    // Let this one run to the lock and wait on it
-    both_second.wait();
-    // Make sure the threads has time now
-    for (int i(0); i < 100; ++ i) {
-        this_thread::yield();
-    }
-    both_second.wait();
-    t3.join();
-    t4.join();
-
-    // Try it the other way around (so it does not depend on the order of nameservers
-    thread t6(lockAndKeep, &z2, &l2, &l1, &both);
-    both.wait();
-    thread t5(lockAndKeep, &z1, &l1, &l2, &both_second);
-    both.wait();
-    both_second.wait();
-    for (int i(0); i < 100; ++ i) {
-        this_thread::yield();
-    }
-    both_second.wait();
-    t5.join();
-    t6.join();
+TEST_F(ZoneEntryTest, CallbackZeroTTL) {
+    shared_ptr<InheritedZoneEntry> zone(new InheritedZoneEntry(resolver_,
+        rr_single_, vector<const AbstractRRset*>(), nameservers_hash_,
+        nameservers_lru_));
+    // It should accept the callback
+    EXPECT_TRUE(zone->addCallback(callback_, ANY_OK, zone));
+    // It should not be answered yet, it should ask for the IP addresses
+    EXPECT_TRUE(callback_->successes_.empty());
+    EXPECT_EQ(0, callback_->unreachable_count_);
+    resolver_->asksIPs(Name("ns.example.net."), 0, 1);
+    // It should reject another one, as it has zero TTL
+    EXPECT_FALSE(zone->addCallback(callback_, ANY_OK, zone));
 }
 }
 
 
-}   // namespace nsas
-}   // namespace isc
+}   // namespace

+ 36 - 21
src/lib/nsas/zone_entry.h

@@ -29,6 +29,8 @@
 #include "nsas_entry.h"
 #include "nsas_entry.h"
 #include "asiolink.h"
 #include "asiolink.h"
 #include "fetchable.h"
 #include "fetchable.h"
+#include "resolver_interface.h"
+#include "nsas_types.h"
 
 
 namespace isc {
 namespace isc {
 namespace nsas {
 namespace nsas {
@@ -50,33 +52,42 @@ public:
 
 
     /// \brief Constructor where no NS records are supplied
     /// \brief Constructor where no NS records are supplied
     ///
     ///
+    /// It is here mostly for testing purposes.
+    ///
+    /// \param resolver The resolver used to ask for IP addresses
     /// \param name Name of the zone
     /// \param name Name of the zone
     /// \param class_code Class of this zone (zones of different classes have
     /// \param class_code Class of this zone (zones of different classes have
     /// different objects.
     /// different objects.
-    ZoneEntry(const std::string& name, uint16_t class_code) :
-        name_(name), classCode_(class_code)
+    ZoneEntry(boost::shared_ptr<ResolverInterface> resolver,
+        const std::string& name, uint16_t class_code) :
+        name_(name), classCode_(class_code), resolver_(resolver)
     {}
     {}
 
 
-    // TODO Constructor from namesarver table and referral information
-
     /// \brief Constructor
     /// \brief Constructor
     ///
     ///
     /// Creates a zone entry object with an RRset representing the nameservers,
     /// Creates a zone entry object with an RRset representing the nameservers,
     /// plus possibly additional RRsets holding address information.
     /// plus possibly additional RRsets holding address information.
-    //ZoneEntry(isc::dns::AbstractRRset* nsrrset,
-    //       const std::vector<isc::dns::AbstractRRset*>& additional);
-
-    /// \brief Destructor
-    virtual ~ZoneEntry()
-    {}
+    ///
+    /// \param resolver The resolver used to ask for IP addresses
+    /// \param authority Specifies the name, code and nameservers of this zone.
+    /// \param additional The additional section to feed to nameservers.
+    /// \param nameservers Hash table of existing nameserves and a place where
+    ///     new ones will be put.
+    /// \param nameserver_lru The lru where the nameservers will be added or
+    ///     touched.
+    ZoneEntry(boost::shared_ptr<ResolverInterface> resolver,
+        const isc::dns::AbstractRRset& authority,
+        const std::vector<const isc::dns::AbstractRRset*>& additional,
+        HashTable<NameserverEntry>& nameservers,
+        LruList<NameserverEntry>& nameserver_lru);
 
 
     /// \return Name of the zone
     /// \return Name of the zone
-    virtual std::string getName() const {
+    std::string getName() const {
         return name_;
         return name_;
     }
     }
 
 
     /// \return Class of zone
     /// \return Class of zone
-    virtual short getClass() const {
+    short getClass() const {
         return classCode_;
         return classCode_;
     }
     }
 
 
@@ -90,10 +101,9 @@ public:
      *
      *
      * This callback is either executed right away, if it is possible,
      * This callback is either executed right away, if it is possible,
      * or queued for later.
      * or queued for later.
+     *
      * \param callback The callback itself.
      * \param callback The callback itself.
-     * \param v4ok Is it ok to give the callback a IPv4 address?
-     * \param v6ok Is it ok to give the callback a IPv6 address? (At last one
-     *     of them must be true or isc::BadValue is thrown)
+     * \param family Which address family is acceptable as an answer?
      * \param self A shared pointer to this zone entry. It is not possible to
      * \param self A shared pointer to this zone entry. It is not possible to
      *     create one from C++ this pointer, since another shared pointer
      *     create one from C++ this pointer, since another shared pointer
      *     will already exist at that point, however it is needed to callback.
      *     will already exist at that point, however it is needed to callback.
@@ -104,24 +114,29 @@ public:
      *     and new instance should be created.
      *     and new instance should be created.
      */
      */
     bool addCallback(boost::shared_ptr<AddressRequestCallback>
     bool addCallback(boost::shared_ptr<AddressRequestCallback>
-        callback, bool v4ok, bool v6ok, boost::shared_ptr<ZoneEntry> self);
+        callback, AddressFamily family, boost::shared_ptr<ZoneEntry> self);
 
 
-private:
+    /// \short Protected members, so they can be accessed by tests.
+    //@{
+protected:
     // TODO Read-Write lock?
     // TODO Read-Write lock?
-    mutable boost::mutex    mutex_;     ///< Mutex protecting this zone entry
-    std::string     name_;      ///< Canonical zone name
-    uint16_t        classCode_; ///< Class code
     typedef boost::shared_ptr<NameserverEntry> NameserverPtr;
     typedef boost::shared_ptr<NameserverEntry> NameserverPtr;
     typedef std::vector<NameserverPtr> NameserverVector;
     typedef std::vector<NameserverPtr> NameserverVector;
     NameserverVector nameservers_; ///< Nameservers
     NameserverVector nameservers_; ///< Nameservers
-    time_t          expiry_;    ///< Expiry time of this entry
     std::list<boost::shared_ptr<AddressRequestCallback> > callbacks_;
     std::list<boost::shared_ptr<AddressRequestCallback> > callbacks_;
+    time_t          expiry_;    ///< Expiry time of this entry
+    //}@
+private:
+    mutable boost::mutex    mutex_;     ///< Mutex protecting this zone entry
+    std::string     name_;      ///< Canonical zone name
+    uint16_t        classCode_; ///< Class code
     // Internal function that adds a callback (if there's one) and processes
     // Internal function that adds a callback (if there's one) and processes
     // the nameservers (if there's chance there's some info) and calls
     // the nameservers (if there's chance there's some info) and calls
     // callbacks. If nameserver is given, it is considered new and valid
     // callbacks. If nameserver is given, it is considered new and valid
     // even if its TTL is 0.
     // even if its TTL is 0.
     void process(boost::shared_ptr<AddressRequestCallback> callback,
     void process(boost::shared_ptr<AddressRequestCallback> callback,
          bool v4ok, bool v6ok, NameserverEntry* nameserver);
          bool v4ok, bool v6ok, NameserverEntry* nameserver);
+    boost::shared_ptr<ResolverInterface> resolver_;
 };
 };
 
 
 } // namespace nsas
 } // namespace nsas