2
0

test_reflog.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. # test_reflog.py -- tests for reflog.py
  2. # Copyright (C) 2015 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  5. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  6. # General Public License as public by the Free Software Foundation; version 2.0
  7. # or (at your option) any later version. You can redistribute it and/or
  8. # modify it under the terms of either of these two licenses.
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. #
  16. # You should have received a copy of the licenses; if not, see
  17. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  18. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  19. # License, Version 2.0.
  20. #
  21. """Tests for dulwich.reflog."""
  22. import tempfile
  23. from io import BytesIO
  24. from dulwich.objects import ZERO_SHA, Blob, Commit, Tree
  25. from dulwich.reflog import (
  26. drop_reflog_entry,
  27. format_reflog_line,
  28. iter_reflogs,
  29. parse_reflog_line,
  30. read_reflog,
  31. )
  32. from dulwich.repo import Repo
  33. from . import TestCase
  34. class ReflogLineTests(TestCase):
  35. def test_format(self) -> None:
  36. self.assertEqual(
  37. b"0000000000000000000000000000000000000000 "
  38. b"49030649db3dfec5a9bc03e5dde4255a14499f16 Jelmer Vernooij "
  39. b"<jelmer@jelmer.uk> 1446552482 +0000 "
  40. b"clone: from git://jelmer.uk/samba",
  41. format_reflog_line(
  42. b"0000000000000000000000000000000000000000",
  43. b"49030649db3dfec5a9bc03e5dde4255a14499f16",
  44. b"Jelmer Vernooij <jelmer@jelmer.uk>",
  45. 1446552482,
  46. 0,
  47. b"clone: from git://jelmer.uk/samba",
  48. ),
  49. )
  50. self.assertEqual(
  51. b"0000000000000000000000000000000000000000 "
  52. b"49030649db3dfec5a9bc03e5dde4255a14499f16 Jelmer Vernooij "
  53. b"<jelmer@jelmer.uk> 1446552482 +0000 "
  54. b"clone: from git://jelmer.uk/samba",
  55. format_reflog_line(
  56. None,
  57. b"49030649db3dfec5a9bc03e5dde4255a14499f16",
  58. b"Jelmer Vernooij <jelmer@jelmer.uk>",
  59. 1446552482,
  60. 0,
  61. b"clone: from git://jelmer.uk/samba",
  62. ),
  63. )
  64. def test_parse(self) -> None:
  65. reflog_line = (
  66. b"0000000000000000000000000000000000000000 "
  67. b"49030649db3dfec5a9bc03e5dde4255a14499f16 Jelmer Vernooij "
  68. b"<jelmer@jelmer.uk> 1446552482 +0000 "
  69. b"clone: from git://jelmer.uk/samba"
  70. )
  71. self.assertEqual(
  72. (
  73. b"0000000000000000000000000000000000000000",
  74. b"49030649db3dfec5a9bc03e5dde4255a14499f16",
  75. b"Jelmer Vernooij <jelmer@jelmer.uk>",
  76. 1446552482,
  77. 0,
  78. b"clone: from git://jelmer.uk/samba",
  79. ),
  80. parse_reflog_line(reflog_line),
  81. )
  82. _TEST_REFLOG = (
  83. b"0000000000000000000000000000000000000000 "
  84. b"49030649db3dfec5a9bc03e5dde4255a14499f16 Jelmer Vernooij "
  85. b"<jelmer@jelmer.uk> 1446552482 +0000 "
  86. b"clone: from git://jelmer.uk/samba\n"
  87. b"49030649db3dfec5a9bc03e5dde4255a14499f16 "
  88. b"42d06bd4b77fed026b154d16493e5deab78f02ec Jelmer Vernooij "
  89. b"<jelmer@jelmer.uk> 1446552483 +0000 "
  90. b"clone: from git://jelmer.uk/samba\n"
  91. b"42d06bd4b77fed026b154d16493e5deab78f02ec "
  92. b"df6800012397fb85c56e7418dd4eb9405dee075c Jelmer Vernooij "
  93. b"<jelmer@jelmer.uk> 1446552484 +0000 "
  94. b"clone: from git://jelmer.uk/samba\n"
  95. )
  96. class ReflogDropTests(TestCase):
  97. def setUp(self) -> None:
  98. TestCase.setUp(self)
  99. self.f = BytesIO(_TEST_REFLOG)
  100. self.original_log = list(read_reflog(self.f))
  101. self.f.seek(0)
  102. def _read_log(self):
  103. self.f.seek(0)
  104. return list(read_reflog(self.f))
  105. def test_invalid(self) -> None:
  106. self.assertRaises(ValueError, drop_reflog_entry, self.f, -1)
  107. def test_drop_entry(self) -> None:
  108. drop_reflog_entry(self.f, 0)
  109. log = self._read_log()
  110. self.assertEqual(len(log), 2)
  111. self.assertEqual(self.original_log[0:2], log)
  112. self.f.seek(0)
  113. drop_reflog_entry(self.f, 1)
  114. log = self._read_log()
  115. self.assertEqual(len(log), 1)
  116. self.assertEqual(self.original_log[1], log[0])
  117. def test_drop_entry_with_rewrite(self) -> None:
  118. drop_reflog_entry(self.f, 1, True)
  119. log = self._read_log()
  120. self.assertEqual(len(log), 2)
  121. self.assertEqual(self.original_log[0], log[0])
  122. self.assertEqual(self.original_log[0].new_sha, log[1].old_sha)
  123. self.assertEqual(self.original_log[2].new_sha, log[1].new_sha)
  124. self.f.seek(0)
  125. drop_reflog_entry(self.f, 1, True)
  126. log = self._read_log()
  127. self.assertEqual(len(log), 1)
  128. self.assertEqual(ZERO_SHA, log[0].old_sha)
  129. self.assertEqual(self.original_log[2].new_sha, log[0].new_sha)
  130. class RepoReflogTests(TestCase):
  131. def setUp(self) -> None:
  132. TestCase.setUp(self)
  133. self.test_dir = tempfile.mkdtemp()
  134. self.repo = Repo.init(self.test_dir)
  135. def tearDown(self) -> None:
  136. TestCase.tearDown(self)
  137. import shutil
  138. shutil.rmtree(self.test_dir)
  139. def test_read_reflog_nonexistent(self) -> None:
  140. # Reading a reflog that doesn't exist should return empty
  141. entries = list(self.repo.read_reflog(b"refs/heads/nonexistent"))
  142. self.assertEqual([], entries)
  143. def test_read_reflog_head(self) -> None:
  144. # Create a commit to generate a reflog entry
  145. blob = Blob.from_string(b"test content")
  146. self.repo.object_store.add_object(blob)
  147. tree = Tree()
  148. tree.add(b"test", 0o100644, blob.id)
  149. self.repo.object_store.add_object(tree)
  150. commit = Commit()
  151. commit.tree = tree.id
  152. commit.author = b"Test Author <test@example.com>"
  153. commit.committer = b"Test Author <test@example.com>"
  154. commit.commit_time = 1234567890
  155. commit.commit_timezone = 0
  156. commit.author_time = 1234567890
  157. commit.author_timezone = 0
  158. commit.message = b"Initial commit"
  159. self.repo.object_store.add_object(commit)
  160. # Manually write a reflog entry
  161. self.repo._write_reflog(
  162. b"HEAD",
  163. ZERO_SHA,
  164. commit.id,
  165. b"Test Author <test@example.com>",
  166. 1234567890,
  167. 0,
  168. b"commit (initial): Initial commit",
  169. )
  170. # Read the reflog
  171. entries = list(self.repo.read_reflog(b"HEAD"))
  172. self.assertEqual(1, len(entries))
  173. self.assertEqual(ZERO_SHA, entries[0].old_sha)
  174. self.assertEqual(commit.id, entries[0].new_sha)
  175. self.assertEqual(b"Test Author <test@example.com>", entries[0].committer)
  176. self.assertEqual(1234567890, entries[0].timestamp)
  177. self.assertEqual(0, entries[0].timezone)
  178. self.assertEqual(b"commit (initial): Initial commit", entries[0].message)
  179. def test_iter_reflogs(self) -> None:
  180. # Create commits and reflog entries
  181. blob = Blob.from_string(b"test content")
  182. self.repo.object_store.add_object(blob)
  183. tree = Tree()
  184. tree.add(b"test", 0o100644, blob.id)
  185. self.repo.object_store.add_object(tree)
  186. commit = Commit()
  187. commit.tree = tree.id
  188. commit.author = b"Test Author <test@example.com>"
  189. commit.committer = b"Test Author <test@example.com>"
  190. commit.commit_time = 1234567890
  191. commit.commit_timezone = 0
  192. commit.author_time = 1234567890
  193. commit.author_timezone = 0
  194. commit.message = b"Initial commit"
  195. self.repo.object_store.add_object(commit)
  196. # Write reflog entries for multiple refs
  197. self.repo._write_reflog(
  198. b"HEAD",
  199. ZERO_SHA,
  200. commit.id,
  201. b"Test Author <test@example.com>",
  202. 1234567890,
  203. 0,
  204. b"commit (initial): Initial commit",
  205. )
  206. self.repo._write_reflog(
  207. b"refs/heads/master",
  208. ZERO_SHA,
  209. commit.id,
  210. b"Test Author <test@example.com>",
  211. 1234567891,
  212. 0,
  213. b"branch: Created from HEAD",
  214. )
  215. self.repo._write_reflog(
  216. b"refs/heads/develop",
  217. ZERO_SHA,
  218. commit.id,
  219. b"Test Author <test@example.com>",
  220. 1234567892,
  221. 0,
  222. b"branch: Created from HEAD",
  223. )
  224. # Use iter_reflogs to get all reflogs
  225. import os
  226. logs_dir = os.path.join(self.repo.controldir(), "logs")
  227. reflogs = list(iter_reflogs(logs_dir))
  228. # Should have at least HEAD, refs/heads/master, and refs/heads/develop
  229. self.assertIn(b"HEAD", reflogs)
  230. self.assertIn(b"refs/heads/master", reflogs)
  231. self.assertIn(b"refs/heads/develop", reflogs)