Browse Source

First part of sync with #356

It compiles, but 2 tests are commented out because of API changes, the tests do not run
and there are many places where the code must be examined (locking, code removed from constructor,
differently stored addresses).

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

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

@@ -30,6 +30,7 @@ run_unittests_SOURCES += nsas_entry_compare_unittest.cc
 run_unittests_SOURCES += nsas_test.h
 run_unittests_SOURCES += zone_entry_unittest.cc
 run_unittests_SOURCES += fetchable_unittest.cc
+run_unittests_SOURCES += random_number_generator_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 30 - 5
src/lib/nsas/tests/nameserver_address_unittest.cc

@@ -58,9 +58,12 @@ public:
 
     // Return the IOAddress corresponding to the index in rrv4_
     asiolink::IOAddress getAddressAtIndex(uint32_t index) {
-        return ns_.get()->getAddressAtIndex(index);
+        return ns_.get()->getAddressAtIndex(index, AF_INET);
     }
 
+    // Return the addresses count stored in RRset
+    unsigned int getAddressesCount() const { return rrv4_->getRdataCount(); }
+
     // Return the RTT of the address
     uint32_t getAddressRTTAtIndex(uint32_t index) { 
         NameserverEntry::AddressVector addresses;
@@ -84,27 +87,49 @@ class NameserverAddressTest : public ::testing::Test {
 protected:
     // Constructor
     NameserverAddressTest(): 
-        ns_address_(ns_sample_.getNameserverEntry(), TEST_ADDRESS_INDEX)
+        ns_address_(ns_sample_.getNameserverEntry(), TEST_ADDRESS_INDEX, AF_INET),
+        invalid_ns_address_(ns_sample_.getNameserverEntry(), ns_sample_.getAddressesCount(), AF_INET)
     {
     }
 
     NameserverEntrySample ns_sample_;
+    // Valid NameserverAddress object
     NameserverAddress ns_address_;
+
+    // NameserverAddress object that constructed with invalid index
+    NameserverAddress invalid_ns_address_;
 };
 
 // Test that the address is equal to the address in NameserverEntry
 TEST_F(NameserverAddressTest, Address) {
     EXPECT_TRUE(ns_address_.getAddress().equal( ns_sample_.getAddressAtIndex(TEST_ADDRESS_INDEX)));
+
+    // It will trigger an assert with the invalid index
+    ASSERT_DEATH(invalid_ns_address_.getAddress(), "");
+
+    boost::shared_ptr<NameserverEntry> empty_ne((NameserverEntry*)NULL);
+    // It will throw an NullNameserverEntryPointer exception with the empty NameserverEntry shared pointer
+    ASSERT_THROW({NameserverAddress empty_ns_address(empty_ne, 0, AF_INET);}, NullNameserverEntryPointer);
 }
 
 // Test that the RTT is updated
 TEST_F(NameserverAddressTest, UpdateRTT) {
     uint32_t old_rtt = ns_sample_.getAddressRTTAtIndex(TEST_ADDRESS_INDEX);
-    uint32_t new_rtt = old_rtt + 1;
+    uint32_t new_rtt = old_rtt + 10;
+
+    uint32_t old_rtt0 = ns_sample_.getAddressRTTAtIndex(0);
+    uint32_t old_rtt2 = ns_sample_.getAddressRTTAtIndex(2);
+
+    for(int i = 0; i < 10000; ++i){
+        ns_address_.updateRTT(new_rtt);
+    }
 
-    ns_address_.updateRTT(new_rtt);
+    //The RTT should have been updated
+    EXPECT_NE(new_rtt, ns_sample_.getAddressRTTAtIndex(TEST_ADDRESS_INDEX));
 
-    EXPECT_EQ(new_rtt, ns_sample_.getAddressRTTAtIndex(TEST_ADDRESS_INDEX));
+    //The RTTs not been updated should remain unchanged
+    EXPECT_EQ(old_rtt0, ns_sample_.getAddressRTTAtIndex(0));
+    EXPECT_EQ(old_rtt2, ns_sample_.getAddressRTTAtIndex(2));
 }
 
 } // namespace nsas

+ 116 - 2
src/lib/nsas/tests/nameserver_entry_unittest.cc

@@ -111,7 +111,7 @@ TEST_F(NameserverEntryTest, InitialRTT) {
 
     // Check they are not 0 and they are all small, they should be some kind
     // of randomish numbers, so we can't expect much more here
-    BOOST_FOREACH(const AddressEntry& entry, vec) {
+    BOOST_FOREACH(AddressEntry& entry, vec) {
         EXPECT_GT(entry.getRTT(), 0);
         // 20 is some arbitrary small value
         EXPECT_LT(entry.getRTT(), 20);
@@ -464,9 +464,123 @@ TEST_F(NameserverEntryTest, KeepRTT) {
     ASSERT_EQ(2, addresses.size());
     EXPECT_EQ("2001:db8::1", addresses[1].getAddress().toText());
     // They should have the RTT we set to them
-    BOOST_FOREACH(const AddressEntry& address, addresses) {
+    BOOST_FOREACH(AddressEntry& address, addresses) {
         EXPECT_EQ(123, address.getRTT());
     }
 }
 
+// TODO This test must be updated, the rrsets are not passed trough constructor
+#if 0
+// Select one address from the address list
+TEST_F(NameserverEntryTest, AddressSelection) {
+    boost::shared_ptr<NameserverEntry> ns(new NameserverEntry(&rrv4_, &rrv6_));
+    NameserverEntry::AddressVector v4Addresses;
+    NameserverEntry::AddressVector v6Addresses;
+    ns->getAddresses(v4Addresses, AF_INET);
+    ns->getAddresses(v6Addresses, AF_INET6);
+
+    int c1 = 0;
+    int c2 = 0;
+    int c3 = 0;
+    NameserverAddress ns_address;
+    for(int i = 0; i < 10000; ++i){
+        ns.get()->getAddress(ns_address, AF_INET);
+        asiolink::IOAddress io_address = ns_address.getAddress();
+        if(io_address.toText() == v4Addresses[0].getAddress().toText()) ++c1;
+        else if(io_address.toText() == v4Addresses[1].getAddress().toText()) ++c2;
+        else if(io_address.toText() == v4Addresses[2].getAddress().toText()) ++c3;
+    }
+    // c1, c2 and c3 should almost be equal
+    ASSERT_EQ(1, (int)(c1*1.0/c2 + 0.5));
+    ASSERT_EQ(1, (int)(c2*1.0/c3 + 0.5));
+
+    // update the rtt to 1, 2, 3
+    ns->setAddressRTT(v4Addresses[0].getAddress(), 1);
+    ns->setAddressRTT(v4Addresses[1].getAddress(), 2);
+    ns->setAddressRTT(v4Addresses[2].getAddress(), 3);
+    c1 = c2 = c3 = 0; 
+    for(int i = 0; i < 100000; ++i){
+        ns.get()->getAddress(ns_address, AF_INET);
+        asiolink::IOAddress io_address = ns_address.getAddress();
+        if(io_address.toText() == v4Addresses[0].getAddress().toText()) ++c1;
+        else if(io_address.toText() == v4Addresses[1].getAddress().toText()) ++c2;
+        else if(io_address.toText() == v4Addresses[2].getAddress().toText()) ++c3;
+    }
+
+    // c1 should be (2*2) times of c2
+    ASSERT_EQ(4, (int)(c1*1.0/c2 + 0.5));
+    // c1 should be (3*3) times of c3
+    ASSERT_EQ(9, (int)(c1*1.0/c3 + 0.5));
+
+    // Test unreachable address
+    ns->setAddressRTT(v4Addresses[0].getAddress(), 1);
+    ns->setAddressRTT(v4Addresses[1].getAddress(), 100);
+    ns->setAddressUnreachable(v4Addresses[2].getAddress());
+    c1 = c2 = c3 = 0;
+    for(int i = 0; i < 100000; ++i){
+        ns.get()->getAddress(ns_address, AF_INET);
+        asiolink::IOAddress io_address = ns_address.getAddress();
+        if(io_address.toText() == v4Addresses[0].getAddress().toText()) ++c1;
+        else if(io_address.toText() == v4Addresses[1].getAddress().toText()) ++c2;
+        else if(io_address.toText() == v4Addresses[2].getAddress().toText()) ++c3;
+    }
+
+    // The 3rd address should not be selected again
+    ASSERT_EQ(0, c3);
+
+    // Test if all the servers are unrachable
+    ns->setAddressUnreachable(v4Addresses[0].getAddress());
+    ns->setAddressUnreachable(v4Addresses[1].getAddress());
+    ns->setAddressUnreachable(v4Addresses[2].getAddress());
+    c1 = c2 = c3 = 0;
+    for(int i = 0; i < 100000; ++i){
+        ns.get()->getAddress(ns_address, AF_INET);
+        asiolink::IOAddress io_address = ns_address.getAddress();
+        if(io_address.toText() == v4Addresses[0].getAddress().toText()) ++c1;
+        else if(io_address.toText() == v4Addresses[1].getAddress().toText()) ++c2;
+        else if(io_address.toText() == v4Addresses[2].getAddress().toText()) ++c3;
+    }
+
+    // All the unreachable servers should be selected with equal opportunity
+    ASSERT_EQ(1, (int)(c1*1.0/c2 + 0.5));
+    ASSERT_EQ(1, (int)(c1*1.0/c3 + 0.5));
+
+    // TODO: The unreachable server should be changed to reachable after 5minutes, but how to test?
+}
+
+// Test the RTT is updated smoothly
+TEST_F(NameserverEntryTest, UpdateRTT) {
+    NameserverEntry ns(&rrv4_, &rrv6_);
+    NameserverEntry::AddressVector vec;
+    ns.getAddresses(vec);
+
+    // Initialize the rtt with a small value
+    uint32_t init_rtt = 1;
+    ns.setAddressRTT(vec[0].getAddress(), init_rtt);
+    // The rtt will be stablized to a large value
+    uint32_t stable_rtt = 100;
+
+    // Update the rtt
+    ns.updateAddressRTTAtIndex(stable_rtt, 0, AF_INET);
+
+    vec.clear();
+    ns.getAddresses(vec);
+    uint32_t new_rtt = vec[0].getRTT();
+
+    // The rtt should not close to new rtt immediately
+    ASSERT_TRUE((stable_rtt - new_rtt) > (new_rtt - init_rtt));
+
+    // Update the rtt for enough times
+    for(int i = 0; i < 10000; ++i){
+        ns.updateAddressRTTAtIndex(stable_rtt, 0, AF_INET);
+    }
+    vec.clear();
+    ns.getAddresses(vec);
+    new_rtt = vec[0].getRTT();
+
+    // The rtt should be close to stable rtt value
+    ASSERT_TRUE((stable_rtt - new_rtt) < (new_rtt - init_rtt));
+}
+#endif
+
 }   // namespace

+ 247 - 0
src/lib/nsas/tests/random_number_generator_unittest.cc

@@ -0,0 +1,247 @@
+// 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 <gtest/gtest.h>
+#include <boost/shared_ptr.hpp>
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include "random_number_generator.h"
+
+namespace isc {
+namespace nsas {
+
+using namespace std;
+
+/// \brief Test Fixture Class for uniform random number generator
+///
+/// The hard part for this test is how to test that the number is random?
+/// and how to test that the number is uniformly distributed? 
+/// Or maybe we can trust the boost implementation
+class UniformRandomIntegerGeneratorTest : public ::testing::Test {
+public:
+    UniformRandomIntegerGeneratorTest():
+        gen_(min_, max_)
+    {
+    }
+    virtual ~UniformRandomIntegerGeneratorTest(){}
+
+    int gen() { return gen_(); }
+    int max() const { return max_; }
+    int min() const { return min_; }
+
+private:
+    UniformRandomIntegerGenerator gen_;
+
+    const static int min_ = 1;
+    const static int max_ = 10;
+};
+
+/// Some validation tests will incur performance penalty, so the tests are
+/// made only in "debug" version with assert(). But if NDEBUG is defined
+/// the tests will be failed since assert() is non-op in non-debug version.
+/// The "#ifndef NDEBUG" is added to make the tests be performed only in
+/// non-debug environment.
+#ifndef NDEBUG
+// Test of the constructor
+TEST_F(UniformRandomIntegerGeneratorTest, Constructor) {
+    // The range must be min<=max
+    ASSERT_DEATH(UniformRandomIntegerGenerator(3, 2), "");
+}
+#endif
+
+// Test of the generated integers are in the range [min, max]
+TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) {
+    vector<int> numbers;
+
+    // Generate a lot of random integers
+    for(int i = 0; i < max()*10; ++i){
+        numbers.push_back(gen());
+    }
+
+    // Remove the duplicated values
+    sort(numbers.begin(), numbers.end());
+    vector<int>::iterator it = unique(numbers.begin(), numbers.end());
+
+    // make sure the numbers are in range [min, max]
+    ASSERT_EQ(it - numbers.begin(), max() - min() + 1); 
+}
+
+
+/// \brief Test Fixture Class for weighted random number generator
+class WeightedRandomIntegerGeneratorTest : public ::testing::Test {
+public:
+    WeightedRandomIntegerGeneratorTest()
+    { }
+
+    virtual ~WeightedRandomIntegerGeneratorTest()
+    { }
+};
+
+// Test of the weighted random number generator constructor
+TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) 
+{
+    vector<double> probabilities;
+
+    // If no probabilities is provided, the smallest integer will always be generated
+    WeightedRandomIntegerGenerator gen(probabilities, 123);
+    for(int i = 0; i < 100; ++i){
+        ASSERT_EQ(gen(), 123);
+    }
+
+/// Some validation tests will incur performance penalty, so the tests are
+/// made only in "debug" version with assert(). But if NDEBUG is defined
+/// the tests will be failed since assert() is non-op in non-debug version.
+/// The "#ifndef NDEBUG" is added to make the tests be performed only in
+/// non-debug environment.
+#ifndef NDEBUG
+    //The probability must be >= 0
+    probabilities.push_back(-0.1);
+    probabilities.push_back(1.1);
+    ASSERT_DEATH(WeightedRandomIntegerGenerator gen2(probabilities), "");
+
+    //The probability must be <= 1.0
+    probabilities.clear();
+    probabilities.push_back(0.1);
+    probabilities.push_back(1.1);
+    ASSERT_DEATH(WeightedRandomIntegerGenerator gen3(probabilities), "");
+
+    //The sum must be equal to 1.0
+    probabilities.clear();
+    probabilities.push_back(0.2);
+    probabilities.push_back(0.9);
+    ASSERT_DEATH(WeightedRandomIntegerGenerator gen4(probabilities), "");
+
+    //The sum must be equal to 1.0
+    probabilities.clear();
+    probabilities.push_back(0.3);
+    probabilities.push_back(0.2);
+    probabilities.push_back(0.1);
+    ASSERT_DEATH(WeightedRandomIntegerGenerator gen5(probabilities), "");
+#endif
+}
+
+// Test the randomization of the generator
+TEST_F(WeightedRandomIntegerGeneratorTest, WeightedRandomization) 
+{
+    {
+        vector<double> probabilities;
+        probabilities.push_back(0.5);
+        probabilities.push_back(0.5);
+
+        // Uniformly generated integers
+        WeightedRandomIntegerGenerator gen(probabilities);
+        int c1 = 0;
+        int c2 = 0;
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+        }
+        // The probabilities should almost equal
+        ASSERT_EQ(1, (int)(c1*1.0/c2 + 0.5));
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        probabilities.push_back(0.2);
+        probabilities.push_back(0.8);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+        }
+        // The 2nd integer count should be 4 times of 1st one
+        ASSERT_EQ(4, (int)(c2*1.0/c1 + 0.5));
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        probabilities.push_back(0.8);
+        probabilities.push_back(0.2);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+        }
+        // The 1st integer count should be 4 times of 2nd one
+        ASSERT_EQ(4, (int)(c1*1.0/c2 + 0.5));
+    }
+
+    {
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        int c3 = 0;
+        probabilities.push_back(0.5);
+        probabilities.push_back(0.25);
+        probabilities.push_back(0.25);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+            else if(n == 2) ++c3;
+        }
+        // The 1st integer count should be double of 2nd one
+        ASSERT_EQ(2, (int)(c1*1.0/c2 + 0.5));
+        // The 1st integer count should be double of 3rd one
+        ASSERT_EQ(2, (int)(c1*1.0/c3 + 0.5));
+    }
+}
+
+// Test the reset function of generator
+TEST_F(WeightedRandomIntegerGeneratorTest, ResetProbabilities) 
+{
+        vector<double> probabilities;
+        int c1 = 0;
+        int c2 = 0;
+        probabilities.push_back(0.8);
+        probabilities.push_back(0.2);
+        WeightedRandomIntegerGenerator gen(probabilities);
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+        }
+        // The 1st integer count should be 4 times of 2nd one
+        ASSERT_EQ(4, (int)(c1*1.0/c2 + 0.5));
+
+        // Reset the probabilities
+        probabilities.clear();
+        c1 = c2 = 0;
+        probabilities.push_back(0.2);
+        probabilities.push_back(0.8);
+        gen.reset(probabilities);
+        for(int i = 0; i < 100000; ++i){
+            int n = gen();
+            if(n == 0) ++c1;
+            else if(n == 1) ++c2;
+        }
+        // The 2nd integer count should be 4 times of 1st one
+        ASSERT_EQ(4, (int)(c2*1.0/c1 + 0.5));
+}
+
+} // namespace nsas
+} // namespace isc