zone_loader_test.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. # Copyright (C) 2012 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. import isc.datasrc
  16. import isc.dns
  17. import os
  18. import unittest
  19. import shutil
  20. # Constants and common data used in tests
  21. TESTDATA_PATH = os.environ['TESTDATA_PATH']
  22. TESTDATA_WRITE_PATH = os.environ['TESTDATA_WRITE_PATH']
  23. ZONE_FILE = TESTDATA_PATH + '/example.com'
  24. STATIC_ZONE_FILE = '../../../../datasrc/static.zone'
  25. SOURCE_DB_FILE = TESTDATA_PATH + '/example.com.source.sqlite3'
  26. ORIG_DB_FILE = TESTDATA_PATH + '/example.com.sqlite3'
  27. DB_FILE = TESTDATA_WRITE_PATH + '/zoneloadertest.sqlite3'
  28. DB_CLIENT_CONFIG = '{ "database_file": "' + DB_FILE + '" }'
  29. DB_SOURCE_CLIENT_CONFIG = '{ "database_file": "' + SOURCE_DB_FILE + '" }'
  30. ORIG_SOA_TXT = 'example.com. 3600 IN SOA master.example.com. ' +\
  31. 'admin.example.com. 1234 3600 1800 2419200 7200\n'
  32. NEW_SOA_TXT = 'example.com. 1000 IN SOA a.dns.example.com. ' +\
  33. 'mail.example.com. 1 1 1 1 1\n'
  34. class ZoneLoaderTests(unittest.TestCase):
  35. def setUp(self):
  36. self.test_name = isc.dns.Name("example.com")
  37. self.test_file = ZONE_FILE
  38. self.client = isc.datasrc.DataSourceClient("sqlite3", DB_CLIENT_CONFIG)
  39. # Make a fresh copy of the database
  40. shutil.copy(ORIG_DB_FILE, DB_FILE)
  41. def test_bad_constructor(self):
  42. self.assertRaises(TypeError, isc.datasrc.ZoneLoader)
  43. self.assertRaises(TypeError, isc.datasrc.ZoneLoader, 1)
  44. self.assertRaises(TypeError, isc.datasrc.ZoneLoader,
  45. None, self.test_name, self.test_file)
  46. self.assertRaises(TypeError, isc.datasrc.ZoneLoader,
  47. self.client, None, self.test_file)
  48. self.assertRaises(TypeError, isc.datasrc.ZoneLoader,
  49. self.client, self.test_name, None)
  50. self.assertRaises(TypeError, isc.datasrc.ZoneLoader,
  51. self.client, self.test_name, self.test_file, 1)
  52. def check_zone_soa(self, soa_txt):
  53. """
  54. Check that the given SOA RR exists and matches the expected string
  55. """
  56. result, finder = self.client.find_zone(self.test_name)
  57. self.assertEqual(self.client.SUCCESS, result)
  58. result, rrset, _ = finder.find(self.test_name, isc.dns.RRType.SOA())
  59. self.assertEqual(finder.SUCCESS, result)
  60. self.assertEqual(soa_txt, rrset.to_text())
  61. def check_load(self, loader):
  62. self.check_zone_soa(ORIG_SOA_TXT)
  63. loader.load()
  64. self.check_zone_soa(NEW_SOA_TXT)
  65. # And after that, it should throw
  66. self.assertRaises(isc.dns.InvalidOperation, loader.load)
  67. def test_load_from_file(self):
  68. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  69. self.test_file)
  70. self.check_load(loader)
  71. def test_load_from_client(self):
  72. source_client = isc.datasrc.DataSourceClient('sqlite3',
  73. DB_SOURCE_CLIENT_CONFIG)
  74. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  75. source_client)
  76. self.check_load(loader)
  77. def test_load_from_file_checkrefs(self):
  78. # A test to see the refcount is increased properly
  79. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  80. self.test_file)
  81. # Explicitely delete the objects here, so we trigger wrong
  82. # DECREF calls
  83. self.client = None
  84. self.test_name = None
  85. self.test_file = None
  86. loader.load()
  87. loader = None
  88. def test_load_from_client_checkrefs(self):
  89. # A test to see the refcount is increased properly
  90. source_client = isc.datasrc.DataSourceClient('sqlite3',
  91. DB_SOURCE_CLIENT_CONFIG)
  92. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  93. source_client)
  94. # Explicitely delete the objects here, so we trigger wrong
  95. # DECREF calls
  96. self.client = None
  97. self.test_name = None
  98. source_client = None
  99. loader.load()
  100. loader = None
  101. def check_load_incremental(self, loader):
  102. # New zone has 8 RRs
  103. # After 5, it should return False
  104. self.assertFalse(loader.load_incremental(5))
  105. # New zone should not have been loaded yet
  106. self.check_zone_soa(ORIG_SOA_TXT)
  107. # After 5 more, it should return True (only having read 3)
  108. self.assertTrue(loader.load_incremental(5))
  109. # New zone should now be loaded
  110. self.check_zone_soa(NEW_SOA_TXT)
  111. # And after that, it should throw
  112. self.assertRaises(isc.dns.InvalidOperation, loader.load_incremental, 5)
  113. def test_load_from_file_incremental(self):
  114. # Create loader and load the zone
  115. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  116. self.test_file)
  117. self.check_load_incremental(loader)
  118. def test_load_from_client_incremental(self):
  119. source_client = isc.datasrc.DataSourceClient('sqlite3',
  120. DB_SOURCE_CLIENT_CONFIG)
  121. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  122. source_client)
  123. self.check_load_incremental(loader)
  124. def test_bad_file(self):
  125. self.check_zone_soa(ORIG_SOA_TXT)
  126. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  127. 'no such file')
  128. self.assertRaises(isc.datasrc.MasterFileError, loader.load)
  129. self.check_zone_soa(ORIG_SOA_TXT)
  130. def test_bad_file_incremental(self):
  131. self.check_zone_soa(ORIG_SOA_TXT)
  132. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  133. 'no such file')
  134. self.assertRaises(isc.datasrc.MasterFileError,
  135. loader.load_incremental, 1)
  136. self.check_zone_soa(ORIG_SOA_TXT)
  137. def test_no_such_zone_in_target(self):
  138. self.assertRaises(isc.datasrc.Error, isc.datasrc.ZoneLoader,
  139. self.client, isc.dns.Name("unknownzone"),
  140. self.test_file)
  141. def test_no_such_zone_in_source(self):
  142. source_client = isc.datasrc.DataSourceClient('sqlite3',
  143. DB_SOURCE_CLIENT_CONFIG)
  144. self.assertRaises(isc.datasrc.Error, isc.datasrc.ZoneLoader,
  145. self.client, isc.dns.Name("unknownzone"),
  146. source_client)
  147. def test_no_ds_load_support(self):
  148. # This may change in the future, but atm, the in-mem ds does
  149. # not support the API the zone loader uses (it has direct load calls)
  150. inmem_client = isc.datasrc.DataSourceClient('memory',
  151. '{ "type": "memory" }');
  152. self.assertRaises(isc.datasrc.NotImplemented,
  153. isc.datasrc.ZoneLoader,
  154. inmem_client, self.test_name, self.test_file)
  155. def test_wrong_class_from_file(self):
  156. # If the file has wrong class, it is not detected until load time
  157. loader = isc.datasrc.ZoneLoader(self.client, self.test_name,
  158. self.test_file + '.ch')
  159. self.assertRaises(isc.datasrc.MasterFileError, loader.load)
  160. def test_wrong_class_from_client(self):
  161. # For ds->ds loading, wrong class is detected upon construction
  162. # Need a bit of the extended setup for CH source client
  163. clientlist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.CH())
  164. clientlist.configure('[ { "type": "static", "params": "' +
  165. STATIC_ZONE_FILE +'" } ]', False)
  166. source_client, _, _ = clientlist.find(isc.dns.Name("bind."),
  167. False, False)
  168. self.assertRaises(isc.dns.InvalidParameter, isc.datasrc.ZoneLoader,
  169. self.client, isc.dns.Name("bind."), source_client)
  170. def test_exception(self):
  171. # Just check if masterfileerror is subclass of datasrc.Error
  172. self.assertTrue(issubclass(isc.datasrc.MasterFileError,
  173. isc.datasrc.Error))
  174. if __name__ == "__main__":
  175. isc.log.init("bind10")
  176. isc.log.resetUnitTestRootLogger()
  177. unittest.main()