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

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

@@ -51,6 +51,12 @@ public:
             ok_ = false;
             ok_ = false;
             callbacks_.error("", 0, error);
             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.
     // Get a string token. Handle it as error if it is not string.
@@ -65,7 +71,6 @@ public:
         }
         }
         if (!initialized_) {
         if (!initialized_) {
             pushSource(master_file_);
             pushSource(master_file_);
-            initialized_ = true;
         }
         }
         size_t count = 0;
         size_t count = 0;
         while (ok_ && count < count_limit) {
         while (ok_ && count < count_limit) {
@@ -184,6 +189,21 @@ MasterLoader::MasterLoader(const char* master_file,
                                  zone_class, callbacks, add_callback, options);
                                  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() {
 MasterLoader::~MasterLoader() {
     delete impl_;
     delete impl_;
 }
 }

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

@@ -71,6 +71,20 @@ public:
                  const AddRRCallback& add_callback,
                  const AddRRCallback& add_callback,
                  Options options = DEFAULT);
                  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
     /// \brief Destructor
     ~MasterLoader();
     ~MasterLoader();
 
 

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

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