Browse 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 12 years ago
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