test_swift_smoke.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. # test_smoke.py -- Functional tests for the Swift backend.
  2. # Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
  3. #
  4. # Author: Fabien Boucher <fabien.boucher@enovance.com>
  5. #
  6. # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  7. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  8. # General Public License as published by the Free Software Foundation; version 2.0
  9. # or (at your option) any later version. You can redistribute it and/or
  10. # modify it under the terms of either of these two licenses.
  11. #
  12. # Unless required by applicable law or agreed to in writing, software
  13. # distributed under the License is distributed on an "AS IS" BASIS,
  14. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. # See the License for the specific language governing permissions and
  16. # limitations under the License.
  17. #
  18. # You should have received a copy of the licenses; if not, see
  19. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  20. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  21. # License, Version 2.0.
  22. #
  23. """Start functional tests.
  24. A Swift installation must be available before
  25. starting those tests. The account and authentication method used
  26. during this functional tests must be changed in the configuration file
  27. passed as environment variable.
  28. The container used to create a fake repository is defined
  29. in cls.fakerepo and will be deleted after the tests.
  30. DULWICH_SWIFT_CFG=/tmp/conf.cfg PYTHONPATH=. python -m unittest \
  31. dulwich.tests_swift.test_smoke
  32. """
  33. import os
  34. import shutil
  35. import tempfile
  36. import unittest
  37. import gevent
  38. from gevent import monkey
  39. monkey.patch_all()
  40. from dulwich import client, index, objects, repo, server # noqa: E402
  41. from dulwich.contrib import swift # noqa: E402
  42. class DulwichServer:
  43. """Start the TCPGitServer with Swift backend."""
  44. def __init__(self, backend, port) -> None:
  45. self.port = port
  46. self.backend = backend
  47. def run(self) -> None:
  48. self.server = server.TCPGitServer(self.backend, "localhost", port=self.port)
  49. self.job = gevent.spawn(self.server.serve_forever)
  50. def stop(self) -> None:
  51. self.server.shutdown()
  52. gevent.joinall((self.job,))
  53. class SwiftSystemBackend(server.Backend):
  54. def open_repository(self, path):
  55. return swift.SwiftRepo(path, conf=swift.load_conf())
  56. class SwiftRepoSmokeTest(unittest.TestCase):
  57. @classmethod
  58. def setUpClass(cls) -> None:
  59. cls.backend = SwiftSystemBackend()
  60. cls.port = 9148
  61. cls.server_address = "localhost"
  62. cls.fakerepo = "fakerepo"
  63. cls.th_server = DulwichServer(cls.backend, cls.port)
  64. cls.th_server.run()
  65. cls.conf = swift.load_conf()
  66. @classmethod
  67. def tearDownClass(cls) -> None:
  68. cls.th_server.stop()
  69. def setUp(self) -> None:
  70. self.scon = swift.SwiftConnector(self.fakerepo, self.conf)
  71. if self.scon.test_root_exists():
  72. try:
  73. self.scon.del_root()
  74. except swift.SwiftException:
  75. pass
  76. self.temp_d = tempfile.mkdtemp()
  77. if os.path.isdir(self.temp_d):
  78. shutil.rmtree(self.temp_d)
  79. def tearDown(self) -> None:
  80. if self.scon.test_root_exists():
  81. try:
  82. self.scon.del_root()
  83. except swift.SwiftException:
  84. pass
  85. if os.path.isdir(self.temp_d):
  86. shutil.rmtree(self.temp_d)
  87. def test_init_bare(self) -> None:
  88. swift.SwiftRepo.init_bare(self.scon, self.conf)
  89. self.assertTrue(self.scon.test_root_exists())
  90. obj = self.scon.get_container_objects()
  91. filtered = [
  92. o for o in obj if o["name"] == "info/refs" or o["name"] == "objects/pack"
  93. ]
  94. self.assertEqual(len(filtered), 2)
  95. def test_clone_bare(self) -> None:
  96. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  97. swift.SwiftRepo.init_bare(self.scon, self.conf)
  98. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  99. remote_refs = tcp_client.fetch(self.fakerepo, local_repo)
  100. # The remote repo is empty (no refs retrieved)
  101. self.assertEqual(remote_refs, None)
  102. def test_push_commit(self) -> None:
  103. def determine_wants(*args, **kwargs):
  104. return {"refs/heads/master": local_repo.refs["HEAD"]}
  105. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  106. # Nothing in the staging area
  107. local_repo.get_worktree().commit("Test commit", "fbo@localhost")
  108. sha = local_repo.refs.read_loose_ref("refs/heads/master")
  109. swift.SwiftRepo.init_bare(self.scon, self.conf)
  110. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  111. tcp_client.send_pack(
  112. self.fakerepo, determine_wants, local_repo.generate_pack_data
  113. )
  114. swift_repo = swift.SwiftRepo("fakerepo", self.conf)
  115. remote_sha = swift_repo.refs.read_loose_ref("refs/heads/master")
  116. self.assertEqual(sha, remote_sha)
  117. def test_push_branch(self) -> None:
  118. def determine_wants(*args, **kwargs):
  119. return {"refs/heads/mybranch": local_repo.refs["refs/heads/mybranch"]}
  120. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  121. # Nothing in the staging area
  122. local_repo.get_worktree().commit(
  123. "Test commit", "fbo@localhost", ref="refs/heads/mybranch"
  124. )
  125. sha = local_repo.refs.read_loose_ref("refs/heads/mybranch")
  126. swift.SwiftRepo.init_bare(self.scon, self.conf)
  127. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  128. tcp_client.send_pack(
  129. "/fakerepo", determine_wants, local_repo.generate_pack_data
  130. )
  131. swift_repo = swift.SwiftRepo(self.fakerepo, self.conf)
  132. remote_sha = swift_repo.refs.read_loose_ref("refs/heads/mybranch")
  133. self.assertEqual(sha, remote_sha)
  134. def test_push_multiple_branch(self) -> None:
  135. def determine_wants(*args, **kwargs):
  136. return {
  137. "refs/heads/mybranch": local_repo.refs["refs/heads/mybranch"],
  138. "refs/heads/master": local_repo.refs["refs/heads/master"],
  139. "refs/heads/pullr-108": local_repo.refs["refs/heads/pullr-108"],
  140. }
  141. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  142. # Nothing in the staging area
  143. local_shas = {}
  144. remote_shas = {}
  145. for branch in ("master", "mybranch", "pullr-108"):
  146. local_shas[branch] = local_repo.get_worktree().commit(
  147. f"Test commit {branch}",
  148. "fbo@localhost",
  149. ref=f"refs/heads/{branch}",
  150. )
  151. swift.SwiftRepo.init_bare(self.scon, self.conf)
  152. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  153. tcp_client.send_pack(
  154. self.fakerepo, determine_wants, local_repo.generate_pack_data
  155. )
  156. swift_repo = swift.SwiftRepo("fakerepo", self.conf)
  157. for branch in ("master", "mybranch", "pullr-108"):
  158. remote_shas[branch] = swift_repo.refs.read_loose_ref(f"refs/heads/{branch}")
  159. self.assertDictEqual(local_shas, remote_shas)
  160. def test_push_data_branch(self) -> None:
  161. def determine_wants(*args, **kwargs):
  162. return {"refs/heads/master": local_repo.refs["HEAD"]}
  163. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  164. os.mkdir(os.path.join(self.temp_d, "dir"))
  165. files = ("testfile", "testfile2", "dir/testfile3")
  166. i = 0
  167. for f in files:
  168. open(os.path.join(self.temp_d, f), "w").write(f"DATA {i}")
  169. i += 1
  170. local_repo.get_worktree().stage(files)
  171. local_repo.get_worktree().commit(
  172. "Test commit", "fbo@localhost", ref="refs/heads/master"
  173. )
  174. swift.SwiftRepo.init_bare(self.scon, self.conf)
  175. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  176. tcp_client.send_pack(
  177. self.fakerepo, determine_wants, local_repo.generate_pack_data
  178. )
  179. swift_repo = swift.SwiftRepo("fakerepo", self.conf)
  180. commit_sha = swift_repo.refs.read_loose_ref("refs/heads/master")
  181. otype, data = swift_repo.object_store.get_raw(commit_sha)
  182. commit = objects.ShaFile.from_raw_string(otype, data)
  183. otype, data = swift_repo.object_store.get_raw(commit._tree)
  184. tree = objects.ShaFile.from_raw_string(otype, data)
  185. objs = tree.items()
  186. objs_ = []
  187. for tree_entry in objs:
  188. objs_.append(swift_repo.object_store.get_raw(tree_entry.sha))
  189. # Blob
  190. self.assertEqual(objs_[1][1], "DATA 0")
  191. self.assertEqual(objs_[2][1], "DATA 1")
  192. # Tree
  193. self.assertEqual(objs_[0][0], 2)
  194. def test_clone_then_push_data(self) -> None:
  195. self.test_push_data_branch()
  196. shutil.rmtree(self.temp_d)
  197. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  198. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  199. remote_refs = tcp_client.fetch(self.fakerepo, local_repo)
  200. files = (
  201. os.path.join(self.temp_d, "testfile"),
  202. os.path.join(self.temp_d, "testfile2"),
  203. )
  204. local_repo["HEAD"] = remote_refs["refs/heads/master"]
  205. indexfile = local_repo.index_path()
  206. tree = local_repo["HEAD"].tree
  207. index.build_index_from_tree(
  208. local_repo.path, indexfile, local_repo.object_store, tree
  209. )
  210. for f in files:
  211. self.assertEqual(os.path.isfile(f), True)
  212. def determine_wants(*args, **kwargs):
  213. return {"refs/heads/master": local_repo.refs["HEAD"]}
  214. os.mkdir(os.path.join(self.temp_d, "test"))
  215. files = ("testfile11", "testfile22", "test/testfile33")
  216. i = 0
  217. for f in files:
  218. open(os.path.join(self.temp_d, f), "w").write(f"DATA {i}")
  219. i += 1
  220. local_repo.get_worktree().stage(files)
  221. local_repo.get_worktree().commit(
  222. "Test commit", "fbo@localhost", ref="refs/heads/master"
  223. )
  224. tcp_client.send_pack(
  225. "/fakerepo", determine_wants, local_repo.generate_pack_data
  226. )
  227. def test_push_remove_branch(self) -> None:
  228. def determine_wants(*args, **kwargs):
  229. return {
  230. "refs/heads/pullr-108": objects.ZERO_SHA,
  231. "refs/heads/master": local_repo.refs["refs/heads/master"],
  232. "refs/heads/mybranch": local_repo.refs["refs/heads/mybranch"],
  233. }
  234. self.test_push_multiple_branch()
  235. local_repo = repo.Repo(self.temp_d)
  236. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  237. tcp_client.send_pack(
  238. self.fakerepo, determine_wants, local_repo.generate_pack_data
  239. )
  240. swift_repo = swift.SwiftRepo("fakerepo", self.conf)
  241. self.assertNotIn("refs/heads/pullr-108", swift_repo.refs.allkeys())
  242. def test_push_annotated_tag(self) -> None:
  243. def determine_wants(*args, **kwargs):
  244. return {
  245. "refs/heads/master": local_repo.refs["HEAD"],
  246. "refs/tags/v1.0": local_repo.refs["refs/tags/v1.0"],
  247. }
  248. local_repo = repo.Repo.init(self.temp_d, mkdir=True)
  249. # Nothing in the staging area
  250. sha = local_repo.get_worktree().commit("Test commit", "fbo@localhost")
  251. otype, data = local_repo.object_store.get_raw(sha)
  252. commit = objects.ShaFile.from_raw_string(otype, data)
  253. tag = objects.Tag()
  254. tag.tagger = "fbo@localhost"
  255. tag.message = "Annotated tag"
  256. tag.tag_timezone = objects.parse_timezone("-0200")[0]
  257. tag.tag_time = commit.author_time
  258. tag.object = (objects.Commit, commit.id)
  259. tag.name = "v0.1"
  260. local_repo.object_store.add_object(tag)
  261. local_repo.refs["refs/tags/v1.0"] = tag.id
  262. swift.SwiftRepo.init_bare(self.scon, self.conf)
  263. tcp_client = client.TCPGitClient(self.server_address, port=self.port)
  264. tcp_client.send_pack(
  265. self.fakerepo, determine_wants, local_repo.generate_pack_data
  266. )
  267. swift_repo = swift.SwiftRepo(self.fakerepo, self.conf)
  268. tag_sha = swift_repo.refs.read_loose_ref("refs/tags/v1.0")
  269. otype, data = swift_repo.object_store.get_raw(tag_sha)
  270. rtag = objects.ShaFile.from_raw_string(otype, data)
  271. self.assertEqual(rtag.object[1], commit.id)
  272. self.assertEqual(rtag.id, tag.id)
  273. if __name__ == "__main__":
  274. unittest.main()