test_create.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import json
  2. import os
  3. import pytest
  4. from flexmock import flexmock
  5. from borgmatic.actions import create as module
  6. def test_run_create_executes_and_calls_hooks_for_configured_repository():
  7. flexmock(module.logger).answer = lambda message: None
  8. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  9. flexmock(),
  10. )
  11. flexmock(module.borgmatic.borg.create).should_receive('create_archive').once()
  12. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return({})
  13. flexmock(module.borgmatic.hooks.dispatch).should_receive(
  14. 'call_hooks_even_if_unconfigured',
  15. ).and_return({})
  16. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  17. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
  18. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
  19. flexmock(os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
  20. create_arguments = flexmock(
  21. repository=None,
  22. progress=flexmock(),
  23. statistics=flexmock(),
  24. json=False,
  25. comment=None,
  26. list_details=flexmock(),
  27. )
  28. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  29. list(
  30. module.run_create(
  31. config_filename='test.yaml',
  32. repository={'path': 'repo'},
  33. config={},
  34. config_paths=['/tmp/test.yaml'],
  35. local_borg_version=None,
  36. create_arguments=create_arguments,
  37. global_arguments=global_arguments,
  38. dry_run_label='',
  39. local_path=None,
  40. remote_path=None,
  41. ),
  42. )
  43. def test_run_create_with_both_list_and_json_errors():
  44. flexmock(module.logger).answer = lambda message: None
  45. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').never()
  46. flexmock(module.borgmatic.borg.create).should_receive('create_archive').never()
  47. create_arguments = flexmock(
  48. repository=flexmock(),
  49. progress=flexmock(),
  50. statistics=flexmock(),
  51. json=True,
  52. comment=None,
  53. list_details=flexmock(),
  54. )
  55. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  56. with pytest.raises(ValueError):
  57. list(
  58. module.run_create(
  59. config_filename='test.yaml',
  60. repository={'path': 'repo'},
  61. config={'list_details': True},
  62. config_paths=['/tmp/test.yaml'],
  63. local_borg_version=None,
  64. create_arguments=create_arguments,
  65. global_arguments=global_arguments,
  66. dry_run_label='',
  67. local_path=None,
  68. remote_path=None,
  69. ),
  70. )
  71. def test_run_create_with_both_list_and_progress_errors():
  72. flexmock(module.logger).answer = lambda message: None
  73. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').never()
  74. flexmock(module.borgmatic.borg.create).should_receive('create_archive').never()
  75. create_arguments = flexmock(
  76. repository=flexmock(),
  77. progress=flexmock(),
  78. statistics=flexmock(),
  79. json=False,
  80. comment=None,
  81. list_details=flexmock(),
  82. )
  83. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  84. with pytest.raises(ValueError):
  85. list(
  86. module.run_create(
  87. config_filename='test.yaml',
  88. repository={'path': 'repo'},
  89. config={'list_details': True, 'progress': True},
  90. config_paths=['/tmp/test.yaml'],
  91. local_borg_version=None,
  92. create_arguments=create_arguments,
  93. global_arguments=global_arguments,
  94. dry_run_label='',
  95. local_path=None,
  96. remote_path=None,
  97. ),
  98. )
  99. def test_run_create_produces_json():
  100. flexmock(module.logger).answer = lambda message: None
  101. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  102. flexmock(),
  103. )
  104. flexmock(module.borgmatic.borg.create).should_receive('create_archive').once().and_return(
  105. flexmock(),
  106. )
  107. parsed_json = flexmock()
  108. flexmock(module.borgmatic.actions.json).should_receive('parse_json').and_return(parsed_json)
  109. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return({})
  110. flexmock(module.borgmatic.hooks.dispatch).should_receive(
  111. 'call_hooks_even_if_unconfigured',
  112. ).and_return({})
  113. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  114. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
  115. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
  116. flexmock(os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
  117. create_arguments = flexmock(
  118. repository=flexmock(),
  119. progress=flexmock(),
  120. statistics=flexmock(),
  121. json=True,
  122. comment=None,
  123. list_details=flexmock(),
  124. )
  125. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  126. assert list(
  127. module.run_create(
  128. config_filename='test.yaml',
  129. repository={'path': 'repo'},
  130. config={},
  131. config_paths=['/tmp/test.yaml'],
  132. local_borg_version=None,
  133. create_arguments=create_arguments,
  134. global_arguments=global_arguments,
  135. dry_run_label='',
  136. local_path=None,
  137. remote_path=None,
  138. ),
  139. ) == [parsed_json]
  140. def test_run_create_with_active_dumps_roundtrips_via_checkpoint_archive():
  141. mock_dump_process = flexmock()
  142. mock_dump_process.should_receive('poll').and_return(None).and_return(0)
  143. flexmock(module.logger).answer = lambda message: None
  144. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  145. flexmock(),
  146. )
  147. flexmock(module.borgmatic.borg.create).should_receive('create_archive').once()
  148. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  149. {'dump': mock_dump_process},
  150. )
  151. flexmock(module.borgmatic.hooks.dispatch).should_receive(
  152. 'call_hooks_even_if_unconfigured',
  153. ).and_return({})
  154. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  155. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
  156. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
  157. flexmock(os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
  158. flexmock(module.borgmatic.borg.repo_list).should_receive('get_latest_archive').and_return(
  159. {'id': 'id1', 'name': 'archive.checkpoint'},
  160. )
  161. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  162. flexmock(module).should_receive('rename_checkpoint_archive').with_args(
  163. repository_path='repo',
  164. global_arguments=global_arguments,
  165. config={},
  166. local_borg_version=None,
  167. local_path=None,
  168. remote_path=None,
  169. ).once()
  170. create_arguments = flexmock(
  171. repository=None,
  172. progress=flexmock(),
  173. statistics=flexmock(),
  174. json=False,
  175. comment=None,
  176. list_details=flexmock(),
  177. )
  178. list(
  179. module.run_create(
  180. config_filename='test.yaml',
  181. repository={'path': 'repo'},
  182. config={},
  183. config_paths=['/tmp/test.yaml'],
  184. local_borg_version=None,
  185. create_arguments=create_arguments,
  186. global_arguments=global_arguments,
  187. dry_run_label='',
  188. local_path=None,
  189. remote_path=None,
  190. ),
  191. )
  192. def test_run_create_with_active_dumps_json_updates_archive_info():
  193. mock_dump_process = flexmock()
  194. mock_dump_process.should_receive('poll').and_return(None).and_return(0)
  195. borg_create_result = {
  196. 'archive': {
  197. 'command_line': ['foo'],
  198. 'name': 'archive.checkpoint',
  199. 'id': 'id1',
  200. },
  201. 'cache': {},
  202. 'repository': {
  203. 'id': 'repo-id',
  204. },
  205. }
  206. expected_create_result = {
  207. 'archive': {
  208. 'command_line': ['foo'],
  209. 'name': 'archive',
  210. 'id': 'id2',
  211. },
  212. 'cache': {},
  213. 'repository': {'id': 'repo-id', 'label': ''},
  214. }
  215. flexmock(module.logger).answer = lambda message: None
  216. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  217. flexmock(),
  218. )
  219. flexmock(module.borgmatic.borg.create).should_receive('create_archive').and_return(
  220. json.dumps(borg_create_result),
  221. ).once()
  222. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  223. {'dump': mock_dump_process},
  224. )
  225. flexmock(module.borgmatic.hooks.dispatch).should_receive(
  226. 'call_hooks_even_if_unconfigured',
  227. ).and_return({})
  228. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  229. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(())
  230. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return([])
  231. flexmock(os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
  232. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  233. flexmock(module).should_receive('rename_checkpoint_archive').with_args(
  234. repository_path='repo',
  235. global_arguments=global_arguments,
  236. config={},
  237. local_borg_version=None,
  238. local_path=None,
  239. remote_path=None,
  240. ).once()
  241. flexmock(module.borgmatic.borg.repo_list).should_receive('get_latest_archive').and_return(
  242. {'id': 'id2', 'name': 'archive'},
  243. )
  244. create_arguments = flexmock(
  245. repository=None,
  246. progress=flexmock(),
  247. statistics=flexmock(),
  248. json=True,
  249. comment=None,
  250. list_details=flexmock(),
  251. )
  252. assert list(
  253. module.run_create(
  254. config_filename='test.yaml',
  255. repository={'path': 'repo'},
  256. config={},
  257. config_paths=['/tmp/test.yaml'],
  258. local_borg_version=None,
  259. create_arguments=create_arguments,
  260. global_arguments=global_arguments,
  261. dry_run_label='',
  262. local_path=None,
  263. remote_path=None,
  264. ),
  265. ) == [expected_create_result]
  266. def test_rename_checkpoint_archive_renames_archive_using_name():
  267. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  268. flexmock(module.borgmatic.borg.repo_list).should_receive('get_latest_archive').and_return(
  269. {'id': 'id1', 'name': 'archive.checkpoint'},
  270. )
  271. flexmock(module.borgmatic.borg.rename).should_receive('rename_archive').with_args(
  272. repository_name='path',
  273. old_archive_name='archive.checkpoint',
  274. new_archive_name='archive',
  275. dry_run=False,
  276. config={},
  277. local_borg_version=None,
  278. local_path=None,
  279. remote_path=None,
  280. )
  281. flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(False)
  282. module.rename_checkpoint_archive(
  283. repository_path='path',
  284. global_arguments=global_arguments,
  285. config={},
  286. local_borg_version=None,
  287. local_path=None,
  288. remote_path=None,
  289. )
  290. def test_rename_checkpoint_with_feature_available_archive_renames_archive_using_id():
  291. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  292. flexmock(module.borgmatic.borg.repo_list).should_receive('get_latest_archive').and_return(
  293. {'id': 'id1', 'name': 'archive.checkpoint'},
  294. )
  295. flexmock(module.borgmatic.borg.rename).should_receive('rename_archive').with_args(
  296. repository_name='path',
  297. old_archive_name='id1',
  298. new_archive_name='archive',
  299. dry_run=False,
  300. config={},
  301. local_borg_version=None,
  302. local_path=None,
  303. remote_path=None,
  304. )
  305. flexmock(module.borgmatic.borg.feature).should_receive('available').and_return(True)
  306. module.rename_checkpoint_archive(
  307. repository_path='path',
  308. global_arguments=global_arguments,
  309. config={},
  310. local_borg_version=None,
  311. local_path=None,
  312. remote_path=None,
  313. )
  314. def test_rename_checkpoint_archive_checks_suffix():
  315. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  316. flexmock(module.borgmatic.borg.repo_list).should_receive('get_latest_archive').and_return(
  317. {'id': 'id1', 'name': 'unexpected-archive'},
  318. )
  319. with pytest.raises(
  320. ValueError,
  321. match=r'Latest archive did not have a .checkpoint suffix. Got: unexpected-archive',
  322. ):
  323. module.rename_checkpoint_archive(
  324. repository_path='path',
  325. global_arguments=global_arguments,
  326. config={},
  327. local_borg_version=None,
  328. local_path=None,
  329. remote_path=None,
  330. )