test_terminology.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. """
  2. Tests functions and classes from the odml terminology module.
  3. """
  4. import os
  5. import unittest
  6. from glob import glob
  7. from sys import platform
  8. from time import sleep
  9. try:
  10. from urllib.request import pathname2url
  11. except ImportError:
  12. from urllib import pathname2url
  13. from odml import Document, save, Section, terminology
  14. from .util import ODML_CACHE_DIR as CACHE_DIR, create_test_dir
  15. class TestTerminology(unittest.TestCase):
  16. def setUp(self):
  17. """
  18. Set up local temporary terminology files in a temporary folder
  19. """
  20. tmp_dir = create_test_dir(__file__)
  21. tmp_name = os.path.basename(tmp_dir)
  22. main_name = "%s_main.xml" % tmp_name
  23. main_file_path = os.path.join(tmp_dir, main_name)
  24. main_url = "file://%s" % pathname2url(main_file_path)
  25. include_name = "%s_include.xml" % tmp_name
  26. include_file_path = os.path.join(tmp_dir, include_name)
  27. include_url = "file://%s" % pathname2url(include_file_path)
  28. include_doc = Document()
  29. _ = Section(name="include_sec", type="test", parent=include_doc)
  30. save(include_doc, include_file_path)
  31. main_doc = Document()
  32. _ = Section(name="main_sec", type="test", include=include_url, parent=main_doc)
  33. save(main_doc, main_file_path)
  34. self.main_terminology_url = main_url
  35. self.temp_dir_base = tmp_name
  36. def tearDown(self):
  37. """
  38. Remove all created files from the odml.cache to not cross pollute other tests.
  39. The created tmp directory should be cleaned up automatically upon startup.
  40. """
  41. temp_file_glob = "*%s*" % self.temp_dir_base
  42. find_us = os.path.join(CACHE_DIR, temp_file_glob)
  43. for file_path in glob(find_us):
  44. os.remove(file_path)
  45. @staticmethod
  46. def _cache_files_map(file_filter="*"):
  47. """
  48. Returns a dict mapping the basefilenames of cached odml files
  49. to their md5 hash and mtime.
  50. :param file_filter: a valid glob to search for files in the odml cache directory.
  51. The cache directory is provided and must not be part of the glob.
  52. Default value is '*'.
  53. :return: dict of the format {filename: [md5_hash, mtime]}
  54. """
  55. temp_file_glob = os.path.join(CACHE_DIR, file_filter)
  56. curr_map = {}
  57. for file_path in glob(temp_file_glob):
  58. split_name = os.path.basename(file_path).split('.')
  59. file_mtime = os.path.getmtime(file_path)
  60. curr_map[split_name[1]] = [split_name[0], file_mtime]
  61. return curr_map
  62. def test_terminology_refresh(self):
  63. """
  64. Test terminology cache refresh using local files to detach
  65. loading and resolving from the live online terminology repository.
  66. """
  67. # Fetch current cache content specific to the two local terminologies
  68. # With the default file glob '*' all files in the odml cache directory would be
  69. # included in the test.
  70. file_filter = "*%s*" % self.temp_dir_base
  71. main_url = self.main_terminology_url
  72. # Initially load main and included file from temp directory into the odml cache directory
  73. terminology.load(main_url)
  74. orig_map = self._cache_files_map(file_filter)
  75. # Test cache content does not change
  76. terminology.load(main_url)
  77. load_map = self._cache_files_map(file_filter)
  78. self.assertEqual(len(orig_map), len(load_map))
  79. for curr_file in orig_map:
  80. self.assertIn(curr_file, load_map)
  81. self.assertEqual(orig_map[curr_file], load_map[curr_file])
  82. sleep_time = 0.5
  83. if platform == "darwin":
  84. sleep_time = 2
  85. # Sleep is needed since the tests might be too fast to result in a
  86. # different file mtime. Travis macOS seems to require sleep time > 1s.
  87. sleep(sleep_time)
  88. # Test refresh loads same cached files but changes them.
  89. # Different mtimes and id strings are sufficient.
  90. terminology.refresh(main_url)
  91. refresh_map = self._cache_files_map(file_filter)
  92. self.assertEqual(len(orig_map), len(refresh_map))
  93. for curr_file in orig_map:
  94. self.assertIn(curr_file, refresh_map)
  95. # Check identical md5 hash
  96. self.assertEqual(orig_map[curr_file][0], refresh_map[curr_file][0])
  97. # Check different mtime
  98. self.assertLess(orig_map[curr_file][1], refresh_map[curr_file][1])