Browse Source

[2378] Very basic test for copy between data sources

This is test for the ZoneLoader and its variant for testing copying
between two data sources. It includes some testing setups and mocks to
be reused in following tests.

Doesn't compile, undefined references to the tested methods.
Michal 'vorner' Vaner 12 years ago
parent
commit
3da9d6198b
2 changed files with 165 additions and 0 deletions
  1. 1 0
      src/lib/datasrc/tests/Makefile.am
  2. 164 0
      src/lib/datasrc/tests/zone_loader_unittest.cc

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

@@ -60,6 +60,7 @@ run_unittests_SOURCES += zone_finder_context_unittest.cc
 run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
 run_unittests_SOURCES += client_list_unittest.cc
 run_unittests_SOURCES += master_loader_callbacks_test.cc
+run_unittests_SOURCES += zone_loader_unittest.cc
 
 # We need the actual module implementation in the tests (they are not part
 # of libdatasrc)

+ 164 - 0
src/lib/datasrc/tests/zone_loader_unittest.cc

@@ -0,0 +1,164 @@
+// Copyright (C) 2012  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.
+
+#include <datasrc/zone_loader.h>
+#include <datasrc/data_source.h>
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/memory_client.h>
+
+#include <dns/rrclass.h>
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <util/memory_segment_local.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+using isc::dns::RRClass;
+using isc::dns::Name;
+using std::string;
+using std::vector;
+using namespace isc::datasrc;
+
+namespace {
+
+class MockClient : public DataSourceClient {
+public:
+    MockClient() :
+        commit_called_(false)
+    {}
+    virtual FindResult findZone(const Name&) const {
+        isc_throw(isc::NotImplemented, "Method not used in tests");
+    };
+    virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
+        getJournalReader(const Name&, uint32_t, uint32_t) const
+    {
+        isc_throw(isc::NotImplemented, "Method not used in tests");
+    }
+    virtual ZoneUpdaterPtr getUpdater(const Name& name, bool replace,
+                                      bool journaling) const;
+    // We store some information about what was happening here.
+    // It is publicly accessible, since this is private testing class
+    // anyway, so no need to dress it fancy into getters. Some are mutable,
+    // since many client methods are const, but we still want to know they
+    // were called.
+    mutable vector<Name> provided_updaters_;
+    // We store string representations of the RRsets. This is simpler than
+    // copying them and we can't really put them into shared pointers, because
+    // we get them as references.
+    vector<string> rrsets_;
+    bool commit_called_;
+};
+
+// The updater isn't really correct according to the API. For example,
+// the whole client can be committed only once in its lifetime. The
+// updaters would influence each other if there were more. But we
+// don't need more updaters in the same test, so it doesn't matter
+// and this way, it is much simpler.
+class Updater : public ZoneUpdater {
+public:
+    Updater(MockClient* client) :
+        client_(client)
+    {}
+    virtual ZoneFinder& getFinder() {
+        isc_throw(isc::NotImplemented, "Method not used in tests");
+    }
+    virtual void addRRset(const isc::dns::AbstractRRset& rrset) {
+        if (client_->commit_called_) {
+            isc_throw(DataSourceError, "Add after commit");
+        }
+        client_->rrsets_.push_back(rrset.toText());
+    }
+    virtual void deleteRRset(const isc::dns::AbstractRRset&) {
+        isc_throw(isc::NotImplemented, "Method not used in tests");
+    }
+    virtual void commit() {
+        client_->commit_called_ = true;
+    }
+private:
+    MockClient* client_;
+};
+
+ZoneUpdaterPtr
+MockClient::getUpdater(const Name& name, bool replace, bool journaling) const {
+    EXPECT_TRUE(replace);
+    EXPECT_FALSE(journaling);
+    provided_updaters_.push_back(name);
+    // const_cast is bad. But the const on getUpdater seems wrong in the first
+    // place, since updater will be modifying the data there. And the updater
+    // wants to store data into the client so we can examine it later.
+    return (ZoneUpdaterPtr(new Updater(const_cast<MockClient*>(this))));
+}
+
+class ZoneLoaderTest : public ::testing::Test {
+protected:
+    ZoneLoaderTest() :
+        rrclass_(RRClass::IN()),
+        ztable_segment_(memory::ZoneTableSegment::
+                        create(isc::data::NullElement(), rrclass_)),
+        source_client_(ztable_segment_, rrclass_)
+    {}
+    void prepareSource(const Name& zone, const char* filename) {
+        // TODO:
+        // Currently, load uses an urelated implementation. In the long term,
+        // the method will probably be deprecated. At that time, we should
+        // probably prepare the data in some other way (using sqlite3 or
+        // something). This is simpler for now.
+        source_client_.load(zone, string(TEST_DATA_DIR) + "/" + filename);
+    }
+private:
+    const RRClass rrclass_;
+    // This is because of the in-memory client. We use it to read data
+    // from. It is still easier than setting up sqlite3 client, since
+    // we have this one in the linked library.
+
+    // FIXME: We should be destroying it by ZoneTableSegment::destroy.
+    // But the shared pointer won't let us, will it?
+    boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
+protected:
+    memory::InMemoryClient source_client_;
+    // This one is mocked. It will help us see what is happening inside.
+    // Also, mocking it is simpler than setting up an sqlite3 client.
+    MockClient destination_client_;
+};
+
+// Use the loader to load an unsigned zone.
+TEST_F(ZoneLoaderTest, copyUnsigned) {
+    prepareSource(Name("example.org"), "example.org");
+    ZoneLoader loader(destination_client_, Name("example.org"),
+                      source_client_);
+    // It gets the updater directly in the constructor
+    ASSERT_EQ(1, destination_client_.provided_updaters_.size());
+    EXPECT_EQ(Name("example.org"), destination_client_.provided_updaters_[0]);
+    // Now load the whole zone
+    loader.load();
+    EXPECT_TRUE(destination_client_.commit_called_);
+    // We don't check the whole zone. We check the first and last and the
+    // count, which should be enough.
+    EXPECT_EQ(7, destination_client_.rrsets_.size());
+    // Ensure known order.
+    std::sort(destination_client_.rrsets_.begin(),
+              destination_client_.rrsets_.end());
+    EXPECT_EQ("TODO - check manually and copy-paste",
+              destination_client_.rrsets_.front());
+    EXPECT_EQ("TODO - check manually and copy-paste",
+              destination_client_.rrsets_.back());
+}
+
+}