test_check.py 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734
  1. import pytest
  2. from flexmock import flexmock
  3. from borgmatic.actions import check as module
  4. from borgmatic.borg.pattern import Pattern
  5. def test_parse_checks_returns_them_as_tuple():
  6. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'bar'}]})
  7. assert checks == ('foo', 'bar')
  8. def test_parse_checks_with_missing_value_returns_defaults():
  9. checks = module.parse_checks({})
  10. assert checks == ('repository', 'archives')
  11. def test_parse_checks_with_empty_list_returns_defaults():
  12. checks = module.parse_checks({'checks': []})
  13. assert checks == ('repository', 'archives')
  14. def test_parse_checks_with_none_value_returns_defaults():
  15. checks = module.parse_checks({'checks': None})
  16. assert checks == ('repository', 'archives')
  17. def test_parse_checks_with_disabled_returns_no_checks():
  18. checks = module.parse_checks({'checks': [{'name': 'foo'}, {'name': 'disabled'}]})
  19. assert checks == ()
  20. def test_parse_checks_prefers_override_checks_to_configured_checks():
  21. checks = module.parse_checks(
  22. {'checks': [{'name': 'archives'}]},
  23. only_checks=['repository', 'extract'],
  24. )
  25. assert checks == ('repository', 'extract')
  26. @pytest.mark.parametrize(
  27. 'frequency,expected_result',
  28. (
  29. (None, None),
  30. ('always', None),
  31. ('1 hour', module.datetime.timedelta(hours=1)),
  32. ('2 hours', module.datetime.timedelta(hours=2)),
  33. ('1 day', module.datetime.timedelta(days=1)),
  34. ('2 days', module.datetime.timedelta(days=2)),
  35. ('1 week', module.datetime.timedelta(weeks=1)),
  36. ('2 weeks', module.datetime.timedelta(weeks=2)),
  37. ('1 month', module.datetime.timedelta(days=30)),
  38. ('2 months', module.datetime.timedelta(days=60)),
  39. ('1 year', module.datetime.timedelta(days=365)),
  40. ('2 years', module.datetime.timedelta(days=365 * 2)),
  41. ),
  42. )
  43. def test_parse_frequency_parses_into_timedeltas(frequency, expected_result):
  44. assert module.parse_frequency(frequency) == expected_result
  45. @pytest.mark.parametrize(
  46. 'frequency',
  47. (
  48. 'sometime',
  49. 'x days',
  50. '3 decades',
  51. ),
  52. )
  53. def test_parse_frequency_raises_on_parse_error(frequency):
  54. with pytest.raises(ValueError):
  55. module.parse_frequency(frequency)
  56. def test_filter_checks_on_frequency_without_config_uses_default_checks():
  57. flexmock(module).should_receive('parse_frequency').and_return(
  58. module.datetime.timedelta(weeks=4),
  59. )
  60. flexmock(module).should_receive('make_check_time_path')
  61. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  62. assert module.filter_checks_on_frequency(
  63. config={},
  64. borg_repository_id='repo',
  65. checks=('repository', 'archives'),
  66. force=False,
  67. archives_check_id='1234',
  68. ) == ('repository', 'archives')
  69. def test_filter_checks_on_frequency_retains_unconfigured_check():
  70. assert module.filter_checks_on_frequency(
  71. config={},
  72. borg_repository_id='repo',
  73. checks=('data',),
  74. force=False,
  75. ) == ('data',)
  76. def test_filter_checks_on_frequency_retains_check_without_frequency():
  77. flexmock(module).should_receive('parse_frequency').and_return(None)
  78. assert module.filter_checks_on_frequency(
  79. config={'checks': [{'name': 'archives'}]},
  80. borg_repository_id='repo',
  81. checks=('archives',),
  82. force=False,
  83. archives_check_id='1234',
  84. ) == ('archives',)
  85. def test_filter_checks_on_frequency_retains_check_with_empty_only_run_on():
  86. flexmock(module).should_receive('parse_frequency').and_return(None)
  87. assert module.filter_checks_on_frequency(
  88. config={'checks': [{'name': 'archives', 'only_run_on': []}]},
  89. borg_repository_id='repo',
  90. checks=('archives',),
  91. force=False,
  92. archives_check_id='1234',
  93. datetime_now=flexmock(weekday=lambda: 0),
  94. ) == ('archives',)
  95. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today():
  96. flexmock(module).should_receive('parse_frequency').and_return(None)
  97. assert module.filter_checks_on_frequency(
  98. config={'checks': [{'name': 'archives', 'only_run_on': [module.calendar.day_name[0]]}]},
  99. borg_repository_id='repo',
  100. checks=('archives',),
  101. force=False,
  102. archives_check_id='1234',
  103. datetime_now=flexmock(weekday=lambda: 0),
  104. ) == ('archives',)
  105. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today_via_weekday_value():
  106. flexmock(module).should_receive('parse_frequency').and_return(None)
  107. assert module.filter_checks_on_frequency(
  108. config={'checks': [{'name': 'archives', 'only_run_on': ['weekday']}]},
  109. borg_repository_id='repo',
  110. checks=('archives',),
  111. force=False,
  112. archives_check_id='1234',
  113. datetime_now=flexmock(weekday=lambda: 0),
  114. ) == ('archives',)
  115. def test_filter_checks_on_frequency_retains_check_with_only_run_on_matching_today_via_weekend_value():
  116. flexmock(module).should_receive('parse_frequency').and_return(None)
  117. assert module.filter_checks_on_frequency(
  118. config={'checks': [{'name': 'archives', 'only_run_on': ['weekend']}]},
  119. borg_repository_id='repo',
  120. checks=('archives',),
  121. force=False,
  122. archives_check_id='1234',
  123. datetime_now=flexmock(weekday=lambda: 6),
  124. ) == ('archives',)
  125. def test_filter_checks_on_frequency_skips_check_with_only_run_on_not_matching_today():
  126. flexmock(module).should_receive('parse_frequency').and_return(None)
  127. assert (
  128. module.filter_checks_on_frequency(
  129. config={'checks': [{'name': 'archives', 'only_run_on': [module.calendar.day_name[5]]}]},
  130. borg_repository_id='repo',
  131. checks=('archives',),
  132. force=False,
  133. archives_check_id='1234',
  134. datetime_now=flexmock(weekday=lambda: 0),
  135. )
  136. == ()
  137. )
  138. def test_filter_checks_on_frequency_retains_check_with_elapsed_frequency():
  139. flexmock(module).should_receive('parse_frequency').and_return(
  140. module.datetime.timedelta(hours=1),
  141. )
  142. flexmock(module).should_receive('make_check_time_path')
  143. flexmock(module).should_receive('probe_for_check_time').and_return(
  144. module.datetime.datetime(year=module.datetime.MINYEAR, month=1, day=1),
  145. )
  146. assert module.filter_checks_on_frequency(
  147. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  148. borg_repository_id='repo',
  149. checks=('archives',),
  150. force=False,
  151. archives_check_id='1234',
  152. ) == ('archives',)
  153. def test_filter_checks_on_frequency_retains_check_with_missing_check_time_file():
  154. flexmock(module).should_receive('parse_frequency').and_return(
  155. module.datetime.timedelta(hours=1),
  156. )
  157. flexmock(module).should_receive('make_check_time_path')
  158. flexmock(module).should_receive('probe_for_check_time').and_return(None)
  159. assert module.filter_checks_on_frequency(
  160. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  161. borg_repository_id='repo',
  162. checks=('archives',),
  163. force=False,
  164. archives_check_id='1234',
  165. ) == ('archives',)
  166. def test_filter_checks_on_frequency_skips_check_with_unelapsed_frequency():
  167. flexmock(module).should_receive('parse_frequency').and_return(
  168. module.datetime.timedelta(hours=1),
  169. )
  170. flexmock(module).should_receive('make_check_time_path')
  171. flexmock(module).should_receive('probe_for_check_time').and_return(
  172. module.datetime.datetime.now(),
  173. )
  174. assert (
  175. module.filter_checks_on_frequency(
  176. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  177. borg_repository_id='repo',
  178. checks=('archives',),
  179. force=False,
  180. archives_check_id='1234',
  181. )
  182. == ()
  183. )
  184. def test_filter_checks_on_frequency_retains_check_with_unelapsed_frequency_and_force():
  185. assert module.filter_checks_on_frequency(
  186. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  187. borg_repository_id='repo',
  188. checks=('archives',),
  189. force=True,
  190. archives_check_id='1234',
  191. ) == ('archives',)
  192. def test_filter_checks_on_frequency_passes_through_empty_checks():
  193. assert (
  194. module.filter_checks_on_frequency(
  195. config={'checks': [{'name': 'archives', 'frequency': '1 hour'}]},
  196. borg_repository_id='repo',
  197. checks=(),
  198. force=False,
  199. archives_check_id='1234',
  200. )
  201. == ()
  202. )
  203. def test_make_archives_check_id_with_flags_returns_a_value_and_does_not_raise():
  204. assert module.make_archives_check_id(('--match-archives', 'sh:foo-*'))
  205. def test_make_archives_check_id_with_empty_flags_returns_none():
  206. assert module.make_archives_check_id(()) is None
  207. def test_make_check_time_path_with_borgmatic_source_directory_includes_it():
  208. flexmock(module.borgmatic.config.paths).should_receive(
  209. 'get_borgmatic_state_directory',
  210. ).and_return(
  211. '/home/user/.local/state/borgmatic',
  212. )
  213. assert (
  214. module.make_check_time_path({}, '1234', 'archives', '5678')
  215. == '/home/user/.local/state/borgmatic/checks/1234/archives/5678'
  216. )
  217. def test_make_check_time_path_with_archives_check_and_no_archives_check_id_defaults_to_all():
  218. flexmock(module.borgmatic.config.paths).should_receive(
  219. 'get_borgmatic_state_directory',
  220. ).and_return(
  221. '/home/user/.local/state/borgmatic',
  222. )
  223. assert (
  224. module.make_check_time_path(
  225. {},
  226. '1234',
  227. 'archives',
  228. )
  229. == '/home/user/.local/state/borgmatic/checks/1234/archives/all'
  230. )
  231. def test_make_check_time_path_with_repositories_check_ignores_archives_check_id():
  232. flexmock(module.borgmatic.config.paths).should_receive(
  233. 'get_borgmatic_state_directory',
  234. ).and_return(
  235. '/home/user/.local/state/borgmatic',
  236. )
  237. assert (
  238. module.make_check_time_path({}, '1234', 'repository', '5678')
  239. == '/home/user/.local/state/borgmatic/checks/1234/repository'
  240. )
  241. def test_read_check_time_does_not_raise():
  242. flexmock(module.os).should_receive('stat').and_return(flexmock(st_mtime=123))
  243. assert module.read_check_time('/path')
  244. def test_read_check_time_on_missing_file_does_not_raise():
  245. flexmock(module.os).should_receive('stat').and_raise(FileNotFoundError)
  246. assert module.read_check_time('/path') is None
  247. def test_probe_for_check_time_uses_maximum_of_multiple_check_times():
  248. flexmock(module).should_receive('make_check_time_path').and_return(
  249. '~/.borgmatic/checks/1234/archives/5678',
  250. ).and_return('~/.borgmatic/checks/1234/archives/all')
  251. flexmock(module).should_receive('read_check_time').and_return(1).and_return(2)
  252. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  253. def test_probe_for_check_time_deduplicates_identical_check_time_paths():
  254. flexmock(module).should_receive('make_check_time_path').and_return(
  255. '~/.borgmatic/checks/1234/archives/5678',
  256. ).and_return('~/.borgmatic/checks/1234/archives/5678')
  257. flexmock(module).should_receive('read_check_time').and_return(1).once()
  258. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  259. def test_probe_for_check_time_skips_none_check_time():
  260. flexmock(module).should_receive('make_check_time_path').and_return(
  261. '~/.borgmatic/checks/1234/archives/5678',
  262. ).and_return('~/.borgmatic/checks/1234/archives/all')
  263. flexmock(module).should_receive('read_check_time').and_return(None).and_return(2)
  264. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 2
  265. def test_probe_for_check_time_uses_single_check_time():
  266. flexmock(module).should_receive('make_check_time_path').and_return(
  267. '~/.borgmatic/checks/1234/archives/5678',
  268. ).and_return('~/.borgmatic/checks/1234/archives/all')
  269. flexmock(module).should_receive('read_check_time').and_return(1).and_return(None)
  270. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) == 1
  271. def test_probe_for_check_time_returns_none_when_no_check_time_found():
  272. flexmock(module).should_receive('make_check_time_path').and_return(
  273. '~/.borgmatic/checks/1234/archives/5678',
  274. ).and_return('~/.borgmatic/checks/1234/archives/all')
  275. flexmock(module).should_receive('read_check_time').and_return(None).and_return(None)
  276. assert module.probe_for_check_time(flexmock(), flexmock(), flexmock(), flexmock()) is None
  277. def test_upgrade_check_times_moves_checks_from_borgmatic_source_directory_to_state_directory():
  278. flexmock(module.borgmatic.config.paths).should_receive(
  279. 'get_borgmatic_source_directory',
  280. ).and_return('/home/user/.borgmatic')
  281. flexmock(module.borgmatic.config.paths).should_receive(
  282. 'get_borgmatic_state_directory',
  283. ).and_return('/home/user/.local/state/borgmatic')
  284. flexmock(module.os.path).should_receive('exists').with_args(
  285. '/home/user/.borgmatic/checks',
  286. ).and_return(True)
  287. flexmock(module.os.path).should_receive('exists').with_args(
  288. '/home/user/.local/state/borgmatic/checks',
  289. ).and_return(False)
  290. flexmock(module.os).should_receive('makedirs')
  291. flexmock(module.shutil).should_receive('move').with_args(
  292. '/home/user/.borgmatic/checks',
  293. '/home/user/.local/state/borgmatic/checks',
  294. ).once()
  295. flexmock(module).should_receive('make_check_time_path').and_return(
  296. '/home/user/.local/state/borgmatic/checks/1234/archives/all',
  297. )
  298. flexmock(module.os.path).should_receive('isfile').and_return(False)
  299. flexmock(module.os).should_receive('mkdir').never()
  300. module.upgrade_check_times(flexmock(), flexmock())
  301. def test_upgrade_check_times_with_checks_already_in_borgmatic_state_directory_does_not_move_anything():
  302. flexmock(module.borgmatic.config.paths).should_receive(
  303. 'get_borgmatic_source_directory',
  304. ).and_return('/home/user/.borgmatic')
  305. flexmock(module.borgmatic.config.paths).should_receive(
  306. 'get_borgmatic_state_directory',
  307. ).and_return('/home/user/.local/state/borgmatic')
  308. flexmock(module.os.path).should_receive('exists').with_args(
  309. '/home/user/.borgmatic/checks',
  310. ).and_return(True)
  311. flexmock(module.os.path).should_receive('exists').with_args(
  312. '/home/user/.local/state/borgmatic/checks',
  313. ).and_return(True)
  314. flexmock(module.os).should_receive('makedirs').never()
  315. flexmock(module.shutil).should_receive('move').never()
  316. flexmock(module).should_receive('make_check_time_path').and_return(
  317. '/home/user/.local/state/borgmatic/checks/1234/archives/all',
  318. )
  319. flexmock(module.os.path).should_receive('isfile').and_return(False)
  320. flexmock(module.shutil).should_receive('move').never()
  321. flexmock(module.os).should_receive('mkdir').never()
  322. module.upgrade_check_times(flexmock(), flexmock())
  323. def test_upgrade_check_times_renames_old_check_paths_to_all():
  324. flexmock(module.borgmatic.config.paths).should_receive(
  325. 'get_borgmatic_source_directory',
  326. ).and_return('/home/user/.borgmatic')
  327. flexmock(module.borgmatic.config.paths).should_receive(
  328. 'get_borgmatic_state_directory',
  329. ).and_return('/home/user/.local/state/borgmatic')
  330. flexmock(module.os.path).should_receive('exists').and_return(False)
  331. base_path = '/home/user/.local/state/borgmatic/checks/1234'
  332. flexmock(module).should_receive('make_check_time_path').with_args(
  333. object,
  334. object,
  335. 'archives',
  336. 'all',
  337. ).and_return(f'{base_path}/archives/all')
  338. flexmock(module).should_receive('make_check_time_path').with_args(
  339. object,
  340. object,
  341. 'data',
  342. 'all',
  343. ).and_return(f'{base_path}/data/all')
  344. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  345. True,
  346. )
  347. flexmock(module.os.path).should_receive('isfile').with_args(
  348. f'{base_path}/archives.temp',
  349. ).and_return(False)
  350. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  351. False,
  352. )
  353. flexmock(module.os.path).should_receive('isfile').with_args(
  354. f'{base_path}/data.temp',
  355. ).and_return(False)
  356. flexmock(module.shutil).should_receive('move').with_args(
  357. f'{base_path}/archives',
  358. f'{base_path}/archives.temp',
  359. ).once()
  360. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  361. flexmock(module.shutil).should_receive('move').with_args(
  362. f'{base_path}/archives.temp',
  363. f'{base_path}/archives/all',
  364. ).once()
  365. module.upgrade_check_times(flexmock(), flexmock())
  366. def test_upgrade_check_times_renames_data_check_paths_when_archives_paths_are_already_upgraded():
  367. flexmock(module.borgmatic.config.paths).should_receive(
  368. 'get_borgmatic_source_directory',
  369. ).and_return('/home/user/.borgmatic')
  370. flexmock(module.borgmatic.config.paths).should_receive(
  371. 'get_borgmatic_state_directory',
  372. ).and_return('/home/user/.local/state/borgmatic')
  373. flexmock(module.os.path).should_receive('exists').and_return(False)
  374. base_path = '/home/user/.local/state/borgmatic/checks/1234'
  375. flexmock(module).should_receive('make_check_time_path').with_args(
  376. object,
  377. object,
  378. 'archives',
  379. 'all',
  380. ).and_return(f'{base_path}/archives/all')
  381. flexmock(module).should_receive('make_check_time_path').with_args(
  382. object,
  383. object,
  384. 'data',
  385. 'all',
  386. ).and_return(f'{base_path}/data/all')
  387. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  388. False,
  389. )
  390. flexmock(module.os.path).should_receive('isfile').with_args(
  391. f'{base_path}/archives.temp',
  392. ).and_return(False)
  393. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  394. True,
  395. )
  396. flexmock(module.shutil).should_receive('move').with_args(
  397. f'{base_path}/data',
  398. f'{base_path}/data.temp',
  399. ).once()
  400. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/data').once()
  401. flexmock(module.shutil).should_receive('move').with_args(
  402. f'{base_path}/data.temp',
  403. f'{base_path}/data/all',
  404. ).once()
  405. module.upgrade_check_times(flexmock(), flexmock())
  406. def test_upgrade_check_times_skips_already_upgraded_check_paths():
  407. flexmock(module.borgmatic.config.paths).should_receive(
  408. 'get_borgmatic_source_directory',
  409. ).and_return('/home/user/.borgmatic')
  410. flexmock(module.borgmatic.config.paths).should_receive(
  411. 'get_borgmatic_state_directory',
  412. ).and_return('/home/user/.local/state/borgmatic')
  413. flexmock(module.os.path).should_receive('exists').and_return(False)
  414. flexmock(module).should_receive('make_check_time_path').and_return(
  415. '/home/user/.local/state/borgmatic/checks/1234/archives/all',
  416. )
  417. flexmock(module.os.path).should_receive('isfile').and_return(False)
  418. flexmock(module.shutil).should_receive('move').never()
  419. flexmock(module.os).should_receive('mkdir').never()
  420. module.upgrade_check_times(flexmock(), flexmock())
  421. def test_upgrade_check_times_renames_stale_temporary_check_path():
  422. flexmock(module.borgmatic.config.paths).should_receive(
  423. 'get_borgmatic_source_directory',
  424. ).and_return('/home/user/.borgmatic')
  425. flexmock(module.borgmatic.config.paths).should_receive(
  426. 'get_borgmatic_state_directory',
  427. ).and_return('/home/user/.local/state/borgmatic')
  428. flexmock(module.os.path).should_receive('exists').and_return(False)
  429. base_path = '/home/borgmatic/.local/state/checks/1234'
  430. flexmock(module).should_receive('make_check_time_path').with_args(
  431. object,
  432. object,
  433. 'archives',
  434. 'all',
  435. ).and_return(f'{base_path}/archives/all')
  436. flexmock(module).should_receive('make_check_time_path').with_args(
  437. object,
  438. object,
  439. 'data',
  440. 'all',
  441. ).and_return(f'{base_path}/data/all')
  442. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/archives').and_return(
  443. False,
  444. )
  445. flexmock(module.os.path).should_receive('isfile').with_args(
  446. f'{base_path}/archives.temp',
  447. ).and_return(True)
  448. flexmock(module.os.path).should_receive('isfile').with_args(f'{base_path}/data').and_return(
  449. False,
  450. )
  451. flexmock(module.os.path).should_receive('isfile').with_args(
  452. f'{base_path}/data.temp',
  453. ).and_return(False)
  454. flexmock(module.shutil).should_receive('move').with_args(
  455. f'{base_path}/archives',
  456. f'{base_path}/archives.temp',
  457. ).and_raise(FileNotFoundError)
  458. flexmock(module.os).should_receive('mkdir').with_args(f'{base_path}/archives').once()
  459. flexmock(module.shutil).should_receive('move').with_args(
  460. f'{base_path}/archives.temp',
  461. f'{base_path}/archives/all',
  462. ).once()
  463. module.upgrade_check_times(flexmock(), flexmock())
  464. def test_collect_spot_check_source_paths_parses_borg_output_and_includes_bootstrap_config_paths():
  465. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  466. {'hook1': False, 'hook2': True},
  467. )
  468. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  469. flexmock(),
  470. )
  471. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  472. (Pattern('collected'),),
  473. )
  474. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').with_args(
  475. (
  476. Pattern('collected', source=module.borgmatic.borg.pattern.Pattern_source.HOOK),
  477. Pattern('extra.yaml', source=module.borgmatic.borg.pattern.Pattern_source.INTERNAL),
  478. ),
  479. config=object,
  480. working_directory=None,
  481. ).and_return(
  482. [Pattern('foo'), Pattern('bar')],
  483. )
  484. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  485. dry_run=True,
  486. repository_path='repo',
  487. config=object,
  488. patterns=[Pattern('foo'), Pattern('bar')],
  489. local_borg_version=object,
  490. global_arguments=object,
  491. borgmatic_runtime_directory='/run/borgmatic',
  492. local_path=object,
  493. remote_path=object,
  494. stream_processes=True,
  495. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  496. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  497. flexmock(),
  498. )
  499. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  500. flexmock(module.borgmatic.execute).should_receive(
  501. 'execute_command_and_capture_output',
  502. ).and_return(
  503. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  504. )
  505. flexmock(module.os.path).should_receive('isfile').and_return(True)
  506. assert module.collect_spot_check_source_paths(
  507. repository={'path': 'repo'},
  508. config={'working_directory': '/'},
  509. local_borg_version=flexmock(),
  510. global_arguments=flexmock(),
  511. local_path=flexmock(),
  512. remote_path=flexmock(),
  513. borgmatic_runtime_directory='/run/borgmatic',
  514. bootstrap_config_paths=('extra.yaml',),
  515. ) == ('/etc/path', '/etc/other')
  516. def test_collect_spot_check_source_paths_omits_progress_from_create_dry_run_command():
  517. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  518. {'hook1': False, 'hook2': False},
  519. )
  520. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  521. flexmock(),
  522. )
  523. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  524. (Pattern('collected'),),
  525. )
  526. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return(
  527. [Pattern('foo'), Pattern('bar')],
  528. )
  529. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  530. dry_run=True,
  531. repository_path='repo',
  532. config={'working_directory': '/', 'list_details': True},
  533. patterns=[Pattern('foo'), Pattern('bar')],
  534. local_borg_version=object,
  535. global_arguments=object,
  536. borgmatic_runtime_directory='/run/borgmatic',
  537. local_path=object,
  538. remote_path=object,
  539. stream_processes=False,
  540. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  541. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  542. flexmock(),
  543. )
  544. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  545. flexmock(module.borgmatic.execute).should_receive(
  546. 'execute_command_and_capture_output',
  547. ).and_return(
  548. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  549. )
  550. flexmock(module.os.path).should_receive('isfile').and_return(True)
  551. assert module.collect_spot_check_source_paths(
  552. repository={'path': 'repo'},
  553. config={'working_directory': '/', 'progress': True},
  554. local_borg_version=flexmock(),
  555. global_arguments=flexmock(),
  556. local_path=flexmock(),
  557. remote_path=flexmock(),
  558. borgmatic_runtime_directory='/run/borgmatic',
  559. bootstrap_config_paths=(),
  560. ) == ('/etc/path', '/etc/other')
  561. def test_collect_spot_check_source_paths_passes_through_stream_processes_false():
  562. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  563. {'hook1': False, 'hook2': False},
  564. )
  565. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  566. flexmock(),
  567. )
  568. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  569. (Pattern('collected'),),
  570. )
  571. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return(
  572. [Pattern('foo'), Pattern('bar')],
  573. )
  574. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  575. dry_run=True,
  576. repository_path='repo',
  577. config=object,
  578. patterns=[Pattern('foo'), Pattern('bar')],
  579. local_borg_version=object,
  580. global_arguments=object,
  581. borgmatic_runtime_directory='/run/borgmatic',
  582. local_path=object,
  583. remote_path=object,
  584. stream_processes=False,
  585. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  586. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  587. flexmock(),
  588. )
  589. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  590. flexmock(module.borgmatic.execute).should_receive(
  591. 'execute_command_and_capture_output',
  592. ).and_return(
  593. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  594. )
  595. flexmock(module.os.path).should_receive('isfile').and_return(True)
  596. assert module.collect_spot_check_source_paths(
  597. repository={'path': 'repo'},
  598. config={'working_directory': '/'},
  599. local_borg_version=flexmock(),
  600. global_arguments=flexmock(),
  601. local_path=flexmock(),
  602. remote_path=flexmock(),
  603. borgmatic_runtime_directory='/run/borgmatic',
  604. bootstrap_config_paths=(),
  605. ) == ('/etc/path', '/etc/other')
  606. def test_collect_spot_check_source_paths_without_working_directory_parses_borg_output():
  607. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  608. {'hook1': False, 'hook2': True},
  609. )
  610. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  611. flexmock(),
  612. )
  613. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  614. (Pattern('collected'),),
  615. )
  616. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return(
  617. [Pattern('foo'), Pattern('bar')],
  618. )
  619. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  620. dry_run=True,
  621. repository_path='repo',
  622. config=object,
  623. patterns=[Pattern('foo'), Pattern('bar')],
  624. local_borg_version=object,
  625. global_arguments=object,
  626. borgmatic_runtime_directory='/run/borgmatic',
  627. local_path=object,
  628. remote_path=object,
  629. stream_processes=True,
  630. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  631. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  632. flexmock(),
  633. )
  634. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  635. flexmock(module.borgmatic.execute).should_receive(
  636. 'execute_command_and_capture_output',
  637. ).and_return(
  638. 'warning: stuff\n- /etc/path\n+ /etc/other\n? /nope',
  639. )
  640. flexmock(module.os.path).should_receive('isfile').and_return(True)
  641. assert module.collect_spot_check_source_paths(
  642. repository={'path': 'repo'},
  643. config={},
  644. local_borg_version=flexmock(),
  645. global_arguments=flexmock(),
  646. local_path=flexmock(),
  647. remote_path=flexmock(),
  648. borgmatic_runtime_directory='/run/borgmatic',
  649. bootstrap_config_paths=(),
  650. ) == ('/etc/path', '/etc/other')
  651. def test_collect_spot_check_source_paths_skips_directories():
  652. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  653. {'hook1': False, 'hook2': True},
  654. )
  655. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  656. flexmock(),
  657. )
  658. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  659. (Pattern('collected'),),
  660. )
  661. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return(
  662. [Pattern('foo'), Pattern('bar')],
  663. )
  664. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  665. dry_run=True,
  666. repository_path='repo',
  667. config=object,
  668. patterns=[Pattern('foo'), Pattern('bar')],
  669. local_borg_version=object,
  670. global_arguments=object,
  671. borgmatic_runtime_directory='/run/borgmatic',
  672. local_path=object,
  673. remote_path=object,
  674. stream_processes=True,
  675. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  676. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  677. flexmock(),
  678. )
  679. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  680. flexmock(module.borgmatic.execute).should_receive(
  681. 'execute_command_and_capture_output',
  682. ).and_return(
  683. 'warning: stuff\n- /etc/path\n+ /etc/dir\n? /nope',
  684. )
  685. flexmock(module.os.path).should_receive('isfile').with_args('/etc/path').and_return(False)
  686. flexmock(module.os.path).should_receive('isfile').with_args('/etc/dir').and_return(False)
  687. assert (
  688. module.collect_spot_check_source_paths(
  689. repository={'path': 'repo'},
  690. config={'working_directory': '/'},
  691. local_borg_version=flexmock(),
  692. global_arguments=flexmock(),
  693. local_path=flexmock(),
  694. remote_path=flexmock(),
  695. borgmatic_runtime_directory='/run/borgmatic',
  696. bootstrap_config_paths=(),
  697. )
  698. == ()
  699. )
  700. def test_collect_spot_check_archive_paths_excludes_directories_and_pipes():
  701. flexmock(module.borgmatic.config.paths).should_receive(
  702. 'get_borgmatic_source_directory',
  703. ).and_return('/home/user/.borgmatic')
  704. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  705. (
  706. 'f etc/path',
  707. 'p var/pipe',
  708. 'f etc/other',
  709. 'd etc/dir',
  710. ),
  711. )
  712. assert module.collect_spot_check_archive_paths(
  713. repository={'path': 'repo'},
  714. archive='archive',
  715. config={},
  716. local_borg_version=flexmock(),
  717. global_arguments=flexmock(),
  718. local_path=flexmock(),
  719. remote_path=flexmock(),
  720. borgmatic_runtime_directory='/run/user/1001/borgmatic',
  721. ) == ('etc/path', 'etc/other')
  722. def test_collect_spot_check_archive_paths_excludes_file_in_borgmatic_runtime_directory_as_stored_with_prefix_truncation():
  723. flexmock(module.borgmatic.config.paths).should_receive(
  724. 'get_borgmatic_source_directory',
  725. ).and_return('/root/.borgmatic')
  726. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  727. (
  728. 'f etc/path',
  729. 'f borgmatic/some/thing',
  730. ),
  731. )
  732. assert module.collect_spot_check_archive_paths(
  733. repository={'path': 'repo'},
  734. archive='archive',
  735. config={},
  736. local_borg_version=flexmock(),
  737. global_arguments=flexmock(),
  738. local_path=flexmock(),
  739. remote_path=flexmock(),
  740. borgmatic_runtime_directory='/run/user/0/borgmatic',
  741. ) == ('etc/path',)
  742. def test_collect_spot_check_archive_paths_excludes_file_in_borgmatic_source_directory():
  743. flexmock(module.borgmatic.config.paths).should_receive(
  744. 'get_borgmatic_source_directory',
  745. ).and_return('/root/.borgmatic')
  746. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  747. (
  748. 'f etc/path',
  749. 'f root/.borgmatic/some/thing',
  750. ),
  751. )
  752. assert module.collect_spot_check_archive_paths(
  753. repository={'path': 'repo'},
  754. archive='archive',
  755. config={},
  756. local_borg_version=flexmock(),
  757. global_arguments=flexmock(),
  758. local_path=flexmock(),
  759. remote_path=flexmock(),
  760. borgmatic_runtime_directory='/run/user/0/borgmatic',
  761. ) == ('etc/path',)
  762. def test_collect_spot_check_archive_paths_excludes_file_in_borgmatic_runtime_directory():
  763. flexmock(module.borgmatic.config.paths).should_receive(
  764. 'get_borgmatic_source_directory',
  765. ).and_return('/root.borgmatic')
  766. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  767. (
  768. 'f etc/path',
  769. 'f run/user/0/borgmatic/some/thing',
  770. ),
  771. )
  772. assert module.collect_spot_check_archive_paths(
  773. repository={'path': 'repo'},
  774. archive='archive',
  775. config={},
  776. local_borg_version=flexmock(),
  777. global_arguments=flexmock(),
  778. local_path=flexmock(),
  779. remote_path=flexmock(),
  780. borgmatic_runtime_directory='/run/user/0/borgmatic',
  781. ) == ('etc/path',)
  782. def test_collect_spot_check_source_paths_uses_working_directory():
  783. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').and_return(
  784. {'hook1': False, 'hook2': True},
  785. )
  786. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  787. flexmock(),
  788. )
  789. flexmock(module.borgmatic.actions.pattern).should_receive('collect_patterns').and_return(
  790. (Pattern('collected'),),
  791. )
  792. flexmock(module.borgmatic.actions.pattern).should_receive('process_patterns').and_return(
  793. [Pattern('foo'), Pattern('bar')],
  794. )
  795. flexmock(module.borgmatic.borg.create).should_receive('make_base_create_command').with_args(
  796. dry_run=True,
  797. repository_path='repo',
  798. config={'working_directory': '/working/dir', 'list_details': True},
  799. patterns=[Pattern('foo'), Pattern('bar')],
  800. local_borg_version=object,
  801. global_arguments=object,
  802. borgmatic_runtime_directory='/run/borgmatic',
  803. local_path=object,
  804. remote_path=object,
  805. stream_processes=True,
  806. ).and_return((('borg', 'create'), ('repo::archive',), flexmock()))
  807. flexmock(module.borgmatic.borg.environment).should_receive('make_environment').and_return(
  808. flexmock(),
  809. )
  810. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  811. '/working/dir',
  812. )
  813. flexmock(module.borgmatic.execute).should_receive(
  814. 'execute_command_and_capture_output',
  815. ).and_return(
  816. 'warning: stuff\n- foo\n+ bar\n? /nope',
  817. )
  818. flexmock(module.os.path).should_receive('isfile').with_args('/working/dir/foo').and_return(True)
  819. flexmock(module.os.path).should_receive('isfile').with_args('/working/dir/bar').and_return(True)
  820. assert module.collect_spot_check_source_paths(
  821. repository={'path': 'repo'},
  822. config={'working_directory': '/working/dir'},
  823. local_borg_version=flexmock(),
  824. global_arguments=flexmock(),
  825. local_path=flexmock(),
  826. remote_path=flexmock(),
  827. borgmatic_runtime_directory='/run/borgmatic',
  828. bootstrap_config_paths=(),
  829. ) == ('foo', 'bar')
  830. def test_compare_spot_check_hashes_returns_paths_having_failing_hashes():
  831. flexmock(module.random).should_receive('SystemRandom').and_return(
  832. flexmock(sample=lambda population, count: population[:count]),
  833. )
  834. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  835. None,
  836. )
  837. flexmock(module.os.path).should_receive('exists').and_return(True)
  838. flexmock(module.os.path).should_receive('islink').and_return(False)
  839. flexmock(module.borgmatic.execute).should_receive(
  840. 'execute_command_and_capture_output',
  841. ).with_args(('xxh64sum', '/foo', '/bar'), working_directory=None).and_return(
  842. 'hash1 /foo\nhash2 /bar',
  843. )
  844. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  845. ['hash1 foo', 'nothash2 bar'],
  846. )
  847. assert module.compare_spot_check_hashes(
  848. repository={'path': 'repo'},
  849. archive='archive',
  850. config={
  851. 'checks': [
  852. {
  853. 'name': 'archives',
  854. 'frequency': '2 weeks',
  855. },
  856. {
  857. 'name': 'spot',
  858. 'data_sample_percentage': 50,
  859. },
  860. ],
  861. },
  862. local_borg_version=flexmock(),
  863. global_arguments=flexmock(),
  864. local_path=flexmock(),
  865. remote_path=flexmock(),
  866. source_paths=('/foo', '/bar', '/baz', '/quux'),
  867. ) == ('/bar',)
  868. def test_compare_spot_check_hashes_returns_relative_paths_having_failing_hashes():
  869. flexmock(module.random).should_receive('SystemRandom').and_return(
  870. flexmock(sample=lambda population, count: population[:count]),
  871. )
  872. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  873. None,
  874. )
  875. flexmock(module.os.path).should_receive('exists').and_return(True)
  876. flexmock(module.os.path).should_receive('islink').and_return(False)
  877. flexmock(module.borgmatic.execute).should_receive(
  878. 'execute_command_and_capture_output',
  879. ).with_args(('xxh64sum', 'foo', 'bar'), working_directory=None).and_return(
  880. 'hash1 foo\nhash2 bar',
  881. )
  882. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  883. ['hash1 foo', 'nothash2 bar'],
  884. )
  885. assert module.compare_spot_check_hashes(
  886. repository={'path': 'repo'},
  887. archive='archive',
  888. config={
  889. 'checks': [
  890. {
  891. 'name': 'archives',
  892. 'frequency': '2 weeks',
  893. },
  894. {
  895. 'name': 'spot',
  896. 'data_sample_percentage': 50,
  897. },
  898. ],
  899. },
  900. local_borg_version=flexmock(),
  901. global_arguments=flexmock(),
  902. local_path=flexmock(),
  903. remote_path=flexmock(),
  904. source_paths=('foo', 'bar', 'baz', 'quux'),
  905. ) == ('bar',)
  906. def test_compare_spot_check_hashes_handles_data_sample_percentage_above_100():
  907. flexmock(module.random).should_receive('SystemRandom').and_return(
  908. flexmock(sample=lambda population, count: population[:count]),
  909. )
  910. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  911. None,
  912. )
  913. flexmock(module.os.path).should_receive('exists').and_return(True)
  914. flexmock(module.os.path).should_receive('islink').and_return(False)
  915. flexmock(module.borgmatic.execute).should_receive(
  916. 'execute_command_and_capture_output',
  917. ).with_args(('xxh64sum', '/foo', '/bar'), working_directory=None).and_return(
  918. 'hash1 /foo\nhash2 /bar',
  919. )
  920. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  921. ['nothash1 foo', 'nothash2 bar'],
  922. )
  923. assert module.compare_spot_check_hashes(
  924. repository={'path': 'repo'},
  925. archive='archive',
  926. config={
  927. 'checks': [
  928. {
  929. 'name': 'archives',
  930. 'frequency': '2 weeks',
  931. },
  932. {
  933. 'name': 'spot',
  934. 'data_sample_percentage': 1000,
  935. },
  936. ],
  937. },
  938. local_borg_version=flexmock(),
  939. global_arguments=flexmock(),
  940. local_path=flexmock(),
  941. remote_path=flexmock(),
  942. source_paths=('/foo', '/bar'),
  943. ) == ('/foo', '/bar')
  944. def test_compare_spot_check_hashes_uses_xxh64sum_command_option():
  945. flexmock(module.random).should_receive('SystemRandom').and_return(
  946. flexmock(sample=lambda population, count: population[:count]),
  947. )
  948. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  949. None,
  950. )
  951. flexmock(module.os.path).should_receive('exists').and_return(True)
  952. flexmock(module.os.path).should_receive('islink').and_return(False)
  953. flexmock(module.borgmatic.execute).should_receive(
  954. 'execute_command_and_capture_output',
  955. ).with_args(
  956. ('/usr/local/bin/xxhsum', '-H64', '/foo', '/bar'),
  957. working_directory=None,
  958. ).and_return('hash1 /foo\nhash2 /bar')
  959. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  960. ['hash1 foo', 'nothash2 bar'],
  961. )
  962. assert module.compare_spot_check_hashes(
  963. repository={'path': 'repo'},
  964. archive='archive',
  965. config={
  966. 'checks': [
  967. {
  968. 'name': 'spot',
  969. 'data_sample_percentage': 50,
  970. 'xxh64sum_command': '/usr/local/bin/xxhsum -H64',
  971. },
  972. ],
  973. },
  974. local_borg_version=flexmock(),
  975. global_arguments=flexmock(),
  976. local_path=flexmock(),
  977. remote_path=flexmock(),
  978. source_paths=('/foo', '/bar', '/baz', '/quux'),
  979. ) == ('/bar',)
  980. def test_compare_spot_check_hashes_considers_path_missing_from_archive_as_not_matching():
  981. flexmock(module.random).should_receive('SystemRandom').and_return(
  982. flexmock(sample=lambda population, count: population[:count]),
  983. )
  984. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  985. None,
  986. )
  987. flexmock(module.os.path).should_receive('exists').and_return(True)
  988. flexmock(module.os.path).should_receive('islink').and_return(False)
  989. flexmock(module.borgmatic.execute).should_receive(
  990. 'execute_command_and_capture_output',
  991. ).with_args(('xxh64sum', '/foo', '/bar'), working_directory=None).and_return(
  992. 'hash1 /foo\nhash2 /bar',
  993. )
  994. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  995. ['hash1 foo'],
  996. )
  997. assert module.compare_spot_check_hashes(
  998. repository={'path': 'repo'},
  999. archive='archive',
  1000. config={
  1001. 'checks': [
  1002. {
  1003. 'name': 'spot',
  1004. 'data_sample_percentage': 50,
  1005. },
  1006. ],
  1007. },
  1008. local_borg_version=flexmock(),
  1009. global_arguments=flexmock(),
  1010. local_path=flexmock(),
  1011. remote_path=flexmock(),
  1012. source_paths=('/foo', '/bar', '/baz', '/quux'),
  1013. ) == ('/bar',)
  1014. def test_compare_spot_check_hashes_considers_symlink_path_as_not_matching():
  1015. flexmock(module.random).should_receive('SystemRandom').and_return(
  1016. flexmock(sample=lambda population, count: population[:count]),
  1017. )
  1018. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1019. None,
  1020. )
  1021. flexmock(module.os.path).should_receive('exists').and_return(True)
  1022. flexmock(module.os.path).should_receive('islink').with_args('/foo').and_return(False)
  1023. flexmock(module.os.path).should_receive('islink').with_args('/bar').and_return(True)
  1024. flexmock(module.borgmatic.execute).should_receive(
  1025. 'execute_command_and_capture_output',
  1026. ).with_args(('xxh64sum', '/foo'), working_directory=None).and_return('hash1 /foo')
  1027. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  1028. ['hash1 foo', 'hash2 bar'],
  1029. )
  1030. assert module.compare_spot_check_hashes(
  1031. repository={'path': 'repo'},
  1032. archive='archive',
  1033. config={
  1034. 'checks': [
  1035. {
  1036. 'name': 'spot',
  1037. 'data_sample_percentage': 50,
  1038. },
  1039. ],
  1040. },
  1041. local_borg_version=flexmock(),
  1042. global_arguments=flexmock(),
  1043. local_path=flexmock(),
  1044. remote_path=flexmock(),
  1045. source_paths=('/foo', '/bar', '/baz', '/quux'),
  1046. ) == ('/bar',)
  1047. def test_compare_spot_check_hashes_considers_non_existent_path_as_not_matching():
  1048. flexmock(module.random).should_receive('SystemRandom').and_return(
  1049. flexmock(sample=lambda population, count: population[:count]),
  1050. )
  1051. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1052. None,
  1053. )
  1054. flexmock(module.os.path).should_receive('exists').with_args('/foo').and_return(True)
  1055. flexmock(module.os.path).should_receive('exists').with_args('/bar').and_return(False)
  1056. flexmock(module.os.path).should_receive('islink').and_return(False)
  1057. flexmock(module.borgmatic.execute).should_receive(
  1058. 'execute_command_and_capture_output',
  1059. ).with_args(('xxh64sum', '/foo'), working_directory=None).and_return('hash1 /foo')
  1060. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  1061. ['hash1 foo', 'hash2 bar'],
  1062. )
  1063. assert module.compare_spot_check_hashes(
  1064. repository={'path': 'repo'},
  1065. archive='archive',
  1066. config={
  1067. 'checks': [
  1068. {
  1069. 'name': 'spot',
  1070. 'data_sample_percentage': 50,
  1071. },
  1072. ],
  1073. },
  1074. local_borg_version=flexmock(),
  1075. global_arguments=flexmock(),
  1076. local_path=flexmock(),
  1077. remote_path=flexmock(),
  1078. source_paths=('/foo', '/bar', '/baz', '/quux'),
  1079. ) == ('/bar',)
  1080. def test_compare_spot_check_hashes_with_too_many_paths_feeds_them_to_commands_in_chunks():
  1081. flexmock(module).SAMPLE_PATHS_SUBSET_COUNT = 2
  1082. flexmock(module.random).should_receive('SystemRandom').and_return(
  1083. flexmock(sample=lambda population, count: population[:count]),
  1084. )
  1085. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1086. None,
  1087. )
  1088. flexmock(module.os.path).should_receive('exists').and_return(True)
  1089. flexmock(module.os.path).should_receive('islink').and_return(False)
  1090. flexmock(module.borgmatic.execute).should_receive(
  1091. 'execute_command_and_capture_output',
  1092. ).with_args(('xxh64sum', '/foo', '/bar'), working_directory=None).and_return(
  1093. 'hash1 /foo\nhash2 /bar',
  1094. )
  1095. flexmock(module.borgmatic.execute).should_receive(
  1096. 'execute_command_and_capture_output',
  1097. ).with_args(('xxh64sum', '/baz', '/quux'), working_directory=None).and_return(
  1098. 'hash3 /baz\nhash4 /quux',
  1099. )
  1100. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  1101. ['hash1 foo', 'hash2 bar'],
  1102. ).and_return(['hash3 baz', 'nothash4 quux'])
  1103. assert module.compare_spot_check_hashes(
  1104. repository={'path': 'repo'},
  1105. archive='archive',
  1106. config={
  1107. 'checks': [
  1108. {
  1109. 'name': 'archives',
  1110. 'frequency': '2 weeks',
  1111. },
  1112. {
  1113. 'name': 'spot',
  1114. 'data_sample_percentage': 100,
  1115. },
  1116. ],
  1117. },
  1118. local_borg_version=flexmock(),
  1119. global_arguments=flexmock(),
  1120. local_path=flexmock(),
  1121. remote_path=flexmock(),
  1122. source_paths=('/foo', '/bar', '/baz', '/quux'),
  1123. ) == ('/quux',)
  1124. def test_compare_spot_check_hashes_uses_working_directory_to_access_source_paths():
  1125. flexmock(module.random).should_receive('SystemRandom').and_return(
  1126. flexmock(sample=lambda population, count: population[:count]),
  1127. )
  1128. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1129. '/working/dir',
  1130. )
  1131. flexmock(module.os.path).should_receive('exists').with_args('/working/dir/foo').and_return(True)
  1132. flexmock(module.os.path).should_receive('exists').with_args('/working/dir/bar').and_return(True)
  1133. flexmock(module.os.path).should_receive('islink').and_return(False)
  1134. flexmock(module.borgmatic.execute).should_receive(
  1135. 'execute_command_and_capture_output',
  1136. ).with_args(('xxh64sum', 'foo', 'bar'), working_directory='/working/dir').and_return(
  1137. 'hash1 foo\nhash2 bar',
  1138. )
  1139. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  1140. ['hash1 foo', 'nothash2 bar'],
  1141. )
  1142. assert module.compare_spot_check_hashes(
  1143. repository={'path': 'repo'},
  1144. archive='archive',
  1145. config={
  1146. 'checks': [
  1147. {
  1148. 'name': 'archives',
  1149. 'frequency': '2 weeks',
  1150. },
  1151. {
  1152. 'name': 'spot',
  1153. 'data_sample_percentage': 50,
  1154. },
  1155. ],
  1156. 'working_directory': '/working/dir',
  1157. },
  1158. local_borg_version=flexmock(),
  1159. global_arguments=flexmock(),
  1160. local_path=flexmock(),
  1161. remote_path=flexmock(),
  1162. source_paths=('foo', 'bar', 'baz', 'quux'),
  1163. ) == ('bar',)
  1164. def test_spot_check_without_spot_configuration_errors():
  1165. with pytest.raises(ValueError):
  1166. module.spot_check(
  1167. repository={'path': 'repo'},
  1168. config={
  1169. 'checks': [
  1170. {
  1171. 'name': 'archives',
  1172. },
  1173. ],
  1174. },
  1175. local_borg_version=flexmock(),
  1176. global_arguments=flexmock(),
  1177. local_path=flexmock(),
  1178. remote_path=flexmock(),
  1179. borgmatic_runtime_directory='/run/borgmatic',
  1180. )
  1181. def test_spot_check_without_any_configuration_errors():
  1182. with pytest.raises(ValueError):
  1183. module.spot_check(
  1184. repository={'path': 'repo'},
  1185. config={},
  1186. local_borg_version=flexmock(),
  1187. global_arguments=flexmock(),
  1188. local_path=flexmock(),
  1189. remote_path=flexmock(),
  1190. borgmatic_runtime_directory='/run/borgmatic',
  1191. )
  1192. def test_spot_check_data_tolerance_percentage_greater_than_data_sample_percentage_errors():
  1193. with pytest.raises(ValueError):
  1194. module.spot_check(
  1195. repository={'path': 'repo'},
  1196. config={
  1197. 'checks': [
  1198. {
  1199. 'name': 'spot',
  1200. 'data_tolerance_percentage': 7,
  1201. 'data_sample_percentage': 5,
  1202. },
  1203. ],
  1204. },
  1205. local_borg_version=flexmock(),
  1206. global_arguments=flexmock(),
  1207. local_path=flexmock(),
  1208. remote_path=flexmock(),
  1209. borgmatic_runtime_directory='/run/borgmatic',
  1210. )
  1211. def test_spot_check_with_count_delta_greater_than_count_tolerance_percentage_errors():
  1212. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  1213. ('/foo', '/bar', '/baz', '/quux'),
  1214. )
  1215. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  1216. 'archive',
  1217. )
  1218. flexmock(module.borgmatic.actions.config.bootstrap).should_receive(
  1219. 'load_config_paths_from_archive'
  1220. ).and_return(('bootstrap.yaml',))
  1221. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(
  1222. ('/foo', '/bar'),
  1223. ).once()
  1224. with pytest.raises(ValueError):
  1225. module.spot_check(
  1226. repository={'path': 'repo'},
  1227. config={
  1228. 'checks': [
  1229. {
  1230. 'name': 'spot',
  1231. 'count_tolerance_percentage': 1,
  1232. 'data_tolerance_percentage': 4,
  1233. 'data_sample_percentage': 5,
  1234. },
  1235. ],
  1236. },
  1237. local_borg_version=flexmock(),
  1238. global_arguments=flexmock(),
  1239. local_path=flexmock(),
  1240. remote_path=flexmock(),
  1241. borgmatic_runtime_directory='/run/borgmatic',
  1242. )
  1243. def test_spot_check_with_failing_percentage_greater_than_data_tolerance_percentage_errors():
  1244. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  1245. ('/foo', '/bar', '/baz', '/quux'),
  1246. )
  1247. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  1248. 'archive',
  1249. )
  1250. flexmock(module.borgmatic.actions.config.bootstrap).should_receive(
  1251. 'load_config_paths_from_archive'
  1252. ).and_return(('bootstrap.yaml',))
  1253. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(('/foo', '/bar'))
  1254. flexmock(module).should_receive('compare_spot_check_hashes').and_return(
  1255. ('/bar', '/baz', '/quux'),
  1256. ).once()
  1257. with pytest.raises(ValueError):
  1258. module.spot_check(
  1259. repository={'path': 'repo'},
  1260. config={
  1261. 'checks': [
  1262. {
  1263. 'name': 'spot',
  1264. 'count_tolerance_percentage': 55,
  1265. 'data_tolerance_percentage': 4,
  1266. 'data_sample_percentage': 5,
  1267. },
  1268. ],
  1269. },
  1270. local_borg_version=flexmock(),
  1271. global_arguments=flexmock(),
  1272. local_path=flexmock(),
  1273. remote_path=flexmock(),
  1274. borgmatic_runtime_directory='/run/borgmatic',
  1275. )
  1276. def test_spot_check_with_high_enough_tolerances_does_not_raise():
  1277. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(
  1278. ('/foo', '/bar', '/baz', '/quux'),
  1279. )
  1280. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  1281. 'archive',
  1282. )
  1283. flexmock(module.borgmatic.actions.config.bootstrap).should_receive(
  1284. 'load_config_paths_from_archive'
  1285. ).and_return(('bootstrap.yaml',))
  1286. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(('/foo', '/bar'))
  1287. flexmock(module).should_receive('compare_spot_check_hashes').and_return(
  1288. ('/bar', '/baz', '/quux'),
  1289. ).once()
  1290. module.spot_check(
  1291. repository={'path': 'repo'},
  1292. config={
  1293. 'checks': [
  1294. {
  1295. 'name': 'spot',
  1296. 'count_tolerance_percentage': 55,
  1297. 'data_tolerance_percentage': 80,
  1298. 'data_sample_percentage': 80,
  1299. },
  1300. ],
  1301. },
  1302. local_borg_version=flexmock(),
  1303. global_arguments=flexmock(),
  1304. local_path=flexmock(),
  1305. remote_path=flexmock(),
  1306. borgmatic_runtime_directory='/run/borgmatic',
  1307. )
  1308. def test_spot_check_without_any_source_paths_errors():
  1309. flexmock(module).should_receive('collect_spot_check_source_paths').and_return(())
  1310. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  1311. 'archive',
  1312. )
  1313. flexmock(module.borgmatic.actions.config.bootstrap).should_receive(
  1314. 'load_config_paths_from_archive'
  1315. ).and_return(('bootstrap.yaml',))
  1316. flexmock(module).should_receive('collect_spot_check_archive_paths').and_return(('/foo', '/bar'))
  1317. flexmock(module).should_receive('compare_spot_check_hashes').never()
  1318. with pytest.raises(ValueError):
  1319. module.spot_check(
  1320. repository={'path': 'repo'},
  1321. config={
  1322. 'checks': [
  1323. {
  1324. 'name': 'spot',
  1325. 'count_tolerance_percentage': 10,
  1326. 'data_tolerance_percentage': 40,
  1327. 'data_sample_percentage': 50,
  1328. },
  1329. ],
  1330. },
  1331. local_borg_version=flexmock(),
  1332. global_arguments=flexmock(),
  1333. local_path=flexmock(),
  1334. remote_path=flexmock(),
  1335. borgmatic_runtime_directory='/run/borgmatic',
  1336. )
  1337. def test_run_check_checks_archives_for_configured_repository():
  1338. flexmock(module.logger).answer = lambda message: None
  1339. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  1340. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1341. flexmock(module).should_receive('upgrade_check_times')
  1342. flexmock(module).should_receive('parse_checks')
  1343. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1344. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1345. flexmock(module).should_receive('filter_checks_on_frequency').and_return(
  1346. {'repository', 'archives'},
  1347. )
  1348. flexmock(module.borgmatic.borg.check).should_receive('check_archives').once()
  1349. flexmock(module).should_receive('make_check_time_path')
  1350. flexmock(module).should_receive('write_check_time')
  1351. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  1352. check_arguments = flexmock(
  1353. repository=None,
  1354. progress=flexmock(),
  1355. repair=flexmock(),
  1356. only_checks=flexmock(),
  1357. force=flexmock(),
  1358. )
  1359. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1360. module.run_check(
  1361. config_filename='test.yaml',
  1362. repository={'path': 'repo'},
  1363. config={'repositories': ['repo']},
  1364. local_borg_version=None,
  1365. check_arguments=check_arguments,
  1366. global_arguments=global_arguments,
  1367. local_path=None,
  1368. remote_path=None,
  1369. )
  1370. def test_run_check_runs_configured_extract_check():
  1371. flexmock(module.logger).answer = lambda message: None
  1372. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  1373. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1374. flexmock(module).should_receive('upgrade_check_times')
  1375. flexmock(module).should_receive('parse_checks')
  1376. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1377. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1378. flexmock(module).should_receive('filter_checks_on_frequency').and_return({'extract'})
  1379. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  1380. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').once()
  1381. flexmock(module).should_receive('make_check_time_path')
  1382. flexmock(module).should_receive('write_check_time')
  1383. check_arguments = flexmock(
  1384. repository=None,
  1385. progress=flexmock(),
  1386. repair=flexmock(),
  1387. only_checks=flexmock(),
  1388. force=flexmock(),
  1389. )
  1390. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1391. module.run_check(
  1392. config_filename='test.yaml',
  1393. repository={'path': 'repo'},
  1394. config={'repositories': ['repo']},
  1395. local_borg_version=None,
  1396. check_arguments=check_arguments,
  1397. global_arguments=global_arguments,
  1398. local_path=None,
  1399. remote_path=None,
  1400. )
  1401. def test_run_check_runs_configured_spot_check():
  1402. flexmock(module.logger).answer = lambda message: None
  1403. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  1404. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1405. flexmock(module).should_receive('upgrade_check_times')
  1406. flexmock(module).should_receive('parse_checks')
  1407. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1408. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1409. flexmock(module).should_receive('filter_checks_on_frequency').and_return({'spot'})
  1410. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  1411. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  1412. flexmock(),
  1413. )
  1414. flexmock(module.borgmatic.actions.check).should_receive('spot_check').once()
  1415. flexmock(module).should_receive('make_check_time_path')
  1416. flexmock(module).should_receive('write_check_time')
  1417. check_arguments = flexmock(
  1418. repository=None,
  1419. progress=flexmock(),
  1420. repair=flexmock(),
  1421. only_checks=flexmock(),
  1422. force=flexmock(),
  1423. )
  1424. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1425. module.run_check(
  1426. config_filename='test.yaml',
  1427. repository={'path': 'repo'},
  1428. config={'repositories': ['repo']},
  1429. local_borg_version=None,
  1430. check_arguments=check_arguments,
  1431. global_arguments=global_arguments,
  1432. local_path=None,
  1433. remote_path=None,
  1434. )
  1435. def test_run_check_without_checks_runs_nothing_except_hooks():
  1436. flexmock(module.logger).answer = lambda message: None
  1437. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
  1438. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1439. flexmock(module).should_receive('upgrade_check_times')
  1440. flexmock(module).should_receive('parse_checks')
  1441. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1442. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1443. flexmock(module).should_receive('filter_checks_on_frequency').and_return({})
  1444. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  1445. flexmock(module).should_receive('make_check_time_path')
  1446. flexmock(module).should_receive('write_check_time').never()
  1447. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  1448. check_arguments = flexmock(
  1449. repository=None,
  1450. progress=flexmock(),
  1451. repair=flexmock(),
  1452. only_checks=flexmock(),
  1453. force=flexmock(),
  1454. )
  1455. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1456. module.run_check(
  1457. config_filename='test.yaml',
  1458. repository={'path': 'repo'},
  1459. config={'repositories': ['repo']},
  1460. local_borg_version=None,
  1461. check_arguments=check_arguments,
  1462. global_arguments=global_arguments,
  1463. local_path=None,
  1464. remote_path=None,
  1465. )
  1466. def test_run_check_checks_archives_in_selected_repository():
  1467. flexmock(module.logger).answer = lambda message: None
  1468. flexmock(module.borgmatic.config.validate).should_receive(
  1469. 'repositories_match',
  1470. ).once().and_return(True)
  1471. flexmock(module.borgmatic.borg.check).should_receive('get_repository_id').and_return(flexmock())
  1472. flexmock(module).should_receive('upgrade_check_times')
  1473. flexmock(module).should_receive('parse_checks')
  1474. flexmock(module.borgmatic.borg.check).should_receive('make_archive_filter_flags').and_return(())
  1475. flexmock(module).should_receive('make_archives_check_id').and_return(None)
  1476. flexmock(module).should_receive('filter_checks_on_frequency').and_return(
  1477. {'repository', 'archives'},
  1478. )
  1479. flexmock(module.borgmatic.borg.check).should_receive('check_archives').once()
  1480. flexmock(module).should_receive('make_check_time_path')
  1481. flexmock(module).should_receive('write_check_time')
  1482. flexmock(module.borgmatic.borg.extract).should_receive('extract_last_archive_dry_run').never()
  1483. check_arguments = flexmock(
  1484. repository=flexmock(),
  1485. progress=flexmock(),
  1486. repair=flexmock(),
  1487. only_checks=flexmock(),
  1488. force=flexmock(),
  1489. )
  1490. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1491. module.run_check(
  1492. config_filename='test.yaml',
  1493. repository={'path': 'repo'},
  1494. config={'repositories': ['repo']},
  1495. local_borg_version=None,
  1496. check_arguments=check_arguments,
  1497. global_arguments=global_arguments,
  1498. local_path=None,
  1499. remote_path=None,
  1500. )
  1501. def test_run_check_bails_if_repository_does_not_match():
  1502. flexmock(module.logger).answer = lambda message: None
  1503. flexmock(module.borgmatic.config.validate).should_receive(
  1504. 'repositories_match',
  1505. ).once().and_return(False)
  1506. flexmock(module.borgmatic.borg.check).should_receive('check_archives').never()
  1507. check_arguments = flexmock(
  1508. repository=flexmock(),
  1509. progress=flexmock(),
  1510. repair=flexmock(),
  1511. only_checks=flexmock(),
  1512. force=flexmock(),
  1513. )
  1514. global_arguments = flexmock(monitoring_verbosity=1, dry_run=False)
  1515. module.run_check(
  1516. config_filename='test.yaml',
  1517. repository={'path': 'repo'},
  1518. config={'repositories': ['repo']},
  1519. local_borg_version=None,
  1520. check_arguments=check_arguments,
  1521. global_arguments=global_arguments,
  1522. local_path=None,
  1523. remote_path=None,
  1524. )