test_create.py 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.borg import create as module
  5. from borgmatic.borg.pattern import Pattern, Pattern_source, Pattern_style, Pattern_type
  6. from ..test_verbosity import insert_logging_mock
  7. @pytest.mark.parametrize(
  8. 'character_device,block_device,fifo,expected_result',
  9. (
  10. (False, False, False, False),
  11. (True, False, False, True),
  12. (False, True, False, True),
  13. (True, True, False, True),
  14. (False, False, True, True),
  15. (False, True, True, True),
  16. (True, False, True, True),
  17. ),
  18. )
  19. def test_special_file_looks_at_file_type(character_device, block_device, fifo, expected_result):
  20. flexmock(module.os).should_receive('stat').and_return(flexmock(st_mode=flexmock()))
  21. flexmock(module.stat).should_receive('S_ISCHR').and_return(character_device)
  22. flexmock(module.stat).should_receive('S_ISBLK').and_return(block_device)
  23. flexmock(module.stat).should_receive('S_ISFIFO').and_return(fifo)
  24. assert module.special_file('/dev/special') == expected_result
  25. def test_special_file_treats_broken_symlink_as_non_special():
  26. flexmock(module.os).should_receive('stat').and_raise(FileNotFoundError)
  27. assert module.special_file('/broken/symlink') is False
  28. def test_special_file_prepends_relative_path_with_working_directory():
  29. flexmock(module.os).should_receive('stat').with_args('/working/dir/relative').and_return(
  30. flexmock(st_mode=flexmock()),
  31. )
  32. flexmock(module.stat).should_receive('S_ISCHR').and_return(False)
  33. flexmock(module.stat).should_receive('S_ISBLK').and_return(False)
  34. flexmock(module.stat).should_receive('S_ISFIFO').and_return(False)
  35. assert module.special_file('relative', '/working/dir') is False
  36. def test_any_parent_directories_treats_parents_as_match():
  37. module.any_parent_directories('/foo/bar.txt', ('/foo', '/etc'))
  38. def test_any_parent_directories_treats_grandparents_as_match():
  39. module.any_parent_directories('/foo/bar/baz.txt', ('/foo', '/etc'))
  40. def test_any_parent_directories_treats_unrelated_paths_as_non_match():
  41. module.any_parent_directories('/foo/bar.txt', ('/usr', '/etc'))
  42. def test_validate_planned_backup_paths_parses_borg_dry_run_file_list():
  43. flexmock(module.flags).should_receive('omit_flag').replace_with(
  44. lambda arguments, flag: arguments,
  45. )
  46. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  47. lambda arguments, flag: arguments,
  48. )
  49. flexmock(module.environment).should_receive('make_environment').and_return(None)
  50. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  51. 'Processing files ...\n- /foo\n+ /bar\n- /baz',
  52. )
  53. flexmock(module.os.path).should_receive('exists').and_return(False)
  54. flexmock(module).should_receive('any_parent_directories').and_return(False)
  55. assert module.validate_planned_backup_paths(
  56. dry_run=False,
  57. create_command=('borg', 'create'),
  58. config={},
  59. patterns=(
  60. module.borgmatic.borg.pattern.Pattern('/foo'),
  61. module.borgmatic.borg.pattern.Pattern('/bar'),
  62. module.borgmatic.borg.pattern.Pattern('/baz'),
  63. ),
  64. local_path=None,
  65. working_directory=None,
  66. borgmatic_runtime_directory='/run/borgmatic',
  67. ) == ('/foo', '/bar', '/baz')
  68. def test_validate_planned_backup_paths_skips_borgmatic_runtime_directory():
  69. flexmock(module.flags).should_receive('omit_flag').replace_with(
  70. lambda arguments, flag: arguments,
  71. )
  72. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  73. lambda arguments, flag: arguments,
  74. )
  75. flexmock(module.environment).should_receive('make_environment').and_return(None)
  76. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  77. '+ /foo\n- /run/borgmatic/bar\n- /baz',
  78. )
  79. flexmock(module.os.path).should_receive('exists').and_return(True)
  80. flexmock(module).should_receive('any_parent_directories').replace_with(
  81. lambda path, candidates: any(path.startswith(parent) for parent in candidates)
  82. )
  83. assert module.validate_planned_backup_paths(
  84. dry_run=False,
  85. create_command=('borg', 'create'),
  86. config={},
  87. patterns=(
  88. module.borgmatic.borg.pattern.Pattern('/foo'),
  89. module.borgmatic.borg.pattern.Pattern(
  90. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.ROOT
  91. ),
  92. module.borgmatic.borg.pattern.Pattern('/baz'),
  93. ),
  94. local_path=None,
  95. working_directory=None,
  96. borgmatic_runtime_directory='/run/borgmatic',
  97. ) == ('/foo', '/baz')
  98. def test_validate_planned_backup_paths_with_borgmatic_runtime_directory_missing_from_paths_output_warns():
  99. flexmock(module.flags).should_receive('omit_flag').replace_with(
  100. lambda arguments, flag: arguments,
  101. )
  102. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  103. lambda arguments, flag: arguments,
  104. )
  105. flexmock(module.environment).should_receive('make_environment').and_return(None)
  106. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  107. '+ /foo\n- /bar\n- /baz',
  108. )
  109. flexmock(module.os.path).should_receive('exists').and_return(True)
  110. flexmock(module).should_receive('any_parent_directories').replace_with(
  111. lambda path, candidates: any(path.startswith(parent) for parent in candidates)
  112. )
  113. flexmock(module.logger).should_receive('warning').once()
  114. assert module.validate_planned_backup_paths(
  115. dry_run=False,
  116. create_command=('borg', 'create'),
  117. config={},
  118. patterns=(
  119. module.borgmatic.borg.pattern.Pattern('/foo'),
  120. module.borgmatic.borg.pattern.Pattern(
  121. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.ROOT
  122. ),
  123. module.borgmatic.borg.pattern.Pattern('/baz'),
  124. ),
  125. local_path=None,
  126. working_directory=None,
  127. borgmatic_runtime_directory='/run/borgmatic',
  128. ) == ('/foo', '/bar', '/baz')
  129. def test_validate_planned_backup_paths_with_borgmatic_runtime_directory_partially_excluded_from_paths_output_does_not_warn():
  130. flexmock(module.flags).should_receive('omit_flag').replace_with(
  131. lambda arguments, flag: arguments,
  132. )
  133. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  134. lambda arguments, flag: arguments,
  135. )
  136. flexmock(module.environment).should_receive('make_environment').and_return(None)
  137. # /run/borgmatic/bar is present, but /run/borgmatic/quux is missing.
  138. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  139. '+ /foo\n- /run/borgmatic/bar\n- /baz',
  140. )
  141. flexmock(module.os.path).should_receive('exists').and_return(True)
  142. flexmock(module).should_receive('any_parent_directories').replace_with(
  143. lambda path, candidates: any(path.startswith(parent) for parent in candidates)
  144. )
  145. flexmock(module.logger).should_receive('warning').never()
  146. assert module.validate_planned_backup_paths(
  147. dry_run=False,
  148. create_command=('borg', 'create'),
  149. config={},
  150. patterns=(
  151. module.borgmatic.borg.pattern.Pattern('/foo'),
  152. module.borgmatic.borg.pattern.Pattern(
  153. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.ROOT
  154. ),
  155. module.borgmatic.borg.pattern.Pattern('/baz'),
  156. module.borgmatic.borg.pattern.Pattern(
  157. '/run/borgmatic/quux', module.borgmatic.borg.pattern.Pattern_type.ROOT
  158. ),
  159. ),
  160. local_path=None,
  161. working_directory=None,
  162. borgmatic_runtime_directory='/run/borgmatic',
  163. ) == ('/foo', '/baz')
  164. def test_validate_planned_backup_paths_with_borgmatic_runtime_directory_with_corresponding_include_and_missing_from_paths_output_does_not_warn():
  165. flexmock(module.flags).should_receive('omit_flag').replace_with(
  166. lambda arguments, flag: arguments,
  167. )
  168. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  169. lambda arguments, flag: arguments,
  170. )
  171. flexmock(module.environment).should_receive('make_environment').and_return(None)
  172. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  173. '+ /foo\n- /bar\n- /baz',
  174. )
  175. flexmock(module.os.path).should_receive('exists').and_return(True)
  176. flexmock(module).should_receive('any_parent_directories').replace_with(
  177. lambda path, candidates: any(path.startswith(parent) for parent in candidates)
  178. )
  179. flexmock(module.logger).should_receive('warning').never()
  180. assert module.validate_planned_backup_paths(
  181. dry_run=False,
  182. create_command=('borg', 'create'),
  183. config={},
  184. patterns=(
  185. module.borgmatic.borg.pattern.Pattern('/foo'),
  186. module.borgmatic.borg.pattern.Pattern(
  187. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.ROOT
  188. ),
  189. module.borgmatic.borg.pattern.Pattern(
  190. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.INCLUDE
  191. ),
  192. module.borgmatic.borg.pattern.Pattern('/baz'),
  193. ),
  194. local_path=None,
  195. working_directory=None,
  196. borgmatic_runtime_directory='/run/borgmatic',
  197. ) == ('/foo', '/bar', '/baz')
  198. def test_validate_planned_backup_paths_with_borgmatic_runtime_directory_missing_from_patterns_does_not_raise():
  199. flexmock(module.flags).should_receive('omit_flag').replace_with(
  200. lambda arguments, flag: arguments,
  201. )
  202. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  203. lambda arguments, flag: arguments,
  204. )
  205. flexmock(module.environment).should_receive('make_environment').and_return(None)
  206. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  207. '+ /foo\n- /run/borgmatic/bar\n- /baz',
  208. )
  209. flexmock(module.os.path).should_receive('exists').and_return(True)
  210. flexmock(module).should_receive('any_parent_directories').replace_with(
  211. lambda path, candidates: any(path.startswith(parent) for parent in candidates)
  212. )
  213. assert module.validate_planned_backup_paths(
  214. dry_run=False,
  215. create_command=('borg', 'create'),
  216. config={},
  217. patterns=(
  218. module.borgmatic.borg.pattern.Pattern('/foo'),
  219. module.borgmatic.borg.pattern.Pattern('/baz'),
  220. ),
  221. local_path=None,
  222. working_directory=None,
  223. borgmatic_runtime_directory='/run/borgmatic',
  224. ) == ('/foo', '/baz')
  225. def test_validate_planned_backup_paths_with_dry_run_and_borgmatic_runtime_directory_missing_from_paths_output_does_not_raise():
  226. flexmock(module.flags).should_receive('omit_flag').replace_with(
  227. lambda arguments, flag: arguments,
  228. )
  229. flexmock(module.flags).should_receive('omit_flag_and_value').replace_with(
  230. lambda arguments, flag: arguments,
  231. )
  232. flexmock(module.environment).should_receive('make_environment').and_return(None)
  233. flexmock(module).should_receive('execute_command_and_capture_output').and_return(
  234. '+ /foo\n- /run/borgmatic/bar\n- /baz',
  235. )
  236. flexmock(module.os.path).should_receive('exists').and_return(True)
  237. flexmock(module).should_receive('any_parent_directories').and_return(False)
  238. assert module.validate_planned_backup_paths(
  239. dry_run=True,
  240. create_command=('borg', 'create'),
  241. config={},
  242. patterns=(
  243. module.borgmatic.borg.pattern.Pattern('/foo'),
  244. module.borgmatic.borg.pattern.Pattern(
  245. '/run/borgmatic/bar', module.borgmatic.borg.pattern.Pattern_type.ROOT
  246. ),
  247. module.borgmatic.borg.pattern.Pattern('/baz'),
  248. ),
  249. local_path=None,
  250. working_directory=None,
  251. borgmatic_runtime_directory='/run/borgmatic',
  252. ) == ('/foo', '/run/borgmatic/bar', '/baz')
  253. DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
  254. REPO_ARCHIVE = (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  255. def test_make_base_create_produces_borg_command():
  256. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  257. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  258. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  259. flexmock(module.feature).should_receive('available').and_return(True)
  260. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  261. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  262. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  263. )
  264. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  265. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  266. dry_run=False,
  267. repository_path='repo',
  268. config={
  269. 'source_directories': ['foo', 'bar'],
  270. 'repositories': ['repo'],
  271. },
  272. patterns=[Pattern('foo'), Pattern('bar')],
  273. local_borg_version='1.2.3',
  274. global_arguments=flexmock(),
  275. borgmatic_runtime_directory='/run/borgmatic',
  276. )
  277. assert create_flags == ('borg', 'create')
  278. assert create_positional_arguments == REPO_ARCHIVE
  279. assert not pattern_file
  280. def test_make_base_create_command_includes_patterns_file_in_borg_command():
  281. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  282. mock_pattern_file = flexmock(name='/tmp/patterns')
  283. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(
  284. mock_pattern_file,
  285. ).and_return(None)
  286. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  287. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  288. '{hostname}',
  289. )
  290. flexmock(module.feature).should_receive('available').and_return(True)
  291. pattern_flags = ('--patterns-from', mock_pattern_file.name)
  292. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  293. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  294. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  295. )
  296. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  297. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  298. dry_run=False,
  299. repository_path='repo',
  300. config={
  301. 'source_directories': ['foo', 'bar'],
  302. 'repositories': ['repo'],
  303. 'patterns': ['pattern'],
  304. },
  305. patterns=[Pattern('foo'), Pattern('bar')],
  306. local_borg_version='1.2.3',
  307. global_arguments=flexmock(),
  308. borgmatic_runtime_directory='/run/borgmatic',
  309. )
  310. assert create_flags == ('borg', 'create', *pattern_flags)
  311. assert create_positional_arguments == (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  312. assert pattern_file == mock_pattern_file
  313. def test_make_base_create_command_with_store_config_false_omits_config_files():
  314. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  315. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  316. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  317. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  318. '{hostname}',
  319. )
  320. flexmock(module.feature).should_receive('available').and_return(True)
  321. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  322. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  323. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  324. )
  325. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  326. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  327. dry_run=False,
  328. repository_path='repo',
  329. config={
  330. 'source_directories': ['foo', 'bar'],
  331. 'repositories': ['repo'],
  332. 'store_config_files': False,
  333. },
  334. patterns=[Pattern('foo'), Pattern('bar')],
  335. local_borg_version='1.2.3',
  336. global_arguments=flexmock(),
  337. borgmatic_runtime_directory='/run/borgmatic',
  338. )
  339. assert create_flags == ('borg', 'create')
  340. assert create_positional_arguments == REPO_ARCHIVE
  341. assert not pattern_file
  342. @pytest.mark.parametrize(
  343. 'option_name,option_value,feature_available,option_flags',
  344. (
  345. ('checkpoint_interval', 600, True, ('--checkpoint-interval', '600')),
  346. ('checkpoint_volume', 1024, True, ('--checkpoint-volume', '1024')),
  347. ('chunker_params', '1,2,3,4', True, ('--chunker-params', '1,2,3,4')),
  348. ('compression', 'rle', True, ('--compression', 'rle')),
  349. ('one_file_system', True, True, ('--one-file-system',)),
  350. ('upload_rate_limit', 100, True, ('--upload-ratelimit', '100')),
  351. ('upload_rate_limit', 100, False, ('--remote-ratelimit', '100')),
  352. ('upload_buffer_size', 160, True, ('--upload-buffer', '160')),
  353. ('numeric_ids', True, True, ('--numeric-ids',)),
  354. ('numeric_ids', True, False, ('--numeric-owner',)),
  355. ('read_special', True, True, ('--read-special',)),
  356. ('ctime', True, True, ()),
  357. ('ctime', False, True, ('--noctime',)),
  358. ('birthtime', True, True, ()),
  359. ('birthtime', False, True, ('--nobirthtime',)),
  360. ('atime', True, True, ('--atime',)),
  361. ('atime', True, False, ()),
  362. ('atime', False, True, ()),
  363. ('atime', False, False, ('--noatime',)),
  364. ('flags', True, True, ()),
  365. ('flags', True, False, ()),
  366. ('flags', False, True, ('--noflags',)),
  367. ('flags', False, False, ('--nobsdflags',)),
  368. ('files_cache', 'ctime,size', True, ('--files-cache', 'ctime,size')),
  369. ('umask', 740, True, ('--umask', '740')),
  370. ('lock_wait', 5, True, ('--lock-wait', '5')),
  371. ),
  372. )
  373. def test_make_base_create_command_includes_configuration_option_as_command_flag(
  374. option_name,
  375. option_value,
  376. feature_available,
  377. option_flags,
  378. ):
  379. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  380. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  381. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  382. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  383. '{hostname}',
  384. )
  385. flexmock(module.feature).should_receive('available').and_return(feature_available)
  386. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  387. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  388. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  389. )
  390. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  391. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  392. dry_run=False,
  393. repository_path='repo',
  394. config={
  395. 'source_directories': ['foo', 'bar'],
  396. 'repositories': ['repo'],
  397. option_name: option_value,
  398. },
  399. patterns=[Pattern('foo'), Pattern('bar')],
  400. local_borg_version='1.2.3',
  401. global_arguments=flexmock(),
  402. borgmatic_runtime_directory='/run/borgmatic',
  403. )
  404. assert create_flags == ('borg', 'create', *option_flags)
  405. assert create_positional_arguments == REPO_ARCHIVE
  406. assert not pattern_file
  407. def test_make_base_create_command_includes_dry_run_in_borg_command():
  408. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  409. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  410. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  411. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  412. '{hostname}',
  413. )
  414. flexmock(module.feature).should_receive('available').and_return(True)
  415. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  416. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  417. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  418. )
  419. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  420. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  421. dry_run=True,
  422. repository_path='repo',
  423. config={
  424. 'source_directories': ['foo', 'bar'],
  425. 'repositories': ['repo'],
  426. 'exclude_patterns': ['exclude'],
  427. },
  428. patterns=[Pattern('foo'), Pattern('bar')],
  429. local_borg_version='1.2.3',
  430. global_arguments=flexmock(),
  431. borgmatic_runtime_directory='/run/borgmatic',
  432. )
  433. assert create_flags == ('borg', 'create', '--dry-run')
  434. assert create_positional_arguments == REPO_ARCHIVE
  435. assert not pattern_file
  436. def test_make_base_create_command_includes_comment_in_borg_command():
  437. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  438. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  439. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  440. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  441. '{hostname}',
  442. )
  443. flexmock(module.feature).should_receive('available').and_return(True)
  444. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  445. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  446. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  447. )
  448. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  449. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  450. dry_run=False,
  451. repository_path='repo',
  452. config={
  453. 'source_directories': ['foo', 'bar'],
  454. 'repositories': ['repo'],
  455. 'exclude_patterns': ['exclude'],
  456. },
  457. patterns=[Pattern('foo'), Pattern('bar')],
  458. local_borg_version='1.2.3',
  459. global_arguments=flexmock(),
  460. borgmatic_runtime_directory='/run/borgmatic',
  461. comment='a comment',
  462. )
  463. assert create_flags == ('borg', 'create', '--comment', 'a comment')
  464. assert create_positional_arguments == REPO_ARCHIVE
  465. assert not pattern_file
  466. def test_make_base_create_command_includes_local_path_in_borg_command():
  467. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  468. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  469. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  470. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  471. '{hostname}',
  472. )
  473. flexmock(module.feature).should_receive('available').and_return(True)
  474. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  475. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  476. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  477. )
  478. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  479. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  480. dry_run=False,
  481. repository_path='repo',
  482. config={
  483. 'source_directories': ['foo', 'bar'],
  484. 'repositories': ['repo'],
  485. },
  486. patterns=[Pattern('foo'), Pattern('bar')],
  487. local_borg_version='1.2.3',
  488. global_arguments=flexmock(),
  489. borgmatic_runtime_directory='/run/borgmatic',
  490. local_path='borg1',
  491. )
  492. assert create_flags == ('borg1', 'create')
  493. assert create_positional_arguments == REPO_ARCHIVE
  494. assert not pattern_file
  495. def test_make_base_create_command_includes_remote_path_in_borg_command():
  496. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  497. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  498. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  499. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  500. '{hostname}',
  501. )
  502. flexmock(module.feature).should_receive('available').and_return(True)
  503. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  504. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  505. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  506. )
  507. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  508. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  509. dry_run=False,
  510. repository_path='repo',
  511. config={
  512. 'source_directories': ['foo', 'bar'],
  513. 'repositories': ['repo'],
  514. },
  515. patterns=[Pattern('foo'), Pattern('bar')],
  516. local_borg_version='1.2.3',
  517. global_arguments=flexmock(),
  518. borgmatic_runtime_directory='/run/borgmatic',
  519. remote_path='borg1',
  520. )
  521. assert create_flags == ('borg', 'create', '--remote-path', 'borg1')
  522. assert create_positional_arguments == REPO_ARCHIVE
  523. assert not pattern_file
  524. def test_make_base_create_command_includes_log_json_in_borg_command():
  525. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  526. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  527. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  528. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  529. '{hostname}',
  530. )
  531. flexmock(module.feature).should_receive('available').and_return(True)
  532. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  533. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  534. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  535. )
  536. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  537. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  538. dry_run=False,
  539. repository_path='repo',
  540. config={
  541. 'source_directories': ['foo', 'bar'],
  542. 'repositories': ['repo'],
  543. 'log_json': True,
  544. },
  545. patterns=[Pattern('foo'), Pattern('bar')],
  546. local_borg_version='1.2.3',
  547. global_arguments=flexmock(),
  548. borgmatic_runtime_directory='/run/borgmatic',
  549. )
  550. assert create_flags == ('borg', 'create', '--log-json')
  551. assert create_positional_arguments == REPO_ARCHIVE
  552. assert not pattern_file
  553. def test_make_base_create_command_includes_list_flags_in_borg_command():
  554. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  555. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  556. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  557. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  558. '{hostname}',
  559. )
  560. flexmock(module.feature).should_receive('available').and_return(True)
  561. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  562. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  563. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  564. )
  565. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  566. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  567. dry_run=False,
  568. repository_path='repo',
  569. config={
  570. 'source_directories': ['foo', 'bar'],
  571. 'repositories': ['repo'],
  572. 'list_details': True,
  573. },
  574. patterns=[Pattern('foo'), Pattern('bar')],
  575. local_borg_version='1.2.3',
  576. global_arguments=flexmock(),
  577. borgmatic_runtime_directory='/run/borgmatic',
  578. )
  579. assert create_flags == ('borg', 'create', '--list', '--filter', 'FOO')
  580. assert create_positional_arguments == REPO_ARCHIVE
  581. assert not pattern_file
  582. def test_make_base_create_command_with_stream_processes_ignores_read_special_false_and_excludes_special_files():
  583. patterns = [Pattern('foo'), Pattern('bar')]
  584. patterns_file = flexmock(name='patterns')
  585. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  586. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').with_args(
  587. patterns,
  588. '/run/borgmatic',
  589. ).and_return(patterns_file)
  590. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  591. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  592. '{hostname}',
  593. )
  594. flexmock(module.feature).should_receive('available').and_return(True)
  595. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  596. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  597. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  598. )
  599. flexmock(module.logger).should_receive('warning').twice()
  600. flexmock(module.environment).should_receive('make_environment')
  601. flexmock(module).should_receive('validate_planned_backup_paths').and_return(
  602. (
  603. '/non/special',
  604. '/dev/null',
  605. )
  606. )
  607. flexmock(module).should_receive('special_file').with_args(
  608. '/non/special', working_directory=None
  609. ).and_return(False)
  610. flexmock(module).should_receive('special_file').with_args(
  611. '/dev/null', working_directory=None
  612. ).and_return(True)
  613. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').with_args(
  614. (
  615. Pattern(
  616. '/dev/null',
  617. Pattern_type.NO_RECURSE,
  618. Pattern_style.FNMATCH,
  619. source=Pattern_source.INTERNAL,
  620. ),
  621. ),
  622. '/run/borgmatic',
  623. patterns_file=patterns_file,
  624. ).and_return(patterns_file).once()
  625. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  626. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  627. dry_run=False,
  628. repository_path='repo',
  629. config={
  630. 'source_directories': ['foo', 'bar'],
  631. 'repositories': ['repo'],
  632. 'read_special': False,
  633. },
  634. patterns=patterns,
  635. local_borg_version='1.2.3',
  636. global_arguments=flexmock(),
  637. borgmatic_runtime_directory='/run/borgmatic',
  638. stream_processes=flexmock(),
  639. )
  640. assert create_flags == ('borg', 'create', '--patterns-from', 'patterns', '--read-special')
  641. assert create_positional_arguments == REPO_ARCHIVE
  642. assert pattern_file
  643. def test_make_base_create_command_without_patterns_and_with_stream_processes_ignores_read_special_false_and_excludes_special_files():
  644. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  645. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').with_args(
  646. [],
  647. '/run/borgmatic',
  648. ).and_return(None)
  649. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  650. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  651. '{hostname}',
  652. )
  653. flexmock(module.feature).should_receive('available').and_return(True)
  654. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  655. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  656. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  657. )
  658. flexmock(module.logger).should_receive('warning').twice()
  659. flexmock(module.environment).should_receive('make_environment')
  660. flexmock(module).should_receive('validate_planned_backup_paths').and_return(
  661. (
  662. '/non/special',
  663. '/dev/null',
  664. )
  665. )
  666. flexmock(module).should_receive('special_file').with_args(
  667. '/non/special', working_directory=None
  668. ).and_return(False)
  669. flexmock(module).should_receive('special_file').with_args(
  670. '/dev/null', working_directory=None
  671. ).and_return(True)
  672. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').with_args(
  673. (
  674. Pattern(
  675. '/dev/null',
  676. Pattern_type.NO_RECURSE,
  677. Pattern_style.FNMATCH,
  678. source=Pattern_source.INTERNAL,
  679. ),
  680. ),
  681. '/run/borgmatic',
  682. patterns_file=None,
  683. ).and_return(flexmock(name='patterns')).once()
  684. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  685. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  686. dry_run=False,
  687. repository_path='repo',
  688. config={
  689. 'source_directories': [],
  690. 'repositories': ['repo'],
  691. 'read_special': False,
  692. },
  693. patterns=[],
  694. local_borg_version='1.2.3',
  695. global_arguments=flexmock(),
  696. borgmatic_runtime_directory='/run/borgmatic',
  697. stream_processes=flexmock(),
  698. )
  699. assert create_flags == ('borg', 'create', '--read-special', '--patterns-from', 'patterns')
  700. assert create_positional_arguments == REPO_ARCHIVE
  701. assert pattern_file
  702. def test_make_base_create_command_with_stream_processes_and_read_special_true_skips_special_files_excludes():
  703. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  704. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  705. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  706. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  707. '{hostname}',
  708. )
  709. flexmock(module.feature).should_receive('available').and_return(True)
  710. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  711. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  712. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  713. )
  714. flexmock(module.logger).should_receive('warning').never()
  715. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  716. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  717. dry_run=False,
  718. repository_path='repo',
  719. config={
  720. 'source_directories': ['foo', 'bar'],
  721. 'repositories': ['repo'],
  722. 'read_special': True,
  723. },
  724. patterns=[Pattern('foo'), Pattern('bar')],
  725. local_borg_version='1.2.3',
  726. global_arguments=flexmock(),
  727. borgmatic_runtime_directory='/run/borgmatic',
  728. stream_processes=flexmock(),
  729. )
  730. assert create_flags == ('borg', 'create', '--read-special')
  731. assert create_positional_arguments == REPO_ARCHIVE
  732. assert not pattern_file
  733. def test_make_base_create_command_includes_archive_name_format_in_borg_command():
  734. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  735. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  736. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  737. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  738. '{hostname}',
  739. )
  740. flexmock(module.feature).should_receive('available').and_return(True)
  741. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  742. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  743. ('repo::ARCHIVE_NAME',),
  744. )
  745. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  746. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  747. dry_run=False,
  748. repository_path='repo',
  749. config={
  750. 'source_directories': ['foo', 'bar'],
  751. 'repositories': ['repo'],
  752. 'archive_name_format': 'ARCHIVE_NAME',
  753. },
  754. patterns=[Pattern('foo'), Pattern('bar')],
  755. local_borg_version='1.2.3',
  756. global_arguments=flexmock(),
  757. borgmatic_runtime_directory='/run/borgmatic',
  758. )
  759. assert create_flags == ('borg', 'create')
  760. assert create_positional_arguments == ('repo::ARCHIVE_NAME',)
  761. assert not pattern_file
  762. def test_make_base_create_command_includes_default_archive_name_format_in_borg_command():
  763. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  764. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  765. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  766. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  767. '{hostname}',
  768. )
  769. flexmock(module.feature).should_receive('available').and_return(True)
  770. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  771. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  772. ('repo::{hostname}',),
  773. )
  774. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  775. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  776. dry_run=False,
  777. repository_path='repo',
  778. config={
  779. 'source_directories': ['foo', 'bar'],
  780. 'repositories': ['repo'],
  781. },
  782. patterns=[Pattern('foo'), Pattern('bar')],
  783. local_borg_version='1.2.3',
  784. global_arguments=flexmock(),
  785. borgmatic_runtime_directory='/run/borgmatic',
  786. )
  787. assert create_flags == ('borg', 'create')
  788. assert create_positional_arguments == ('repo::{hostname}',)
  789. assert not pattern_file
  790. def test_make_base_create_command_includes_archive_name_format_with_placeholders_in_borg_command():
  791. repository_archive_pattern = 'repo::Documents_{hostname}-{now}'
  792. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  793. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  794. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  795. '{hostname}',
  796. )
  797. flexmock(module.feature).should_receive('available').and_return(True)
  798. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  799. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  800. (repository_archive_pattern,),
  801. )
  802. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  803. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  804. dry_run=False,
  805. repository_path='repo',
  806. config={
  807. 'source_directories': ['foo', 'bar'],
  808. 'repositories': ['repo'],
  809. 'archive_name_format': 'Documents_{hostname}-{now}',
  810. },
  811. patterns=[Pattern('foo'), Pattern('bar')],
  812. local_borg_version='1.2.3',
  813. global_arguments=flexmock(),
  814. borgmatic_runtime_directory='/run/borgmatic',
  815. )
  816. assert create_flags == ('borg', 'create')
  817. assert create_positional_arguments == (repository_archive_pattern,)
  818. assert not pattern_file
  819. def test_make_base_create_command_includes_repository_and_archive_name_format_with_placeholders_in_borg_command():
  820. repository_archive_pattern = '{fqdn}::Documents_{hostname}-{now}'
  821. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  822. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  823. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  824. '{hostname}',
  825. )
  826. flexmock(module.feature).should_receive('available').and_return(True)
  827. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  828. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  829. (repository_archive_pattern,),
  830. )
  831. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  832. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  833. dry_run=False,
  834. repository_path='{fqdn}',
  835. config={
  836. 'source_directories': ['foo', 'bar'],
  837. 'repositories': ['{fqdn}'],
  838. 'archive_name_format': 'Documents_{hostname}-{now}',
  839. },
  840. patterns=[Pattern('foo'), Pattern('bar')],
  841. local_borg_version='1.2.3',
  842. global_arguments=flexmock(),
  843. borgmatic_runtime_directory='/run/borgmatic',
  844. )
  845. assert create_flags == ('borg', 'create')
  846. assert create_positional_arguments == (repository_archive_pattern,)
  847. assert not pattern_file
  848. def test_make_base_create_command_includes_archive_suffix_in_borg_command():
  849. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  850. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  851. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  852. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  853. DEFAULT_ARCHIVE_NAME,
  854. )
  855. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  856. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  857. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  858. dry_run=False,
  859. repository_path='repo',
  860. config={
  861. 'source_directories': ['foo', 'bar'],
  862. 'repositories': ['repo'],
  863. },
  864. patterns=[Pattern('foo'), Pattern('bar')],
  865. local_borg_version='1.2.3',
  866. global_arguments=flexmock(),
  867. borgmatic_runtime_directory='/run/borgmatic',
  868. archive_suffix='.checkpoint',
  869. )
  870. assert create_flags == ('borg', 'create')
  871. assert create_positional_arguments == (f'repo::{DEFAULT_ARCHIVE_NAME}.checkpoint',)
  872. assert not pattern_file
  873. def test_make_base_create_command_includes_extra_borg_options_in_borg_command():
  874. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  875. flexmock(module.borgmatic.borg.pattern).should_receive('write_patterns_file').and_return(None)
  876. flexmock(module.borgmatic.borg.flags).should_receive('make_list_filter_flags').and_return('FOO')
  877. flexmock(module.flags).should_receive('get_default_archive_name_format').and_return(
  878. '{hostname}',
  879. )
  880. flexmock(module.feature).should_receive('available').and_return(True)
  881. flexmock(module.borgmatic.borg.flags).should_receive('make_exclude_flags').and_return(())
  882. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  883. (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  884. )
  885. flexmock(module).should_receive('validate_planned_backup_paths').and_return(())
  886. (create_flags, create_positional_arguments, pattern_file) = module.make_base_create_command(
  887. dry_run=False,
  888. repository_path='repo',
  889. config={
  890. 'source_directories': ['foo', 'bar'],
  891. 'repositories': ['repo'],
  892. 'extra_borg_options': {'create': '--extra --options "value with space"'},
  893. },
  894. patterns=[Pattern('foo'), Pattern('bar')],
  895. local_borg_version='1.2.3',
  896. global_arguments=flexmock(),
  897. borgmatic_runtime_directory='/run/borgmatic',
  898. )
  899. assert create_flags == ('borg', 'create', '--extra', '--options', 'value with space')
  900. assert create_positional_arguments == REPO_ARCHIVE
  901. assert not pattern_file
  902. def test_make_base_create_command_with_non_existent_directory_and_source_directories_must_exist_raises():
  903. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  904. flexmock(module.borgmatic.borg.pattern).should_receive(
  905. 'check_all_root_patterns_exist',
  906. ).and_raise(ValueError)
  907. with pytest.raises(ValueError):
  908. module.make_base_create_command(
  909. dry_run=False,
  910. repository_path='repo',
  911. config={
  912. 'source_directories': ['foo', 'bar'],
  913. 'repositories': ['repo'],
  914. 'source_directories_must_exist': True,
  915. },
  916. patterns=[Pattern('foo'), Pattern('bar')],
  917. local_borg_version='1.2.3',
  918. global_arguments=flexmock(),
  919. borgmatic_runtime_directory='/run/borgmatic',
  920. )
  921. def test_create_archive_calls_borg_with_flags():
  922. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  923. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  924. flexmock(module).should_receive('make_base_create_command').and_return(
  925. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  926. )
  927. flexmock(module.environment).should_receive('make_environment')
  928. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  929. flexmock(module).should_receive('execute_command').with_args(
  930. ('borg', 'create', *REPO_ARCHIVE),
  931. output_log_level=logging.INFO,
  932. output_file=None,
  933. borg_local_path='borg',
  934. borg_exit_codes=None,
  935. working_directory=None,
  936. environment=None,
  937. )
  938. module.create_archive(
  939. dry_run=False,
  940. repository_path='repo',
  941. config={
  942. 'source_directories': ['foo', 'bar'],
  943. 'repositories': ['repo'],
  944. 'exclude_patterns': None,
  945. },
  946. patterns=[Pattern('foo'), Pattern('bar')],
  947. local_borg_version='1.2.3',
  948. global_arguments=flexmock(),
  949. borgmatic_runtime_directory='/borgmatic/run',
  950. )
  951. def test_create_archive_calls_borg_with_environment():
  952. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  953. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  954. flexmock(module).should_receive('make_base_create_command').and_return(
  955. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  956. )
  957. environment = {'BORG_THINGY': 'YUP'}
  958. flexmock(module.environment).should_receive('make_environment').and_return(environment)
  959. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  960. flexmock(module).should_receive('execute_command').with_args(
  961. ('borg', 'create', *REPO_ARCHIVE),
  962. output_log_level=logging.INFO,
  963. output_file=None,
  964. borg_local_path='borg',
  965. borg_exit_codes=None,
  966. working_directory=None,
  967. environment=environment,
  968. )
  969. module.create_archive(
  970. dry_run=False,
  971. repository_path='repo',
  972. config={
  973. 'source_directories': ['foo', 'bar'],
  974. 'repositories': ['repo'],
  975. 'exclude_patterns': None,
  976. },
  977. patterns=[Pattern('foo'), Pattern('bar')],
  978. local_borg_version='1.2.3',
  979. global_arguments=flexmock(),
  980. borgmatic_runtime_directory='/borgmatic/run',
  981. )
  982. def test_create_archive_with_log_info_calls_borg_with_info_flag():
  983. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  984. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  985. flexmock(module).should_receive('make_base_create_command').and_return(
  986. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  987. )
  988. flexmock(module.environment).should_receive('make_environment')
  989. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  990. flexmock(module).should_receive('execute_command').with_args(
  991. ('borg', 'create', '--info', *REPO_ARCHIVE),
  992. output_log_level=logging.INFO,
  993. output_file=None,
  994. borg_local_path='borg',
  995. borg_exit_codes=None,
  996. working_directory=None,
  997. environment=None,
  998. )
  999. insert_logging_mock(logging.INFO)
  1000. module.create_archive(
  1001. dry_run=False,
  1002. repository_path='repo',
  1003. config={
  1004. 'source_directories': ['foo', 'bar'],
  1005. 'repositories': ['repo'],
  1006. 'exclude_patterns': None,
  1007. },
  1008. patterns=[Pattern('foo'), Pattern('bar')],
  1009. local_borg_version='1.2.3',
  1010. global_arguments=flexmock(),
  1011. borgmatic_runtime_directory='/borgmatic/run',
  1012. )
  1013. def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
  1014. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1015. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1016. flexmock(module).should_receive('make_base_create_command').and_return(
  1017. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1018. )
  1019. flexmock(module.environment).should_receive('make_environment')
  1020. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1021. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  1022. ('borg', 'create', '--json', *REPO_ARCHIVE),
  1023. working_directory=None,
  1024. environment=None,
  1025. borg_local_path='borg',
  1026. borg_exit_codes=None,
  1027. )
  1028. insert_logging_mock(logging.INFO)
  1029. module.create_archive(
  1030. dry_run=False,
  1031. repository_path='repo',
  1032. config={
  1033. 'source_directories': ['foo', 'bar'],
  1034. 'repositories': ['repo'],
  1035. 'exclude_patterns': None,
  1036. },
  1037. patterns=[Pattern('foo'), Pattern('bar')],
  1038. local_borg_version='1.2.3',
  1039. global_arguments=flexmock(),
  1040. borgmatic_runtime_directory='/borgmatic/run',
  1041. json=True,
  1042. )
  1043. def test_create_archive_with_log_debug_calls_borg_with_debug_flag():
  1044. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1045. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1046. flexmock(module).should_receive('make_base_create_command').and_return(
  1047. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1048. )
  1049. flexmock(module.environment).should_receive('make_environment')
  1050. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1051. flexmock(module).should_receive('execute_command').with_args(
  1052. ('borg', 'create', '--debug', '--show-rc', *REPO_ARCHIVE),
  1053. output_log_level=logging.INFO,
  1054. output_file=None,
  1055. borg_local_path='borg',
  1056. borg_exit_codes=None,
  1057. working_directory=None,
  1058. environment=None,
  1059. )
  1060. insert_logging_mock(logging.DEBUG)
  1061. module.create_archive(
  1062. dry_run=False,
  1063. repository_path='repo',
  1064. config={
  1065. 'source_directories': ['foo', 'bar'],
  1066. 'repositories': ['repo'],
  1067. 'exclude_patterns': None,
  1068. },
  1069. patterns=[Pattern('foo'), Pattern('bar')],
  1070. local_borg_version='1.2.3',
  1071. global_arguments=flexmock(),
  1072. borgmatic_runtime_directory='/borgmatic/run',
  1073. )
  1074. def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
  1075. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1076. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1077. flexmock(module).should_receive('make_base_create_command').and_return(
  1078. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1079. )
  1080. flexmock(module.environment).should_receive('make_environment')
  1081. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1082. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  1083. ('borg', 'create', '--json', *REPO_ARCHIVE),
  1084. working_directory=None,
  1085. environment=None,
  1086. borg_local_path='borg',
  1087. borg_exit_codes=None,
  1088. )
  1089. insert_logging_mock(logging.DEBUG)
  1090. module.create_archive(
  1091. dry_run=False,
  1092. repository_path='repo',
  1093. config={
  1094. 'source_directories': ['foo', 'bar'],
  1095. 'repositories': ['repo'],
  1096. 'exclude_patterns': None,
  1097. },
  1098. patterns=[Pattern('foo'), Pattern('bar')],
  1099. local_borg_version='1.2.3',
  1100. global_arguments=flexmock(),
  1101. borgmatic_runtime_directory='/borgmatic/run',
  1102. json=True,
  1103. )
  1104. def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats():
  1105. # --dry-run and --stats are mutually exclusive, see:
  1106. # https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
  1107. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1108. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1109. flexmock(module).should_receive('make_base_create_command').and_return(
  1110. (('borg', 'create', '--dry-run'), REPO_ARCHIVE, flexmock()),
  1111. )
  1112. flexmock(module.environment).should_receive('make_environment')
  1113. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1114. flexmock(module).should_receive('execute_command').with_args(
  1115. ('borg', 'create', '--dry-run', '--info', *REPO_ARCHIVE),
  1116. output_log_level=logging.INFO,
  1117. output_file=None,
  1118. borg_local_path='borg',
  1119. borg_exit_codes=None,
  1120. working_directory=None,
  1121. environment=None,
  1122. )
  1123. insert_logging_mock(logging.INFO)
  1124. module.create_archive(
  1125. dry_run=True,
  1126. repository_path='repo',
  1127. config={
  1128. 'source_directories': ['foo', 'bar'],
  1129. 'repositories': ['repo'],
  1130. 'exclude_patterns': None,
  1131. },
  1132. patterns=[Pattern('foo'), Pattern('bar')],
  1133. local_borg_version='1.2.3',
  1134. global_arguments=flexmock(),
  1135. borgmatic_runtime_directory='/borgmatic/run',
  1136. )
  1137. def test_create_archive_with_working_directory_calls_borg_with_working_directory():
  1138. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1139. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1140. flexmock(module).should_receive('make_base_create_command').and_return(
  1141. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1142. )
  1143. flexmock(module.environment).should_receive('make_environment')
  1144. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1145. '/working/dir',
  1146. )
  1147. flexmock(module).should_receive('execute_command').with_args(
  1148. ('borg', 'create', *REPO_ARCHIVE),
  1149. output_log_level=logging.INFO,
  1150. output_file=None,
  1151. borg_local_path='borg',
  1152. borg_exit_codes=None,
  1153. working_directory='/working/dir',
  1154. environment=None,
  1155. )
  1156. module.create_archive(
  1157. dry_run=False,
  1158. repository_path='repo',
  1159. config={
  1160. 'source_directories': ['foo', 'bar'],
  1161. 'repositories': ['repo'],
  1162. 'working_directory': '/working/dir',
  1163. 'exclude_patterns': None,
  1164. },
  1165. patterns=[Pattern('foo'), Pattern('bar')],
  1166. local_borg_version='1.2.3',
  1167. global_arguments=flexmock(),
  1168. borgmatic_runtime_directory='/borgmatic/run',
  1169. )
  1170. def test_create_archive_with_exit_codes_calls_borg_using_them():
  1171. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1172. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1173. flexmock(module).should_receive('make_base_create_command').and_return(
  1174. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1175. )
  1176. flexmock(module.environment).should_receive('make_environment')
  1177. borg_exit_codes = flexmock()
  1178. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1179. flexmock(module).should_receive('execute_command').with_args(
  1180. ('borg', 'create', *REPO_ARCHIVE),
  1181. output_log_level=logging.INFO,
  1182. output_file=None,
  1183. borg_local_path='borg',
  1184. borg_exit_codes=borg_exit_codes,
  1185. working_directory=None,
  1186. environment=None,
  1187. )
  1188. module.create_archive(
  1189. dry_run=False,
  1190. repository_path='repo',
  1191. config={
  1192. 'source_directories': ['foo', 'bar'],
  1193. 'repositories': ['repo'],
  1194. 'exclude_patterns': None,
  1195. 'borg_exit_codes': borg_exit_codes,
  1196. },
  1197. patterns=[Pattern('foo'), Pattern('bar')],
  1198. local_borg_version='1.2.3',
  1199. global_arguments=flexmock(),
  1200. borgmatic_runtime_directory='/borgmatic/run',
  1201. )
  1202. def test_create_archive_with_stats_calls_borg_with_stats_flag_and_answer_output_log_level():
  1203. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1204. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1205. flexmock(module).should_receive('make_base_create_command').and_return(
  1206. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1207. )
  1208. flexmock(module.environment).should_receive('make_environment')
  1209. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1210. flexmock(module).should_receive('execute_command').with_args(
  1211. ('borg', 'create', '--stats', *REPO_ARCHIVE),
  1212. output_log_level=module.borgmatic.logger.ANSWER,
  1213. output_file=None,
  1214. borg_local_path='borg',
  1215. borg_exit_codes=None,
  1216. working_directory=None,
  1217. environment=None,
  1218. )
  1219. module.create_archive(
  1220. dry_run=False,
  1221. repository_path='repo',
  1222. config={
  1223. 'source_directories': ['foo', 'bar'],
  1224. 'repositories': ['repo'],
  1225. 'exclude_patterns': None,
  1226. 'statistics': True,
  1227. },
  1228. patterns=[Pattern('foo'), Pattern('bar')],
  1229. local_borg_version='1.2.3',
  1230. global_arguments=flexmock(),
  1231. borgmatic_runtime_directory='/borgmatic/run',
  1232. )
  1233. def test_create_archive_with_files_calls_borg_with_answer_output_log_level():
  1234. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1235. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1236. flexmock(module).should_receive('make_base_create_command').and_return(
  1237. (
  1238. ('borg', 'create', '--list', '--filter', 'FOO'),
  1239. REPO_ARCHIVE,
  1240. flexmock(),
  1241. ),
  1242. )
  1243. flexmock(module.environment).should_receive('make_environment')
  1244. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1245. flexmock(module).should_receive('execute_command').with_args(
  1246. ('borg', 'create', '--list', '--filter', 'FOO', *REPO_ARCHIVE),
  1247. output_log_level=module.borgmatic.logger.ANSWER,
  1248. output_file=None,
  1249. borg_local_path='borg',
  1250. borg_exit_codes=None,
  1251. working_directory=None,
  1252. environment=None,
  1253. )
  1254. module.create_archive(
  1255. dry_run=False,
  1256. repository_path='repo',
  1257. config={
  1258. 'source_directories': ['foo', 'bar'],
  1259. 'repositories': ['repo'],
  1260. 'exclude_patterns': None,
  1261. 'list_details': True,
  1262. },
  1263. patterns=[Pattern('foo'), Pattern('bar')],
  1264. local_borg_version='1.2.3',
  1265. global_arguments=flexmock(),
  1266. borgmatic_runtime_directory='/borgmatic/run',
  1267. )
  1268. def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_flag_and_no_list():
  1269. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1270. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1271. flexmock(module).should_receive('make_base_create_command').and_return(
  1272. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1273. )
  1274. flexmock(module.environment).should_receive('make_environment')
  1275. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1276. flexmock(module).should_receive('execute_command').with_args(
  1277. ('borg', 'create', '--info', '--progress', *REPO_ARCHIVE),
  1278. output_log_level=logging.INFO,
  1279. output_file=module.DO_NOT_CAPTURE,
  1280. borg_local_path='borg',
  1281. borg_exit_codes=None,
  1282. working_directory=None,
  1283. environment=None,
  1284. )
  1285. insert_logging_mock(logging.INFO)
  1286. module.create_archive(
  1287. dry_run=False,
  1288. repository_path='repo',
  1289. config={
  1290. 'source_directories': ['foo', 'bar'],
  1291. 'repositories': ['repo'],
  1292. 'exclude_patterns': None,
  1293. 'progress': True,
  1294. },
  1295. patterns=[Pattern('foo'), Pattern('bar')],
  1296. local_borg_version='1.2.3',
  1297. global_arguments=flexmock(),
  1298. borgmatic_runtime_directory='/borgmatic/run',
  1299. )
  1300. def test_create_archive_with_progress_calls_borg_with_progress_flag():
  1301. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1302. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1303. flexmock(module).should_receive('make_base_create_command').and_return(
  1304. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1305. )
  1306. flexmock(module.environment).should_receive('make_environment')
  1307. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1308. flexmock(module).should_receive('execute_command').with_args(
  1309. ('borg', 'create', '--progress', *REPO_ARCHIVE),
  1310. output_log_level=logging.INFO,
  1311. output_file=module.DO_NOT_CAPTURE,
  1312. borg_local_path='borg',
  1313. borg_exit_codes=None,
  1314. working_directory=None,
  1315. environment=None,
  1316. )
  1317. module.create_archive(
  1318. dry_run=False,
  1319. repository_path='repo',
  1320. config={
  1321. 'source_directories': ['foo', 'bar'],
  1322. 'repositories': ['repo'],
  1323. 'exclude_patterns': None,
  1324. 'progress': True,
  1325. },
  1326. patterns=[Pattern('foo'), Pattern('bar')],
  1327. local_borg_version='1.2.3',
  1328. global_arguments=flexmock(),
  1329. borgmatic_runtime_directory='/borgmatic/run',
  1330. )
  1331. def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progress_flag():
  1332. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1333. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1334. processes = flexmock()
  1335. flexmock(module).should_receive('make_base_create_command').and_return(
  1336. (
  1337. ('borg', 'create', '--read-special'),
  1338. REPO_ARCHIVE,
  1339. flexmock(),
  1340. ),
  1341. )
  1342. flexmock(module.environment).should_receive('make_environment')
  1343. create_command = ('borg', 'create', '--read-special', '--progress', *REPO_ARCHIVE)
  1344. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1345. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1346. (*create_command, '--dry-run', '--list'),
  1347. processes=processes,
  1348. output_log_level=logging.INFO,
  1349. output_file=module.DO_NOT_CAPTURE,
  1350. borg_local_path='borg',
  1351. borg_exit_codes=None,
  1352. working_directory=None,
  1353. environment=None,
  1354. )
  1355. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1356. create_command,
  1357. processes=processes,
  1358. output_log_level=logging.INFO,
  1359. output_file=module.DO_NOT_CAPTURE,
  1360. borg_local_path='borg',
  1361. borg_exit_codes=None,
  1362. working_directory=None,
  1363. environment=None,
  1364. )
  1365. module.create_archive(
  1366. dry_run=False,
  1367. repository_path='repo',
  1368. config={
  1369. 'source_directories': ['foo', 'bar'],
  1370. 'repositories': ['repo'],
  1371. 'exclude_patterns': None,
  1372. 'progress': True,
  1373. },
  1374. patterns=[Pattern('foo'), Pattern('bar')],
  1375. local_borg_version='1.2.3',
  1376. global_arguments=flexmock(),
  1377. borgmatic_runtime_directory='/borgmatic/run',
  1378. stream_processes=processes,
  1379. )
  1380. def test_create_archive_with_json_calls_borg_with_json_flag():
  1381. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1382. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1383. flexmock(module).should_receive('make_base_create_command').and_return(
  1384. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1385. )
  1386. flexmock(module.environment).should_receive('make_environment')
  1387. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1388. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  1389. ('borg', 'create', '--json', *REPO_ARCHIVE),
  1390. working_directory=None,
  1391. environment=None,
  1392. borg_local_path='borg',
  1393. borg_exit_codes=None,
  1394. ).and_return('[]')
  1395. json_output = module.create_archive(
  1396. dry_run=False,
  1397. repository_path='repo',
  1398. config={
  1399. 'source_directories': ['foo', 'bar'],
  1400. 'repositories': ['repo'],
  1401. 'exclude_patterns': None,
  1402. },
  1403. patterns=[Pattern('foo'), Pattern('bar')],
  1404. local_borg_version='1.2.3',
  1405. global_arguments=flexmock(),
  1406. borgmatic_runtime_directory='/borgmatic/run',
  1407. json=True,
  1408. )
  1409. assert json_output == '[]'
  1410. def test_create_archive_with_stats_and_json_calls_borg_without_stats_flag():
  1411. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1412. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1413. flexmock(module).should_receive('make_base_create_command').and_return(
  1414. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1415. )
  1416. flexmock(module.environment).should_receive('make_environment')
  1417. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1418. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  1419. ('borg', 'create', '--json', *REPO_ARCHIVE),
  1420. working_directory=None,
  1421. environment=None,
  1422. borg_local_path='borg',
  1423. borg_exit_codes=None,
  1424. ).and_return('[]')
  1425. json_output = module.create_archive(
  1426. dry_run=False,
  1427. repository_path='repo',
  1428. config={
  1429. 'source_directories': ['foo*'],
  1430. 'repositories': ['repo'],
  1431. 'exclude_patterns': None,
  1432. },
  1433. patterns=[Pattern('foo'), Pattern('bar')],
  1434. local_borg_version='1.2.3',
  1435. global_arguments=flexmock(),
  1436. borgmatic_runtime_directory='/borgmatic/run',
  1437. json=True,
  1438. )
  1439. assert json_output == '[]'
  1440. def test_create_archive_with_comment_calls_borg_with_comment_flag():
  1441. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1442. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1443. flexmock(module).should_receive('make_base_create_command').and_return(
  1444. (('borg', 'create', '--comment', 'a comment'), REPO_ARCHIVE, flexmock()),
  1445. )
  1446. flexmock(module.environment).should_receive('make_environment')
  1447. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(None)
  1448. flexmock(module).should_receive('execute_command').with_args(
  1449. ('borg', 'create', '--comment', 'a comment', *REPO_ARCHIVE),
  1450. output_log_level=logging.INFO,
  1451. output_file=None,
  1452. borg_local_path='borg',
  1453. borg_exit_codes=None,
  1454. working_directory=None,
  1455. environment=None,
  1456. )
  1457. module.create_archive(
  1458. dry_run=False,
  1459. repository_path='repo',
  1460. config={
  1461. 'source_directories': ['foo', 'bar'],
  1462. 'repositories': ['repo'],
  1463. 'exclude_patterns': None,
  1464. },
  1465. patterns=[Pattern('foo'), Pattern('bar')],
  1466. local_borg_version='1.2.3',
  1467. global_arguments=flexmock(),
  1468. borgmatic_runtime_directory='/borgmatic/run',
  1469. json=False,
  1470. comment='a comment',
  1471. )
  1472. def test_create_archive_calls_borg_with_working_directory():
  1473. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  1474. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  1475. flexmock(module).should_receive('make_base_create_command').and_return(
  1476. (('borg', 'create'), REPO_ARCHIVE, flexmock()),
  1477. )
  1478. flexmock(module.environment).should_receive('make_environment')
  1479. flexmock(module.borgmatic.config.paths).should_receive('get_working_directory').and_return(
  1480. '/working/dir',
  1481. )
  1482. flexmock(module).should_receive('execute_command').with_args(
  1483. ('borg', 'create', *REPO_ARCHIVE),
  1484. output_log_level=logging.INFO,
  1485. output_file=None,
  1486. borg_local_path='borg',
  1487. borg_exit_codes=None,
  1488. working_directory='/working/dir',
  1489. environment=None,
  1490. )
  1491. module.create_archive(
  1492. dry_run=False,
  1493. repository_path='repo',
  1494. config={
  1495. 'source_directories': ['foo', 'bar'],
  1496. 'repositories': ['repo'],
  1497. 'exclude_patterns': None,
  1498. 'working_directory': '/working/dir',
  1499. },
  1500. patterns=[Pattern('foo'), Pattern('bar')],
  1501. local_borg_version='1.2.3',
  1502. global_arguments=flexmock(),
  1503. borgmatic_runtime_directory='/borgmatic/run',
  1504. )