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()
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()
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):
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. '''