test_create.py 67 KB

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