Browse Source

[2905] add an "empty zone" in the auth query test setup, fixing a test bug.

the mock findZone() implementation was buggy and wouldn't work correctly
if there were actually more than one zone.  fixed it by porting
MockDataSourceClient::findZone() from datasrc/tests/mock_client.cc.
JINMEI Tatuya 12 years ago
parent
commit
2f0e203d44
1 changed files with 46 additions and 36 deletions
  1. 46 36
      src/bin/auth/tests/query_unittest.cc

+ 46 - 36
src/bin/auth/tests/query_unittest.cc

@@ -133,6 +133,12 @@ const char* const unsigned_delegation_nsec3_txt =
     "q81r598950igr1eqvc60aedlq66425b5.example.com. 3600 IN NSEC3 1 1 12 "
     "aabbccdd 0p9mhaveqvm6t7vbl5lop2u3t2rp3tom NS RRSIG\n";
 
+// Name of an "empty" zone: used to simulate the case of
+// configured-but-available zone (due to load errors, etc).
+// Each tested data source client is expected to have this zone (SQLite3
+// currently doesn't have this concept so it's skipped)
+const char* const EMPTY_ZONE_NAME = "empty.example.org";
+
 // A helper function that generates a textual representation of RRSIG RDATA
 // for the given covered type.  The resulting RRSIG may not necessarily make
 // sense in terms of the DNSSEC protocol, but for our testing purposes it's
@@ -799,11 +805,14 @@ createDataSrcClientList(DataSrcType type, DataSourceClient& client) {
         return (boost::shared_ptr<ClientList>(new SingletonList(client)));
     case INMEMORY:
         list.reset(new ConfigurableClientList(RRClass::IN()));
+        // Configure one normal zone and one "empty" zone.
         list->configure(isc::data::Element::fromJSON(
                             "[{\"type\": \"MasterFiles\","
                             "  \"cache-enable\": true, "
                             "  \"params\": {\"example.com\": \"" +
-                            string(TEST_OWN_DATA_BUILDDIR "/example.zone") +
+                            string(TEST_OWN_DATA_BUILDDIR "/example.zone\",") +
+                            + "\"" + EMPTY_ZONE_NAME + "\": \"" +
+                            string(TEST_OWN_DATA_BUILDDIR "/nosuchfile.zone") +
                             "\"}}]"), true);
         return (list);
     case SQLITE3:
@@ -834,39 +843,38 @@ createDataSrcClientList(DataSrcType type, DataSourceClient& client) {
 class MockClient : public DataSourceClient {
 public:
     virtual FindResult findZone(const isc::dns::Name& origin) const {
-        const Name r_origin(origin.reverse());
-        std::map<Name, ZoneFinderPtr>::const_iterator it =
-            zone_finders_.lower_bound(r_origin);
-
-        if (it != zone_finders_.end()) {
-            const NameComparisonResult result =
-                origin.compare((it->first).reverse());
-            if (result.getRelation() == NameComparisonResult::EQUAL) {
-                return (FindResult(result::SUCCESS, it->second));
-            } else if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
-                return (FindResult(result::PARTIALMATCH, it->second));
-            }
-        }
+        // Identify the next (strictly) larger name than the given 'origin' in
+        // the map.  Its predecessor (if any) is the longest matching name
+        // if it's either an exact match or a super domain; otherwise there's
+        // no match in the map.  See also datasrc/tests/mock_client.cc.
 
-        // If it is at the beginning of the map, then the name was not
-        // found (we have already handled the element the iterator
-        // points to).
-        if (it == zone_finders_.begin()) {
+        // Eliminate the case of empty map to simply the rest of the code
+        if (zone_finders_.empty()) {
             return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
         }
 
-        // Check if the previous element is a partial match.
-        --it;
-        const NameComparisonResult result =
-            origin.compare((it->first).reverse());
-        if (result.getRelation() == NameComparisonResult::SUBDOMAIN) {
-            return (FindResult(result::PARTIALMATCH, it->second));
+        std::map<Name, ZoneFinderPtr>::const_iterator it =
+            zone_finders_.upper_bound(origin);
+        if (it == zone_finders_.begin()) { // no predecessor
+            return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
         }
 
-        return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+        --it;                   // get the predecessor
+        const result::ResultFlags flags =
+            it->second ? result::FLAGS_DEFAULT : result::ZONE_EMPTY;
+        const NameComparisonResult compar(it->first.compare(origin));
+        switch (compar.getRelation()) {
+        case NameComparisonResult::EQUAL:
+            return (FindResult(result::SUCCESS, it->second, flags));
+        case NameComparisonResult::SUPERDOMAIN:
+            return (FindResult(result::PARTIALMATCH, it->second, flags));
+        default:
+            return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+        }
     }
 
-    virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name&, bool, bool) const {
+    virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name&, bool, bool) const
+    {
         isc_throw(isc::NotImplemented,
                   "Updater isn't supported in the MockClient");
     }
@@ -878,18 +886,21 @@ public:
     }
 
     result::Result addZone(ZoneFinderPtr finder) {
-        // Use the reverse of the name as the key, so we can quickly
-        // find partial matches in the map.
-        zone_finders_[finder->getOrigin().reverse()] = finder;
+        zone_finders_[finder->getOrigin()] = finder;
+        return (result::SUCCESS);
+    }
+
+    // "configure" a zone with no data.  This will cause the ZONE_EMPTY flag
+    // on in finZone().
+    result::Result addEmptyZone(const Name& zone_name) {
+        zone_finders_[zone_name] = ZoneFinderPtr();
         return (result::SUCCESS);
     }
 
 private:
     // Note that because we no longer have the old RBTree, and the new
     // in-memory DomainTree is not useful as it returns const nodes, we
-    // use a std::map instead. In this map, the key is a name stored in
-    // reverse order of labels to aid in finding partial matches
-    // quickly.
+    // use a std::map instead.
     std::map<Name, ZoneFinderPtr> zone_finders_;
 };
 
@@ -916,9 +927,10 @@ protected:
 
         response.setRcode(Rcode::NOERROR());
         response.setOpcode(Opcode::QUERY());
-        // create and add a matching zone.
+        // create and add a matching zone.  One is a "broken, empty" zone.
         mock_finder = new MockZoneFinder();
         mock_client.addZone(ZoneFinderPtr(mock_finder));
+        mock_client.addEmptyZone(Name(EMPTY_ZONE_NAME));
     }
 
     virtual void SetUp() {
@@ -1144,8 +1156,7 @@ TEST_P(QueryTest, noZone) {
     // REFUSED.
     MockClient empty_mock_client;
     SingletonList empty_list(empty_mock_client);
-    EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
-                                  response));
+    EXPECT_NO_THROW(query.process(empty_list, qname, qtype, response));
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
@@ -1400,7 +1411,6 @@ TEST_F(QueryTestForMockOnly, badSecureDelegation) {
                                   qtype, response));
 }
 
-
 TEST_P(QueryTest, nxdomain) {
     EXPECT_NO_THROW(query.process(*list_,
                                   Name("nxdomain.example.com"), qtype,