Browse Source

[1512] added python wrapper for Message::clearSection().

We'll need this for creating RFC-compliant update responses.
also tightened parameter validation a bit, and added test cases for
bad parameters.
JINMEI Tatuya 13 years ago
parent
commit
f3e8996dc5

+ 4 - 0
src/lib/dns/message.cc

@@ -561,6 +561,10 @@ Message::removeRRset(const Section section, RRsetIterator& iterator) {
 
 void
 Message::clearSection(const Section section) {
+    if (impl_->mode_ != Message::RENDER) {
+        isc_throw(InvalidMessageOperation,
+                  "clearSection performed in non-render mode");
+    }
     if (section >= MessageImpl::NUM_SECTIONS) {
         isc_throw(OutOfRange, "Invalid message section: " << section);
     }

+ 6 - 0
src/lib/dns/message.h

@@ -513,6 +513,12 @@ public:
 
     /// \brief Remove all RRSets from the given Section
     ///
+    /// This method is only allowed in the \c RENDER mode, and the given
+    /// section must be valid.
+    ///
+    /// \throw InvalidMessageOperation Message is not in the \c RENDER mode
+    /// \throw OutOfRange The specified section is not valid
+    ///
     /// \param section Section to remove all rrsets from
     void clearSection(const Section section);
 

+ 27 - 0
src/lib/dns/python/message_python.cc

@@ -76,6 +76,7 @@ PyObject* Message_getSection(PyObject* self, PyObject* args);
 PyObject* Message_addQuestion(s_Message* self, PyObject* args);
 PyObject* Message_addRRset(s_Message* self, PyObject* args);
 PyObject* Message_clear(s_Message* self, PyObject* args);
+PyObject* Message_clearSection(PyObject* pyself, PyObject* args);
 PyObject* Message_makeResponse(s_Message* self);
 PyObject* Message_toText(s_Message* self);
 PyObject* Message_str(PyObject* self);
@@ -149,6 +150,8 @@ PyMethodDef Message_methods[] = {
       "Clears the message content (if any) and reinitialize the "
       "message in the given mode\n"
       "The argument must be either Message.PARSE or Message.RENDER"},
+    { "clear_section", Message_clearSection, METH_VARARGS,
+      Message_clearSection_doc },
     { "make_response", reinterpret_cast<PyCFunction>(Message_makeResponse), METH_NOARGS,
       "Prepare for making a response from a request.\n"
       "This will clear the DNS header except those fields that should be kept "
@@ -564,6 +567,30 @@ Message_clear(s_Message* self, PyObject* args) {
 }
 
 PyObject*
+Message_clearSection(PyObject* pyself, PyObject* args) {
+    s_Message* const self = static_cast<s_Message*>(pyself);
+    int section;
+
+    if (!PyArg_ParseTuple(args, "i", &section)) {
+        return (NULL);
+    }
+    try {
+        self->cppobj->clearSection(static_cast<Message::Section>(section));
+        Py_RETURN_NONE;
+    } catch (const InvalidMessageOperation& imo) {
+        PyErr_SetString(po_InvalidMessageOperation, imo.what());
+        return (NULL);
+    } catch (const isc::OutOfRange& ex) {
+        PyErr_SetString(PyExc_OverflowError, ex.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(po_IscException,
+                        "Unexpected exception in adding RRset");
+        return (NULL);
+    }
+}
+
+PyObject*
 Message_makeResponse(s_Message* self) {
     self->cppobj->makeResponse();
     Py_RETURN_NONE;

+ 17 - 0
src/lib/dns/python/message_python_inc.cc

@@ -38,4 +38,21 @@ Parameters:\n\
   options    Parse options\n\
 \n\
 ";
+
+const char* const Message_clearSection_doc = "\
+clear_section(section) -> void\n\
+\n\
+Remove all RRSets from the given Section.\n\
+\n\
+This method is only allowed in the RENDER mode, and the given section\n\
+must be valid.\n\
+\n\
+Exceptions:\n\
+  InvalidMessageOperation Message is not in the RENDER mode\n\
+  OverflowError The specified section is not valid\n\
+\n\
+Parameters:\n\
+  section    Section to remove all rrsets from\n\
+\n\
+";
 } // unnamed namespace

+ 20 - 0
src/lib/dns/python/tests/message_python_test.py

@@ -289,6 +289,26 @@ class MessageTest(unittest.TestCase):
         self.assertRaises(TypeError, self.r.clear, "wrong")
         self.assertRaises(TypeError, self.r.clear, 3)
 
+    def test_clear_question_section(self):
+        self.r.add_question(Question(Name("www.example.com"), RRClass.IN(),
+                                     RRType.A()))
+        self.assertEqual(1, self.r.get_rr_count(Message.SECTION_QUESTION))
+        self.r.clear_section(Message.SECTION_QUESTION)
+        self.assertEqual(0, self.r.get_rr_count(Message.SECTION_QUESTION))
+
+    def test_clear_section(self):
+        for section in [Message.SECTION_ANSWER, Message.SECTION_AUTHORITY,
+                        Message.SECTION_ADDITIONAL]:
+            self.r.add_rrset(section, self.rrset_a)
+            self.assertEqual(2, self.r.get_rr_count(section))
+            self.r.clear_section(section)
+            self.assertEqual(0, self.r.get_rr_count(section))
+
+        self.assertRaises(InvalidMessageOperation, self.p.clear_section,
+                          Message.SECTION_ANSWER)
+        self.assertRaises(OverflowError, self.r.clear_section,
+                          self.bogus_section)
+
     def test_to_wire(self):
         self.assertRaises(TypeError, self.r.to_wire, 1)
         self.assertRaises(InvalidMessageOperation,

+ 7 - 0
src/lib/dns/tests/message_unittest.cc

@@ -466,6 +466,13 @@ TEST_F(MessageTest, clearAdditionalSection) {
     EXPECT_EQ(0, message_render.getRRCount(Message::SECTION_ADDITIONAL));
 }
 
+TEST_F(MessageTest, badClearSection) {
+    // attempt of clearing a message in the parse mode.
+    EXPECT_THROW(message_parse.clearSection(Message::SECTION_QUESTION),
+                 InvalidMessageOperation);
+    // attempt of clearing out-of-range section
+    EXPECT_THROW(message_render.clearSection(bogus_section), OutOfRange);
+}
 
 TEST_F(MessageTest, badBeginSection) {
     // valid cases are tested via other tests