Browse Source

[1261] implemented IXFRAdd, IXFREnd and AXFR (currently just raise an
exception) classes.

JINMEI Tatuya 13 years ago
parent
commit
48bec4c73b
2 changed files with 118 additions and 7 deletions
  1. 79 3
      src/bin/xfrin/tests/xfrin_test.py
  2. 39 4
      src/bin/xfrin/xfrin.py.in

+ 79 - 3
src/bin/xfrin/tests/xfrin_test.py

@@ -256,7 +256,7 @@ class TestXfrinFirstData(TestXfrinState):
         self.assertFalse(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual(type(XfrinAXFR()), type(self.conn.get_xfrstate()))
 
-class TestXfrinIAXFDeleteSOA(TestXfrinState):
+class TestXfrinIXFRDeleteSOA(TestXfrinState):
     def setUp(self):
         super().setUp()
         self.state = XfrinIXFRDeleteSOA()
@@ -272,9 +272,11 @@ class TestXfrinIAXFDeleteSOA(TestXfrinState):
         self.assertRaises(XfrinException, self.state.handle_rr, self.conn,
                           self.ns_rrset)
 
-class TestXfrinIAXFDelete(TestXfrinState):
+class TestXfrinIXFRDelete(TestXfrinState):
     def setUp(self):
         super().setUp()
+        # We need record the state in 'conn' to check the case where the
+        # state doesn't change.
         XfrinIXFRDelete().set_xfrstate(self.conn, XfrinIXFRDelete())
         self.state = self.conn.get_xfrstate()
 
@@ -294,9 +296,83 @@ class TestXfrinIAXFDelete(TestXfrinState):
         self.assertFalse(self.state.handle_rr(self.conn, soa_rrset))
         self.assertEqual([], self.conn._diff.get_buffer())
         self.assertEqual(1234, self.conn._current_serial)
-        self.assertEqual(type(XfrinAddSOA()),
+        self.assertEqual(type(XfrinIXFRAddSOA()),
                          type(self.conn.get_xfrstate()))
 
+class TestXfrinIXFRAddSOA(TestXfrinState):
+    def setUp(self):
+        super().setUp()
+        self.state = XfrinIXFRAddSOA()
+
+    def test_handle_rr(self):
+        self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
+        self.assertEqual(type(XfrinIXFRAdd()), type(self.conn.get_xfrstate()))
+        self.assertEqual([('add', soa_rrset)],
+                         self.conn._diff.get_buffer())
+
+    def test_handle_non_soa(self):
+        self.assertRaises(XfrinException, self.state.handle_rr, self.conn,
+                          self.ns_rrset)
+
+class TestXfrinIXFRAdd(TestXfrinState):
+    def setUp(self):
+        super().setUp()
+        # We need record the state in 'conn' to check the case where the
+        # state doesn't change.
+        XfrinIXFRAdd().set_xfrstate(self.conn, XfrinIXFRAdd())
+        self.conn._current_serial = 1230
+        self.state = self.conn.get_xfrstate()
+
+    def test_handle_add_rr(self):
+        # Non SOA RRs are simply (goting to be) added in this state
+        self.assertTrue(self.state.handle_rr(self.conn, self.ns_rrset))
+        self.assertEqual([('add', self.ns_rrset)],
+                         self.conn._diff.get_buffer())
+        # The state shouldn't change
+        self.assertEqual(type(XfrinIXFRAdd()), type(self.conn.get_xfrstate()))
+
+    def test_handle_end_soa(self):
+        self.conn._end_serial = 1234
+        self.conn._diff.add_data(self.ns_rrset) # put some dummy change
+        self.assertTrue(self.state.handle_rr(self.conn, soa_rrset))
+        self.assertEqual(type(XfrinIXFREnd()), type(self.conn.get_xfrstate()))
+        # handle_rr should have caused commit, and the buffer should now be
+        # empty.
+        self.assertEqual([], self.conn._diff.get_buffer())
+
+    def test_handle_new_delete(self):
+        # SOA RR whose serial is the current one means we are going to a new
+        # difference, starting with removing that SOA.
+        self.conn._diff.add_data(self.ns_rrset) # put some dummy change
+        self.assertFalse(self.state.handle_rr(self.conn, self.begin_soa))
+        self.assertEqual([], self.conn._diff.get_buffer())
+        self.assertEqual(type(XfrinIXFRDeleteSOA()),
+                         type(self.conn.get_xfrstate()))
+
+    def test_handle_out_of_sync(self):
+        # getting SOA with an inconsistent serial.  This is an error.
+        self.conn._end_serial = 1235
+        self.assertRaises(XfrinProtocolError, self.state.handle_rr,
+                          self.conn, soa_rrset)
+
+class TestXfrinIXFREnd(TestXfrinState):
+    def setUp(self):
+        super().setUp()
+        self.state = XfrinIXFREnd()
+
+    def test_handle_rr(self):
+        self.assertRaises(XfrinProtocolError, self.state.handle_rr, self.conn,
+                          self.ns_rrset)
+
+class TestXfrinAXFR(TestXfrinState):
+    def setUp(self):
+        super().setUp()
+        self.state = XfrinAXFR()
+
+    def test_handle_rr(self):
+        self.assertRaises(XfrinException, self.state.handle_rr, self.conn,
+                          soa_rrset)
+
 class TestXfrinConnection(unittest.TestCase):
     def setUp(self):
         if os.path.exists(TEST_DB_FILE):

+ 39 - 4
src/bin/xfrin/xfrin.py.in

@@ -192,16 +192,51 @@ class XfrinIXFRDelete(XfrinState):
     def handle_rr(self, conn, rr):
         if rr.get_type() == RRType.SOA():
             conn._current_serial = get_soa_serial(rr.get_rdata()[0])
-            self.set_xfrstate(conn, XfrinAddSOA())
+            self.set_xfrstate(conn, XfrinIXFRAddSOA())
             return False
         conn._diff.remove_data(rr)
         return True
 
-class XfrinAddSOA(XfrinState):
-    pass
+class XfrinIXFRAddSOA(XfrinState):
+    def handle_rr(self, conn, rr):
+        if rr.get_type() != RRType.SOA():
+            # this shouldn't happen; should this occur it means an internal
+            #
+            raise XfrinException(rr.get_type().to_text() + \
+                                     ' RR is given in IXFRAddSOA state')
+        conn._diff.add_data(rr)
+        self.set_xfrstate(conn, XfrinIXFRAdd())
+        return True
+
+class XfrinIXFRAdd(XfrinState):
+    def handle_rr(self, conn, rr):
+        if rr.get_type() == RRType.SOA():
+            soa_serial = get_soa_serial(rr.get_rdata()[0])
+            if soa_serial == conn._end_serial:
+                conn._diff.commit()
+                self.set_xfrstate(conn, XfrinIXFREnd())
+                return True
+            elif soa_serial != conn._current_serial:
+                raise XfrinProtocolError('IXFR out of sync: expected ' + \
+                                             'serial ' + \
+                                             str(conn._current_serial) + \
+                                             ', got ' + str(soa_serial))
+            else:
+                conn._diff.commit()
+                self.set_xfrstate(conn, XfrinIXFRDeleteSOA())
+                return False
+        conn._diff.add_data(rr)
+        return True
+
+class XfrinIXFREnd(XfrinState):
+    def handle_rr(self, conn, rr):
+        raise XfrinProtocolError('Extra data after the end of IXFR diffs: ' + \
+                                     rr.to_text())
 
 class XfrinAXFR(XfrinState):
-    pass
+    def handle_rr(self, conn, rr):
+        raise XfrinException('Falling back from IXFR to AXFR not ' + \
+                                 'supported yet')
 
 class XfrinConnection(asyncore.dispatcher):
     '''Do xfrin in this class. '''