test_atomicfilecache.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # Copyright 2012 Canonical Ltd.
  2. # This file is part of lazr.restfulclient.
  3. #
  4. # lazr.restfulclient is free software: you can redistribute it and/or
  5. # modify it under the terms of the GNU Lesser General Public License
  6. # as published by the Free Software Foundation, version 3 of the
  7. # License.
  8. #
  9. # lazr.restfulclient is distributed in the hope that it will be
  10. # useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  11. # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. # Lesser General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU Lesser General Public License
  15. # along with lazr.restfulclient. If not, see <http://www.gnu.org/licenses/>.
  16. """Tests for the atomic file cache."""
  17. __metaclass__ = type
  18. import shutil
  19. import sys
  20. import tempfile
  21. import unittest
  22. import httplib2
  23. from lazr.restfulclient._browser import AtomicFileCache, safename
  24. PY3 = sys.version_info[0] >= 3
  25. if PY3:
  26. binary_type = bytes
  27. else:
  28. binary_type = str
  29. class TestFileCacheInterface(unittest.TestCase):
  30. """Tests for ``AtomicFileCache``."""
  31. file_cache_factory = httplib2.FileCache
  32. unicode_bytes = b"pa\xc9\xaa\xce\xb8\xc9\x99n"
  33. unicode_text = unicode_bytes.decode("utf-8")
  34. def setUp(self):
  35. super(TestFileCacheInterface, self).setUp()
  36. self.cache_dir = tempfile.mkdtemp()
  37. def tearDown(self):
  38. shutil.rmtree(self.cache_dir)
  39. super(TestFileCacheInterface, self).tearDown()
  40. def make_file_cache(self):
  41. """Make a FileCache-like object to be tested."""
  42. return self.file_cache_factory(self.cache_dir, safename)
  43. def test_get_non_existent_key(self):
  44. # get() returns None if the key does not exist.
  45. cache = self.make_file_cache()
  46. self.assertIs(None, cache.get("nonexistent"))
  47. def test_set_key(self):
  48. # A key set with set() can be got by get().
  49. cache = self.make_file_cache()
  50. cache.set("key", b"value")
  51. self.assertEqual(b"value", cache.get("key"))
  52. def test_set_twice_overrides(self):
  53. # Setting a key again overrides the value.
  54. cache = self.make_file_cache()
  55. cache.set("key", b"value")
  56. cache.set("key", b"new-value")
  57. self.assertEqual(b"new-value", cache.get("key"))
  58. def test_delete_absent_key(self):
  59. # Deleting a key that's not there does nothing.
  60. cache = self.make_file_cache()
  61. cache.delete("nonexistent")
  62. self.assertIs(None, cache.get("nonexistent"))
  63. def test_delete_key(self):
  64. # A key once set can be deleted. Further attempts to get that key
  65. # return None.
  66. cache = self.make_file_cache()
  67. cache.set("key", b"value")
  68. cache.delete("key")
  69. self.assertIs(None, cache.get("key"))
  70. def test_get_non_string_key(self):
  71. # get() raises TypeError if asked to get a non-string key.
  72. cache = self.make_file_cache()
  73. self.assertRaises(TypeError, cache.get, 42)
  74. def test_delete_non_string_key(self):
  75. # delete() raises TypeError if asked to delete a non-string key.
  76. cache = self.make_file_cache()
  77. self.assertRaises(TypeError, cache.delete, 42)
  78. def test_set_non_string_key(self):
  79. # set() raises TypeError if asked to set a non-string key.
  80. cache = self.make_file_cache()
  81. self.assertRaises(TypeError, cache.set, 42, "the answer")
  82. def test_set_non_string_value(self):
  83. # set() raises TypeError if asked to set a key to a non-string value.
  84. # Attempts to retrieve that value return the empty string. This is
  85. # probably a bug in httplib2.FileCache.
  86. cache = self.make_file_cache()
  87. self.assertRaises(TypeError, cache.set, "answer", 42)
  88. self.assertEqual(b"", cache.get("answer"))
  89. def test_get_unicode(self):
  90. # get() can retrieve unicode keys.
  91. cache = self.make_file_cache()
  92. self.assertIs(None, cache.get(self.unicode_text))
  93. def test_set_unicode_keys(self):
  94. cache = self.make_file_cache()
  95. cache.set(self.unicode_text, b"value")
  96. self.assertEqual(b"value", cache.get(self.unicode_text))
  97. def test_set_unicode_value(self):
  98. # set() cannot store unicode values. Values must be bytes.
  99. cache = self.make_file_cache()
  100. error = TypeError if PY3 else UnicodeEncodeError
  101. self.assertRaises(error, cache.set, "key", self.unicode_text)
  102. def test_delete_unicode(self):
  103. # delete() can remove unicode keys.
  104. cache = self.make_file_cache()
  105. cache.set(self.unicode_text, b"value")
  106. cache.delete(self.unicode_text)
  107. self.assertIs(None, cache.get(self.unicode_text))
  108. class TestAtomicFileCache(TestFileCacheInterface):
  109. """Tests for ``AtomicFileCache``."""
  110. file_cache_factory = AtomicFileCache
  111. @staticmethod
  112. def prefix_safename(x):
  113. if isinstance(x, binary_type):
  114. x = x.decode("utf-8")
  115. return AtomicFileCache.TEMPFILE_PREFIX + x
  116. def test_set_non_string_value(self):
  117. # set() raises TypeError if asked to set a key to a non-string value.
  118. # Attempts to retrieve that value act is if it were never set.
  119. #
  120. # Note: This behaviour differs from httplib2.FileCache.
  121. cache = self.make_file_cache()
  122. self.assertRaises(TypeError, cache.set, "answer", 42)
  123. self.assertIs(None, cache.get("answer"))
  124. # Implementation-specific tests follow.
  125. def test_bad_safename_get(self):
  126. safename = self.prefix_safename
  127. cache = AtomicFileCache(self.cache_dir, safename)
  128. self.assertRaises(ValueError, cache.get, "key")
  129. def test_bad_safename_set(self):
  130. safename = self.prefix_safename
  131. cache = AtomicFileCache(self.cache_dir, safename)
  132. self.assertRaises(ValueError, cache.set, "key", b"value")
  133. def test_bad_safename_delete(self):
  134. safename = self.prefix_safename
  135. cache = AtomicFileCache(self.cache_dir, safename)
  136. self.assertRaises(ValueError, cache.delete, "key")