Parcourir la 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 il y a 12 ans
Parent
commit
e5fb484fba

+ 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.