Browse Source

[2377] Provide MasterLoader constructor from stream

Instead of file name. And use it for some of the tests, to avoid
juggling with files.
Michal 'vorner' Vaner 12 years ago
parent
commit
e5fb484fba
3 changed files with 80 additions and 18 deletions
  1. 21 1
      src/lib/dns/master_loader.cc
  2. 14 0
      src/lib/dns/master_loader.h
  3. 45 17
      src/lib/dns/tests/master_loader_unittest.cc

+ 21 - 1
src/lib/dns/master_loader.cc

@@ -51,6 +51,12 @@ public:
             ok_ = false;
             callbacks_.error("", 0, error);
         }
+        initialized_ = true;
+    }
+
+    void pushStreamSource(std::istream& stream) {
+        lexer_.pushSource(stream);
+        initialized_ = true;
     }
 
     // Get a string token. Handle it as error if it is not string.
@@ -65,7 +71,6 @@ public:
         }
         if (!initialized_) {
             pushSource(master_file_);
-            initialized_ = true;
         }
         size_t count = 0;
         while (ok_ && count < count_limit) {
@@ -184,6 +189,21 @@ MasterLoader::MasterLoader(const char* master_file,
                                  zone_class, callbacks, add_callback, options);
 }
 
+MasterLoader::MasterLoader(std::istream& stream,
+                           const Name& zone_origin,
+                           const RRClass& zone_class,
+                           const MasterLoaderCallbacks& callbacks,
+                           const AddRRCallback& add_callback,
+                           Options options)
+{
+    if (add_callback.empty()) {
+        isc_throw(isc::InvalidParameter, "Empty add RR callback");
+    }
+    impl_ = new MasterLoaderImpl("", zone_origin, zone_class, callbacks,
+                                 add_callback, options);
+    impl_->pushStreamSource(stream);
+}
+
 MasterLoader::~MasterLoader() {
     delete impl_;
 }

+ 14 - 0
src/lib/dns/master_loader.h

@@ -71,6 +71,20 @@ public:
                  const AddRRCallback& add_callback,
                  Options options = DEFAULT);
 
+    /// \brief Constructor from a stream
+    ///
+    /// This is a constructor very similar to the previous one. The only
+    /// difference is it doesn't take a filename, but an input stream
+    /// to read the data from. It is expected to be mostly used in tests,
+    /// but it is public as it may possibly be useful for other currently
+    /// unknown purposes.
+    MasterLoader(std::istream& input,
+                 const Name& zone_origin,
+                 const RRClass& zone_class,
+                 const MasterLoaderCallbacks& callbacks,
+                 const AddRRCallback& add_callback,
+                 Options options = DEFAULT);
+
     /// \brief Destructor
     ~MasterLoader();
 

+ 45 - 17
src/lib/dns/tests/master_loader_unittest.cc

@@ -26,13 +26,13 @@
 #include <string>
 #include <vector>
 #include <list>
-#include <fstream>
+#include <sstream>
 
 using namespace isc::dns;
 using std::vector;
 using std::string;
 using std::list;
-using std::ofstream;
+using std::stringstream;
 using std::endl;
 
 namespace {
@@ -67,8 +67,8 @@ public:
         rrsets_.push_back(rrset);
     }
 
-    void setLoader(const char* file, const Name& origin, const RRClass rrclass,
-                   const MasterLoader::Options options)
+    void setLoader(const char* file, const Name& origin,
+                   const RRClass& rrclass, const MasterLoader::Options options)
     {
         loader_.reset(new MasterLoader(file, origin, rrclass, callbacks_,
                                        boost::bind(&MasterLoaderTest::addRRset,
@@ -76,15 +76,22 @@ public:
                                        options));
     }
 
-    void prepareBrokenZone(const string& filename, const string& line) {
-        ofstream out(filename.c_str(),
-                     std::ios_base::out | std::ios_base::trunc);
-        ASSERT_FALSE(out.fail());
-        out << "example.org. 3600 IN SOA ns1.example.org. "
-            "admin.example.org. 1234 3600 1800 2419200 7200" << endl;
-        out << line << endl;
-        out << "correct 3600    IN  A 192.0.2.2" << endl;
-        out.close();
+    void setLoader(std::istream& stream, const Name& origin,
+                   const RRClass& rrclass, const MasterLoader::Options options)
+    {
+        loader_.reset(new MasterLoader(stream, origin, rrclass, callbacks_,
+                                       boost::bind(&MasterLoaderTest::addRRset,
+                                                   this, _1, _2, _3, _4, _5),
+                                       options));
+    }
+
+    string prepareZone(const string& line) {
+        string result;
+        result += "example.org. 3600 IN SOA ns1.example.org. "
+            "admin.example.org. 1234 3600 1800 2419200 7200\n";
+        result += line + "\n";
+        result += "correct 3600    IN  A 192.0.2.2\n";
+        return (result);
     }
 
     void clear() {
@@ -131,6 +138,21 @@ TEST_F(MasterLoaderTest, basicLoad) {
     checkRR("www.example.org", RRType::A(), "192.0.2.1");
 }
 
+// Check it works the same when created based on a stream, not filename
+TEST_F(MasterLoaderTest, streamConstructor) {
+    stringstream zone_stream(prepareZone(""));
+    setLoader(zone_stream, Name("example.org."), RRClass::IN(),
+              MasterLoader::MANY_ERRORS);
+
+    loader_->load();
+
+    EXPECT_TRUE(errors_.empty());
+    EXPECT_TRUE(warnings_.empty());
+    checkRR("example.org", RRType::SOA(), "ns1.example.org. "
+            "admin.example.org. 1234 3600 1800 2419200 7200");
+    checkRR("correct.example.org", RRType::A(), "192.0.2.2");
+}
+
 // Try loading data incrementally.
 TEST_F(MasterLoaderTest, incrementalLoad) {
     setLoader(TEST_DATA_SRCDIR "/example.org", Name("example.org."),
@@ -193,15 +215,15 @@ struct ErrorCase {
 // Test a broken zone is handled properly. We test several problems,
 // both in strict and lenient mode.
 TEST_F(MasterLoaderTest, brokenZone) {
-    const string filename(TEST_DATA_BUILDDIR "/broken.zone");
     for (const ErrorCase* ec = error_cases; ec->line != NULL; ++ec) {
         SCOPED_TRACE(ec->problem);
-        prepareBrokenZone(filename, ec->line);
+        const string zone(prepareZone(ec->line));
 
         {
             SCOPED_TRACE("Strict mode");
             clear();
-            setLoader(filename.c_str(), Name("example.org."), RRClass::IN(),
+            stringstream zone_stream(zone);
+            setLoader(zone_stream, Name("example.org."), RRClass::IN(),
                       MasterLoader::DEFAULT);
             loader_->load();
             EXPECT_EQ(1, errors_.size());
@@ -217,7 +239,8 @@ TEST_F(MasterLoaderTest, brokenZone) {
         {
             SCOPED_TRACE("Lenient mode");
             clear();
-            setLoader(filename.c_str(), Name("example.org."), RRClass::IN(),
+            stringstream zone_stream(zone);
+            setLoader(zone_stream, Name("example.org."), RRClass::IN(),
                       MasterLoader::MANY_ERRORS);
             loader_->load();
             EXPECT_EQ(1, errors_.size());
@@ -236,6 +259,11 @@ TEST_F(MasterLoaderTest, emptyCallback) {
     EXPECT_THROW(MasterLoader(TEST_DATA_SRCDIR "/example.org",
                               Name("example.org"), RRClass::IN(), callbacks_,
                               AddRRCallback()), isc::InvalidParameter);
+    // And the same with the second constructor
+    stringstream ss("");
+    EXPECT_THROW(MasterLoader(ss, Name("example.org"), RRClass::IN(),
+                              callbacks_, AddRRCallback()),
+                 isc::InvalidParameter);
 }
 
 // Check it throws when we try to load after loading was complete.