test_create.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.borg import create as module
  5. from ..test_verbosity import insert_logging_mock
  6. def test_expand_directory_with_basic_path_passes_it_through():
  7. flexmock(module.os.path).should_receive('expanduser').and_return('foo')
  8. flexmock(module.glob).should_receive('glob').and_return([])
  9. paths = module._expand_directory('foo')
  10. assert paths == ['foo']
  11. def test_expand_directory_with_glob_expands():
  12. flexmock(module.os.path).should_receive('expanduser').and_return('foo*')
  13. flexmock(module.glob).should_receive('glob').and_return(['foo', 'food'])
  14. paths = module._expand_directory('foo*')
  15. assert paths == ['foo', 'food']
  16. def test_expand_directories_flattens_expanded_directories():
  17. flexmock(module).should_receive('_expand_directory').with_args('~/foo').and_return(
  18. ['/root/foo']
  19. )
  20. flexmock(module).should_receive('_expand_directory').with_args('bar*').and_return(
  21. ['bar', 'barf']
  22. )
  23. paths = module._expand_directories(('~/foo', 'bar*'))
  24. assert paths == ('/root/foo', 'bar', 'barf')
  25. def test_expand_directories_considers_none_as_no_directories():
  26. paths = module._expand_directories(None)
  27. assert paths == ()
  28. def test_expand_home_directories_expands_tildes():
  29. flexmock(module.os.path).should_receive('expanduser').with_args('~/bar').and_return('/foo/bar')
  30. flexmock(module.os.path).should_receive('expanduser').with_args('baz').and_return('baz')
  31. paths = module._expand_home_directories(('~/bar', 'baz'))
  32. assert paths == ('/foo/bar', 'baz')
  33. def test_expand_home_directories_considers_none_as_no_directories():
  34. paths = module._expand_home_directories(None)
  35. assert paths == ()
  36. def test_write_pattern_file_does_not_raise():
  37. temporary_file = flexmock(name='filename', write=lambda mode: None, flush=lambda: None)
  38. flexmock(module.tempfile).should_receive('NamedTemporaryFile').and_return(temporary_file)
  39. module._write_pattern_file(['exclude'])
  40. def test_write_pattern_file_with_empty_exclude_patterns_does_not_raise():
  41. module._write_pattern_file([])
  42. def test_make_pattern_flags_includes_pattern_filename_when_given():
  43. pattern_flags = module._make_pattern_flags(
  44. location_config={'patterns': ['R /', '- /var']}, pattern_filename='/tmp/patterns'
  45. )
  46. assert pattern_flags == ('--patterns-from', '/tmp/patterns')
  47. def test_make_pattern_flags_includes_patterns_from_filenames_when_in_config():
  48. pattern_flags = module._make_pattern_flags(
  49. location_config={'patterns_from': ['patterns', 'other']}
  50. )
  51. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', 'other')
  52. def test_make_pattern_flags_includes_both_filenames_when_patterns_given_and_patterns_from_in_config():
  53. pattern_flags = module._make_pattern_flags(
  54. location_config={'patterns_from': ['patterns']}, pattern_filename='/tmp/patterns'
  55. )
  56. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', '/tmp/patterns')
  57. def test_make_pattern_flags_considers_none_patterns_from_filenames_as_empty():
  58. pattern_flags = module._make_pattern_flags(location_config={'patterns_from': None})
  59. assert pattern_flags == ()
  60. def test_make_exclude_flags_includes_exclude_patterns_filename_when_given():
  61. exclude_flags = module._make_exclude_flags(
  62. location_config={'exclude_patterns': ['*.pyc', '/var']}, exclude_filename='/tmp/excludes'
  63. )
  64. assert exclude_flags == ('--exclude-from', '/tmp/excludes')
  65. def test_make_exclude_flags_includes_exclude_from_filenames_when_in_config():
  66. exclude_flags = module._make_exclude_flags(
  67. location_config={'exclude_from': ['excludes', 'other']}
  68. )
  69. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', 'other')
  70. def test_make_exclude_flags_includes_both_filenames_when_patterns_given_and_exclude_from_in_config():
  71. exclude_flags = module._make_exclude_flags(
  72. location_config={'exclude_from': ['excludes']}, exclude_filename='/tmp/excludes'
  73. )
  74. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', '/tmp/excludes')
  75. def test_make_exclude_flags_considers_none_exclude_from_filenames_as_empty():
  76. exclude_flags = module._make_exclude_flags(location_config={'exclude_from': None})
  77. assert exclude_flags == ()
  78. def test_make_exclude_flags_includes_exclude_caches_when_true_in_config():
  79. exclude_flags = module._make_exclude_flags(location_config={'exclude_caches': True})
  80. assert exclude_flags == ('--exclude-caches',)
  81. def test_make_exclude_flags_does_not_include_exclude_caches_when_false_in_config():
  82. exclude_flags = module._make_exclude_flags(location_config={'exclude_caches': False})
  83. assert exclude_flags == ()
  84. def test_make_exclude_flags_includes_exclude_if_present_when_in_config():
  85. exclude_flags = module._make_exclude_flags(
  86. location_config={'exclude_if_present': ['exclude_me', 'also_me']}
  87. )
  88. assert exclude_flags == (
  89. '--exclude-if-present',
  90. 'exclude_me',
  91. '--exclude-if-present',
  92. 'also_me',
  93. )
  94. def test_make_exclude_flags_includes_keep_exclude_tags_when_true_in_config():
  95. exclude_flags = module._make_exclude_flags(location_config={'keep_exclude_tags': True})
  96. assert exclude_flags == ('--keep-exclude-tags',)
  97. def test_make_exclude_flags_does_not_include_keep_exclude_tags_when_false_in_config():
  98. exclude_flags = module._make_exclude_flags(location_config={'keep_exclude_tags': False})
  99. assert exclude_flags == ()
  100. def test_make_exclude_flags_includes_exclude_nodump_when_true_in_config():
  101. exclude_flags = module._make_exclude_flags(location_config={'exclude_nodump': True})
  102. assert exclude_flags == ('--exclude-nodump',)
  103. def test_make_exclude_flags_does_not_include_exclude_nodump_when_false_in_config():
  104. exclude_flags = module._make_exclude_flags(location_config={'exclude_nodump': False})
  105. assert exclude_flags == ()
  106. def test_make_exclude_flags_is_empty_when_config_has_no_excludes():
  107. exclude_flags = module._make_exclude_flags(location_config={})
  108. assert exclude_flags == ()
  109. def test_borgmatic_source_directories_set_when_directory_exists():
  110. flexmock(module.os.path).should_receive('exists').and_return(True)
  111. flexmock(module.os.path).should_receive('expanduser')
  112. assert module.borgmatic_source_directories('/tmp') == ['/tmp']
  113. def test_borgmatic_source_directories_empty_when_directory_does_not_exist():
  114. flexmock(module.os.path).should_receive('exists').and_return(False)
  115. flexmock(module.os.path).should_receive('expanduser')
  116. assert module.borgmatic_source_directories('/tmp') == []
  117. def test_borgmatic_source_directories_defaults_when_directory_not_given():
  118. flexmock(module.os.path).should_receive('exists').and_return(True)
  119. flexmock(module.os.path).should_receive('expanduser')
  120. assert module.borgmatic_source_directories(None) == [module.DEFAULT_BORGMATIC_SOURCE_DIRECTORY]
  121. DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
  122. ARCHIVE_WITH_PATHS = ('repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'bar')
  123. def test_create_archive_calls_borg_with_parameters():
  124. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  125. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  126. flexmock(module).should_receive('_expand_home_directories').and_return(())
  127. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  128. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  129. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  130. flexmock(module).should_receive('execute_command').with_args(
  131. ('borg', 'create') + ARCHIVE_WITH_PATHS,
  132. output_log_level=logging.INFO,
  133. output_file=None,
  134. error_on_warnings=False,
  135. )
  136. module.create_archive(
  137. dry_run=False,
  138. repository='repo',
  139. location_config={
  140. 'source_directories': ['foo', 'bar'],
  141. 'repositories': ['repo'],
  142. 'exclude_patterns': None,
  143. },
  144. storage_config={},
  145. )
  146. def test_create_archive_with_patterns_calls_borg_with_patterns():
  147. pattern_flags = ('--patterns-from', 'patterns')
  148. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  149. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  150. flexmock(module).should_receive('_expand_home_directories').and_return(())
  151. flexmock(module).should_receive('_write_pattern_file').and_return(
  152. flexmock(name='/tmp/patterns')
  153. ).and_return(None)
  154. flexmock(module).should_receive('_make_pattern_flags').and_return(pattern_flags)
  155. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  156. flexmock(module).should_receive('execute_command').with_args(
  157. ('borg', 'create') + pattern_flags + ARCHIVE_WITH_PATHS,
  158. output_log_level=logging.INFO,
  159. output_file=None,
  160. error_on_warnings=False,
  161. )
  162. module.create_archive(
  163. dry_run=False,
  164. repository='repo',
  165. location_config={
  166. 'source_directories': ['foo', 'bar'],
  167. 'repositories': ['repo'],
  168. 'patterns': ['pattern'],
  169. },
  170. storage_config={},
  171. )
  172. def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
  173. exclude_flags = ('--exclude-from', 'excludes')
  174. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  175. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  176. flexmock(module).should_receive('_expand_home_directories').and_return(('exclude',))
  177. flexmock(module).should_receive('_write_pattern_file').and_return(None).and_return(
  178. flexmock(name='/tmp/excludes')
  179. )
  180. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  181. flexmock(module).should_receive('_make_exclude_flags').and_return(exclude_flags)
  182. flexmock(module).should_receive('execute_command').with_args(
  183. ('borg', 'create') + exclude_flags + ARCHIVE_WITH_PATHS,
  184. output_log_level=logging.INFO,
  185. output_file=None,
  186. error_on_warnings=False,
  187. )
  188. module.create_archive(
  189. dry_run=False,
  190. repository='repo',
  191. location_config={
  192. 'source_directories': ['foo', 'bar'],
  193. 'repositories': ['repo'],
  194. 'exclude_patterns': ['exclude'],
  195. },
  196. storage_config={},
  197. )
  198. def test_create_archive_with_log_info_calls_borg_with_info_parameter():
  199. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  200. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  201. flexmock(module).should_receive('_expand_home_directories').and_return(())
  202. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  203. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  204. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  205. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  206. flexmock(module).should_receive('execute_command').with_args(
  207. ('borg', 'create', '--info') + ARCHIVE_WITH_PATHS,
  208. output_log_level=logging.INFO,
  209. output_file=None,
  210. error_on_warnings=False,
  211. )
  212. insert_logging_mock(logging.INFO)
  213. module.create_archive(
  214. dry_run=False,
  215. repository='repo',
  216. location_config={
  217. 'source_directories': ['foo', 'bar'],
  218. 'repositories': ['repo'],
  219. 'exclude_patterns': None,
  220. },
  221. storage_config={},
  222. )
  223. def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
  224. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  225. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  226. flexmock(module).should_receive('_expand_home_directories').and_return(())
  227. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  228. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  229. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  230. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  231. flexmock(module).should_receive('execute_command').with_args(
  232. ('borg', 'create', '--json') + ARCHIVE_WITH_PATHS,
  233. output_log_level=None,
  234. output_file=None,
  235. error_on_warnings=False,
  236. )
  237. insert_logging_mock(logging.INFO)
  238. module.create_archive(
  239. dry_run=False,
  240. repository='repo',
  241. location_config={
  242. 'source_directories': ['foo', 'bar'],
  243. 'repositories': ['repo'],
  244. 'exclude_patterns': None,
  245. },
  246. storage_config={},
  247. json=True,
  248. )
  249. def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
  250. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  251. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  252. flexmock(module).should_receive('_expand_home_directories').and_return(())
  253. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  254. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  255. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  256. flexmock(module).should_receive('execute_command').with_args(
  257. ('borg', 'create', '--debug', '--show-rc') + ARCHIVE_WITH_PATHS,
  258. output_log_level=logging.INFO,
  259. output_file=None,
  260. error_on_warnings=False,
  261. )
  262. insert_logging_mock(logging.DEBUG)
  263. module.create_archive(
  264. dry_run=False,
  265. repository='repo',
  266. location_config={
  267. 'source_directories': ['foo', 'bar'],
  268. 'repositories': ['repo'],
  269. 'exclude_patterns': None,
  270. },
  271. storage_config={},
  272. )
  273. def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
  274. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  275. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  276. flexmock(module).should_receive('_expand_home_directories').and_return(())
  277. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  278. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  279. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  280. flexmock(module).should_receive('execute_command').with_args(
  281. ('borg', 'create', '--json') + ARCHIVE_WITH_PATHS,
  282. output_log_level=None,
  283. output_file=None,
  284. error_on_warnings=False,
  285. )
  286. insert_logging_mock(logging.DEBUG)
  287. module.create_archive(
  288. dry_run=False,
  289. repository='repo',
  290. location_config={
  291. 'source_directories': ['foo', 'bar'],
  292. 'repositories': ['repo'],
  293. 'exclude_patterns': None,
  294. },
  295. storage_config={},
  296. json=True,
  297. )
  298. def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
  299. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  300. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  301. flexmock(module).should_receive('_expand_home_directories').and_return(())
  302. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  303. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  304. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  305. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  306. flexmock(module).should_receive('execute_command').with_args(
  307. ('borg', 'create', '--dry-run') + ARCHIVE_WITH_PATHS,
  308. output_log_level=logging.INFO,
  309. output_file=None,
  310. error_on_warnings=False,
  311. )
  312. module.create_archive(
  313. dry_run=True,
  314. repository='repo',
  315. location_config={
  316. 'source_directories': ['foo', 'bar'],
  317. 'repositories': ['repo'],
  318. 'exclude_patterns': None,
  319. },
  320. storage_config={},
  321. )
  322. def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_parameter():
  323. # --dry-run and --stats are mutually exclusive, see:
  324. # https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
  325. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  326. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  327. flexmock(module).should_receive('_expand_home_directories').and_return(())
  328. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  329. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  330. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  331. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  332. flexmock(module).should_receive('execute_command').with_args(
  333. ('borg', 'create', '--info', '--dry-run') + ARCHIVE_WITH_PATHS,
  334. output_log_level=logging.INFO,
  335. output_file=None,
  336. error_on_warnings=False,
  337. )
  338. insert_logging_mock(logging.INFO)
  339. module.create_archive(
  340. dry_run=True,
  341. repository='repo',
  342. location_config={
  343. 'source_directories': ['foo', 'bar'],
  344. 'repositories': ['repo'],
  345. 'exclude_patterns': None,
  346. },
  347. storage_config={},
  348. stats=True,
  349. )
  350. def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
  351. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  352. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  353. flexmock(module).should_receive('_expand_home_directories').and_return(())
  354. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  355. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  356. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  357. flexmock(module).should_receive('execute_command').with_args(
  358. ('borg', 'create', '--checkpoint-interval', '600') + ARCHIVE_WITH_PATHS,
  359. output_log_level=logging.INFO,
  360. output_file=None,
  361. error_on_warnings=False,
  362. )
  363. module.create_archive(
  364. dry_run=False,
  365. repository='repo',
  366. location_config={
  367. 'source_directories': ['foo', 'bar'],
  368. 'repositories': ['repo'],
  369. 'exclude_patterns': None,
  370. },
  371. storage_config={'checkpoint_interval': 600},
  372. )
  373. def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_parameters():
  374. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  375. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  376. flexmock(module).should_receive('_expand_home_directories').and_return(())
  377. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  378. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  379. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  380. flexmock(module).should_receive('execute_command').with_args(
  381. ('borg', 'create', '--chunker-params', '1,2,3,4') + ARCHIVE_WITH_PATHS,
  382. output_log_level=logging.INFO,
  383. output_file=None,
  384. error_on_warnings=False,
  385. )
  386. module.create_archive(
  387. dry_run=False,
  388. repository='repo',
  389. location_config={
  390. 'source_directories': ['foo', 'bar'],
  391. 'repositories': ['repo'],
  392. 'exclude_patterns': None,
  393. },
  394. storage_config={'chunker_params': '1,2,3,4'},
  395. )
  396. def test_create_archive_with_compression_calls_borg_with_compression_parameters():
  397. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  398. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  399. flexmock(module).should_receive('_expand_home_directories').and_return(())
  400. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  401. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  402. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  403. flexmock(module).should_receive('execute_command').with_args(
  404. ('borg', 'create', '--compression', 'rle') + ARCHIVE_WITH_PATHS,
  405. output_log_level=logging.INFO,
  406. output_file=None,
  407. error_on_warnings=False,
  408. )
  409. module.create_archive(
  410. dry_run=False,
  411. repository='repo',
  412. location_config={
  413. 'source_directories': ['foo', 'bar'],
  414. 'repositories': ['repo'],
  415. 'exclude_patterns': None,
  416. },
  417. storage_config={'compression': 'rle'},
  418. )
  419. def test_create_archive_with_remote_rate_limit_calls_borg_with_remote_ratelimit_parameters():
  420. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  421. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  422. flexmock(module).should_receive('_expand_home_directories').and_return(())
  423. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  424. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  425. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  426. flexmock(module).should_receive('execute_command').with_args(
  427. ('borg', 'create', '--remote-ratelimit', '100') + ARCHIVE_WITH_PATHS,
  428. output_log_level=logging.INFO,
  429. output_file=None,
  430. error_on_warnings=False,
  431. )
  432. module.create_archive(
  433. dry_run=False,
  434. repository='repo',
  435. location_config={
  436. 'source_directories': ['foo', 'bar'],
  437. 'repositories': ['repo'],
  438. 'exclude_patterns': None,
  439. },
  440. storage_config={'remote_rate_limit': 100},
  441. )
  442. def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_parameter():
  443. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  444. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  445. flexmock(module).should_receive('_expand_home_directories').and_return(())
  446. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  447. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  448. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  449. flexmock(module).should_receive('execute_command').with_args(
  450. ('borg', 'create', '--one-file-system') + ARCHIVE_WITH_PATHS,
  451. output_log_level=logging.INFO,
  452. output_file=None,
  453. error_on_warnings=False,
  454. )
  455. module.create_archive(
  456. dry_run=False,
  457. repository='repo',
  458. location_config={
  459. 'source_directories': ['foo', 'bar'],
  460. 'repositories': ['repo'],
  461. 'one_file_system': True,
  462. 'exclude_patterns': None,
  463. },
  464. storage_config={},
  465. )
  466. def test_create_archive_with_numeric_owner_calls_borg_with_numeric_owner_parameter():
  467. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  468. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  469. flexmock(module).should_receive('_expand_home_directories').and_return(())
  470. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  471. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  472. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  473. flexmock(module).should_receive('execute_command').with_args(
  474. ('borg', 'create', '--numeric-owner') + ARCHIVE_WITH_PATHS,
  475. output_log_level=logging.INFO,
  476. output_file=None,
  477. error_on_warnings=False,
  478. )
  479. module.create_archive(
  480. dry_run=False,
  481. repository='repo',
  482. location_config={
  483. 'source_directories': ['foo', 'bar'],
  484. 'repositories': ['repo'],
  485. 'numeric_owner': True,
  486. 'exclude_patterns': None,
  487. },
  488. storage_config={},
  489. )
  490. def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
  491. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  492. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  493. flexmock(module).should_receive('_expand_home_directories').and_return(())
  494. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  495. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  496. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  497. flexmock(module).should_receive('execute_command').with_args(
  498. ('borg', 'create', '--read-special') + ARCHIVE_WITH_PATHS,
  499. output_log_level=logging.INFO,
  500. output_file=None,
  501. error_on_warnings=False,
  502. )
  503. module.create_archive(
  504. dry_run=False,
  505. repository='repo',
  506. location_config={
  507. 'source_directories': ['foo', 'bar'],
  508. 'repositories': ['repo'],
  509. 'read_special': True,
  510. 'exclude_patterns': None,
  511. },
  512. storage_config={},
  513. )
  514. @pytest.mark.parametrize('option_name', ('atime', 'ctime', 'birthtime', 'bsd_flags'))
  515. def test_create_archive_with_option_true_calls_borg_without_corresponding_parameter(option_name):
  516. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  517. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  518. flexmock(module).should_receive('_expand_home_directories').and_return(())
  519. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  520. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  521. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  522. flexmock(module).should_receive('execute_command').with_args(
  523. ('borg', 'create') + ARCHIVE_WITH_PATHS,
  524. output_log_level=logging.INFO,
  525. output_file=None,
  526. error_on_warnings=False,
  527. )
  528. module.create_archive(
  529. dry_run=False,
  530. repository='repo',
  531. location_config={
  532. 'source_directories': ['foo', 'bar'],
  533. 'repositories': ['repo'],
  534. option_name: True,
  535. 'exclude_patterns': None,
  536. },
  537. storage_config={},
  538. )
  539. @pytest.mark.parametrize('option_name', ('atime', 'ctime', 'birthtime', 'bsd_flags'))
  540. def test_create_archive_with_option_false_calls_borg_with_corresponding_parameter(option_name):
  541. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  542. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  543. flexmock(module).should_receive('_expand_home_directories').and_return(())
  544. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  545. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  546. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  547. flexmock(module).should_receive('execute_command').with_args(
  548. ('borg', 'create', '--no' + option_name.replace('_', '')) + ARCHIVE_WITH_PATHS,
  549. output_log_level=logging.INFO,
  550. output_file=None,
  551. error_on_warnings=False,
  552. )
  553. module.create_archive(
  554. dry_run=False,
  555. repository='repo',
  556. location_config={
  557. 'source_directories': ['foo', 'bar'],
  558. 'repositories': ['repo'],
  559. option_name: False,
  560. 'exclude_patterns': None,
  561. },
  562. storage_config={},
  563. )
  564. def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
  565. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  566. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  567. flexmock(module).should_receive('_expand_home_directories').and_return(())
  568. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  569. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  570. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  571. flexmock(module).should_receive('execute_command').with_args(
  572. ('borg', 'create', '--files-cache', 'ctime,size') + ARCHIVE_WITH_PATHS,
  573. output_log_level=logging.INFO,
  574. output_file=None,
  575. error_on_warnings=False,
  576. )
  577. module.create_archive(
  578. dry_run=False,
  579. repository='repo',
  580. location_config={
  581. 'source_directories': ['foo', 'bar'],
  582. 'repositories': ['repo'],
  583. 'files_cache': 'ctime,size',
  584. 'exclude_patterns': None,
  585. },
  586. storage_config={},
  587. )
  588. def test_create_archive_with_local_path_calls_borg_via_local_path():
  589. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  590. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  591. flexmock(module).should_receive('_expand_home_directories').and_return(())
  592. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  593. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  594. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  595. flexmock(module).should_receive('execute_command').with_args(
  596. ('borg1', 'create') + ARCHIVE_WITH_PATHS,
  597. output_log_level=logging.INFO,
  598. output_file=None,
  599. error_on_warnings=False,
  600. )
  601. module.create_archive(
  602. dry_run=False,
  603. repository='repo',
  604. location_config={
  605. 'source_directories': ['foo', 'bar'],
  606. 'repositories': ['repo'],
  607. 'exclude_patterns': None,
  608. },
  609. storage_config={},
  610. local_path='borg1',
  611. )
  612. def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters():
  613. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  614. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  615. flexmock(module).should_receive('_expand_home_directories').and_return(())
  616. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  617. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  618. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  619. flexmock(module).should_receive('execute_command').with_args(
  620. ('borg', 'create', '--remote-path', 'borg1') + ARCHIVE_WITH_PATHS,
  621. output_log_level=logging.INFO,
  622. output_file=None,
  623. error_on_warnings=False,
  624. )
  625. module.create_archive(
  626. dry_run=False,
  627. repository='repo',
  628. location_config={
  629. 'source_directories': ['foo', 'bar'],
  630. 'repositories': ['repo'],
  631. 'exclude_patterns': None,
  632. },
  633. storage_config={},
  634. remote_path='borg1',
  635. )
  636. def test_create_archive_with_umask_calls_borg_with_umask_parameters():
  637. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  638. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  639. flexmock(module).should_receive('_expand_home_directories').and_return(())
  640. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  641. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  642. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  643. flexmock(module).should_receive('execute_command').with_args(
  644. ('borg', 'create', '--umask', '740') + ARCHIVE_WITH_PATHS,
  645. output_log_level=logging.INFO,
  646. output_file=None,
  647. error_on_warnings=False,
  648. )
  649. module.create_archive(
  650. dry_run=False,
  651. repository='repo',
  652. location_config={
  653. 'source_directories': ['foo', 'bar'],
  654. 'repositories': ['repo'],
  655. 'exclude_patterns': None,
  656. },
  657. storage_config={'umask': 740},
  658. )
  659. def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
  660. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  661. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  662. flexmock(module).should_receive('_expand_home_directories').and_return(())
  663. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  664. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  665. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  666. flexmock(module).should_receive('execute_command').with_args(
  667. ('borg', 'create', '--lock-wait', '5') + ARCHIVE_WITH_PATHS,
  668. output_log_level=logging.INFO,
  669. output_file=None,
  670. error_on_warnings=False,
  671. )
  672. module.create_archive(
  673. dry_run=False,
  674. repository='repo',
  675. location_config={
  676. 'source_directories': ['foo', 'bar'],
  677. 'repositories': ['repo'],
  678. 'exclude_patterns': None,
  679. },
  680. storage_config={'lock_wait': 5},
  681. )
  682. def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
  683. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  684. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  685. flexmock(module).should_receive('_expand_home_directories').and_return(())
  686. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  687. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  688. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  689. flexmock(module).should_receive('execute_command').with_args(
  690. ('borg', 'create', '--stats') + ARCHIVE_WITH_PATHS,
  691. output_log_level=logging.WARNING,
  692. output_file=None,
  693. error_on_warnings=False,
  694. )
  695. module.create_archive(
  696. dry_run=False,
  697. repository='repo',
  698. location_config={
  699. 'source_directories': ['foo', 'bar'],
  700. 'repositories': ['repo'],
  701. 'exclude_patterns': None,
  702. },
  703. storage_config={},
  704. stats=True,
  705. )
  706. def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
  707. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  708. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  709. flexmock(module).should_receive('_expand_home_directories').and_return(())
  710. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  711. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  712. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  713. flexmock(module).should_receive('execute_command').with_args(
  714. ('borg', 'create', '--info', '--stats') + ARCHIVE_WITH_PATHS,
  715. output_log_level=logging.INFO,
  716. output_file=None,
  717. error_on_warnings=False,
  718. )
  719. insert_logging_mock(logging.INFO)
  720. module.create_archive(
  721. dry_run=False,
  722. repository='repo',
  723. location_config={
  724. 'source_directories': ['foo', 'bar'],
  725. 'repositories': ['repo'],
  726. 'exclude_patterns': None,
  727. },
  728. storage_config={},
  729. stats=True,
  730. )
  731. def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
  732. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  733. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  734. flexmock(module).should_receive('_expand_home_directories').and_return(())
  735. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  736. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  737. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  738. flexmock(module).should_receive('execute_command').with_args(
  739. ('borg', 'create', '--list', '--filter', 'AME-') + ARCHIVE_WITH_PATHS,
  740. output_log_level=logging.WARNING,
  741. output_file=None,
  742. error_on_warnings=False,
  743. )
  744. module.create_archive(
  745. dry_run=False,
  746. repository='repo',
  747. location_config={
  748. 'source_directories': ['foo', 'bar'],
  749. 'repositories': ['repo'],
  750. 'exclude_patterns': None,
  751. },
  752. storage_config={},
  753. files=True,
  754. )
  755. def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
  756. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  757. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  758. flexmock(module).should_receive('_expand_home_directories').and_return(())
  759. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  760. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  761. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  762. flexmock(module).should_receive('execute_command').with_args(
  763. ('borg', 'create', '--list', '--filter', 'AME-', '--info') + ARCHIVE_WITH_PATHS,
  764. output_log_level=logging.INFO,
  765. output_file=None,
  766. error_on_warnings=False,
  767. )
  768. insert_logging_mock(logging.INFO)
  769. module.create_archive(
  770. dry_run=False,
  771. repository='repo',
  772. location_config={
  773. 'source_directories': ['foo', 'bar'],
  774. 'repositories': ['repo'],
  775. 'exclude_patterns': None,
  776. },
  777. storage_config={},
  778. files=True,
  779. )
  780. def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_parameter_and_no_list():
  781. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  782. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  783. flexmock(module).should_receive('_expand_home_directories').and_return(())
  784. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  785. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  786. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  787. flexmock(module).should_receive('execute_command').with_args(
  788. ('borg', 'create', '--info', '--progress') + ARCHIVE_WITH_PATHS,
  789. output_log_level=logging.INFO,
  790. output_file=module.DO_NOT_CAPTURE,
  791. error_on_warnings=False,
  792. )
  793. insert_logging_mock(logging.INFO)
  794. module.create_archive(
  795. dry_run=False,
  796. repository='repo',
  797. location_config={
  798. 'source_directories': ['foo', 'bar'],
  799. 'repositories': ['repo'],
  800. 'exclude_patterns': None,
  801. },
  802. storage_config={},
  803. progress=True,
  804. )
  805. def test_create_archive_with_progress_calls_borg_with_progress_parameter():
  806. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  807. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  808. flexmock(module).should_receive('_expand_home_directories').and_return(())
  809. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  810. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  811. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  812. flexmock(module).should_receive('execute_command').with_args(
  813. ('borg', 'create', '--progress') + ARCHIVE_WITH_PATHS,
  814. output_log_level=logging.INFO,
  815. output_file=module.DO_NOT_CAPTURE,
  816. error_on_warnings=False,
  817. )
  818. module.create_archive(
  819. dry_run=False,
  820. repository='repo',
  821. location_config={
  822. 'source_directories': ['foo', 'bar'],
  823. 'repositories': ['repo'],
  824. 'exclude_patterns': None,
  825. },
  826. storage_config={},
  827. progress=True,
  828. )
  829. def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progress_parameter():
  830. processes = flexmock()
  831. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  832. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  833. flexmock(module).should_receive('_expand_home_directories').and_return(())
  834. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  835. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  836. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  837. flexmock(module).should_receive('execute_command_with_processes').with_args(
  838. ('borg', 'create', '--read-special', '--progress') + ARCHIVE_WITH_PATHS,
  839. processes=processes,
  840. output_log_level=logging.INFO,
  841. output_file=module.DO_NOT_CAPTURE,
  842. error_on_warnings=False,
  843. )
  844. module.create_archive(
  845. dry_run=False,
  846. repository='repo',
  847. location_config={
  848. 'source_directories': ['foo', 'bar'],
  849. 'repositories': ['repo'],
  850. 'exclude_patterns': None,
  851. },
  852. storage_config={},
  853. progress=True,
  854. stream_processes=processes,
  855. )
  856. def test_create_archive_with_json_calls_borg_with_json_parameter():
  857. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  858. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  859. flexmock(module).should_receive('_expand_home_directories').and_return(())
  860. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  861. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  862. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  863. flexmock(module).should_receive('execute_command').with_args(
  864. ('borg', 'create', '--json') + ARCHIVE_WITH_PATHS,
  865. output_log_level=None,
  866. output_file=None,
  867. error_on_warnings=False,
  868. ).and_return('[]')
  869. json_output = module.create_archive(
  870. dry_run=False,
  871. repository='repo',
  872. location_config={
  873. 'source_directories': ['foo', 'bar'],
  874. 'repositories': ['repo'],
  875. 'exclude_patterns': None,
  876. },
  877. storage_config={},
  878. json=True,
  879. )
  880. assert json_output == '[]'
  881. def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter():
  882. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  883. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  884. flexmock(module).should_receive('_expand_home_directories').and_return(())
  885. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  886. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  887. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  888. flexmock(module).should_receive('execute_command').with_args(
  889. ('borg', 'create', '--json') + ARCHIVE_WITH_PATHS,
  890. output_log_level=None,
  891. output_file=None,
  892. error_on_warnings=False,
  893. ).and_return('[]')
  894. json_output = module.create_archive(
  895. dry_run=False,
  896. repository='repo',
  897. location_config={
  898. 'source_directories': ['foo', 'bar'],
  899. 'repositories': ['repo'],
  900. 'exclude_patterns': None,
  901. },
  902. storage_config={},
  903. json=True,
  904. stats=True,
  905. )
  906. assert json_output == '[]'
  907. def test_create_archive_with_source_directories_glob_expands():
  908. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  909. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food'))
  910. flexmock(module).should_receive('_expand_home_directories').and_return(())
  911. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  912. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  913. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  914. flexmock(module).should_receive('execute_command').with_args(
  915. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  916. output_log_level=logging.INFO,
  917. output_file=None,
  918. error_on_warnings=False,
  919. )
  920. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return(['foo', 'food'])
  921. module.create_archive(
  922. dry_run=False,
  923. repository='repo',
  924. location_config={
  925. 'source_directories': ['foo*'],
  926. 'repositories': ['repo'],
  927. 'exclude_patterns': None,
  928. },
  929. storage_config={},
  930. )
  931. def test_create_archive_with_non_matching_source_directories_glob_passes_through():
  932. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  933. flexmock(module).should_receive('_expand_directories').and_return(('foo*',))
  934. flexmock(module).should_receive('_expand_home_directories').and_return(())
  935. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  936. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  937. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  938. flexmock(module).should_receive('execute_command').with_args(
  939. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo*'),
  940. output_log_level=logging.INFO,
  941. output_file=None,
  942. error_on_warnings=False,
  943. )
  944. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return([])
  945. module.create_archive(
  946. dry_run=False,
  947. repository='repo',
  948. location_config={
  949. 'source_directories': ['foo*'],
  950. 'repositories': ['repo'],
  951. 'exclude_patterns': None,
  952. },
  953. storage_config={},
  954. )
  955. def test_create_archive_with_glob_calls_borg_with_expanded_directories():
  956. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  957. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food'))
  958. flexmock(module).should_receive('_expand_home_directories').and_return(())
  959. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  960. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  961. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  962. flexmock(module).should_receive('execute_command').with_args(
  963. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  964. output_log_level=logging.INFO,
  965. output_file=None,
  966. error_on_warnings=False,
  967. )
  968. module.create_archive(
  969. dry_run=False,
  970. repository='repo',
  971. location_config={
  972. 'source_directories': ['foo*'],
  973. 'repositories': ['repo'],
  974. 'exclude_patterns': None,
  975. },
  976. storage_config={},
  977. )
  978. def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
  979. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  980. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  981. flexmock(module).should_receive('_expand_home_directories').and_return(())
  982. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  983. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  984. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  985. flexmock(module).should_receive('execute_command').with_args(
  986. ('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar'),
  987. output_log_level=logging.INFO,
  988. output_file=None,
  989. error_on_warnings=False,
  990. )
  991. module.create_archive(
  992. dry_run=False,
  993. repository='repo',
  994. location_config={
  995. 'source_directories': ['foo', 'bar'],
  996. 'repositories': ['repo'],
  997. 'exclude_patterns': None,
  998. },
  999. storage_config={'archive_name_format': 'ARCHIVE_NAME'},
  1000. )
  1001. def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
  1002. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1003. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  1004. flexmock(module).should_receive('_expand_home_directories').and_return(())
  1005. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  1006. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  1007. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  1008. flexmock(module).should_receive('execute_command').with_args(
  1009. ('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar'),
  1010. output_log_level=logging.INFO,
  1011. output_file=None,
  1012. error_on_warnings=False,
  1013. )
  1014. module.create_archive(
  1015. dry_run=False,
  1016. repository='repo',
  1017. location_config={
  1018. 'source_directories': ['foo', 'bar'],
  1019. 'repositories': ['repo'],
  1020. 'exclude_patterns': None,
  1021. },
  1022. storage_config={'archive_name_format': 'Documents_{hostname}-{now}'},
  1023. )
  1024. def test_create_archive_with_extra_borg_options_calls_borg_with_extra_options():
  1025. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1026. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  1027. flexmock(module).should_receive('_expand_home_directories').and_return(())
  1028. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  1029. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  1030. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  1031. flexmock(module).should_receive('execute_command').with_args(
  1032. ('borg', 'create', '--extra', '--options') + ARCHIVE_WITH_PATHS,
  1033. output_log_level=logging.INFO,
  1034. output_file=None,
  1035. error_on_warnings=False,
  1036. )
  1037. module.create_archive(
  1038. dry_run=False,
  1039. repository='repo',
  1040. location_config={
  1041. 'source_directories': ['foo', 'bar'],
  1042. 'repositories': ['repo'],
  1043. 'exclude_patterns': None,
  1044. },
  1045. storage_config={'extra_borg_options': {'create': '--extra --options'}},
  1046. )
  1047. def test_create_archive_with_stream_processes_calls_borg_with_processes():
  1048. processes = flexmock()
  1049. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1050. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  1051. flexmock(module).should_receive('_expand_home_directories').and_return(())
  1052. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  1053. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  1054. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  1055. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1056. ('borg', 'create', '--read-special') + ARCHIVE_WITH_PATHS,
  1057. processes=processes,
  1058. output_log_level=logging.INFO,
  1059. output_file=None,
  1060. error_on_warnings=False,
  1061. )
  1062. module.create_archive(
  1063. dry_run=False,
  1064. repository='repo',
  1065. location_config={
  1066. 'source_directories': ['foo', 'bar'],
  1067. 'repositories': ['repo'],
  1068. 'exclude_patterns': None,
  1069. },
  1070. storage_config={},
  1071. stream_processes=processes,
  1072. )