Browse Source

[1288] switch to new API 6: don't use the old API loader to prepare test
data. also added some more test cases for _get_notify_slaves_from_ns
and some log messages.

JINMEI Tatuya 13 years ago
parent
commit
d99d546be0

+ 30 - 6
src/lib/python/isc/notify/notify_out.py

@@ -52,6 +52,16 @@ _BAD_REPLY_PACKET = 5
 
 SOCK_DATA = b's'
 
+# borrowed from xfrin.py @ #1298.  We should eventually unify it.
+def format_zone_str(zone_name, zone_class):
+    """Helper function to format a zone name and class as a string of
+       the form '<name>/<class>'.
+       Parameters:
+       zone_name (isc.dns.Name) name to format
+       zone_class (isc.dns.RRClass) class to format
+    """
+    return zone_name.to_text() + '/' + str(zone_class)
+
 class NotifyOutDataSourceError(Exception):
     """An exception raised when data source error happens within notify out.
 
@@ -255,23 +265,37 @@ class NotifyOut:
         Note: this is the simplest way to get the address of slaves,
         but not correct, it can't handle the delegation slaves, or the CNAME
         and DNAME logic.
-        TODO. the function should be provided by one library.'''
+        TODO. the function should be provided by one library.
+
+        '''
+        # Prepare data source client.  This should eventually be moved to
+        # an earlier stage of initialization and also support multiple
+        # data sources.
         datasrc_config = '{ "database_file": "' + self._db_file + '"}'
-        result, finder = DataSourceClient('sqlite3',
-                                          datasrc_config).find_zone(zone_name)
+        try:
+            result, finder = DataSourceClient('sqlite3',
+                                              datasrc_config).find_zone(
+                zone_name)
+        except isc.datasrc.Error as ex:
+            logger.error(NOTIFY_OUT_DATASRC_ACCESS_FAILURE, ex)
+            return []
         if result is not DataSourceClient.SUCCESS:
+            logger.error(NOTIFY_OUT_DATASRC_ZONE_NOT_FOUND,
+                         format_zone_str(zone_name, zone_class))
             return []
 
         result, ns_rrset = finder.find(zone_name, RRType.NS(), None,
                                        finder.FIND_DEFAULT)
         if result is not finder.SUCCESS or ns_rrset is None:
-            # TODO: Log it.
+            logger.warn(NOTIFY_OUT_ZONE_NO_NS,
+                        format_zone_str(zone_name, zone_class))
             return []
         result, soa_rrset = finder.find(zone_name, RRType.SOA(), None,
-                                       finder.FIND_DEFAULT)
+                                        finder.FIND_DEFAULT)
         if result is not finder.SUCCESS or soa_rrset is None or \
                 soa_rrset.get_rdata_count() != 1:
-            # TODO: Log it.
+            logger.warn(NOTIFY_OUT_ZONE_BAD_SOA,
+                        format_zone_str(zone_name, zone_class))
             return []           # broken zone anyway, stop here.
         soa_mname = Name(soa_rrset.get_rdata()[0].to_text().split(' ')[0])
 

+ 22 - 0
src/lib/python/isc/notify/notify_out_messages.mes

@@ -81,3 +81,25 @@ programming error, since all exceptions should have been caught
 explicitly. Please file a bug report. Since there was a response,
 no more notifies will be sent to this server for this notification
 event.
+
+% NOTIFY_OUT_DATASRC_ACCESS_FAILURE failed to get access to data source: %1
+notify_out failed to get access to one of configured data sources.
+Detailed error is shown in the log message.  This can be either a
+configuration error or installation setup failure.
+
+% NOTIFY_OUT_DATASRC_ZONE_NOT_FOUND Zone %1 is not found
+notify_out attempted to get slave information of a zone but the zone
+isn't found in the expected data source.  This shouldn't happen,
+because notify_out first identifies a list of available zones before
+this process.  So this means some critical inconsistency in the data
+source or software bug.
+
+% NOTIFY_OUT_ZONE_NO_NS Zone %1 doesn't have NS RR
+This is a warning issued when the notify_out module finds a zone that
+doesn't have an NS RR.  Notify message won't be sent to such a zone.
+
+% NOTIFY_OUT_ZONE_BAD_SOA Zone %1 is invalid in terms of SOA
+This is a warning issued when the notify_out module finds a zone that
+doesn't have an SOA RR or has multiple SOA RRs.  Notify message won't
+be sent to such a zone.
+

+ 6 - 0
src/lib/python/isc/notify/tests/Makefile.am

@@ -1,6 +1,11 @@
 PYCOVERAGE_RUN=@PYCOVERAGE_RUN@
 PYTESTS = notify_out_test.py
 EXTRA_DIST = $(PYTESTS)
+EXTRA_DIST += testdata/test.sqlite3 testdata/brokentest.sqlite3
+# The rest of the files are actually not necessary, but added for reference
+EXTRA_DIST += testdata/example.com testdata/example.net
+EXTRA_DIST += testdata/nons.example testdata/nosoa.example
+EXTRA_DIST += testdata/multisoa.example
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
 # required by loadable python modules.
@@ -20,5 +25,6 @@ endif
 	echo Running test: $$pytest ; \
 	PYTHONPATH=$(COMMON_PYTHON_PATH):$(abs_top_builddir)/src/lib/dns/python/.libs \
 	$(LIBRARY_PATH_PLACEHOLDER) \
+	TESTDATASRCDIR=$(abs_top_srcdir)/src/lib/python/isc/notify/tests/testdata/ \
 	$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
 	done

+ 22 - 41
src/lib/python/isc/notify/tests/notify_out_test.py

@@ -19,11 +19,12 @@ import os
 import tempfile
 import time
 import socket
-from isc.datasrc import sqlite3_ds
 from isc.notify import notify_out, SOCK_DATA
 import isc.log
 from isc.dns import *
 
+TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
+
 # our fake socket, where we can read and insert messages
 class MockSocket():
     def __init__(self):
@@ -93,10 +94,8 @@ class TestZoneNotifyInfo(unittest.TestCase):
 
 class TestNotifyOut(unittest.TestCase):
     def setUp(self):
-        self._db_file = tempfile.NamedTemporaryFile(delete=False)
-        sqlite3_ds.load(self._db_file.name, 'example.net.', self._example_net_data_reader)
-        sqlite3_ds.load(self._db_file.name, 'example.com.', self._example_com_data_reader)
-        self._notify = notify_out.NotifyOut(self._db_file.name)
+        self._db_file = TESTDATA_SRCDIR + '/test.sqlite3'
+        self._notify = notify_out.NotifyOut(self._db_file)
         self._notify._notify_infos[('example.com.', 'IN')] = MockZoneNotifyInfo('example.com.', 'IN')
         self._notify._notify_infos[('example.com.', 'CH')] = MockZoneNotifyInfo('example.com.', 'CH')
         self._notify._notify_infos[('example.net.', 'IN')] = MockZoneNotifyInfo('example.net.', 'IN')
@@ -111,10 +110,6 @@ class TestNotifyOut(unittest.TestCase):
         com_ch_info = self._notify._notify_infos[('example.com.', 'CH')]
         com_ch_info.notify_slaves.append(('1.1.1.1', 5353))
 
-    def tearDown(self):
-        self._db_file.close()
-        os.unlink(self._db_file.name)
-
     def test_send_notify(self):
         notify_out._MAX_NOTIFY_NUM = 2
 
@@ -310,37 +305,6 @@ class TestNotifyOut(unittest.TestCase):
         self._notify._zone_notify_handler(example_net_info, notify_out._EVENT_READ)
         self.assertNotEqual(cur_tgt, example_net_info._notify_current)
 
-
-    def _example_net_data_reader(self):
-        zone_data = [
-        ('example.net.',         '1000',  'IN',  'SOA', 'a.dns.example.net. mail.example.net. 1 1 1 1 1'),
-        ('example.net.',         '1000',  'IN',  'NS',  'a.dns.example.net.'),
-        ('example.net.',         '1000',  'IN',  'NS',  'b.dns.example.net.'),
-        ('example.net.',         '1000',  'IN',  'NS',  'c.dns.example.net.'),
-        ('a.dns.example.net.',   '1000',  'IN',  'A',    '1.1.1.1'),
-        ('a.dns.example.net.',   '1000',  'IN',  'AAAA', '2:2::2:2'),
-        ('b.dns.example.net.',   '1000',  'IN',  'A',    '3.3.3.3'),
-        ('b.dns.example.net.',   '1000',  'IN',  'AAAA', '4:4::4:4'),
-        ('b.dns.example.net.',   '1000',  'IN',  'AAAA', '5:5::5:5'),
-        ('c.dns.example.net.',   '1000',  'IN',  'A',    '6.6.6.6'),
-        ('c.dns.example.net.',   '1000',  'IN',  'A',    '7.7.7.7'),
-        ('c.dns.example.net.',   '1000',  'IN',  'AAAA', '8:8::8:8')]
-        for item in zone_data:
-            yield item
-
-    def _example_com_data_reader(self):
-        zone_data = [
-        ('example.com.',         '1000',  'IN',  'SOA', 'a.dns.example.com. mail.example.com. 1 1 1 1 1'),
-        ('example.com.',         '1000',  'IN',  'NS',  'a.dns.example.com.'),
-        ('example.com.',         '1000',  'IN',  'NS',  'b.dns.example.com.'),
-        ('example.com.',         '1000',  'IN',  'NS',  'c.dns.example.com.'),
-        ('a.dns.example.com.',   '1000',  'IN',  'A',    '1.1.1.1'),
-        ('b.dns.example.com.',   '1000',  'IN',  'A',    '3.3.3.3'),
-        ('b.dns.example.com.',   '1000',  'IN',  'AAAA', '4:4::4:4'),
-        ('b.dns.example.com.',   '1000',  'IN',  'AAAA', '5:5::5:5')]
-        for item in zone_data:
-            yield item
-
     def test_get_notify_slaves_from_ns(self):
         records = self._notify._get_notify_slaves_from_ns(Name('example.net.'),
                                                           RRClass.IN())
@@ -359,8 +323,25 @@ class TestNotifyOut(unittest.TestCase):
         self.assertEqual('4:4::4:4', records[1])
         self.assertEqual('3.3.3.3', records[0])
 
+    def test_get_notify_slaves_from_ns_unusual(self):
+        self._notify._db_file = TESTDATA_SRCDIR + '/brokentest.sqlite3'
+        self.assertEqual([], self._notify._get_notify_slaves_from_ns(
+                Name('nons.example'), RRClass.IN()))
+        self.assertEqual([], self._notify._get_notify_slaves_from_ns(
+                Name('nosoa.example'), RRClass.IN()))
+        self.assertEqual([], self._notify._get_notify_slaves_from_ns(
+                Name('multisoa.example'), RRClass.IN()))
+
+        self.assertEqual([], self._notify._get_notify_slaves_from_ns(
+                Name('nosuchzone.example'), RRClass.IN()))
+
+        # This will cause failure in getting access to the data source.
+        self._notify._db_file = TESTDATA_SRCDIR + '/nodir/error.sqlite3'
+        self.assertEqual([], self._notify._get_notify_slaves_from_ns(
+                Name('example.com'), RRClass.IN()))
+
     def test_init_notify_out(self):
-        self._notify._init_notify_out(self._db_file.name)
+        self._notify._init_notify_out(self._db_file)
         self.assertListEqual([('3.3.3.3', 53), ('4:4::4:4', 53), ('5:5::5:5', 53)],
                              self._notify._notify_infos[('example.com.', 'IN')].notify_slaves)
 

BIN
src/lib/python/isc/notify/tests/testdata/brokentest.sqlite3


+ 10 - 0
src/lib/python/isc/notify/tests/testdata/example.com

@@ -0,0 +1,10 @@
+;; This is the source of a zone stored in test.sqlite3.  It's provided
+;; for reference purposes only.
+example.com.         1000  IN  SOA a.dns.example.com. mail.example.com. 1 1 1 1 1
+example.com.         1000  IN  NS  a.dns.example.com.
+example.com.         1000  IN  NS  b.dns.example.com.
+example.com.         1000  IN  NS  c.dns.example.com.
+a.dns.example.com.   1000  IN  A    1.1.1.1
+b.dns.example.com.   1000  IN  A    3.3.3.3
+b.dns.example.com.   1000  IN  AAAA 4:4::4:4
+b.dns.example.com.   1000  IN  AAAA 5:5::5:5

+ 14 - 0
src/lib/python/isc/notify/tests/testdata/example.net

@@ -0,0 +1,14 @@
+;; This is the source of a zone stored in test.sqlite3.  It's provided
+;; for reference purposes only.
+example.net.         1000  IN  SOA a.dns.example.net. mail.example.net. 1 1 1 1 1
+example.net.         1000  IN  NS  a.dns.example.net.
+example.net.         1000  IN  NS  b.dns.example.net.
+example.net.         1000  IN  NS  c.dns.example.net.
+a.dns.example.net.   1000  IN  A    1.1.1.1
+a.dns.example.net.   1000  IN  AAAA 2:2::2:2
+b.dns.example.net.   1000  IN  A    3.3.3.3
+b.dns.example.net.   1000  IN  AAAA 4:4::4:4
+b.dns.example.net.   1000  IN  AAAA 5:5::5:5
+c.dns.example.net.   1000  IN  A    6.6.6.6
+c.dns.example.net.   1000  IN  A    7.7.7.7
+c.dns.example.net.   1000  IN  AAAA 8:8::8:8

+ 5 - 0
src/lib/python/isc/notify/tests/testdata/multisoa.example

@@ -0,0 +1,5 @@
+;; This is the source of a zone stored in test.sqlite3.  It's provided
+;; for reference purposes only.
+multisoa.example.         1000  IN  SOA a.dns.multisoa.example. mail.multisoa.example. 1 1 1 1 1
+multisoa.example.         1000  IN  SOA a.dns.multisoa.example. mail.multisoa.example. 2 2 2 2 2
+multisoa.example.         1000  IN  NS  a.dns.multisoa.example.

+ 3 - 0
src/lib/python/isc/notify/tests/testdata/nons.example

@@ -0,0 +1,3 @@
+;; This is the source of a zone stored in test.sqlite3.  It's provided
+;; for reference purposes only.
+nons.example.         1000  IN  SOA a.dns.nons.example. mail.nons.example. 1 1 1 1 1

+ 7 - 0
src/lib/python/isc/notify/tests/testdata/nosoa.example

@@ -0,0 +1,7 @@
+;; This is the source of a zone stored in test.sqlite3.  It's provided
+;; for reference purposes only.
+;; (SOA has been removed)
+nosoa.example.         1000  IN  SOA a.dns.example.com. mail.example.com. 1 1 1 1 1
+nosoa.example.         1000  IN  NS  a.dns.nosoa.example.
+nosoa.example.         1000  IN  NS  b.dns.nosoa.example.
+nosoa.example.         1000  IN  NS  c.dns.nosoa.example.

BIN
src/lib/python/isc/notify/tests/testdata/test.sqlite3