test_check.py 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. import pytest
  2. from flexmock import flexmock
  3. from borgmatic.actions import check as module
  4. def test_parse_checks_returns_them_as_tuple():
  5. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'bar'}]})
  6. assert checks == ('foo', 'bar')
  7. def test_parse_checks_with_missing_value_returns_defaults():
  8. checks = module.parse_checks({})
  9. assert checks == ('repository', 'archives')
  10. def test_parse_checks_with_empty_list_returns_defaults():
  11. checks = module.parse_checks({'checks': []})
  12. assert checks == ('repository', 'archives')
  13. def test_parse_checks_with_none_value_returns_defaults():
  14. checks = module.parse_checks({'checks': None})
  15. assert checks == ('repository', 'archives')
  16. def test_parse_checks_with_disabled_returns_no_checks():
  17. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'disabled'}]})
  18. assert checks == ()
  19. def test_parse_checks_prefers_override_checks_to_configured_checks():
  20. checks = module.parse_checks(
  21. {'checks': [{'name': 'archives'}]}, only_checks=['repository', 'extract']
  22. )
  23. assert checks == ('repository', 'extract')
  24. @pytest.mark.parametrize(
  25. 'frequency,expected_result',
  26. (
  27. (None, None),
  28. ('always', None),
  29. ('1 hour', module.datetime.timedelta(hours=1)),
  30. ('2 hours', module.datetime.timedelta(hours=2)),
  31. ('1 day', module.datetime.timedelta(days=1)),
  32. ('2 days', module.datetime.timedelta(days=2)),
  33. ('1 week', module.datetime.timedelta(weeks=1)),
  34. ('2 weeks', module.datetime.timedelta(weeks=2)),
  35. ('1 month', module.datetime.timedelta(days=30)),
  36. ('2 months', module.datetime.timedelta(days=60)),
  37. ('1 year', module.datetime.timedelta(days=365)),
  38. ('2 years', module.datetime.timedelta(days=365 * 2)),
  39. ),
  40. )
  41. def test_parse_frequency_parses_into_timedeltas(frequency, expected_result):
  42. assert module.parse_frequency(frequency) == expected_result
  43. @pytest.mark.parametrize(
  44. 'frequency',
  45. (
  46. 'sometime',
  47. 'x days',
  48. '3 decades',
  49. ),
  50. )
  51. def test_parse_frequency_raises_on_parse_error(frequency):
  52. with pytest.raises(ValueError):
  53. module.parse_frequency(frequency)
  54. def test_filter_checks_on_frequency_without_config_uses_default_checks():
  55. flexmock(module).should_receive('parse_frequency').and_return(
  56. module.datetime.timedelta(weeks=4)
  57. )
  58. flexmock(module).should_receive('make_check_time_path')
  59. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  60. assert module.filter_checks_on_frequency(
  61. config={},
  62. borg_repository_id='repo',
  63. checks=('repository', 'archives'),
  64. force=False,
  65. archives_check_id='1234',
  66. ) == ('repository', 'archives')
  67. def test_filter_checks_on_frequency_retains_unconfigured_check():
  68. assert module.filter_checks_on_frequency(
  69. config={},
  70. borg_repository_id='repo',
  71. checks=('data',),
  72. force=False,
  73. ) == ('data',)
  74. def test_filter_checks_on_frequency_retains_check_without_frequency():
  75. flexmock(module).should_receive('parse_frequency').and_return(None)
  76. assert module.filter_checks_on_frequency(
  77. config={'checks': [{'name': 'archives'}]},
  78. borg_repository_id='repo',
  79. checks=('archives',),
  80. force=False,
  81. archives_check_id='1234',
  82. ) == ('archives',)
  83. def test_filter_checks_on_frequency_retains_check_with_empty_only_run_on():
  84. flexmock(module).should_receive('parse_frequency').and_return(None)
  85. assert module.filter_checks_on_frequency(
  86. config={'checks': [{'name': 'archives', 'only_run_on': []}]},
  87. borg_repository_id='repo',
  88. checks=('archives',),
  89. force=False,
  90. archives_check_id='1234',
  91. datetime_now=flexmock(weekday=lambda: 0),
  92. ) == ('archives',)
  93. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today():
  94. flexmock(module).should_receive('parse_frequency').and_return(None)
  95. assert module.filter_checks_on_frequency(
  96. config={'checks': [{'name': 'archives', 'only_run_on': [module.calendar.day_name[0]]}]},
  97. borg_repository_id='repo',
  98. checks=('archives',),
  99. force=False,
  100. archives_check_id='1234',
  101. datetime_now=flexmock(weekday=lambda: 0),
  102. ) == ('archives',)
  103. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today_via_weekday_value():
  104. flexmock(module).should_receive('parse_frequency').and_return(None)
  105. assert module.filter_checks_on_frequency(
  106. config={'checks': [{'name': 'archives', 'only_run_on': ['weekday']}]},
  107. borg_repository_id='repo',
  108. checks=('archives',),
  109. force=False,
  110. archives_check_id='1234',
  111. datetime_now=flexmock(weekday=lambda: 0),
  112. ) == ('archives',)
  113. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today_via_weekend_value():
  114. flexmock(module).should_receive('parse_frequency').and_return(None)
  115. assert module.filter_checks_on_frequency(
  116. config={'checks': [{'name': 'archives', 'only_run_on': ['weekend']}]},
  117. borg_repository_id='repo',
  118. checks=('archives',),
  119. force=False,
  120. archives_check_id='1234',
  121. datetime_now=flexmock(weekday=lambda: 6),
  122. ) == ('archives',)
  123. def test_filter_checks_on_frequency_skips_check_with_only_run_on_not_matching_today():
  124. flexmock(module).should_receive('parse_frequency').and_return(None)
  125. assert (
  126. module.filter_checks_on_frequency(
  127. config={'checks': [{'name': 'archives', 'only_run_on': [module.calendar.day_name[5]]}]},
  128. borg_repository_id='repo',
  129. checks=('archives',),
  130. force=False,
  131. archives_check_id='1234',
  132. datetime_now=flexmock(weekday=lambda: 0),
  133. )
  134. == ()
  135. )
  136. def test_filter_checks_on_frequency_retains_check_with_elapsed_frequency():
  137. flexmock(module).should_receive('parse_frequency').and_return(
  138. module.datetime.timedelta(hours=1)
  139. )
  140. flexmock(module).should_receive('make_check_time_path')
  141. flexmock(module).should_receive('probe_for_check_time').and_return(
  142. module.datetime.datetime(year=module.datetime.MINYEAR, month=1, day=1)
  143. )
  144. assert module.filter_checks_on_frequency(
  145. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  146. borg_repository_id='repo',
  147. checks=('archives',),
  148. force=False,
  149. archives_check_id='1234',
  150. ) == ('archives',)
  151. def test_filter_checks_on_frequency_retains_check_with_missing_check_time_file():
  152. flexmock(module).should_receive('parse_frequency').and_return(
  153. module.datetime.timedelta(hours=1)
  154. )
  155. flexmock(module).should_receive('make_check_time_path')
  156. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  157. assert module.filter_checks_on_frequency(
  158. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  159. borg_repository_id='repo',
  160. checks=('archives',),
  161. force=False,
  162. archives_check_id='1234',
  163. ) == ('archives',)
  164. def test_filter_checks_on_frequency_skips_check_with_unelapsed_frequency():
  165. flexmock(module).should_receive('parse_frequency').and_return(
  166. module.datetime.timedelta(hours=1)
  167. )
  168. flexmock(module).should_receive('make_check_time_path')
  169. flexmock(module).should_receive('probe_for_check_time').and_return(
  170. module.datetime.datetime.now()
  171. )
  172. assert (
  173. module.filter_checks_on_frequency(
  174. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  175. borg_repository_id='repo',
  176. checks=('archives',),
  177. force=False,
  178. archives_check_id='1234',
  179. )
  180. == ()
  181. )
  182. def test_filter_checks_on_frequency_retains_check_with_unelapsed_frequency_and_force():
  183. assert module.filter_checks_on_frequency(
  184. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  185. borg_repository_id='repo',
  186. checks=('archives',),
  187. force=True,
  188. archives_check_id='1234',
  189. ) == ('archives',)
  190. def test_filter_checks_on_frequency_passes_through_empty_checks():
  191. assert (
  192. module.filter_checks_on_frequency(
  193. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  194. borg_repository_id='repo',
  195. checks=(),
  196. force=False,
  197. archives_check_id='1234',
  198. )
  199. == ()
  200. )
  201. def test_make_archives_check_id_with_flags_returns_a_value_and_does_not_raise():
  202. assert module.make_archives_check_id(('--match-archives', 'sh:foo-*'))
  203. def test_make_archives_check_id_with_empty_flags_returns_none():
  204. assert module.make_archives_check_id(()) is None
  205. def test_make_check_time_path_with_borgmatic_source_directory_includes_it():
  206. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  207. '/home/user/.borgmatic'
  208. )
  209. assert (
  210. module.make_check_time_path(
  211. {'borgmatic_source_directory': '~/.borgmatic'}, '1234', 'archives', '5678'
  212. )
  213. == '/home/user/.borgmatic/checks/1234/archives/5678'
  214. )
  215. def test_make_check_time_path_without_borgmatic_source_directory_uses_default():
  216. flexmock(module.os.path).should_receive('expanduser').with_args(
  217. module.borgmatic.borg.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
  218. ).and_return('/home/user/.borgmatic')
  219. assert (
  220. module.make_check_time_path({}, '1234', 'archives', '5678')
  221. == '/home/user/.borgmatic/checks/1234/archives/5678'
  222. )
  223. def test_make_check_time_path_with_archives_check_and_no_archives_check_id_defaults_to_all():
  224. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  225. '/home/user/.borgmatic'
  226. )
  227. assert (
  228. module.make_check_time_path(
  229. {'borgmatic_source_directory': '~/.borgmatic'},
  230. '1234',
  231. 'archives',
  232. )
  233. == '/home/user/.borgmatic/checks/1234/archives/all'
  234. )
  235. def test_make_check_time_path_with_repositories_check_ignores_archives_check_id():
  236. flexmock(module.os.path).should_receive('expanduser').with_args('~/.borgmatic').and_return(
  237. '/home/user/.borgmatic'
  238. )
  239. assert (
  240. module.make_check_time_path(
  241. {'borgmatic_source_directory': '~/.borgmatic'}, '1234', 'repository', '5678'
  242. )
  243. == '/home/user/.borgmatic/checks/1234/repository'
  244. )
  245. def test_read_check_time_does_not_raise():
  246. flexmock(module.os).should_receive('stat').and_return(flexmock(st_mtime=123))
  247. assert module.read_check_time('/path')
  248. def test_read_check_time_on_missing_file_does_not_raise():
  249. flexmock(module.os).should_receive('stat').and_raise(FileNotFoundError)
  250. assert module.read_check_time('/path') is None
  251. def test_probe_for_check_time_uses_maximum_of_multiple_check_times():
  252. flexmock(module).should_receive('make_check_time_path').and_return(
  253. '~/.borgmatic/checks/1234/archives/5678'
  254. ).and_return('~/.borgmatic/checks/1234/archives/all')
  255. flexmock(module).should_receive('read_check_time').and_return(1).and_return(2)
  256. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  257. def test_probe_for_check_time_deduplicates_identical_check_time_paths():
  258. flexmock(module).should_receive('make_check_time_path').and_return(
  259. '~/.borgmatic/checks/1234/archives/5678'
  260. ).and_return('~/.borgmatic/checks/1234/archives/5678')
  261. flexmock(module).should_receive('read_check_time').and_return(1).once()
  262. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  263. def test_probe_for_check_time_skips_none_check_time():
  264. flexmock(module).should_receive('make_check_time_path').and_return(
  265. '~/.borgmatic/checks/1234/archives/5678'
  266. ).and_return('~/.borgmatic/checks/1234/archives/all')
  267. flexmock(module).should_receive('read_check_time').and_return(None).and_return(2)
  268. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  269. def test_probe_for_check_time_uses_single_check_time():
  270. flexmock(module).should_receive('make_check_time_path').and_return(
  271. '~/.borgmatic/checks/1234/archives/5678'
  272. ).and_return('~/.borgmatic/checks/1234/archives/all')
  273. flexmock(module).should_receive('read_check_time').and_return(1).and_return(None)
  274. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  275. def test_probe_for_check_time_returns_none_when_no_check_time_found():
  276. flexmock(module).should_receive('make_check_time_path').and_return(
  277. '~/.borgmatic/checks/1234/archives/5678'
  278. ).and_return('~/.borgmatic/checks/1234/archives/all')
  279. flexmock(module).should_receive('read_check_time').and_return(None).and_return(None)
  280. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) is None
  281. def test_upgrade_check_times_renames_old_check_paths_to_all():
  282. base_path = '~/.borgmatic/checks/1234'
  283. flexmock(module).should_receive('make_check_time_path').with_args(
  284. object, object, 'archives', 'all'
  285. ).and_return(f'{base_path}/archives/all')
  286. flexmock(module).should_receive('make_check_time_path').with_args(
  287. object, object, 'data', 'all'
  288. ).and_return(f'{base_path}/data/all')
  289. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  290. True
  291. )
  292. flexmock(module.os.path).should_receive('isfile').with_args(
  293. f'{base_path}/archives.temp'
  294. ).and_return(False)
  295. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  296. False
  297. )
  298. flexmock(module.os.path).should_receive('isfile').with_args(
  299. f'{base_path}/data.temp'
  300. ).and_return(False)
  301. flexmock(module.os).should_receive('rename').with_args(
  302. f'{base_path}/archives', f'{base_path}/archives.temp'
  303. ).once()
  304. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  305. flexmock(module.os).should_receive('rename').with_args(
  306. f'{base_path}/archives.temp', f'{base_path}/archives/all'
  307. ).once()
  308. module.upgrade_check_times(flexmock(), flexmock())
  309. def test_upgrade_check_times_renames_data_check_paths_when_archives_paths_are_already_upgraded():
  310. base_path = '~/.borgmatic/checks/1234'
  311. flexmock(module).should_receive('make_check_time_path').with_args(
  312. object, object, 'archives', 'all'
  313. ).and_return(f'{base_path}/archives/all')
  314. flexmock(module).should_receive('make_check_time_path').with_args(
  315. object, object, 'data', 'all'
  316. ).and_return(f'{base_path}/data/all')
  317. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  318. False
  319. )
  320. flexmock(module.os.path).should_receive('isfile').with_args(
  321. f'{base_path}/archives.temp'
  322. ).and_return(False)
  323. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  324. True
  325. )
  326. flexmock(module.os).should_receive('rename').with_args(
  327. f'{base_path}/data', f'{base_path}/data.temp'
  328. ).once()
  329. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/data').once()
  330. flexmock(module.os).should_receive('rename').with_args(
  331. f'{base_path}/data.temp', f'{base_path}/data/all'
  332. ).once()
  333. module.upgrade_check_times(flexmock(), flexmock())
  334. def test_upgrade_check_times_skips_missing_check_paths():
  335. flexmock(module).should_receive('make_check_time_path').and_return(
  336. '~/.borgmatic/checks/1234/archives/all'
  337. )
  338. flexmock(module.os.path).should_receive('isfile').and_return(False)
  339. flexmock(module.os).should_receive('rename').never()
  340. flexmock(module.os).should_receive('mkdir').never()
  341. module.upgrade_check_times(flexmock(), flexmock())
  342. def test_upgrade_check_times_renames_stale_temporary_check_path():
  343. base_path = '~/.borgmatic/checks/1234'
  344. flexmock(module).should_receive('make_check_time_path').with_args(
  345. object, object, 'archives', 'all'
  346. ).and_return(f'{base_path}/archives/all')
  347. flexmock(module).should_receive('make_check_time_path').with_args(
  348. object, object, 'data', 'all'
  349. ).and_return(f'{base_path}/data/all')
  350. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  351. False
  352. )
  353. flexmock(module.os.path).should_receive('isfile').with_args(
  354. f'{base_path}/archives.temp'
  355. ).and_return(True)
  356. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  357. False
  358. )
  359. flexmock(module.os.path).should_receive('isfile').with_args(
  360. f'{base_path}/data.temp'
  361. ).and_return(False)
  362. flexmock(module.os).should_receive('rename').with_args(
  363. f'{base_path}/archives', f'{base_path}/archives.temp'
  364. ).and_raise(FileNotFoundError)
  365. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  366. flexmock(module.os).should_receive('rename').with_args(
  367. f'{base_path}/archives.temp', f'{base_path}/archives/all'
  368. ).once()
  369. module.upgrade_check_times(flexmock(), flexmock())
  370. def test_collect_spot_check_source_paths_parses_borg_output():
  371. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  372. {'hook1': False, 'hook2': True}
  373. )
  374. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  375. dry_run=True,
  376. repository_path='repo',
  377. config=object,
  378. config_paths=(),
  379. local_borg_version=object,
  380. global_arguments=object,
  381. borgmatic_source_directories=(),
  382. local_path=object,
  383. remote_path=object,
  384. list_files=True,
  385. stream_processes=True,
  386. ).and_return((('borg', 'create'), ('repo::archive',), flexmock(), flexmock()))
  387. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  388. flexmock()
  389. )
  390. flexmock(module.borgmatic.execute).should_receive(
  391. 'execute_command_and_capture_output'
  392. ).and_return(
  393. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  394. )
  395. flexmock(module.os.path).should_receive('isfile').and_return(True)
  396. assert module.collect_spot_check_source_paths(
  397. repository={'path': 'repo'},
  398. config={'working_directory': '/'},
  399. local_borg_version=flexmock(),
  400. global_arguments=flexmock(),
  401. local_path=flexmock(),
  402. remote_path=flexmock(),
  403. ) == ('/etc/path', '/etc/other')
  404. def test_collect_spot_check_source_paths_passes_through_stream_processes_false():
  405. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  406. {'hook1': False, 'hook2': False}
  407. )
  408. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  409. dry_run=True,
  410. repository_path='repo',
  411. config=object,
  412. config_paths=(),
  413. local_borg_version=object,
  414. global_arguments=object,
  415. borgmatic_source_directories=(),
  416. local_path=object,
  417. remote_path=object,
  418. list_files=True,
  419. stream_processes=False,
  420. ).and_return((('borg', 'create'), ('repo::archive',), flexmock(), flexmock()))
  421. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  422. flexmock()
  423. )
  424. flexmock(module.borgmatic.execute).should_receive(
  425. 'execute_command_and_capture_output'
  426. ).and_return(
  427. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  428. )
  429. flexmock(module.os.path).should_receive('isfile').and_return(True)
  430. assert module.collect_spot_check_source_paths(
  431. repository={'path': 'repo'},
  432. config={'working_directory': '/'},
  433. local_borg_version=flexmock(),
  434. global_arguments=flexmock(),
  435. local_path=flexmock(),
  436. remote_path=flexmock(),
  437. ) == ('/etc/path', '/etc/other')
  438. def test_collect_spot_check_source_paths_without_working_directory_parses_borg_output():
  439. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  440. {'hook1': False, 'hook2': True}
  441. )
  442. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  443. dry_run=True,
  444. repository_path='repo',
  445. config=object,
  446. config_paths=(),
  447. local_borg_version=object,
  448. global_arguments=object,
  449. borgmatic_source_directories=(),
  450. local_path=object,
  451. remote_path=object,
  452. list_files=True,
  453. stream_processes=True,
  454. ).and_return((('borg', 'create'), ('repo::archive',), flexmock(), flexmock()))
  455. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  456. flexmock()
  457. )
  458. flexmock(module.borgmatic.execute).should_receive(
  459. 'execute_command_and_capture_output'
  460. ).and_return(
  461. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  462. )
  463. flexmock(module.os.path).should_receive('isfile').and_return(True)
  464. assert module.collect_spot_check_source_paths(
  465. repository={'path': 'repo'},
  466. config={},
  467. local_borg_version=flexmock(),
  468. global_arguments=flexmock(),
  469. local_path=flexmock(),
  470. remote_path=flexmock(),
  471. ) == ('/etc/path', '/etc/other')
  472. def test_collect_spot_check_source_paths_skips_directories():
  473. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  474. {'hook1': False, 'hook2': True}
  475. )
  476. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  477. dry_run=True,
  478. repository_path='repo',
  479. config=object,
  480. config_paths=(),
  481. local_borg_version=object,
  482. global_arguments=object,
  483. borgmatic_source_directories=(),
  484. local_path=object,
  485. remote_path=object,
  486. list_files=True,
  487. stream_processes=True,
  488. ).and_return((('borg', 'create'), ('repo::archive',), flexmock(), flexmock()))
  489. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  490. flexmock()
  491. )
  492. flexmock(module.borgmatic.execute).should_receive(
  493. 'execute_command_and_capture_output'
  494. ).and_return(
  495. 'warning: stuff\n- /etc/path\n+ /etc/dir\n? /nope',
  496. )
  497. flexmock(module.os.path).should_receive('isfile').with_args('/etc/path').and_return(False)
  498. flexmock(module.os.path).should_receive('isfile').with_args('/etc/dir').and_return(False)
  499. assert (
  500. module.collect_spot_check_source_paths(
  501. repository={'path': 'repo'},
  502. config={'working_directory': '/'},
  503. local_borg_version=flexmock(),
  504. global_arguments=flexmock(),
  505. local_path=flexmock(),
  506. remote_path=flexmock(),
  507. )
  508. == ()
  509. )
  510. def test_collect_spot_check_archive_paths_excludes_directories():
  511. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  512. (
  513. 'f /etc/path',
  514. 'f /etc/other',
  515. 'd /etc/dir',
  516. )
  517. )
  518. assert module.collect_spot_check_archive_paths(
  519. repository={'path': 'repo'},
  520. archive='archive',
  521. config={},
  522. local_borg_version=flexmock(),
  523. global_arguments=flexmock(),
  524. local_path=flexmock(),
  525. remote_path=flexmock(),
  526. ) == ('/etc/path', '/etc/other')
  527. def test_collect_spot_check_archive_paths_excludes_file_in_borgmatic_source_directory():
  528. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  529. (
  530. 'f /etc/path',
  531. 'f /root/.borgmatic/some/thing',
  532. )
  533. )
  534. assert module.collect_spot_check_archive_paths(
  535. repository={'path': 'repo'},
  536. archive='archive',
  537. config={'borgmatic_source_directory': '/root/.borgmatic'},
  538. local_borg_version=flexmock(),
  539. global_arguments=flexmock(),
  540. local_path=flexmock(),
  541. remote_path=flexmock(),
  542. ) == ('/etc/path',)
  543. def test_compare_spot_check_hashes_returns_paths_having_failing_hashes():
  544. flexmock(module.random).should_receive('sample').replace_with(
  545. lambda population, count: population[:count]
  546. )
  547. flexmock(module.os.path).should_receive('exists').and_return(True)
  548. flexmock(module.borgmatic.execute).should_receive(
  549. 'execute_command_and_capture_output'
  550. ).with_args(('xxh64sum', '/foo', '/bar')).and_return('hash1 /foo\nhash2 /bar')
  551. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  552. ['hash1 /foo', 'nothash2 /bar']
  553. )
  554. assert module.compare_spot_check_hashes(
  555. repository={'path': 'repo'},
  556. archive='archive',
  557. config={
  558. 'checks': [
  559. {
  560. 'name': 'archives',
  561. 'frequency': '2 weeks',
  562. },
  563. {
  564. 'name': 'spot',
  565. 'data_sample_percentage': 50,
  566. },
  567. ]
  568. },
  569. local_borg_version=flexmock(),
  570. global_arguments=flexmock(),
  571. local_path=flexmock(),
  572. remote_path=flexmock(),
  573. log_label='repo',
  574. source_paths=('/foo', '/bar', '/baz', '/quux'),
  575. ) == ('/bar',)
  576. def test_compare_spot_check_hashes_handles_data_sample_percentage_above_100():
  577. flexmock(module.random).should_receive('sample').replace_with(
  578. lambda population, count: population[:count]
  579. )
  580. flexmock(module.os.path).should_receive('exists').and_return(True)
  581. flexmock(module.borgmatic.execute).should_receive(
  582. 'execute_command_and_capture_output'
  583. ).with_args(('xxh64sum', '/foo', '/bar')).and_return('hash1 /foo\nhash2 /bar')
  584. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  585. ['nothash1 /foo', 'nothash2 /bar']
  586. )
  587. assert module.compare_spot_check_hashes(
  588. repository={'path': 'repo'},
  589. archive='archive',
  590. config={
  591. 'checks': [
  592. {
  593. 'name': 'archives',
  594. 'frequency': '2 weeks',
  595. },
  596. {
  597. 'name': 'spot',
  598. 'data_sample_percentage': 1000,
  599. },
  600. ]
  601. },
  602. local_borg_version=flexmock(),
  603. global_arguments=flexmock(),
  604. local_path=flexmock(),
  605. remote_path=flexmock(),
  606. log_label='repo',
  607. source_paths=('/foo', '/bar'),
  608. ) == ('/foo', '/bar')
  609. def test_compare_spot_check_hashes_uses_xxh64sum_command_option():
  610. flexmock(module.random).should_receive('sample').replace_with(
  611. lambda population, count: population[:count]
  612. )
  613. flexmock(module.os.path).should_receive('exists').and_return(True)
  614. flexmock(module.borgmatic.execute).should_receive(
  615. 'execute_command_and_capture_output'
  616. ).with_args(('/usr/local/bin/xxh64sum', '/foo', '/bar')).and_return('hash1 /foo\nhash2 /bar')
  617. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  618. ['hash1 /foo', 'nothash2 /bar']
  619. )
  620. assert module.compare_spot_check_hashes(
  621. repository={'path': 'repo'},
  622. archive='archive',
  623. config={
  624. 'checks': [
  625. {
  626. 'name': 'spot',
  627. 'data_sample_percentage': 50,
  628. 'xxh64sum_command': '/usr/local/bin/xxh64sum',
  629. },
  630. ]
  631. },
  632. local_borg_version=flexmock(),
  633. global_arguments=flexmock(),
  634. local_path=flexmock(),
  635. remote_path=flexmock(),
  636. log_label='repo',
  637. source_paths=('/foo', '/bar', '/baz', '/quux'),
  638. ) == ('/bar',)
  639. def test_compare_spot_check_hashes_consider_path_missing_from_archive_as_not_matching():
  640. flexmock(module.random).should_receive('sample').replace_with(
  641. lambda population, count: population[:count]
  642. )
  643. flexmock(module.os.path).should_receive('exists').and_return(True)
  644. flexmock(module.borgmatic.execute).should_receive(
  645. 'execute_command_and_capture_output'
  646. ).with_args(('xxh64sum', '/foo', '/bar')).and_return('hash1 /foo\nhash2 /bar')
  647. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  648. ['hash1 /foo']
  649. )
  650. assert module.compare_spot_check_hashes(
  651. repository={'path': 'repo'},
  652. archive='archive',
  653. config={
  654. 'checks': [
  655. {
  656. 'name': 'spot',
  657. 'data_sample_percentage': 50,
  658. },
  659. ]
  660. },
  661. local_borg_version=flexmock(),
  662. global_arguments=flexmock(),
  663. local_path=flexmock(),
  664. remote_path=flexmock(),
  665. log_label='repo',
  666. source_paths=('/foo', '/bar', '/baz', '/quux'),
  667. ) == ('/bar',)
  668. def test_compare_spot_check_hashes_considers_non_existent_path_as_not_matching():
  669. flexmock(module.random).should_receive('sample').replace_with(
  670. lambda population, count: population[:count]
  671. )
  672. flexmock(module.os.path).should_receive('exists').with_args('/foo').and_return(True)
  673. flexmock(module.os.path).should_receive('exists').with_args('/bar').and_return(False)
  674. flexmock(module.borgmatic.execute).should_receive(
  675. 'execute_command_and_capture_output'
  676. ).with_args(('xxh64sum', '/foo')).and_return('hash1 /foo')
  677. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  678. ['hash1 /foo', 'hash2 /bar']
  679. )
  680. assert module.compare_spot_check_hashes(
  681. repository={'path': 'repo'},
  682. archive='archive',
  683. config={
  684. 'checks': [
  685. {
  686. 'name': 'spot',
  687. 'data_sample_percentage': 50,
  688. },
  689. ]
  690. },
  691. local_borg_version=flexmock(),
  692. global_arguments=flexmock(),
  693. local_path=flexmock(),
  694. remote_path=flexmock(),
  695. log_label='repo',
  696. source_paths=('/foo', '/bar', '/baz', '/quux'),
  697. ) == ('/bar',)
  698. def test_compare_spot_check_hashes_with_too_many_paths_feeds_them_to_commands_in_chunks():
  699. flexmock(module).SAMPLE_PATHS_SUBSET_COUNT = 2
  700. flexmock(module.random).should_receive('sample').replace_with(
  701. lambda population, count: population[:count]
  702. )
  703. flexmock(module.os.path).should_receive('exists').and_return(True)
  704. flexmock(module.borgmatic.execute).should_receive(
  705. 'execute_command_and_capture_output'
  706. ).with_args(('xxh64sum', '/foo', '/bar')).and_return('hash1 /foo\nhash2 /bar')
  707. flexmock(module.borgmatic.execute).should_receive(
  708. 'execute_command_and_capture_output'
  709. ).with_args(('xxh64sum', '/baz', '/quux')).and_return('hash3 /baz\nhash4 /quux')
  710. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  711. ['hash1 /foo', 'hash2 /bar']
  712. ).and_return(['hash3 /baz', 'nothash4 /quux'])
  713. assert module.compare_spot_check_hashes(
  714. repository={'path': 'repo'},
  715. archive='archive',
  716. config={
  717. 'checks': [
  718. {
  719. 'name': 'archives',
  720. 'frequency': '2 weeks',
  721. },
  722. {
  723. 'name': 'spot',
  724. 'data_sample_percentage': 100,
  725. },
  726. ]
  727. },
  728. local_borg_version=flexmock(),
  729. global_arguments=flexmock(),
  730. local_path=flexmock(),
  731. remote_path=flexmock(),
  732. log_label='repo',
  733. source_paths=('/foo', '/bar', '/baz', '/quux'),
  734. ) == ('/quux',)
  735. def test_spot_check_without_spot_configuration_errors():
  736. with pytest.raises(ValueError):
  737. module.spot_check(
  738. repository={'path': 'repo'},
  739. config={
  740. 'checks': [
  741. {
  742. 'name': 'archives',
  743. },
  744. ]
  745. },
  746. local_borg_version=flexmock(),
  747. global_arguments=flexmock(),
  748. local_path=flexmock(),
  749. remote_path=flexmock(),
  750. )
  751. def test_spot_check_without_any_configuration_errors():
  752. with pytest.raises(ValueError):
  753. module.spot_check(
  754. repository={'path': 'repo'},
  755. config={},
  756. local_borg_version=flexmock(),
  757. global_arguments=flexmock(),
  758. local_path=flexmock(),
  759. remote_path=flexmock(),
  760. )
  761. def test_spot_check_data_tolerance_percenatge_greater_than_data_sample_percentage_errors():
  762. with pytest.raises(ValueError):
  763. module.spot_check(
  764. repository={'path': 'repo'},
  765. config={
  766. 'checks': [
  767. {
  768. 'name': 'spot',
  769. 'data_tolerance_percentage': 7,
  770. 'data_sample_percentage': 5,
  771. },
  772. ]
  773. },
  774. local_borg_version=flexmock(),
  775. global_arguments=flexmock(),
  776. local_path=flexmock(),
  777. remote_path=flexmock(),
  778. )
  779. def test_spot_check_with_count_delta_greater_than_count_tolerance_percentage_errors():
  780. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  781. ('/foo', '/bar', '/baz', '/quux')
  782. )
  783. flexmock(module.borgmatic.borg.rlist).should_receive('resolve_archive_name').and_return(
  784. 'archive'
  785. )
  786. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(
  787. ('/foo', '/bar')
  788. ).once()
  789. with pytest.raises(ValueError):
  790. module.spot_check(
  791. repository={'path': 'repo'},
  792. config={
  793. 'checks': [
  794. {
  795. 'name': 'spot',
  796. 'count_tolerance_percentage': 1,
  797. 'data_tolerance_percentage': 4,
  798. 'data_sample_percentage': 5,
  799. },
  800. ]
  801. },
  802. local_borg_version=flexmock(),
  803. global_arguments=flexmock(),
  804. local_path=flexmock(),
  805. remote_path=flexmock(),
  806. )
  807. def test_spot_check_with_failing_percentage_greater_than_data_tolerance_percentage_errors():
  808. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  809. ('/foo', '/bar', '/baz', '/quux')
  810. )
  811. flexmock(module.borgmatic.borg.rlist).should_receive('resolve_archive_name').and_return(
  812. 'archive'
  813. )
  814. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(('/foo', '/bar'))
  815. flexmock(module).should_receive('compare_spot_check_hashes').and_return(
  816. ('/bar', '/baz', '/quux')
  817. ).once()
  818. with pytest.raises(ValueError):
  819. module.spot_check(
  820. repository={'path': 'repo'},
  821. config={
  822. 'checks': [
  823. {
  824. 'name': 'spot',
  825. 'count_tolerance_percentage': 55,
  826. 'data_tolerance_percentage': 4,
  827. 'data_sample_percentage': 5,
  828. },
  829. ]
  830. },
  831. local_borg_version=flexmock(),
  832. global_arguments=flexmock(),
  833. local_path=flexmock(),
  834. remote_path=flexmock(),
  835. )
  836. def test_spot_check_with_high_enough_tolerances_does_not_raise():
  837. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  838. ('/foo', '/bar', '/baz', '/quux')
  839. )
  840. flexmock(module.borgmatic.borg.rlist).should_receive('resolve_archive_name').and_return(
  841. 'archive'
  842. )
  843. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(('/foo', '/bar'))
  844. flexmock(module).should_receive('compare_spot_check_hashes').and_return(
  845. ('/bar', '/baz', '/quux')
  846. ).once()
  847. module.spot_check(
  848. repository={'path': 'repo'},
  849. config={
  850. 'checks': [
  851. {
  852. 'name': 'spot',
  853. 'count_tolerance_percentage': 55,
  854. 'data_tolerance_percentage': 80,
  855. 'data_sample_percentage': 80,
  856. },
  857. ]
  858. },
  859. local_borg_version=flexmock(),
  860. global_arguments=flexmock(),
  861. local_path=flexmock(),
  862. remote_path=flexmock(),
  863. )
  864. def test_run_check_checks_archives_for_configured_repository():
  865. flexmock(module.logger).answer = lambda message: None
  866. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  867. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  868. flexmock(module).should_receive('upgrade_check_times')
  869. flexmock(module).should_receive('parse_checks')
  870. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  871. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  872. flexmock(module).should_receive('filter_checks_on_frequency').and_return(
  873. {'repository', 'archives'}
  874. )
  875. flexmock(module.borgmatic.borg.check).should_receive('check_archives').once()
  876. flexmock(module).should_receive('make_check_time_path')
  877. flexmock(module).should_receive('write_check_time')
  878. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  879. flexmock(module.borgmatic.hooks.command).should_receive('execute_hook').times(2)
  880. check_arguments = flexmock(
  881. repository=None,
  882. progress=flexmock(),
  883. repair=flexmock(),
  884. only_checks=flexmock(),
  885. force=flexmock(),
  886. )
  887. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  888. module.run_check(
  889. config_filename='test.yaml',
  890. repository={'path': 'repo'},
  891. config={'repositories': ['repo']},
  892. hook_context={},
  893. local_borg_version=None,
  894. check_arguments=check_arguments,
  895. global_arguments=global_arguments,
  896. local_path=None,
  897. remote_path=None,
  898. )
  899. def test_run_check_runs_configured_extract_check():
  900. flexmock(module.logger).answer = lambda message: None
  901. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  902. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  903. flexmock(module).should_receive('upgrade_check_times')
  904. flexmock(module).should_receive('parse_checks')
  905. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  906. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  907. flexmock(module).should_receive('filter_checks_on_frequency').and_return({'extract'})
  908. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  909. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').once()
  910. flexmock(module).should_receive('make_check_time_path')
  911. flexmock(module).should_receive('write_check_time')
  912. flexmock(module.borgmatic.hooks.command).should_receive('execute_hook').times(2)
  913. check_arguments = flexmock(
  914. repository=None,
  915. progress=flexmock(),
  916. repair=flexmock(),
  917. only_checks=flexmock(),
  918. force=flexmock(),
  919. )
  920. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  921. module.run_check(
  922. config_filename='test.yaml',
  923. repository={'path': 'repo'},
  924. config={'repositories': ['repo']},
  925. hook_context={},
  926. local_borg_version=None,
  927. check_arguments=check_arguments,
  928. global_arguments=global_arguments,
  929. local_path=None,
  930. remote_path=None,
  931. )
  932. def test_run_check_runs_configured_spot_check():
  933. flexmock(module.logger).answer = lambda message: None
  934. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  935. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  936. flexmock(module).should_receive('upgrade_check_times')
  937. flexmock(module).should_receive('parse_checks')
  938. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  939. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  940. flexmock(module).should_receive('filter_checks_on_frequency').and_return({'spot'})
  941. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  942. flexmock(module.borgmatic.actions.check).should_receive('spot_check').once()
  943. flexmock(module).should_receive('make_check_time_path')
  944. flexmock(module).should_receive('write_check_time')
  945. flexmock(module.borgmatic.hooks.command).should_receive('execute_hook').times(2)
  946. check_arguments = flexmock(
  947. repository=None,
  948. progress=flexmock(),
  949. repair=flexmock(),
  950. only_checks=flexmock(),
  951. force=flexmock(),
  952. )
  953. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  954. module.run_check(
  955. config_filename='test.yaml',
  956. repository={'path': 'repo'},
  957. config={'repositories': ['repo']},
  958. hook_context={},
  959. local_borg_version=None,
  960. check_arguments=check_arguments,
  961. global_arguments=global_arguments,
  962. local_path=None,
  963. remote_path=None,
  964. )
  965. def test_run_check_without_checks_runs_nothing_except_hooks():
  966. flexmock(module.logger).answer = lambda message: None
  967. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  968. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  969. flexmock(module).should_receive('upgrade_check_times')
  970. flexmock(module).should_receive('parse_checks')
  971. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  972. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  973. flexmock(module).should_receive('filter_checks_on_frequency').and_return({})
  974. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  975. flexmock(module).should_receive('make_check_time_path')
  976. flexmock(module).should_receive('write_check_time').never()
  977. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  978. flexmock(module.borgmatic.hooks.command).should_receive('execute_hook').times(2)
  979. check_arguments = flexmock(
  980. repository=None,
  981. progress=flexmock(),
  982. repair=flexmock(),
  983. only_checks=flexmock(),
  984. force=flexmock(),
  985. )
  986. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  987. module.run_check(
  988. config_filename='test.yaml',
  989. repository={'path': 'repo'},
  990. config={'repositories': ['repo']},
  991. hook_context={},
  992. local_borg_version=None,
  993. check_arguments=check_arguments,
  994. global_arguments=global_arguments,
  995. local_path=None,
  996. remote_path=None,
  997. )
  998. def test_run_check_checks_archives_in_selected_repository():
  999. flexmock(module.logger).answer = lambda message: None
  1000. flexmock(module.borgmatic.config.validate).should_receive(
  1001. 'repositories_match'
  1002. ).once().and_return(True)
  1003. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1004. flexmock(module).should_receive('upgrade_check_times')
  1005. flexmock(module).should_receive('parse_checks')
  1006. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1007. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1008. flexmock(module).should_receive('filter_checks_on_frequency').and_return(
  1009. {'repository', 'archives'}
  1010. )
  1011. flexmock(module.borgmatic.borg.check).should_receive('check_archives').once()
  1012. flexmock(module).should_receive('make_check_time_path')
  1013. flexmock(module).should_receive('write_check_time')
  1014. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  1015. check_arguments = flexmock(
  1016. repository=flexmock(),
  1017. progress=flexmock(),
  1018. repair=flexmock(),
  1019. only_checks=flexmock(),
  1020. force=flexmock(),
  1021. )
  1022. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1023. module.run_check(
  1024. config_filename='test.yaml',
  1025. repository={'path': 'repo'},
  1026. config={'repositories': ['repo']},
  1027. hook_context={},
  1028. local_borg_version=None,
  1029. check_arguments=check_arguments,
  1030. global_arguments=global_arguments,
  1031. local_path=None,
  1032. remote_path=None,
  1033. )
  1034. def test_run_check_bails_if_repository_does_not_match():
  1035. flexmock(module.logger).answer = lambda message: None
  1036. flexmock(module.borgmatic.config.validate).should_receive(
  1037. 'repositories_match'
  1038. ).once().and_return(False)
  1039. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  1040. check_arguments = flexmock(
  1041. repository=flexmock(),
  1042. progress=flexmock(),
  1043. repair=flexmock(),
  1044. only_checks=flexmock(),
  1045. force=flexmock(),
  1046. )
  1047. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1048. module.run_check(
  1049. config_filename='test.yaml',
  1050. repository={'path': 'repo'},
  1051. config={'repositories': ['repo']},
  1052. hook_context={},
  1053. local_borg_version=None,
  1054. check_arguments=check_arguments,
  1055. global_arguments=global_arguments,
  1056. local_path=None,
  1057. remote_path=None,
  1058. )