2
0

test_check.py 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.borg import check as module
  5. from ..test_verbosity import insert_logging_mock
  6. def insert_execute_command_mock(command):
  7. flexmock(module.environment).should_receive('make_environment')
  8. flexmock(module).should_receive('execute_command').with_args(
  9. command, extra_environment=None
  10. ).once()
  11. def insert_execute_command_never():
  12. flexmock(module).should_receive('execute_command').never()
  13. def test_parse_checks_returns_them_as_tuple():
  14. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'bar'}]})
  15. assert checks == ('foo', 'bar')
  16. def test_parse_checks_with_missing_value_returns_defaults():
  17. checks = module.parse_checks({})
  18. assert checks == ('repository', 'archives')
  19. def test_parse_checks_with_empty_list_returns_defaults():
  20. checks = module.parse_checks({'checks': []})
  21. assert checks == ('repository', 'archives')
  22. def test_parse_checks_with_none_value_returns_defaults():
  23. checks = module.parse_checks({'checks': None})
  24. assert checks == ('repository', 'archives')
  25. def test_parse_checks_with_disabled_returns_no_checks():
  26. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'disabled'}]})
  27. assert checks == ()
  28. def test_parse_checks_prefers_override_checks_to_configured_checks():
  29. checks = module.parse_checks(
  30. {'checks': [{'name': 'archives'}]}, only_checks=['repository', 'extract']
  31. )
  32. assert checks == ('repository', 'extract')
  33. @pytest.mark.parametrize(
  34. 'frequency,expected_result',
  35. (
  36. (None, None),
  37. ('always', None),
  38. ('1 hour', module.datetime.timedelta(hours=1)),
  39. ('2 hours', module.datetime.timedelta(hours=2)),
  40. ('1 day', module.datetime.timedelta(days=1)),
  41. ('2 days', module.datetime.timedelta(days=2)),
  42. ('1 week', module.datetime.timedelta(weeks=1)),
  43. ('2 weeks', module.datetime.timedelta(weeks=2)),
  44. ('1 month', module.datetime.timedelta(days=30)),
  45. ('2 months', module.datetime.timedelta(days=60)),
  46. ('1 year', module.datetime.timedelta(days=365)),
  47. ('2 years', module.datetime.timedelta(days=365 * 2)),
  48. ),
  49. )
  50. def test_parse_frequency_parses_into_timedeltas(frequency, expected_result):
  51. assert module.parse_frequency(frequency) == expected_result
  52. @pytest.mark.parametrize(
  53. 'frequency',
  54. (
  55. 'sometime',
  56. 'x days',
  57. '3 decades',
  58. ),
  59. )
  60. def test_parse_frequency_raises_on_parse_error(frequency):
  61. with pytest.raises(ValueError):
  62. module.parse_frequency(frequency)
  63. def test_filter_checks_on_frequency_without_config_uses_default_checks():
  64. flexmock(module).should_receive('parse_frequency').and_return(
  65. module.datetime.timedelta(weeks=4)
  66. )
  67. flexmock(module).should_receive('make_check_time_path')
  68. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  69. assert module.filter_checks_on_frequency(
  70. config={},
  71. borg_repository_id='repo',
  72. checks=('repository', 'archives'),
  73. force=False,
  74. archives_check_id='1234',
  75. ) == ('repository', 'archives')
  76. def test_filter_checks_on_frequency_retains_unconfigured_check():
  77. assert module.filter_checks_on_frequency(
  78. config={},
  79. borg_repository_id='repo',
  80. checks=('data',),
  81. force=False,
  82. ) == ('data',)
  83. def test_filter_checks_on_frequency_retains_check_without_frequency():
  84. flexmock(module).should_receive('parse_frequency').and_return(None)
  85. assert module.filter_checks_on_frequency(
  86. config={'checks': [{'name': 'archives'}]},
  87. borg_repository_id='repo',
  88. checks=('archives',),
  89. force=False,
  90. archives_check_id='1234',
  91. ) == ('archives',)
  92. def test_filter_checks_on_frequency_retains_check_with_elapsed_frequency():
  93. flexmock(module).should_receive('parse_frequency').and_return(
  94. module.datetime.timedelta(hours=1)
  95. )
  96. flexmock(module).should_receive('make_check_time_path')
  97. flexmock(module).should_receive('probe_for_check_time').and_return(
  98. module.datetime.datetime(year=module.datetime.MINYEAR, month=1, day=1)
  99. )
  100. assert module.filter_checks_on_frequency(
  101. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  102. borg_repository_id='repo',
  103. checks=('archives',),
  104. force=False,
  105. archives_check_id='1234',
  106. ) == ('archives',)
  107. def test_filter_checks_on_frequency_retains_check_with_missing_check_time_file():
  108. flexmock(module).should_receive('parse_frequency').and_return(
  109. module.datetime.timedelta(hours=1)
  110. )
  111. flexmock(module).should_receive('make_check_time_path')
  112. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  113. assert module.filter_checks_on_frequency(
  114. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  115. borg_repository_id='repo',
  116. checks=('archives',),
  117. force=False,
  118. archives_check_id='1234',
  119. ) == ('archives',)
  120. def test_filter_checks_on_frequency_skips_check_with_unelapsed_frequency():
  121. flexmock(module).should_receive('parse_frequency').and_return(
  122. module.datetime.timedelta(hours=1)
  123. )
  124. flexmock(module).should_receive('make_check_time_path')
  125. flexmock(module).should_receive('probe_for_check_time').and_return(
  126. module.datetime.datetime.now()
  127. )
  128. assert (
  129. module.filter_checks_on_frequency(
  130. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  131. borg_repository_id='repo',
  132. checks=('archives',),
  133. force=False,
  134. archives_check_id='1234',
  135. )
  136. == ()
  137. )
  138. def test_filter_checks_on_frequency_restains_check_with_unelapsed_frequency_and_force():
  139. assert module.filter_checks_on_frequency(
  140. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  141. borg_repository_id='repo',
  142. checks=('archives',),
  143. force=True,
  144. archives_check_id='1234',
  145. ) == ('archives',)
  146. def test_make_archive_filter_flags_with_default_checks_and_prefix_returns_default_flags():
  147. flexmock(module.feature).should_receive('available').and_return(True)
  148. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  149. flags = module.make_archive_filter_flags(
  150. '1.2.3',
  151. {},
  152. ('repository', 'archives'),
  153. prefix='foo',
  154. )
  155. assert flags == ('--match-archives', 'sh:foo*')
  156. def test_make_archive_filter_flags_with_all_checks_and_prefix_returns_default_flags():
  157. flexmock(module.feature).should_receive('available').and_return(True)
  158. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  159. flags = module.make_archive_filter_flags(
  160. '1.2.3',
  161. {},
  162. ('repository', 'archives', 'extract'),
  163. prefix='foo',
  164. )
  165. assert flags == ('--match-archives', 'sh:foo*')
  166. def test_make_archive_filter_flags_with_all_checks_and_prefix_without_borg_features_returns_glob_archives_flags():
  167. flexmock(module.feature).should_receive('available').and_return(False)
  168. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  169. flags = module.make_archive_filter_flags(
  170. '1.2.3',
  171. {},
  172. ('repository', 'archives', 'extract'),
  173. prefix='foo',
  174. )
  175. assert flags == ('--glob-archives', 'foo*')
  176. def test_make_archive_filter_flags_with_archives_check_and_last_includes_last_flag():
  177. flexmock(module.feature).should_receive('available').and_return(True)
  178. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  179. flags = module.make_archive_filter_flags('1.2.3', {}, ('archives',), check_last=3)
  180. assert flags == ('--last', '3')
  181. def test_make_archive_filter_flags_with_data_check_and_last_includes_last_flag():
  182. flexmock(module.feature).should_receive('available').and_return(True)
  183. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  184. flags = module.make_archive_filter_flags('1.2.3', {}, ('data',), check_last=3)
  185. assert flags == ('--last', '3')
  186. def test_make_archive_filter_flags_with_repository_check_and_last_omits_last_flag():
  187. flexmock(module.feature).should_receive('available').and_return(True)
  188. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  189. flags = module.make_archive_filter_flags('1.2.3', {}, ('repository',), check_last=3)
  190. assert flags == ()
  191. def test_make_archive_filter_flags_with_default_checks_and_last_includes_last_flag():
  192. flexmock(module.feature).should_receive('available').and_return(True)
  193. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  194. flags = module.make_archive_filter_flags('1.2.3', {}, ('repository', 'archives'), check_last=3)
  195. assert flags == ('--last', '3')
  196. def test_make_archive_filter_flags_with_archives_check_and_prefix_includes_match_archives_flag():
  197. flexmock(module.feature).should_receive('available').and_return(True)
  198. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  199. flags = module.make_archive_filter_flags('1.2.3', {}, ('archives',), prefix='foo-')
  200. assert flags == ('--match-archives', 'sh:foo-*')
  201. def test_make_archive_filter_flags_with_data_check_and_prefix_includes_match_archives_flag():
  202. flexmock(module.feature).should_receive('available').and_return(True)
  203. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  204. flags = module.make_archive_filter_flags('1.2.3', {}, ('data',), prefix='foo-')
  205. assert flags == ('--match-archives', 'sh:foo-*')
  206. def test_make_archive_filter_flags_with_archives_check_and_empty_prefix_uses_archive_name_format_instead():
  207. flexmock(module.feature).should_receive('available').and_return(True)
  208. flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
  209. None, 'bar-{now}', '1.2.3' # noqa: FS003
  210. ).and_return(('--match-archives', 'sh:bar-*'))
  211. flags = module.make_archive_filter_flags(
  212. '1.2.3', {'archive_name_format': 'bar-{now}'}, ('archives',), prefix='' # noqa: FS003
  213. )
  214. assert flags == ('--match-archives', 'sh:bar-*')
  215. def test_make_archive_filter_flags_with_archives_check_and_none_prefix_omits_match_archives_flag():
  216. flexmock(module.feature).should_receive('available').and_return(True)
  217. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  218. flags = module.make_archive_filter_flags('1.2.3', {}, ('archives',), prefix=None)
  219. assert flags == ()
  220. def test_make_archive_filter_flags_with_repository_check_and_prefix_omits_match_archives_flag():
  221. flexmock(module.feature).should_receive('available').and_return(True)
  222. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  223. flags = module.make_archive_filter_flags('1.2.3', {}, ('repository',), prefix='foo-')
  224. assert flags == ()
  225. def test_make_archive_filter_flags_with_default_checks_and_prefix_includes_match_archives_flag():
  226. flexmock(module.feature).should_receive('available').and_return(True)
  227. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  228. flags = module.make_archive_filter_flags('1.2.3', {}, ('repository', 'archives'), prefix='foo-')
  229. assert flags == ('--match-archives', 'sh:foo-*')
  230. def test_make_archives_check_id_with_flags_returns_a_value_and_does_not_raise():
  231. assert module.make_archives_check_id(('--match-archives', 'sh:foo-*'))
  232. def test_make_archives_check_id_with_empty_flags_returns_none():
  233. assert module.make_archives_check_id(()) is None
  234. def test_make_check_flags_with_repository_check_returns_flag():
  235. flags = module.make_check_flags(('repository',), ())
  236. assert flags == ('--repository-only',)
  237. def test_make_check_flags_with_archives_check_returns_flag():
  238. flags = module.make_check_flags(('archives',), ())
  239. assert flags == ('--archives-only',)
  240. def test_make_check_flags_with_archives_check_and_archive_filter_flags_includes_those_flags():
  241. flags = module.make_check_flags(('archives',), ('--match-archives', 'sh:foo-*'))
  242. assert flags == ('--archives-only', '--match-archives', 'sh:foo-*')
  243. def test_make_check_flags_without_archives_check_and_with_archive_filter_flags_includes_those_flags():
  244. flags = module.make_check_flags(('repository',), ('--match-archives', 'sh:foo-*'))
  245. assert flags == ('--repository-only',)
  246. def test_make_check_flags_with_data_check_returns_flag_and_implies_archives():
  247. flexmock(module.feature).should_receive('available').and_return(True)
  248. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  249. flags = module.make_check_flags(('data',), ())
  250. assert flags == (
  251. '--archives-only',
  252. '--verify-data',
  253. )
  254. def test_make_check_flags_with_extract_omits_extract_flag():
  255. flexmock(module.feature).should_receive('available').and_return(True)
  256. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  257. flags = module.make_check_flags(('extract',), ())
  258. assert flags == ()
  259. def test_make_check_flags_with_repository_and_data_checks_does_not_return_repository_only():
  260. flexmock(module.feature).should_receive('available').and_return(True)
  261. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  262. flags = module.make_check_flags(
  263. (
  264. 'repository',
  265. 'data',
  266. ),
  267. (),
  268. )
  269. assert flags == ('--verify-data',)
  270. def test_make_check_time_path_with_borgmatic_source_directory_includes_it():
  271. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  272. '/home/user/.borgmatic'
  273. )
  274. assert (
  275. module.make_check_time_path(
  276. {'borgmatic_source_directory': '~/.borgmatic'}, '1234', 'archives', '5678'
  277. )
  278. == '/home/user/.borgmatic/checks/1234/archives/5678'
  279. )
  280. def test_make_check_time_path_without_borgmatic_source_directory_uses_default():
  281. flexmock(module.os.path).should_receive('expanduser').with_args(
  282. module.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
  283. ).and_return('/home/user/.borgmatic')
  284. assert (
  285. module.make_check_time_path({}, '1234', 'archives', '5678')
  286. == '/home/user/.borgmatic/checks/1234/archives/5678'
  287. )
  288. def test_make_check_time_path_with_archives_check_and_no_archives_check_id_defaults_to_all():
  289. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  290. '/home/user/.borgmatic'
  291. )
  292. assert (
  293. module.make_check_time_path(
  294. {'borgmatic_source_directory': '~/.borgmatic'},
  295. '1234',
  296. 'archives',
  297. )
  298. == '/home/user/.borgmatic/checks/1234/archives/all'
  299. )
  300. def test_make_check_time_path_with_repositories_check_ignores_archives_check_id():
  301. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  302. '/home/user/.borgmatic'
  303. )
  304. assert (
  305. module.make_check_time_path(
  306. {'borgmatic_source_directory': '~/.borgmatic'}, '1234', 'repository', '5678'
  307. )
  308. == '/home/user/.borgmatic/checks/1234/repository'
  309. )
  310. def test_read_check_time_does_not_raise():
  311. flexmock(module.os).should_receive('stat').and_return(flexmock(st_mtime=123))
  312. assert module.read_check_time('/path')
  313. def test_read_check_time_on_missing_file_does_not_raise():
  314. flexmock(module.os).should_receive('stat').and_raise(FileNotFoundError)
  315. assert module.read_check_time('/path') is None
  316. def test_probe_for_check_time_uses_maximum_of_multiple_check_times():
  317. flexmock(module).should_receive('make_check_time_path').and_return(
  318. '~/.borgmatic/checks/1234/archives/5678'
  319. ).and_return('~/.borgmatic/checks/1234/archives/all')
  320. flexmock(module).should_receive('read_check_time').and_return(1).and_return(2)
  321. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  322. def test_probe_for_check_time_deduplicates_identical_check_time_paths():
  323. flexmock(module).should_receive('make_check_time_path').and_return(
  324. '~/.borgmatic/checks/1234/archives/5678'
  325. ).and_return('~/.borgmatic/checks/1234/archives/5678')
  326. flexmock(module).should_receive('read_check_time').and_return(1).once()
  327. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  328. def test_probe_for_check_time_skips_none_check_time():
  329. flexmock(module).should_receive('make_check_time_path').and_return(
  330. '~/.borgmatic/checks/1234/archives/5678'
  331. ).and_return('~/.borgmatic/checks/1234/archives/all')
  332. flexmock(module).should_receive('read_check_time').and_return(None).and_return(2)
  333. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  334. def test_probe_for_check_time_uses_single_check_time():
  335. flexmock(module).should_receive('make_check_time_path').and_return(
  336. '~/.borgmatic/checks/1234/archives/5678'
  337. ).and_return('~/.borgmatic/checks/1234/archives/all')
  338. flexmock(module).should_receive('read_check_time').and_return(1).and_return(None)
  339. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  340. def test_probe_for_check_time_returns_none_when_no_check_time_found():
  341. flexmock(module).should_receive('make_check_time_path').and_return(
  342. '~/.borgmatic/checks/1234/archives/5678'
  343. ).and_return('~/.borgmatic/checks/1234/archives/all')
  344. flexmock(module).should_receive('read_check_time').and_return(None).and_return(None)
  345. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) is None
  346. def test_upgrade_check_times_renames_old_check_paths_to_all():
  347. base_path = '~/.borgmatic/checks/1234'
  348. flexmock(module).should_receive('make_check_time_path').with_args(
  349. object, object, 'archives', 'all'
  350. ).and_return(f'{base_path}/archives/all')
  351. flexmock(module).should_receive('make_check_time_path').with_args(
  352. object, object, 'data', 'all'
  353. ).and_return(f'{base_path}/data/all')
  354. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  355. True
  356. )
  357. flexmock(module.os.path).should_receive('isfile').with_args(
  358. f'{base_path}/archives.temp'
  359. ).and_return(False)
  360. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  361. False
  362. )
  363. flexmock(module.os.path).should_receive('isfile').with_args(
  364. f'{base_path}/data.temp'
  365. ).and_return(False)
  366. flexmock(module.os).should_receive('rename').with_args(
  367. f'{base_path}/archives', f'{base_path}/archives.temp'
  368. ).once()
  369. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  370. flexmock(module.os).should_receive('rename').with_args(
  371. f'{base_path}/archives.temp', f'{base_path}/archives/all'
  372. ).once()
  373. module.upgrade_check_times(flexmock(), flexmock())
  374. def test_upgrade_check_times_renames_data_check_paths_when_archives_paths_are_already_upgraded():
  375. base_path = '~/.borgmatic/checks/1234'
  376. flexmock(module).should_receive('make_check_time_path').with_args(
  377. object, object, 'archives', 'all'
  378. ).and_return(f'{base_path}/archives/all')
  379. flexmock(module).should_receive('make_check_time_path').with_args(
  380. object, object, 'data', 'all'
  381. ).and_return(f'{base_path}/data/all')
  382. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  383. False
  384. )
  385. flexmock(module.os.path).should_receive('isfile').with_args(
  386. f'{base_path}/archives.temp'
  387. ).and_return(False)
  388. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  389. True
  390. )
  391. flexmock(module.os).should_receive('rename').with_args(
  392. f'{base_path}/data', f'{base_path}/data.temp'
  393. ).once()
  394. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/data').once()
  395. flexmock(module.os).should_receive('rename').with_args(
  396. f'{base_path}/data.temp', f'{base_path}/data/all'
  397. ).once()
  398. module.upgrade_check_times(flexmock(), flexmock())
  399. def test_upgrade_check_times_skips_missing_check_paths():
  400. flexmock(module).should_receive('make_check_time_path').and_return(
  401. '~/.borgmatic/checks/1234/archives/all'
  402. )
  403. flexmock(module.os.path).should_receive('isfile').and_return(False)
  404. flexmock(module.os).should_receive('rename').never()
  405. flexmock(module.os).should_receive('mkdir').never()
  406. module.upgrade_check_times(flexmock(), flexmock())
  407. def test_upgrade_check_times_renames_stale_temporary_check_path():
  408. base_path = '~/.borgmatic/checks/1234'
  409. flexmock(module).should_receive('make_check_time_path').with_args(
  410. object, object, 'archives', 'all'
  411. ).and_return(f'{base_path}/archives/all')
  412. flexmock(module).should_receive('make_check_time_path').with_args(
  413. object, object, 'data', 'all'
  414. ).and_return(f'{base_path}/data/all')
  415. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  416. False
  417. )
  418. flexmock(module.os.path).should_receive('isfile').with_args(
  419. f'{base_path}/archives.temp'
  420. ).and_return(True)
  421. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  422. False
  423. )
  424. flexmock(module.os.path).should_receive('isfile').with_args(
  425. f'{base_path}/data.temp'
  426. ).and_return(False)
  427. flexmock(module.os).should_receive('rename').with_args(
  428. f'{base_path}/archives', f'{base_path}/archives.temp'
  429. ).and_raise(FileNotFoundError)
  430. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  431. flexmock(module.os).should_receive('rename').with_args(
  432. f'{base_path}/archives.temp', f'{base_path}/archives/all'
  433. ).once()
  434. module.upgrade_check_times(flexmock(), flexmock())
  435. def test_check_archives_with_progress_calls_borg_with_progress_parameter():
  436. checks = ('repository',)
  437. config = {'check_last': None}
  438. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  439. '{"repository": {"id": "repo"}}'
  440. )
  441. flexmock(module).should_receive('upgrade_check_times')
  442. flexmock(module).should_receive('parse_checks')
  443. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  444. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  445. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  446. flexmock(module).should_receive('make_check_flags').and_return(())
  447. flexmock(module).should_receive('execute_command').never()
  448. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  449. flexmock(module.environment).should_receive('make_environment')
  450. flexmock(module).should_receive('execute_command').with_args(
  451. ('borg', 'check', '--progress', 'repo'),
  452. output_file=module.DO_NOT_CAPTURE,
  453. extra_environment=None,
  454. ).once()
  455. flexmock(module).should_receive('make_check_time_path')
  456. flexmock(module).should_receive('write_check_time')
  457. module.check_archives(
  458. repository_path='repo',
  459. config=config,
  460. local_borg_version='1.2.3',
  461. global_arguments=flexmock(log_json=False),
  462. progress=True,
  463. )
  464. def test_check_archives_with_repair_calls_borg_with_repair_parameter():
  465. checks = ('repository',)
  466. config = {'check_last': None}
  467. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  468. '{"repository": {"id": "repo"}}'
  469. )
  470. flexmock(module).should_receive('upgrade_check_times')
  471. flexmock(module).should_receive('parse_checks')
  472. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  473. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  474. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  475. flexmock(module).should_receive('make_check_flags').and_return(())
  476. flexmock(module).should_receive('execute_command').never()
  477. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  478. flexmock(module.environment).should_receive('make_environment')
  479. flexmock(module).should_receive('execute_command').with_args(
  480. ('borg', 'check', '--repair', 'repo'),
  481. output_file=module.DO_NOT_CAPTURE,
  482. extra_environment=None,
  483. ).once()
  484. flexmock(module).should_receive('make_check_time_path')
  485. flexmock(module).should_receive('write_check_time')
  486. module.check_archives(
  487. repository_path='repo',
  488. config=config,
  489. local_borg_version='1.2.3',
  490. global_arguments=flexmock(log_json=False),
  491. repair=True,
  492. )
  493. @pytest.mark.parametrize(
  494. 'checks',
  495. (
  496. ('repository',),
  497. ('archives',),
  498. ('repository', 'archives'),
  499. ('repository', 'archives', 'other'),
  500. ),
  501. )
  502. def test_check_archives_calls_borg_with_parameters(checks):
  503. check_last = flexmock()
  504. config = {'check_last': check_last}
  505. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  506. '{"repository": {"id": "repo"}}'
  507. )
  508. flexmock(module).should_receive('upgrade_check_times')
  509. flexmock(module).should_receive('parse_checks')
  510. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  511. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  512. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  513. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  514. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  515. insert_execute_command_mock(('borg', 'check', 'repo'))
  516. flexmock(module).should_receive('make_check_time_path')
  517. flexmock(module).should_receive('write_check_time')
  518. module.check_archives(
  519. repository_path='repo',
  520. config=config,
  521. local_borg_version='1.2.3',
  522. global_arguments=flexmock(log_json=False),
  523. )
  524. def test_check_archives_with_json_error_raises():
  525. checks = ('archives',)
  526. check_last = flexmock()
  527. config = {'check_last': check_last}
  528. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  529. '{"unexpected": {"id": "repo"}}'
  530. )
  531. flexmock(module).should_receive('upgrade_check_times')
  532. flexmock(module).should_receive('parse_checks')
  533. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  534. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  535. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  536. with pytest.raises(ValueError):
  537. module.check_archives(
  538. repository_path='repo',
  539. config=config,
  540. local_borg_version='1.2.3',
  541. global_arguments=flexmock(log_json=False),
  542. )
  543. def test_check_archives_with_missing_json_keys_raises():
  544. checks = ('archives',)
  545. check_last = flexmock()
  546. config = {'check_last': check_last}
  547. flexmock(module.rinfo).should_receive('display_repository_info').and_return('{invalid JSON')
  548. flexmock(module).should_receive('upgrade_check_times')
  549. flexmock(module).should_receive('parse_checks')
  550. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  551. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  552. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  553. with pytest.raises(ValueError):
  554. module.check_archives(
  555. repository_path='repo',
  556. config=config,
  557. local_borg_version='1.2.3',
  558. global_arguments=flexmock(log_json=False),
  559. )
  560. def test_check_archives_with_extract_check_calls_extract_only():
  561. checks = ('extract',)
  562. check_last = flexmock()
  563. config = {'check_last': check_last}
  564. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  565. '{"repository": {"id": "repo"}}'
  566. )
  567. flexmock(module).should_receive('upgrade_check_times')
  568. flexmock(module).should_receive('parse_checks')
  569. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  570. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  571. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  572. flexmock(module).should_receive('make_check_flags').never()
  573. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  574. flexmock(module.extract).should_receive('extract_last_archive_dry_run').once()
  575. flexmock(module).should_receive('write_check_time')
  576. insert_execute_command_never()
  577. module.check_archives(
  578. repository_path='repo',
  579. config=config,
  580. local_borg_version='1.2.3',
  581. global_arguments=flexmock(log_json=False),
  582. )
  583. def test_check_archives_with_log_info_calls_borg_with_info_parameter():
  584. checks = ('repository',)
  585. config = {'check_last': None}
  586. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  587. '{"repository": {"id": "repo"}}'
  588. )
  589. flexmock(module).should_receive('upgrade_check_times')
  590. flexmock(module).should_receive('parse_checks')
  591. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  592. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  593. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  594. flexmock(module).should_receive('make_check_flags').and_return(())
  595. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  596. insert_logging_mock(logging.INFO)
  597. insert_execute_command_mock(('borg', 'check', '--info', 'repo'))
  598. flexmock(module).should_receive('make_check_time_path')
  599. flexmock(module).should_receive('write_check_time')
  600. module.check_archives(
  601. repository_path='repo',
  602. config=config,
  603. local_borg_version='1.2.3',
  604. global_arguments=flexmock(log_json=False),
  605. )
  606. def test_check_archives_with_log_debug_calls_borg_with_debug_parameter():
  607. checks = ('repository',)
  608. config = {'check_last': None}
  609. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  610. '{"repository": {"id": "repo"}}'
  611. )
  612. flexmock(module).should_receive('upgrade_check_times')
  613. flexmock(module).should_receive('parse_checks')
  614. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  615. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  616. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  617. flexmock(module).should_receive('make_check_flags').and_return(())
  618. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  619. insert_logging_mock(logging.DEBUG)
  620. insert_execute_command_mock(('borg', 'check', '--debug', '--show-rc', 'repo'))
  621. flexmock(module).should_receive('make_check_time_path')
  622. flexmock(module).should_receive('write_check_time')
  623. module.check_archives(
  624. repository_path='repo',
  625. config=config,
  626. local_borg_version='1.2.3',
  627. global_arguments=flexmock(log_json=False),
  628. )
  629. def test_check_archives_without_any_checks_bails():
  630. config = {'check_last': None}
  631. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  632. '{"repository": {"id": "repo"}}'
  633. )
  634. flexmock(module).should_receive('upgrade_check_times')
  635. flexmock(module).should_receive('parse_checks')
  636. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  637. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  638. flexmock(module).should_receive('filter_checks_on_frequency').and_return(())
  639. insert_execute_command_never()
  640. module.check_archives(
  641. repository_path='repo',
  642. config=config,
  643. local_borg_version='1.2.3',
  644. global_arguments=flexmock(log_json=False),
  645. )
  646. def test_check_archives_with_local_path_calls_borg_via_local_path():
  647. checks = ('repository',)
  648. check_last = flexmock()
  649. config = {'check_last': check_last}
  650. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  651. '{"repository": {"id": "repo"}}'
  652. )
  653. flexmock(module).should_receive('upgrade_check_times')
  654. flexmock(module).should_receive('parse_checks')
  655. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  656. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  657. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  658. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  659. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  660. insert_execute_command_mock(('borg1', 'check', 'repo'))
  661. flexmock(module).should_receive('make_check_time_path')
  662. flexmock(module).should_receive('write_check_time')
  663. module.check_archives(
  664. repository_path='repo',
  665. config=config,
  666. local_borg_version='1.2.3',
  667. global_arguments=flexmock(log_json=False),
  668. local_path='borg1',
  669. )
  670. def test_check_archives_with_remote_path_calls_borg_with_remote_path_parameters():
  671. checks = ('repository',)
  672. check_last = flexmock()
  673. config = {'check_last': check_last}
  674. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  675. '{"repository": {"id": "repo"}}'
  676. )
  677. flexmock(module).should_receive('upgrade_check_times')
  678. flexmock(module).should_receive('parse_checks')
  679. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  680. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  681. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  682. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  683. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  684. insert_execute_command_mock(('borg', 'check', '--remote-path', 'borg1', 'repo'))
  685. flexmock(module).should_receive('make_check_time_path')
  686. flexmock(module).should_receive('write_check_time')
  687. module.check_archives(
  688. repository_path='repo',
  689. config=config,
  690. local_borg_version='1.2.3',
  691. global_arguments=flexmock(log_json=False),
  692. remote_path='borg1',
  693. )
  694. def test_check_archives_with_log_json_calls_borg_with_log_json_parameters():
  695. checks = ('repository',)
  696. check_last = flexmock()
  697. config = {'check_last': check_last}
  698. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  699. '{"repository": {"id": "repo"}}'
  700. )
  701. flexmock(module).should_receive('upgrade_check_times')
  702. flexmock(module).should_receive('parse_checks')
  703. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  704. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  705. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  706. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  707. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  708. insert_execute_command_mock(('borg', 'check', '--log-json', 'repo'))
  709. flexmock(module).should_receive('make_check_time_path')
  710. flexmock(module).should_receive('write_check_time')
  711. module.check_archives(
  712. repository_path='repo',
  713. config=config,
  714. local_borg_version='1.2.3',
  715. global_arguments=flexmock(log_json=True),
  716. )
  717. def test_check_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
  718. checks = ('repository',)
  719. check_last = flexmock()
  720. config = {'lock_wait': 5, 'check_last': check_last}
  721. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  722. '{"repository": {"id": "repo"}}'
  723. )
  724. flexmock(module).should_receive('upgrade_check_times')
  725. flexmock(module).should_receive('parse_checks')
  726. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  727. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  728. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  729. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  730. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  731. insert_execute_command_mock(('borg', 'check', '--lock-wait', '5', 'repo'))
  732. flexmock(module).should_receive('make_check_time_path')
  733. flexmock(module).should_receive('write_check_time')
  734. module.check_archives(
  735. repository_path='repo',
  736. config=config,
  737. local_borg_version='1.2.3',
  738. global_arguments=flexmock(log_json=False),
  739. )
  740. def test_check_archives_with_retention_prefix():
  741. checks = ('repository',)
  742. check_last = flexmock()
  743. prefix = 'foo-'
  744. config = {'check_last': check_last, 'prefix': prefix}
  745. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  746. '{"repository": {"id": "repo"}}'
  747. )
  748. flexmock(module).should_receive('upgrade_check_times')
  749. flexmock(module).should_receive('parse_checks')
  750. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  751. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  752. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  753. flexmock(module).should_receive('make_check_flags').with_args(checks, ()).and_return(())
  754. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  755. insert_execute_command_mock(('borg', 'check', 'repo'))
  756. flexmock(module).should_receive('make_check_time_path')
  757. flexmock(module).should_receive('write_check_time')
  758. module.check_archives(
  759. repository_path='repo',
  760. config=config,
  761. local_borg_version='1.2.3',
  762. global_arguments=flexmock(log_json=False),
  763. )
  764. def test_check_archives_with_extra_borg_options_calls_borg_with_extra_options():
  765. checks = ('repository',)
  766. config = {'check_last': None, 'extra_borg_options': {'check': '--extra --options'}}
  767. flexmock(module.rinfo).should_receive('display_repository_info').and_return(
  768. '{"repository": {"id": "repo"}}'
  769. )
  770. flexmock(module).should_receive('upgrade_check_times')
  771. flexmock(module).should_receive('parse_checks')
  772. flexmock(module).should_receive('make_archive_filter_flags').and_return(())
  773. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  774. flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
  775. flexmock(module).should_receive('make_check_flags').and_return(())
  776. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  777. insert_execute_command_mock(('borg', 'check', '--extra', '--options', 'repo'))
  778. flexmock(module).should_receive('make_check_time_path')
  779. flexmock(module).should_receive('write_check_time')
  780. module.check_archives(
  781. repository_path='repo',
  782. config=config,
  783. local_borg_version='1.2.3',
  784. global_arguments=flexmock(log_json=False),
  785. )