Parcourir la source

[2096] Further RdataReader tests

Testing rewinding it and accessing the stuff out of the usual order
(intermixing iteration of Rdata and the signatures).
Michal 'vorner' Vaner il y a 12 ans
Parent
commit
6bcd73aa1c

+ 11 - 4
src/lib/datasrc/memory/rdata_reader.cc

@@ -83,21 +83,23 @@ RdataReader::rewind() {
 }
 
 RdataReader::Result
-RdataReader::next() {
+RdataReader::nextInternal(const NameAction& name_action,
+                          const DataAction& data_action)
+{
     if (spec_pos_ < spec_count_) {
         const RdataFieldSpec& spec(spec_.fields[(spec_pos_ ++) %
                                                 spec_.field_count]);
         if (spec.type == RdataFieldSpec::DOMAIN_NAME) {
             const LabelSequence sequence(data_ + data_pos_);
             data_pos_ += sequence.getSerializedLength();
-            name_action_(sequence, spec.name_attributes);
+            name_action(sequence, spec.name_attributes);
             return (Result(sequence, spec.name_attributes));
         } else {
             const size_t length(spec.type == RdataFieldSpec::FIXEDLEN_DATA ?
                                 spec.fixeddata_len : lengths_[length_pos_ ++]);
             Result result(data_ + data_pos_, length);
             data_pos_ += length;
-            data_action_(result.data(), result.size());
+            data_action(result.data(), result.size());
             return (result);
         }
     } else {
@@ -107,6 +109,11 @@ RdataReader::next() {
 }
 
 RdataReader::Result
+RdataReader::next() {
+    return (nextInternal(name_action_, data_action_));
+}
+
+RdataReader::Result
 RdataReader::nextSig() {
     if (sig_pos_ < sig_count_) {
         if (sigs_ == NULL) {
@@ -117,7 +124,7 @@ RdataReader::nextSig() {
             size_t spec_pos = spec_pos_;
             size_t length_pos = length_pos_;
             // When the next() gets to the last item, it sets the sigs_
-            iterate();
+            while (nextInternal(emptyNameAction, emptyDataAction)) {}
             assert(sigs_ != NULL);
             // Return the state
             data_pos_ = data_pos;

+ 2 - 0
src/lib/datasrc/memory/rdata_reader.h

@@ -269,6 +269,8 @@ private:
     // The positions in data.
     size_t data_pos_, spec_pos_, length_pos_;
     size_t sig_pos_, sig_data_pos_;
+    Result nextInternal(const NameAction& name_action,
+                        const DataAction& data_action);
 };
 
 }

+ 110 - 2
src/lib/datasrc/memory/tests/rdata_serialization_unittest.cc

@@ -351,6 +351,50 @@ public:
     }
 };
 
+// Decode using reader with the return value of next, but after the reader
+// was used and rewund.
+class RewundDecoder {
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data,
+                       MessageRenderer& renderer)
+    {
+        RdataReader reader(rrclass, rrtype, encoded_data.size(),
+                           &encoded_data[0], rdata_count, sig_count);
+        // Use the reader first and rewind it
+        reader.iterateSig();
+        reader.iterate();
+        reader.rewind();
+        RdataReader::Result field;
+        while (field = reader.next()) {
+            switch (field.type()) {
+                case RdataReader::DATA:
+                    renderer.writeData(field.data(), field.size());
+                    break;
+                case RdataReader::NAME:
+                    renderer.writeName(field.label(), field.compressible());
+                    break;
+                default:
+                    FAIL();
+            }
+        }
+
+        renderer.writeName(dummy_name2);
+
+        while (field = reader.nextSig()) {
+            switch (field.type()) {
+                case RdataReader::DATA:
+                    renderer.writeData(field.data(), field.size());
+                    break;
+                default: // There are also no NAME fields in RRSigs
+                    FAIL();
+            }
+        }
+    }
+};
+
 // Check using callbacks and calling next until the end.
 class CallbackDecoder {
 public:
@@ -391,8 +435,72 @@ public:
     }
 };
 
-typedef ::testing::Types<ManualDecoderStyle, NextDecoder, CallbackDecoder,
-                         IterateDecoder> DecoderStyles;
+// This one does not adhere to the usual way the reader is used, trying
+// to confuse it. It iterates part of the data manually and then reads
+// the rest through iterate. It also reads the signatures in the middle
+// of rendering.
+template<bool start_data, bool start_sig>
+class HybridDecoder {
+private:
+    // Append data either to the renderer or to the vector passed.
+    // The double pointer is there so we can change the renderer to NULL
+    // and back during the test.
+    static void appendData(vector<uint8_t>* where, MessageRenderer** renderer,
+                           const uint8_t* data, size_t size)
+    {
+        if (*renderer != NULL) {
+            (*renderer)->writeData(data, size);
+        } else {
+            where->insert(where->end(), data, data + size);
+        }
+    }
+public:
+    static void decode(const isc::dns::RRClass& rrclass,
+                       const isc::dns::RRType& rrtype,
+                       size_t rdata_count, size_t sig_count, size_t,
+                       const vector<uint8_t>& encoded_data,
+                       MessageRenderer& renderer)
+    {
+        vector<uint8_t> data;
+        MessageRenderer* current;
+        RdataReader reader(rrclass, rrtype, encoded_data.size(),
+                           &encoded_data[0], rdata_count, sig_count,
+                           boost::bind(renderNameField, &renderer,
+                                       additionalRequired(rrtype), _1, _2),
+                           boost::bind(appendData, &data, &current, _1, _2));
+        if (start_sig) {
+            current = NULL;
+            reader.nextSig();
+        }
+        // Render first part of data. If there's none, return empty Result and
+        // do nothing.
+        if (start_data) {
+            current = &renderer;
+            reader.next();
+        }
+        // Now, we let all sigs to be copied to data. We disable the
+        // renderer for this.
+        current = NULL;
+        reader.iterateSig();
+        // Now return the renderer and render the rest of the data
+        current = &renderer;
+        reader.iterate();
+        // Now, this should not break anything and should be valid, but should
+        // return ends.
+        EXPECT_FALSE(reader.next());
+        EXPECT_FALSE(reader.nextSig());
+        // Render the name and the sigs
+        renderer.writeName(dummy_name2);
+        renderer.writeData(&data[0], data.size());
+    }
+};
+
+typedef ::testing::Types<ManualDecoderStyle, NextDecoder, RewundDecoder,
+                         CallbackDecoder, IterateDecoder,
+                         HybridDecoder<true, true>, HybridDecoder<true, false>,
+                         HybridDecoder<false, true>,
+                         HybridDecoder<false, false> >
+    DecoderStyles;
 TYPED_TEST_CASE(RdataEncodeDecodeTest, DecoderStyles);
 
 void