repository.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import os
  2. import shutil
  3. import tempfile
  4. from attic.hashindex import NSIndex
  5. from attic.helpers import Location
  6. from attic.remote import RemoteRepository
  7. from attic.repository import Repository
  8. from attic.testsuite import AtticTestCase
  9. class RepositoryTestCase(AtticTestCase):
  10. def open(self, create=False):
  11. return Repository(os.path.join(self.tmppath, 'repository'), create=create)
  12. def setUp(self):
  13. self.tmppath = tempfile.mkdtemp()
  14. self.repository = self.open(create=True)
  15. def tearDown(self):
  16. self.repository.close()
  17. shutil.rmtree(self.tmppath)
  18. def test1(self):
  19. for x in range(100):
  20. self.repository.put(('%-32d' % x).encode('ascii'), b'SOMEDATA')
  21. key50 = ('%-32d' % 50).encode('ascii')
  22. self.assert_equal(self.repository.get(key50), b'SOMEDATA')
  23. self.repository.delete(key50)
  24. self.assert_raises(Repository.DoesNotExist, lambda: self.repository.get(key50))
  25. self.repository.commit()
  26. self.repository.close()
  27. repository2 = self.open()
  28. self.assert_raises(Repository.DoesNotExist, lambda: repository2.get(key50))
  29. for x in range(100):
  30. if x == 50:
  31. continue
  32. self.assert_equal(repository2.get(('%-32d' % x).encode('ascii')), b'SOMEDATA')
  33. repository2.close()
  34. def test2(self):
  35. """Test multiple sequential transactions
  36. """
  37. self.repository.put(b'00000000000000000000000000000000', b'foo')
  38. self.repository.put(b'00000000000000000000000000000001', b'foo')
  39. self.repository.commit()
  40. self.repository.delete(b'00000000000000000000000000000000')
  41. self.repository.put(b'00000000000000000000000000000001', b'bar')
  42. self.repository.commit()
  43. self.assert_equal(self.repository.get(b'00000000000000000000000000000001'), b'bar')
  44. def test_consistency(self):
  45. """Test cache consistency
  46. """
  47. self.repository.put(b'00000000000000000000000000000000', b'foo')
  48. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'foo')
  49. self.repository.put(b'00000000000000000000000000000000', b'foo2')
  50. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'foo2')
  51. self.repository.put(b'00000000000000000000000000000000', b'bar')
  52. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'bar')
  53. self.repository.delete(b'00000000000000000000000000000000')
  54. self.assert_raises(Repository.DoesNotExist, lambda: self.repository.get(b'00000000000000000000000000000000'))
  55. def test_consistency2(self):
  56. """Test cache consistency2
  57. """
  58. self.repository.put(b'00000000000000000000000000000000', b'foo')
  59. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'foo')
  60. self.repository.commit()
  61. self.repository.put(b'00000000000000000000000000000000', b'foo2')
  62. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'foo2')
  63. self.repository.rollback()
  64. self.assert_equal(self.repository.get(b'00000000000000000000000000000000'), b'foo')
  65. def test_single_kind_transactions(self):
  66. # put
  67. self.repository.put(b'00000000000000000000000000000000', b'foo')
  68. self.repository.commit()
  69. self.repository.close()
  70. # replace
  71. self.repository = self.open()
  72. self.repository.put(b'00000000000000000000000000000000', b'bar')
  73. self.repository.commit()
  74. self.repository.close()
  75. # delete
  76. self.repository = self.open()
  77. self.repository.delete(b'00000000000000000000000000000000')
  78. self.repository.commit()
  79. class RepositoryCheckTestCase(AtticTestCase):
  80. def open(self, create=False):
  81. return Repository(os.path.join(self.tmppath, 'repository'), create=create)
  82. def reopen(self):
  83. if self.repository:
  84. self.repository.close()
  85. self.repository = self.open()
  86. def setUp(self):
  87. self.tmppath = tempfile.mkdtemp()
  88. self.repository = self.open(create=True)
  89. def tearDown(self):
  90. self.repository.close()
  91. shutil.rmtree(self.tmppath)
  92. def add_objects(self, ids):
  93. for id_ in ids:
  94. self.repository.put(('%032d' % id_).encode('ascii'), b'data')
  95. self.repository.commit()
  96. def get_head(self):
  97. return sorted(int(n) for n in os.listdir(os.path.join(self.tmppath, 'repository', 'data', '0')) if n.isdigit())[-1]
  98. def open_index(self):
  99. return NSIndex(os.path.join(self.tmppath, 'repository', 'index.{}'.format(self.get_head())))
  100. def corrupt_object(self, id_):
  101. idx = self.open_index()
  102. segment, offset = idx[('%032d' % id_).encode('ascii')]
  103. with open(os.path.join(self.tmppath, 'repository', 'data', '0', str(segment)), 'r+b') as fd:
  104. fd.seek(offset)
  105. fd.write(b'BOOM')
  106. def list_objects(self):
  107. return set((int(key) for key, _ in list(self.open_index().iteritems())))
  108. def test_check(self):
  109. self.add_objects([1, 2, 3])
  110. self.add_objects([4, 5, 6])
  111. self.assert_equal(set([1, 2, 3, 4, 5, 6]), self.list_objects())
  112. self.assert_equal(True, self.repository.check())
  113. self.corrupt_object(5)
  114. self.reopen()
  115. self.assert_equal(False, self.repository.check())
  116. self.assert_equal(set([1, 2, 3, 4, 5, 6]), self.list_objects())
  117. def test_check_repair(self):
  118. self.add_objects([1, 2, 3])
  119. self.add_objects([4, 5, 6])
  120. self.assert_equal(set([1, 2, 3, 4, 5, 6]), self.list_objects())
  121. self.assert_equal(True, self.repository.check())
  122. self.corrupt_object(5)
  123. self.reopen()
  124. self.assert_equal(False, self.repository.check(repair=True))
  125. self.assert_equal(set([1, 2, 3, 4, 6]), self.list_objects())
  126. def test_check_missing_or_corrupt_commit_tag(self):
  127. self.add_objects([1, 2, 3])
  128. self.assert_equal(set([1, 2, 3]), self.list_objects())
  129. with open(os.path.join(self.tmppath, 'repository', 'data', '0', str(self.get_head())), 'ab') as fd:
  130. fd.write(b'X')
  131. self.assert_raises(Repository.CheckNeeded, lambda: self.repository.get(bytes(32)))
  132. class RemoteRepositoryTestCase(RepositoryTestCase):
  133. def open(self, create=False):
  134. return RemoteRepository(Location('__testsuite__:' + os.path.join(self.tmppath, 'repository')), create=create)
  135. class RemoteRepositoryCheckTestCase(RepositoryCheckTestCase):
  136. def open(self, create=False):
  137. return RemoteRepository(Location('__testsuite__:' + os.path.join(self.tmppath, 'repository')), create=create)