|
@@ -13,11 +13,18 @@
|
|
|
// PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
|
#include <dns/labelsequence.h>
|
|
|
+#include <dns/name.h>
|
|
|
#include <exceptions/exceptions.h>
|
|
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
+#include <boost/functional/hash.hpp>
|
|
|
+
|
|
|
+#include <string>
|
|
|
+#include <set>
|
|
|
+
|
|
|
using namespace isc::dns;
|
|
|
+using namespace std;
|
|
|
|
|
|
namespace {
|
|
|
|
|
@@ -257,4 +264,98 @@ TEST_F(LabelSequenceTest, isAbsolute) {
|
|
|
ASSERT_TRUE(ls3.isAbsolute());
|
|
|
}
|
|
|
|
|
|
+// A helper function that constructs the textual representation of a name label
|
|
|
+// character for the given char value in the form of \DDD
|
|
|
+string
|
|
|
+getNumericLabel(char ch) {
|
|
|
+ string result;
|
|
|
+ result.push_back(0x5c); // push '\'
|
|
|
+ result.push_back(0x30 + ((ch / 100) % 10)); // encode the 1st digit
|
|
|
+ result.push_back(0x30 + ((ch / 10) % 10)); // encode the 2nd digit
|
|
|
+ result.push_back(0x30 + (ch % 10)); // encode the 3rd digit
|
|
|
+
|
|
|
+ return (result);
|
|
|
+}
|
|
|
+
|
|
|
+// The following are test data used in the getHash test below. Normally
|
|
|
+// we use example/documentation domain names for testing, but in this case
|
|
|
+// we'd specifically like to use more realistic data, and are intentionally
|
|
|
+// using real-world samples: They are the NS names of root and some top level
|
|
|
+// domains as of this test.
|
|
|
+const char* const root_servers[] = {
|
|
|
+ "a.root-servers.net", "b.root-servers.net", "c.root-servers.net",
|
|
|
+ "d.root-servers.net", "e.root-servers.net", "f.root-servers.net",
|
|
|
+ "g.root-servers.net", "h.root-servers.net", "i.root-servers.net",
|
|
|
+ "j.root-servers.net", "k.root-servers.net", "l.root-servers.net",
|
|
|
+ "m.root-servers.net", NULL
|
|
|
+};
|
|
|
+const char* const gtld_servers[] = {
|
|
|
+ "a.gtld-servers.net", "b.gtld-servers.net", "c.gtld-servers.net",
|
|
|
+ "d.gtld-servers.net", "e.gtld-servers.net", "f.gtld-servers.net",
|
|
|
+ "g.gtld-servers.net", "h.gtld-servers.net", "i.gtld-servers.net",
|
|
|
+ "j.gtld-servers.net", "k.gtld-servers.net", "l.gtld-servers.net",
|
|
|
+ "m.gtld-servers.net", NULL
|
|
|
+};
|
|
|
+const char* const jp_servers[] = {
|
|
|
+ "a.dns.jp", "b.dns.jp", "c.dns.jp", "d.dns.jp", "e.dns.jp",
|
|
|
+ "f.dns.jp", "g.dns.jp", NULL
|
|
|
+};
|
|
|
+const char* const cn_servers[] = {
|
|
|
+ "a.dns.cn", "b.dns.cn", "c.dns.cn", "d.dns.cn", "e.dns.cn",
|
|
|
+ "ns.cernet.net", NULL
|
|
|
+};
|
|
|
+const char* const ca_servers[] = {
|
|
|
+ "k.ca-servers.ca", "e.ca-servers.ca", "a.ca-servers.ca", "z.ca-servers.ca",
|
|
|
+ "tld.isc-sns.net", "c.ca-servers.ca", "j.ca-servers.ca", "l.ca-servers.ca",
|
|
|
+ "sns-pb.isc.org", "f.ca-servers.ca", NULL
|
|
|
+};
|
|
|
+
|
|
|
+// A helper function used in the getHash test below.
|
|
|
+void
|
|
|
+hashDistributionCheck(const char* const* servers) {
|
|
|
+ const size_t BUCKETS = 64; // constant used in the MessageRenderer
|
|
|
+ set<Name> names;
|
|
|
+ vector<size_t> hash_counts(BUCKETS);
|
|
|
+
|
|
|
+ // Store all test names and their super domain names (excluding the
|
|
|
+ // "root" label) in the set, calculates their hash values, and increments
|
|
|
+ // the counter for the corresponding hash "bucket".
|
|
|
+ for (size_t i = 0; servers[i] != NULL; ++i) {
|
|
|
+ const Name name(servers[i]);
|
|
|
+ for (size_t l = 0; l < name.getLabelCount() - 1; ++l) {
|
|
|
+ pair<set<Name>::const_iterator, bool> ret =
|
|
|
+ names.insert(name.split(l));
|
|
|
+ if (ret.second) {
|
|
|
+ hash_counts[LabelSequence((*ret.first)).getHash(false) %
|
|
|
+ BUCKETS]++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // See how many conflicts we have in the buckets. For the testing purpose
|
|
|
+ // we expect there's at most 2 conflicts in each set, which is an
|
|
|
+ // arbitrary choice (it should happen to succeed with the hash function
|
|
|
+ // and data we are using; if it's not the case, maybe with an update to
|
|
|
+ // the hash implementation, we should revise the test).
|
|
|
+ for (size_t i = 0; i < BUCKETS; ++i) {
|
|
|
+ EXPECT_GE(3, hash_counts[i]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(LabelSequenceTest, getHash) {
|
|
|
+ // Trivial case. The same sequence should have the same hash.
|
|
|
+ EXPECT_EQ(ls1.getHash(true), ls1.getHash(true));
|
|
|
+
|
|
|
+ // Check the case-insensitive mode behavior.
|
|
|
+ EXPECT_EQ(ls1.getHash(false), ls5.getHash(false));
|
|
|
+
|
|
|
+ // Check that the distribution of hash values is "not too bad" (such as
|
|
|
+ // everything has the same hash value due to a stupid bug). It's
|
|
|
+ // difficult to check such things reliably. We do some ad hoc tests here.
|
|
|
+ hashDistributionCheck(root_servers);
|
|
|
+ hashDistributionCheck(jp_servers);
|
|
|
+ hashDistributionCheck(cn_servers);
|
|
|
+ hashDistributionCheck(ca_servers);
|
|
|
+}
|
|
|
+
|
|
|
}
|