test_create.py 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019
  1. import logging
  2. import sys
  3. import pytest
  4. from flexmock import flexmock
  5. from borgmatic.borg import create as module
  6. from ..test_verbosity import insert_logging_mock
  7. def test_expand_directory_with_basic_path_passes_it_through():
  8. flexmock(module.os.path).should_receive('expanduser').and_return('foo')
  9. flexmock(module.glob).should_receive('glob').and_return([])
  10. paths = module.expand_directory('foo')
  11. assert paths == ['foo']
  12. def test_expand_directory_with_glob_expands():
  13. flexmock(module.os.path).should_receive('expanduser').and_return('foo*')
  14. flexmock(module.glob).should_receive('glob').and_return(['foo', 'food'])
  15. paths = module.expand_directory('foo*')
  16. assert paths == ['foo', 'food']
  17. def test_expand_directories_flattens_expanded_directories():
  18. flexmock(module).should_receive('expand_directory').with_args('~/foo').and_return(['/root/foo'])
  19. flexmock(module).should_receive('expand_directory').with_args('bar*').and_return(
  20. ['bar', 'barf']
  21. )
  22. paths = module.expand_directories(('~/foo', 'bar*'))
  23. assert paths == ('/root/foo', 'bar', 'barf')
  24. def test_expand_directories_considers_none_as_no_directories():
  25. paths = module.expand_directories(None)
  26. assert paths == ()
  27. def test_expand_home_directories_expands_tildes():
  28. flexmock(module.os.path).should_receive('expanduser').with_args('~/bar').and_return('/foo/bar')
  29. flexmock(module.os.path).should_receive('expanduser').with_args('baz').and_return('baz')
  30. paths = module.expand_home_directories(('~/bar', 'baz'))
  31. assert paths == ('/foo/bar', 'baz')
  32. def test_expand_home_directories_considers_none_as_no_directories():
  33. paths = module.expand_home_directories(None)
  34. assert paths == ()
  35. def test_map_directories_to_devices_gives_device_id_per_path():
  36. flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
  37. flexmock(module.os).should_receive('stat').with_args('/bar').and_return(flexmock(st_dev=66))
  38. device_map = module.map_directories_to_devices(('/foo', '/bar'))
  39. assert device_map == {
  40. '/foo': 55,
  41. '/bar': 66,
  42. }
  43. def test_map_directories_to_devices_with_missing_path_does_not_error():
  44. flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
  45. flexmock(module.os).should_receive('stat').with_args('/bar').and_raise(FileNotFoundError)
  46. device_map = module.map_directories_to_devices(('/foo', '/bar'))
  47. assert device_map == {
  48. '/foo': 55,
  49. '/bar': None,
  50. }
  51. @pytest.mark.parametrize(
  52. 'directories,expected_directories',
  53. (
  54. ({'/': 1, '/root': 1}, ('/',)),
  55. ({'/': 1, '/root/': 1}, ('/',)),
  56. ({'/': 1, '/root': 2}, ('/', '/root')),
  57. ({'/root': 1, '/': 1}, ('/',)),
  58. ({'/root': 1, '/root/foo': 1}, ('/root',)),
  59. ({'/root/': 1, '/root/foo': 1}, ('/root/',)),
  60. ({'/root': 1, '/root/foo/': 1}, ('/root',)),
  61. ({'/root': 1, '/root/foo': 2}, ('/root', '/root/foo')),
  62. ({'/root/foo': 1, '/root': 1}, ('/root',)),
  63. ({'/root': None, '/root/foo': None}, ('/root', '/root/foo')),
  64. ({'/root': 1, '/etc': 1, '/root/foo/bar': 1}, ('/etc', '/root')),
  65. ({'/root': 1, '/root/foo': 1, '/root/foo/bar': 1}, ('/root',)),
  66. ({'/dup': 1, '/dup': 1}, ('/dup',)),
  67. ({'/foo': 1, '/bar': 1}, ('/bar', '/foo')),
  68. ({'/foo': 1, '/bar': 2}, ('/bar', '/foo')),
  69. ),
  70. )
  71. def test_deduplicate_directories_removes_child_paths_on_the_same_filesystem(
  72. directories, expected_directories
  73. ):
  74. assert module.deduplicate_directories(directories) == expected_directories
  75. def test_write_pattern_file_writes_pattern_lines():
  76. temporary_file = flexmock(name='filename', flush=lambda: None)
  77. temporary_file.should_receive('write').with_args('R /foo\n+ /foo/bar')
  78. flexmock(module.tempfile).should_receive('NamedTemporaryFile').and_return(temporary_file)
  79. module.write_pattern_file(['R /foo', '+ /foo/bar'])
  80. def test_write_pattern_file_with_sources_writes_sources_as_roots():
  81. temporary_file = flexmock(name='filename', flush=lambda: None)
  82. temporary_file.should_receive('write').with_args('R /foo\n+ /foo/bar\nR /baz\nR /quux')
  83. flexmock(module.tempfile).should_receive('NamedTemporaryFile').and_return(temporary_file)
  84. module.write_pattern_file(['R /foo', '+ /foo/bar'], sources=['/baz', '/quux'])
  85. def test_write_pattern_file_with_empty_exclude_patterns_does_not_raise():
  86. module.write_pattern_file([])
  87. @pytest.mark.parametrize(
  88. 'filename_lists,opened_filenames',
  89. (
  90. ([('foo', 'bar'), ('baz', 'quux')], ('foo', 'bar', 'baz', 'quux')),
  91. ([None, ('foo', 'bar')], ('foo', 'bar')),
  92. ([None, None], ()),
  93. ),
  94. )
  95. def test_ensure_files_readable_opens_filenames(filename_lists, opened_filenames):
  96. for expected_filename in opened_filenames:
  97. flexmock(sys.modules['builtins']).should_receive('open').with_args(
  98. expected_filename
  99. ).and_return(flexmock(close=lambda: None))
  100. module.ensure_files_readable(*filename_lists)
  101. def test_make_pattern_flags_includes_pattern_filename_when_given():
  102. pattern_flags = module.make_pattern_flags(
  103. location_config={'patterns': ['R /', '- /var']}, pattern_filename='/tmp/patterns'
  104. )
  105. assert pattern_flags == ('--patterns-from', '/tmp/patterns')
  106. def test_make_pattern_flags_includes_patterns_from_filenames_when_in_config():
  107. pattern_flags = module.make_pattern_flags(
  108. location_config={'patterns_from': ['patterns', 'other']}
  109. )
  110. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', 'other')
  111. def test_make_pattern_flags_includes_both_filenames_when_patterns_given_and_patterns_from_in_config():
  112. pattern_flags = module.make_pattern_flags(
  113. location_config={'patterns_from': ['patterns']}, pattern_filename='/tmp/patterns'
  114. )
  115. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', '/tmp/patterns')
  116. def test_make_pattern_flags_considers_none_patterns_from_filenames_as_empty():
  117. pattern_flags = module.make_pattern_flags(location_config={'patterns_from': None})
  118. assert pattern_flags == ()
  119. def test_make_exclude_flags_includes_exclude_patterns_filename_when_given():
  120. exclude_flags = module.make_exclude_flags(
  121. location_config={'exclude_patterns': ['*.pyc', '/var']}, exclude_filename='/tmp/excludes'
  122. )
  123. assert exclude_flags == ('--exclude-from', '/tmp/excludes')
  124. def test_make_exclude_flags_includes_exclude_from_filenames_when_in_config():
  125. exclude_flags = module.make_exclude_flags(
  126. location_config={'exclude_from': ['excludes', 'other']}
  127. )
  128. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', 'other')
  129. def test_make_exclude_flags_includes_both_filenames_when_patterns_given_and_exclude_from_in_config():
  130. exclude_flags = module.make_exclude_flags(
  131. location_config={'exclude_from': ['excludes']}, exclude_filename='/tmp/excludes'
  132. )
  133. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', '/tmp/excludes')
  134. def test_make_exclude_flags_considers_none_exclude_from_filenames_as_empty():
  135. exclude_flags = module.make_exclude_flags(location_config={'exclude_from': None})
  136. assert exclude_flags == ()
  137. def test_make_exclude_flags_includes_exclude_caches_when_true_in_config():
  138. exclude_flags = module.make_exclude_flags(location_config={'exclude_caches': True})
  139. assert exclude_flags == ('--exclude-caches',)
  140. def test_make_exclude_flags_does_not_include_exclude_caches_when_false_in_config():
  141. exclude_flags = module.make_exclude_flags(location_config={'exclude_caches': False})
  142. assert exclude_flags == ()
  143. def test_make_exclude_flags_includes_exclude_if_present_when_in_config():
  144. exclude_flags = module.make_exclude_flags(
  145. location_config={'exclude_if_present': ['exclude_me', 'also_me']}
  146. )
  147. assert exclude_flags == (
  148. '--exclude-if-present',
  149. 'exclude_me',
  150. '--exclude-if-present',
  151. 'also_me',
  152. )
  153. def test_make_exclude_flags_includes_keep_exclude_tags_when_true_in_config():
  154. exclude_flags = module.make_exclude_flags(location_config={'keep_exclude_tags': True})
  155. assert exclude_flags == ('--keep-exclude-tags',)
  156. def test_make_exclude_flags_does_not_include_keep_exclude_tags_when_false_in_config():
  157. exclude_flags = module.make_exclude_flags(location_config={'keep_exclude_tags': False})
  158. assert exclude_flags == ()
  159. def test_make_exclude_flags_includes_exclude_nodump_when_true_in_config():
  160. exclude_flags = module.make_exclude_flags(location_config={'exclude_nodump': True})
  161. assert exclude_flags == ('--exclude-nodump',)
  162. def test_make_exclude_flags_does_not_include_exclude_nodump_when_false_in_config():
  163. exclude_flags = module.make_exclude_flags(location_config={'exclude_nodump': False})
  164. assert exclude_flags == ()
  165. def test_make_exclude_flags_is_empty_when_config_has_no_excludes():
  166. exclude_flags = module.make_exclude_flags(location_config={})
  167. assert exclude_flags == ()
  168. def test_borgmatic_source_directories_set_when_directory_exists():
  169. flexmock(module.os.path).should_receive('exists').and_return(True)
  170. flexmock(module.os.path).should_receive('expanduser')
  171. assert module.borgmatic_source_directories('/tmp') == ['/tmp']
  172. def test_borgmatic_source_directories_empty_when_directory_does_not_exist():
  173. flexmock(module.os.path).should_receive('exists').and_return(False)
  174. flexmock(module.os.path).should_receive('expanduser')
  175. assert module.borgmatic_source_directories('/tmp') == []
  176. def test_borgmatic_source_directories_defaults_when_directory_not_given():
  177. flexmock(module.os.path).should_receive('exists').and_return(True)
  178. flexmock(module.os.path).should_receive('expanduser')
  179. assert module.borgmatic_source_directories(None) == [
  180. module.state.DEFAULT_BORGMATIC_SOURCE_DIRECTORY
  181. ]
  182. DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
  183. REPO_ARCHIVE_WITH_PATHS = (f'repo::{DEFAULT_ARCHIVE_NAME}', 'foo', 'bar')
  184. def test_create_archive_calls_borg_with_parameters():
  185. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  186. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  187. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  188. flexmock(module).should_receive('expand_directories').and_return(())
  189. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  190. flexmock(module).should_receive('expand_home_directories').and_return(())
  191. flexmock(module).should_receive('write_pattern_file').and_return(None)
  192. flexmock(module.feature).should_receive('available').and_return(True)
  193. flexmock(module).should_receive('ensure_files_readable')
  194. flexmock(module).should_receive('make_pattern_flags').and_return(())
  195. flexmock(module).should_receive('make_exclude_flags').and_return(())
  196. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  197. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  198. )
  199. flexmock(module.environment).should_receive('make_environment')
  200. flexmock(module).should_receive('execute_command').with_args(
  201. ('borg', 'create') + REPO_ARCHIVE_WITH_PATHS,
  202. output_log_level=logging.INFO,
  203. output_file=None,
  204. borg_local_path='borg',
  205. working_directory=None,
  206. extra_environment=None,
  207. )
  208. module.create_archive(
  209. dry_run=False,
  210. repository='repo',
  211. location_config={
  212. 'source_directories': ['foo', 'bar'],
  213. 'repositories': ['repo'],
  214. 'exclude_patterns': None,
  215. },
  216. storage_config={},
  217. local_borg_version='1.2.3',
  218. )
  219. def test_create_archive_calls_borg_with_environment():
  220. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  221. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  222. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  223. flexmock(module).should_receive('expand_directories').and_return(())
  224. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  225. flexmock(module).should_receive('expand_home_directories').and_return(())
  226. flexmock(module).should_receive('write_pattern_file').and_return(None)
  227. flexmock(module.feature).should_receive('available').and_return(True)
  228. flexmock(module).should_receive('ensure_files_readable')
  229. flexmock(module).should_receive('make_pattern_flags').and_return(())
  230. flexmock(module).should_receive('make_exclude_flags').and_return(())
  231. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  232. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  233. )
  234. environment = {'BORG_THINGY': 'YUP'}
  235. flexmock(module.environment).should_receive('make_environment').and_return(environment)
  236. flexmock(module).should_receive('execute_command').with_args(
  237. ('borg', 'create') + REPO_ARCHIVE_WITH_PATHS,
  238. output_log_level=logging.INFO,
  239. output_file=None,
  240. borg_local_path='borg',
  241. working_directory=None,
  242. extra_environment=environment,
  243. )
  244. module.create_archive(
  245. dry_run=False,
  246. repository='repo',
  247. location_config={
  248. 'source_directories': ['foo', 'bar'],
  249. 'repositories': ['repo'],
  250. 'exclude_patterns': None,
  251. },
  252. storage_config={},
  253. local_borg_version='1.2.3',
  254. )
  255. def test_create_archive_with_patterns_calls_borg_with_patterns_including_converted_source_directories():
  256. pattern_flags = ('--patterns-from', 'patterns')
  257. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  258. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  259. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  260. flexmock(module).should_receive('expand_directories').and_return(())
  261. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  262. flexmock(module).should_receive('expand_home_directories').and_return(())
  263. flexmock(module).should_receive('write_pattern_file').and_return(
  264. flexmock(name='/tmp/patterns')
  265. ).and_return(None)
  266. flexmock(module.feature).should_receive('available').and_return(True)
  267. flexmock(module).should_receive('ensure_files_readable')
  268. flexmock(module).should_receive('make_pattern_flags').and_return(pattern_flags)
  269. flexmock(module).should_receive('make_exclude_flags').and_return(())
  270. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  271. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  272. )
  273. flexmock(module.environment).should_receive('make_environment')
  274. flexmock(module).should_receive('execute_command').with_args(
  275. ('borg', 'create') + pattern_flags + (f'repo::{DEFAULT_ARCHIVE_NAME}',),
  276. output_log_level=logging.INFO,
  277. output_file=None,
  278. borg_local_path='borg',
  279. working_directory=None,
  280. extra_environment=None,
  281. )
  282. module.create_archive(
  283. dry_run=False,
  284. repository='repo',
  285. location_config={
  286. 'source_directories': ['foo', 'bar'],
  287. 'repositories': ['repo'],
  288. 'patterns': ['pattern'],
  289. },
  290. storage_config={},
  291. local_borg_version='1.2.3',
  292. )
  293. def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
  294. exclude_flags = ('--exclude-from', 'excludes')
  295. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  296. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  297. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  298. flexmock(module).should_receive('expand_directories').and_return(())
  299. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  300. flexmock(module).should_receive('expand_home_directories').and_return(('exclude',))
  301. flexmock(module).should_receive('write_pattern_file').and_return(None).and_return(
  302. flexmock(name='/tmp/excludes')
  303. )
  304. flexmock(module.feature).should_receive('available').and_return(True)
  305. flexmock(module).should_receive('ensure_files_readable')
  306. flexmock(module).should_receive('make_pattern_flags').and_return(())
  307. flexmock(module).should_receive('make_exclude_flags').and_return(exclude_flags)
  308. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  309. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  310. )
  311. flexmock(module.environment).should_receive('make_environment')
  312. flexmock(module).should_receive('execute_command').with_args(
  313. ('borg', 'create') + exclude_flags + REPO_ARCHIVE_WITH_PATHS,
  314. output_log_level=logging.INFO,
  315. output_file=None,
  316. borg_local_path='borg',
  317. working_directory=None,
  318. extra_environment=None,
  319. )
  320. module.create_archive(
  321. dry_run=False,
  322. repository='repo',
  323. location_config={
  324. 'source_directories': ['foo', 'bar'],
  325. 'repositories': ['repo'],
  326. 'exclude_patterns': ['exclude'],
  327. },
  328. storage_config={},
  329. local_borg_version='1.2.3',
  330. )
  331. def test_create_archive_with_log_info_calls_borg_with_info_parameter():
  332. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  333. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  334. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  335. flexmock(module).should_receive('expand_directories').and_return(())
  336. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  337. flexmock(module).should_receive('expand_home_directories').and_return(())
  338. flexmock(module).should_receive('write_pattern_file').and_return(None)
  339. flexmock(module.feature).should_receive('available').and_return(True)
  340. flexmock(module).should_receive('ensure_files_readable')
  341. flexmock(module).should_receive('make_pattern_flags').and_return(())
  342. flexmock(module).should_receive('make_exclude_flags').and_return(())
  343. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  344. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  345. )
  346. flexmock(module.environment).should_receive('make_environment')
  347. flexmock(module).should_receive('execute_command').with_args(
  348. ('borg', 'create', '--info') + REPO_ARCHIVE_WITH_PATHS,
  349. output_log_level=logging.INFO,
  350. output_file=None,
  351. borg_local_path='borg',
  352. working_directory=None,
  353. extra_environment=None,
  354. )
  355. insert_logging_mock(logging.INFO)
  356. module.create_archive(
  357. dry_run=False,
  358. repository='repo',
  359. location_config={
  360. 'source_directories': ['foo', 'bar'],
  361. 'repositories': ['repo'],
  362. 'exclude_patterns': None,
  363. },
  364. storage_config={},
  365. local_borg_version='1.2.3',
  366. )
  367. def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
  368. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  369. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  370. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  371. flexmock(module).should_receive('expand_directories').and_return(())
  372. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  373. flexmock(module).should_receive('expand_home_directories').and_return(())
  374. flexmock(module).should_receive('write_pattern_file').and_return(None)
  375. flexmock(module.feature).should_receive('available').and_return(True)
  376. flexmock(module).should_receive('ensure_files_readable')
  377. flexmock(module).should_receive('make_pattern_flags').and_return(())
  378. flexmock(module).should_receive('make_exclude_flags').and_return(())
  379. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  380. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  381. )
  382. flexmock(module.environment).should_receive('make_environment')
  383. flexmock(module).should_receive('execute_command').with_args(
  384. ('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
  385. output_log_level=None,
  386. output_file=None,
  387. borg_local_path='borg',
  388. working_directory=None,
  389. extra_environment=None,
  390. )
  391. insert_logging_mock(logging.INFO)
  392. module.create_archive(
  393. dry_run=False,
  394. repository='repo',
  395. location_config={
  396. 'source_directories': ['foo', 'bar'],
  397. 'repositories': ['repo'],
  398. 'exclude_patterns': None,
  399. },
  400. storage_config={},
  401. local_borg_version='1.2.3',
  402. json=True,
  403. )
  404. def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
  405. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  406. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  407. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  408. flexmock(module).should_receive('expand_directories').and_return(())
  409. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  410. flexmock(module).should_receive('expand_home_directories').and_return(())
  411. flexmock(module).should_receive('write_pattern_file').and_return(None)
  412. flexmock(module.feature).should_receive('available').and_return(True)
  413. flexmock(module).should_receive('ensure_files_readable')
  414. flexmock(module).should_receive('make_pattern_flags').and_return(())
  415. flexmock(module).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.environment).should_receive('make_environment')
  420. flexmock(module).should_receive('execute_command').with_args(
  421. ('borg', 'create', '--debug', '--show-rc') + REPO_ARCHIVE_WITH_PATHS,
  422. output_log_level=logging.INFO,
  423. output_file=None,
  424. borg_local_path='borg',
  425. working_directory=None,
  426. extra_environment=None,
  427. )
  428. insert_logging_mock(logging.DEBUG)
  429. module.create_archive(
  430. dry_run=False,
  431. repository='repo',
  432. location_config={
  433. 'source_directories': ['foo', 'bar'],
  434. 'repositories': ['repo'],
  435. 'exclude_patterns': None,
  436. },
  437. storage_config={},
  438. local_borg_version='1.2.3',
  439. )
  440. def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
  441. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  442. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  443. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  444. flexmock(module).should_receive('expand_directories').and_return(())
  445. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  446. flexmock(module).should_receive('expand_home_directories').and_return(())
  447. flexmock(module).should_receive('write_pattern_file').and_return(None)
  448. flexmock(module.feature).should_receive('available').and_return(True)
  449. flexmock(module).should_receive('ensure_files_readable')
  450. flexmock(module).should_receive('make_pattern_flags').and_return(())
  451. flexmock(module).should_receive('make_exclude_flags').and_return(())
  452. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  453. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  454. )
  455. flexmock(module.environment).should_receive('make_environment')
  456. flexmock(module).should_receive('execute_command').with_args(
  457. ('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
  458. output_log_level=None,
  459. output_file=None,
  460. borg_local_path='borg',
  461. working_directory=None,
  462. extra_environment=None,
  463. )
  464. insert_logging_mock(logging.DEBUG)
  465. module.create_archive(
  466. dry_run=False,
  467. repository='repo',
  468. location_config={
  469. 'source_directories': ['foo', 'bar'],
  470. 'repositories': ['repo'],
  471. 'exclude_patterns': None,
  472. },
  473. storage_config={},
  474. local_borg_version='1.2.3',
  475. json=True,
  476. )
  477. def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
  478. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  479. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  480. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  481. flexmock(module).should_receive('expand_directories').and_return(())
  482. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  483. flexmock(module).should_receive('expand_home_directories').and_return(())
  484. flexmock(module).should_receive('write_pattern_file').and_return(None)
  485. flexmock(module.feature).should_receive('available').and_return(True)
  486. flexmock(module).should_receive('ensure_files_readable')
  487. flexmock(module).should_receive('make_pattern_flags').and_return(())
  488. flexmock(module).should_receive('make_exclude_flags').and_return(())
  489. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  490. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  491. )
  492. flexmock(module.environment).should_receive('make_environment')
  493. flexmock(module).should_receive('execute_command').with_args(
  494. ('borg', 'create', '--dry-run') + REPO_ARCHIVE_WITH_PATHS,
  495. output_log_level=logging.INFO,
  496. output_file=None,
  497. borg_local_path='borg',
  498. working_directory=None,
  499. extra_environment=None,
  500. )
  501. module.create_archive(
  502. dry_run=True,
  503. repository='repo',
  504. location_config={
  505. 'source_directories': ['foo', 'bar'],
  506. 'repositories': ['repo'],
  507. 'exclude_patterns': None,
  508. },
  509. storage_config={},
  510. local_borg_version='1.2.3',
  511. )
  512. def test_create_archive_with_stats_and_dry_run_calls_borg_without_stats_parameter():
  513. # --dry-run and --stats are mutually exclusive, see:
  514. # https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
  515. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  516. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  517. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  518. flexmock(module).should_receive('expand_directories').and_return(())
  519. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  520. flexmock(module).should_receive('expand_home_directories').and_return(())
  521. flexmock(module).should_receive('write_pattern_file').and_return(None)
  522. flexmock(module.feature).should_receive('available').and_return(True)
  523. flexmock(module).should_receive('ensure_files_readable')
  524. flexmock(module).should_receive('make_pattern_flags').and_return(())
  525. flexmock(module).should_receive('make_exclude_flags').and_return(())
  526. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  527. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  528. )
  529. flexmock(module.environment).should_receive('make_environment')
  530. flexmock(module).should_receive('execute_command').with_args(
  531. ('borg', 'create', '--info', '--dry-run') + REPO_ARCHIVE_WITH_PATHS,
  532. output_log_level=logging.INFO,
  533. output_file=None,
  534. borg_local_path='borg',
  535. working_directory=None,
  536. extra_environment=None,
  537. )
  538. insert_logging_mock(logging.INFO)
  539. module.create_archive(
  540. dry_run=True,
  541. repository='repo',
  542. location_config={
  543. 'source_directories': ['foo', 'bar'],
  544. 'repositories': ['repo'],
  545. 'exclude_patterns': None,
  546. },
  547. storage_config={},
  548. local_borg_version='1.2.3',
  549. stats=True,
  550. )
  551. def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
  552. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  553. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  554. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  555. flexmock(module).should_receive('expand_directories').and_return(())
  556. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  557. flexmock(module).should_receive('expand_home_directories').and_return(())
  558. flexmock(module).should_receive('write_pattern_file').and_return(None)
  559. flexmock(module.feature).should_receive('available').and_return(True)
  560. flexmock(module).should_receive('ensure_files_readable')
  561. flexmock(module).should_receive('make_pattern_flags').and_return(())
  562. flexmock(module).should_receive('make_exclude_flags').and_return(())
  563. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  564. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  565. )
  566. flexmock(module.environment).should_receive('make_environment')
  567. flexmock(module).should_receive('execute_command').with_args(
  568. ('borg', 'create', '--checkpoint-interval', '600') + REPO_ARCHIVE_WITH_PATHS,
  569. output_log_level=logging.INFO,
  570. output_file=None,
  571. borg_local_path='borg',
  572. working_directory=None,
  573. extra_environment=None,
  574. )
  575. module.create_archive(
  576. dry_run=False,
  577. repository='repo',
  578. location_config={
  579. 'source_directories': ['foo', 'bar'],
  580. 'repositories': ['repo'],
  581. 'exclude_patterns': None,
  582. },
  583. storage_config={'checkpoint_interval': 600},
  584. local_borg_version='1.2.3',
  585. )
  586. def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_parameters():
  587. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  588. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  589. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  590. flexmock(module).should_receive('expand_directories').and_return(())
  591. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  592. flexmock(module).should_receive('expand_home_directories').and_return(())
  593. flexmock(module).should_receive('write_pattern_file').and_return(None)
  594. flexmock(module.feature).should_receive('available').and_return(True)
  595. flexmock(module).should_receive('ensure_files_readable')
  596. flexmock(module).should_receive('make_pattern_flags').and_return(())
  597. flexmock(module).should_receive('make_exclude_flags').and_return(())
  598. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  599. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  600. )
  601. flexmock(module.environment).should_receive('make_environment')
  602. flexmock(module).should_receive('execute_command').with_args(
  603. ('borg', 'create', '--chunker-params', '1,2,3,4') + REPO_ARCHIVE_WITH_PATHS,
  604. output_log_level=logging.INFO,
  605. output_file=None,
  606. borg_local_path='borg',
  607. working_directory=None,
  608. extra_environment=None,
  609. )
  610. module.create_archive(
  611. dry_run=False,
  612. repository='repo',
  613. location_config={
  614. 'source_directories': ['foo', 'bar'],
  615. 'repositories': ['repo'],
  616. 'exclude_patterns': None,
  617. },
  618. storage_config={'chunker_params': '1,2,3,4'},
  619. local_borg_version='1.2.3',
  620. )
  621. def test_create_archive_with_compression_calls_borg_with_compression_parameters():
  622. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  623. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  624. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  625. flexmock(module).should_receive('expand_directories').and_return(())
  626. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  627. flexmock(module).should_receive('expand_home_directories').and_return(())
  628. flexmock(module).should_receive('write_pattern_file').and_return(None)
  629. flexmock(module.feature).should_receive('available').and_return(True)
  630. flexmock(module).should_receive('ensure_files_readable')
  631. flexmock(module).should_receive('make_pattern_flags').and_return(())
  632. flexmock(module).should_receive('make_exclude_flags').and_return(())
  633. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  634. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  635. )
  636. flexmock(module.environment).should_receive('make_environment')
  637. flexmock(module).should_receive('execute_command').with_args(
  638. ('borg', 'create', '--compression', 'rle') + REPO_ARCHIVE_WITH_PATHS,
  639. output_log_level=logging.INFO,
  640. output_file=None,
  641. borg_local_path='borg',
  642. working_directory=None,
  643. extra_environment=None,
  644. )
  645. module.create_archive(
  646. dry_run=False,
  647. repository='repo',
  648. location_config={
  649. 'source_directories': ['foo', 'bar'],
  650. 'repositories': ['repo'],
  651. 'exclude_patterns': None,
  652. },
  653. storage_config={'compression': 'rle'},
  654. local_borg_version='1.2.3',
  655. )
  656. @pytest.mark.parametrize(
  657. 'feature_available,option_flag', ((True, '--upload-ratelimit'), (False, '--remote-ratelimit')),
  658. )
  659. def test_create_archive_with_upload_rate_limit_calls_borg_with_upload_ratelimit_parameters(
  660. feature_available, option_flag
  661. ):
  662. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  663. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  664. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  665. flexmock(module).should_receive('expand_directories').and_return(())
  666. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  667. flexmock(module).should_receive('expand_home_directories').and_return(())
  668. flexmock(module).should_receive('write_pattern_file').and_return(None)
  669. flexmock(module.feature).should_receive('available').and_return(feature_available)
  670. flexmock(module).should_receive('ensure_files_readable')
  671. flexmock(module).should_receive('make_pattern_flags').and_return(())
  672. flexmock(module).should_receive('make_exclude_flags').and_return(())
  673. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  674. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  675. )
  676. flexmock(module.environment).should_receive('make_environment')
  677. flexmock(module).should_receive('execute_command').with_args(
  678. ('borg', 'create', option_flag, '100') + REPO_ARCHIVE_WITH_PATHS,
  679. output_log_level=logging.INFO,
  680. output_file=None,
  681. borg_local_path='borg',
  682. working_directory=None,
  683. extra_environment=None,
  684. )
  685. module.create_archive(
  686. dry_run=False,
  687. repository='repo',
  688. location_config={
  689. 'source_directories': ['foo', 'bar'],
  690. 'repositories': ['repo'],
  691. 'exclude_patterns': None,
  692. },
  693. storage_config={'upload_rate_limit': 100},
  694. local_borg_version='1.2.3',
  695. )
  696. def test_create_archive_with_working_directory_calls_borg_with_working_directory():
  697. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  698. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  699. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  700. flexmock(module).should_receive('expand_directories').and_return(())
  701. flexmock(module.os.path).should_receive('expanduser').with_args('/working/dir').and_return(
  702. '/working/dir'
  703. )
  704. flexmock(module).should_receive('expand_home_directories').and_return(())
  705. flexmock(module).should_receive('write_pattern_file').and_return(None)
  706. flexmock(module.feature).should_receive('available').and_return(True)
  707. flexmock(module).should_receive('ensure_files_readable')
  708. flexmock(module).should_receive('make_pattern_flags').and_return(())
  709. flexmock(module).should_receive('make_exclude_flags').and_return(())
  710. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  711. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  712. )
  713. flexmock(module.environment).should_receive('make_environment')
  714. flexmock(module).should_receive('execute_command').with_args(
  715. ('borg', 'create') + REPO_ARCHIVE_WITH_PATHS,
  716. output_log_level=logging.INFO,
  717. output_file=None,
  718. borg_local_path='borg',
  719. working_directory='/working/dir',
  720. extra_environment=None,
  721. )
  722. module.create_archive(
  723. dry_run=False,
  724. repository='repo',
  725. location_config={
  726. 'source_directories': ['foo', 'bar'],
  727. 'repositories': ['repo'],
  728. 'working_directory': '/working/dir',
  729. 'exclude_patterns': None,
  730. },
  731. storage_config={},
  732. local_borg_version='1.2.3',
  733. )
  734. def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_parameter():
  735. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  736. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  737. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  738. flexmock(module).should_receive('expand_directories').and_return(())
  739. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  740. flexmock(module).should_receive('expand_home_directories').and_return(())
  741. flexmock(module).should_receive('write_pattern_file').and_return(None)
  742. flexmock(module.feature).should_receive('available').and_return(True)
  743. flexmock(module).should_receive('ensure_files_readable')
  744. flexmock(module).should_receive('make_pattern_flags').and_return(())
  745. flexmock(module).should_receive('make_exclude_flags').and_return(())
  746. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  747. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  748. )
  749. flexmock(module.environment).should_receive('make_environment')
  750. flexmock(module).should_receive('execute_command').with_args(
  751. ('borg', 'create', '--one-file-system') + REPO_ARCHIVE_WITH_PATHS,
  752. output_log_level=logging.INFO,
  753. output_file=None,
  754. borg_local_path='borg',
  755. working_directory=None,
  756. extra_environment=None,
  757. )
  758. module.create_archive(
  759. dry_run=False,
  760. repository='repo',
  761. location_config={
  762. 'source_directories': ['foo', 'bar'],
  763. 'repositories': ['repo'],
  764. 'one_file_system': True,
  765. 'exclude_patterns': None,
  766. },
  767. storage_config={},
  768. local_borg_version='1.2.3',
  769. )
  770. @pytest.mark.parametrize(
  771. 'feature_available,option_flag', ((True, '--numeric-ids'), (False, '--numeric-owner')),
  772. )
  773. def test_create_archive_with_numeric_ids_calls_borg_with_numeric_ids_parameter(
  774. feature_available, option_flag
  775. ):
  776. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  777. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  778. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  779. flexmock(module).should_receive('expand_directories').and_return(())
  780. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  781. flexmock(module).should_receive('expand_home_directories').and_return(())
  782. flexmock(module).should_receive('write_pattern_file').and_return(None)
  783. flexmock(module.feature).should_receive('available').and_return(feature_available)
  784. flexmock(module).should_receive('ensure_files_readable')
  785. flexmock(module).should_receive('make_pattern_flags').and_return(())
  786. flexmock(module).should_receive('make_exclude_flags').and_return(())
  787. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  788. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  789. )
  790. flexmock(module.environment).should_receive('make_environment')
  791. flexmock(module).should_receive('execute_command').with_args(
  792. ('borg', 'create', option_flag) + REPO_ARCHIVE_WITH_PATHS,
  793. output_log_level=logging.INFO,
  794. output_file=None,
  795. borg_local_path='borg',
  796. working_directory=None,
  797. extra_environment=None,
  798. )
  799. module.create_archive(
  800. dry_run=False,
  801. repository='repo',
  802. location_config={
  803. 'source_directories': ['foo', 'bar'],
  804. 'repositories': ['repo'],
  805. 'numeric_ids': True,
  806. 'exclude_patterns': None,
  807. },
  808. storage_config={},
  809. local_borg_version='1.2.3',
  810. )
  811. def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
  812. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  813. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  814. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  815. flexmock(module).should_receive('expand_directories').and_return(())
  816. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  817. flexmock(module).should_receive('expand_home_directories').and_return(())
  818. flexmock(module).should_receive('write_pattern_file').and_return(None)
  819. flexmock(module.feature).should_receive('available').and_return(True)
  820. flexmock(module).should_receive('ensure_files_readable')
  821. flexmock(module).should_receive('make_pattern_flags').and_return(())
  822. flexmock(module).should_receive('make_exclude_flags').and_return(())
  823. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  824. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  825. )
  826. flexmock(module.environment).should_receive('make_environment')
  827. flexmock(module).should_receive('execute_command').with_args(
  828. ('borg', 'create', '--read-special') + REPO_ARCHIVE_WITH_PATHS,
  829. output_log_level=logging.INFO,
  830. output_file=None,
  831. borg_local_path='borg',
  832. working_directory=None,
  833. extra_environment=None,
  834. )
  835. module.create_archive(
  836. dry_run=False,
  837. repository='repo',
  838. location_config={
  839. 'source_directories': ['foo', 'bar'],
  840. 'repositories': ['repo'],
  841. 'read_special': True,
  842. 'exclude_patterns': None,
  843. },
  844. storage_config={},
  845. local_borg_version='1.2.3',
  846. )
  847. @pytest.mark.parametrize(
  848. 'option_name,option_value',
  849. (('ctime', True), ('ctime', False), ('birthtime', True), ('birthtime', False),),
  850. )
  851. def test_create_archive_with_basic_option_calls_borg_with_corresponding_parameter(
  852. option_name, option_value
  853. ):
  854. option_flag = '--no' + option_name.replace('', '') if option_value is False else None
  855. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  856. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  857. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  858. flexmock(module).should_receive('expand_directories').and_return(())
  859. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  860. flexmock(module).should_receive('expand_home_directories').and_return(())
  861. flexmock(module).should_receive('write_pattern_file').and_return(None)
  862. flexmock(module.feature).should_receive('available').and_return(True)
  863. flexmock(module).should_receive('ensure_files_readable')
  864. flexmock(module).should_receive('make_pattern_flags').and_return(())
  865. flexmock(module).should_receive('make_exclude_flags').and_return(())
  866. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  867. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  868. )
  869. flexmock(module.environment).should_receive('make_environment')
  870. flexmock(module).should_receive('execute_command').with_args(
  871. ('borg', 'create') + ((option_flag,) if option_flag else ()) + REPO_ARCHIVE_WITH_PATHS,
  872. output_log_level=logging.INFO,
  873. output_file=None,
  874. borg_local_path='borg',
  875. working_directory=None,
  876. extra_environment=None,
  877. )
  878. module.create_archive(
  879. dry_run=False,
  880. repository='repo',
  881. location_config={
  882. 'source_directories': ['foo', 'bar'],
  883. 'repositories': ['repo'],
  884. option_name: option_value,
  885. 'exclude_patterns': None,
  886. },
  887. storage_config={},
  888. local_borg_version='1.2.3',
  889. )
  890. @pytest.mark.parametrize(
  891. 'option_value,feature_available,option_flag',
  892. (
  893. (True, True, '--atime'),
  894. (True, False, None),
  895. (False, True, None),
  896. (False, False, '--noatime'),
  897. ),
  898. )
  899. def test_create_archive_with_atime_option_calls_borg_with_corresponding_parameter(
  900. option_value, feature_available, option_flag
  901. ):
  902. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  903. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  904. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  905. flexmock(module).should_receive('expand_directories').and_return(())
  906. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  907. flexmock(module).should_receive('expand_home_directories').and_return(())
  908. flexmock(module).should_receive('write_pattern_file').and_return(None)
  909. flexmock(module.feature).should_receive('available').and_return(feature_available)
  910. flexmock(module).should_receive('ensure_files_readable')
  911. flexmock(module).should_receive('make_pattern_flags').and_return(())
  912. flexmock(module).should_receive('make_exclude_flags').and_return(())
  913. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  914. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  915. )
  916. flexmock(module.environment).should_receive('make_environment')
  917. flexmock(module).should_receive('execute_command').with_args(
  918. ('borg', 'create') + ((option_flag,) if option_flag else ()) + REPO_ARCHIVE_WITH_PATHS,
  919. output_log_level=logging.INFO,
  920. output_file=None,
  921. borg_local_path='borg',
  922. working_directory=None,
  923. extra_environment=None,
  924. )
  925. module.create_archive(
  926. dry_run=False,
  927. repository='repo',
  928. location_config={
  929. 'source_directories': ['foo', 'bar'],
  930. 'repositories': ['repo'],
  931. 'atime': option_value,
  932. 'exclude_patterns': None,
  933. },
  934. storage_config={},
  935. local_borg_version='1.2.3',
  936. )
  937. @pytest.mark.parametrize(
  938. 'option_value,feature_available,option_flag',
  939. (
  940. (True, True, None),
  941. (True, False, None),
  942. (False, True, '--noflags'),
  943. (False, False, '--nobsdflags'),
  944. ),
  945. )
  946. def test_create_archive_with_flags_option_calls_borg_with_corresponding_parameter(
  947. option_value, feature_available, option_flag
  948. ):
  949. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  950. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  951. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  952. flexmock(module).should_receive('expand_directories').and_return(())
  953. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  954. flexmock(module).should_receive('expand_home_directories').and_return(())
  955. flexmock(module).should_receive('write_pattern_file').and_return(None)
  956. flexmock(module.feature).should_receive('available').and_return(feature_available)
  957. flexmock(module).should_receive('ensure_files_readable')
  958. flexmock(module).should_receive('make_pattern_flags').and_return(())
  959. flexmock(module).should_receive('make_exclude_flags').and_return(())
  960. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  961. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  962. )
  963. flexmock(module.environment).should_receive('make_environment')
  964. flexmock(module).should_receive('execute_command').with_args(
  965. ('borg', 'create') + ((option_flag,) if option_flag else ()) + REPO_ARCHIVE_WITH_PATHS,
  966. output_log_level=logging.INFO,
  967. output_file=None,
  968. borg_local_path='borg',
  969. working_directory=None,
  970. extra_environment=None,
  971. )
  972. module.create_archive(
  973. dry_run=False,
  974. repository='repo',
  975. location_config={
  976. 'source_directories': ['foo', 'bar'],
  977. 'repositories': ['repo'],
  978. 'flags': option_value,
  979. 'exclude_patterns': None,
  980. },
  981. storage_config={},
  982. local_borg_version='1.2.3',
  983. )
  984. def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
  985. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  986. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  987. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  988. flexmock(module).should_receive('expand_directories').and_return(())
  989. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  990. flexmock(module).should_receive('expand_home_directories').and_return(())
  991. flexmock(module).should_receive('write_pattern_file').and_return(None)
  992. flexmock(module.feature).should_receive('available').and_return(True)
  993. flexmock(module).should_receive('ensure_files_readable')
  994. flexmock(module).should_receive('make_pattern_flags').and_return(())
  995. flexmock(module).should_receive('make_exclude_flags').and_return(())
  996. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  997. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  998. )
  999. flexmock(module.environment).should_receive('make_environment')
  1000. flexmock(module).should_receive('execute_command').with_args(
  1001. ('borg', 'create', '--files-cache', 'ctime,size') + REPO_ARCHIVE_WITH_PATHS,
  1002. output_log_level=logging.INFO,
  1003. output_file=None,
  1004. borg_local_path='borg',
  1005. working_directory=None,
  1006. extra_environment=None,
  1007. )
  1008. module.create_archive(
  1009. dry_run=False,
  1010. repository='repo',
  1011. location_config={
  1012. 'source_directories': ['foo', 'bar'],
  1013. 'repositories': ['repo'],
  1014. 'files_cache': 'ctime,size',
  1015. 'exclude_patterns': None,
  1016. },
  1017. storage_config={},
  1018. local_borg_version='1.2.3',
  1019. )
  1020. def test_create_archive_with_local_path_calls_borg_via_local_path():
  1021. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1022. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1023. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1024. flexmock(module).should_receive('expand_directories').and_return(())
  1025. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1026. flexmock(module).should_receive('expand_home_directories').and_return(())
  1027. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1028. flexmock(module.feature).should_receive('available').and_return(True)
  1029. flexmock(module).should_receive('ensure_files_readable')
  1030. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1031. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1032. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1033. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1034. )
  1035. flexmock(module.environment).should_receive('make_environment')
  1036. flexmock(module).should_receive('execute_command').with_args(
  1037. ('borg1', 'create') + REPO_ARCHIVE_WITH_PATHS,
  1038. output_log_level=logging.INFO,
  1039. output_file=None,
  1040. borg_local_path='borg1',
  1041. working_directory=None,
  1042. extra_environment=None,
  1043. )
  1044. module.create_archive(
  1045. dry_run=False,
  1046. repository='repo',
  1047. location_config={
  1048. 'source_directories': ['foo', 'bar'],
  1049. 'repositories': ['repo'],
  1050. 'exclude_patterns': None,
  1051. },
  1052. storage_config={},
  1053. local_borg_version='1.2.3',
  1054. local_path='borg1',
  1055. )
  1056. def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters():
  1057. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1058. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1059. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1060. flexmock(module).should_receive('expand_directories').and_return(())
  1061. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1062. flexmock(module).should_receive('expand_home_directories').and_return(())
  1063. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1064. flexmock(module.feature).should_receive('available').and_return(True)
  1065. flexmock(module).should_receive('ensure_files_readable')
  1066. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1067. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1068. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1069. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1070. )
  1071. flexmock(module.environment).should_receive('make_environment')
  1072. flexmock(module).should_receive('execute_command').with_args(
  1073. ('borg', 'create', '--remote-path', 'borg1') + REPO_ARCHIVE_WITH_PATHS,
  1074. output_log_level=logging.INFO,
  1075. output_file=None,
  1076. borg_local_path='borg',
  1077. working_directory=None,
  1078. extra_environment=None,
  1079. )
  1080. module.create_archive(
  1081. dry_run=False,
  1082. repository='repo',
  1083. location_config={
  1084. 'source_directories': ['foo', 'bar'],
  1085. 'repositories': ['repo'],
  1086. 'exclude_patterns': None,
  1087. },
  1088. storage_config={},
  1089. local_borg_version='1.2.3',
  1090. remote_path='borg1',
  1091. )
  1092. def test_create_archive_with_umask_calls_borg_with_umask_parameters():
  1093. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1094. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1095. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1096. flexmock(module).should_receive('expand_directories').and_return(())
  1097. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1098. flexmock(module).should_receive('expand_home_directories').and_return(())
  1099. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1100. flexmock(module.feature).should_receive('available').and_return(True)
  1101. flexmock(module).should_receive('ensure_files_readable')
  1102. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1103. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1104. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1105. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1106. )
  1107. flexmock(module.environment).should_receive('make_environment')
  1108. flexmock(module).should_receive('execute_command').with_args(
  1109. ('borg', 'create', '--umask', '740') + REPO_ARCHIVE_WITH_PATHS,
  1110. output_log_level=logging.INFO,
  1111. output_file=None,
  1112. borg_local_path='borg',
  1113. working_directory=None,
  1114. extra_environment=None,
  1115. )
  1116. module.create_archive(
  1117. dry_run=False,
  1118. repository='repo',
  1119. location_config={
  1120. 'source_directories': ['foo', 'bar'],
  1121. 'repositories': ['repo'],
  1122. 'exclude_patterns': None,
  1123. },
  1124. storage_config={'umask': 740},
  1125. local_borg_version='1.2.3',
  1126. )
  1127. def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
  1128. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1129. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1130. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1131. flexmock(module).should_receive('expand_directories').and_return(())
  1132. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1133. flexmock(module).should_receive('expand_home_directories').and_return(())
  1134. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1135. flexmock(module.feature).should_receive('available').and_return(True)
  1136. flexmock(module).should_receive('ensure_files_readable')
  1137. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1138. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1139. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1140. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1141. )
  1142. flexmock(module.environment).should_receive('make_environment')
  1143. flexmock(module).should_receive('execute_command').with_args(
  1144. ('borg', 'create', '--lock-wait', '5') + REPO_ARCHIVE_WITH_PATHS,
  1145. output_log_level=logging.INFO,
  1146. output_file=None,
  1147. borg_local_path='borg',
  1148. working_directory=None,
  1149. extra_environment=None,
  1150. )
  1151. module.create_archive(
  1152. dry_run=False,
  1153. repository='repo',
  1154. location_config={
  1155. 'source_directories': ['foo', 'bar'],
  1156. 'repositories': ['repo'],
  1157. 'exclude_patterns': None,
  1158. },
  1159. storage_config={'lock_wait': 5},
  1160. local_borg_version='1.2.3',
  1161. )
  1162. def test_create_archive_with_stats_calls_borg_with_stats_parameter_and_warning_output_log_level():
  1163. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1164. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1165. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1166. flexmock(module).should_receive('expand_directories').and_return(())
  1167. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1168. flexmock(module).should_receive('expand_home_directories').and_return(())
  1169. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1170. flexmock(module.feature).should_receive('available').and_return(True)
  1171. flexmock(module).should_receive('ensure_files_readable')
  1172. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1173. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1174. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1175. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1176. )
  1177. flexmock(module.environment).should_receive('make_environment')
  1178. flexmock(module).should_receive('execute_command').with_args(
  1179. ('borg', 'create', '--stats') + REPO_ARCHIVE_WITH_PATHS,
  1180. output_log_level=logging.WARNING,
  1181. output_file=None,
  1182. borg_local_path='borg',
  1183. working_directory=None,
  1184. extra_environment=None,
  1185. )
  1186. module.create_archive(
  1187. dry_run=False,
  1188. repository='repo',
  1189. location_config={
  1190. 'source_directories': ['foo', 'bar'],
  1191. 'repositories': ['repo'],
  1192. 'exclude_patterns': None,
  1193. },
  1194. storage_config={},
  1195. local_borg_version='1.2.3',
  1196. stats=True,
  1197. )
  1198. def test_create_archive_with_stats_and_log_info_calls_borg_with_stats_parameter_and_info_output_log_level():
  1199. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1200. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1201. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1202. flexmock(module).should_receive('expand_directories').and_return(())
  1203. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1204. flexmock(module).should_receive('expand_home_directories').and_return(())
  1205. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1206. flexmock(module.feature).should_receive('available').and_return(True)
  1207. flexmock(module).should_receive('ensure_files_readable')
  1208. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1209. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1210. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1211. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1212. )
  1213. flexmock(module.environment).should_receive('make_environment')
  1214. flexmock(module).should_receive('execute_command').with_args(
  1215. ('borg', 'create', '--info', '--stats') + REPO_ARCHIVE_WITH_PATHS,
  1216. output_log_level=logging.INFO,
  1217. output_file=None,
  1218. borg_local_path='borg',
  1219. working_directory=None,
  1220. extra_environment=None,
  1221. )
  1222. insert_logging_mock(logging.INFO)
  1223. module.create_archive(
  1224. dry_run=False,
  1225. repository='repo',
  1226. location_config={
  1227. 'source_directories': ['foo', 'bar'],
  1228. 'repositories': ['repo'],
  1229. 'exclude_patterns': None,
  1230. },
  1231. storage_config={},
  1232. local_borg_version='1.2.3',
  1233. stats=True,
  1234. )
  1235. def test_create_archive_with_files_calls_borg_with_list_parameter_and_warning_output_log_level():
  1236. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1237. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1238. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1239. flexmock(module).should_receive('expand_directories').and_return(())
  1240. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1241. flexmock(module).should_receive('expand_home_directories').and_return(())
  1242. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1243. flexmock(module.feature).should_receive('available').and_return(True)
  1244. flexmock(module).should_receive('ensure_files_readable')
  1245. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1246. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1247. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1248. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1249. )
  1250. flexmock(module.environment).should_receive('make_environment')
  1251. flexmock(module).should_receive('execute_command').with_args(
  1252. ('borg', 'create', '--list', '--filter', 'AME-') + REPO_ARCHIVE_WITH_PATHS,
  1253. output_log_level=logging.WARNING,
  1254. output_file=None,
  1255. borg_local_path='borg',
  1256. working_directory=None,
  1257. extra_environment=None,
  1258. )
  1259. module.create_archive(
  1260. dry_run=False,
  1261. repository='repo',
  1262. location_config={
  1263. 'source_directories': ['foo', 'bar'],
  1264. 'repositories': ['repo'],
  1265. 'exclude_patterns': None,
  1266. },
  1267. storage_config={},
  1268. local_borg_version='1.2.3',
  1269. list_files=True,
  1270. )
  1271. def test_create_archive_with_files_and_log_info_calls_borg_with_list_parameter_and_info_output_log_level():
  1272. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1273. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1274. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1275. flexmock(module).should_receive('expand_directories').and_return(())
  1276. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1277. flexmock(module).should_receive('expand_home_directories').and_return(())
  1278. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1279. flexmock(module.feature).should_receive('available').and_return(True)
  1280. flexmock(module).should_receive('ensure_files_readable')
  1281. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1282. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1283. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1284. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1285. )
  1286. flexmock(module.environment).should_receive('make_environment')
  1287. flexmock(module).should_receive('execute_command').with_args(
  1288. ('borg', 'create', '--list', '--filter', 'AME-', '--info') + REPO_ARCHIVE_WITH_PATHS,
  1289. output_log_level=logging.INFO,
  1290. output_file=None,
  1291. borg_local_path='borg',
  1292. working_directory=None,
  1293. extra_environment=None,
  1294. )
  1295. insert_logging_mock(logging.INFO)
  1296. module.create_archive(
  1297. dry_run=False,
  1298. repository='repo',
  1299. location_config={
  1300. 'source_directories': ['foo', 'bar'],
  1301. 'repositories': ['repo'],
  1302. 'exclude_patterns': None,
  1303. },
  1304. storage_config={},
  1305. local_borg_version='1.2.3',
  1306. list_files=True,
  1307. )
  1308. def test_create_archive_with_progress_and_log_info_calls_borg_with_progress_parameter_and_no_list():
  1309. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1310. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1311. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1312. flexmock(module).should_receive('expand_directories').and_return(())
  1313. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1314. flexmock(module).should_receive('expand_home_directories').and_return(())
  1315. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1316. flexmock(module.feature).should_receive('available').and_return(True)
  1317. flexmock(module).should_receive('ensure_files_readable')
  1318. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1319. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1320. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1321. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1322. )
  1323. flexmock(module.environment).should_receive('make_environment')
  1324. flexmock(module).should_receive('execute_command').with_args(
  1325. ('borg', 'create', '--info', '--progress') + REPO_ARCHIVE_WITH_PATHS,
  1326. output_log_level=logging.INFO,
  1327. output_file=module.DO_NOT_CAPTURE,
  1328. borg_local_path='borg',
  1329. working_directory=None,
  1330. extra_environment=None,
  1331. )
  1332. insert_logging_mock(logging.INFO)
  1333. module.create_archive(
  1334. dry_run=False,
  1335. repository='repo',
  1336. location_config={
  1337. 'source_directories': ['foo', 'bar'],
  1338. 'repositories': ['repo'],
  1339. 'exclude_patterns': None,
  1340. },
  1341. storage_config={},
  1342. local_borg_version='1.2.3',
  1343. progress=True,
  1344. )
  1345. def test_create_archive_with_progress_calls_borg_with_progress_parameter():
  1346. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1347. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1348. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1349. flexmock(module).should_receive('expand_directories').and_return(())
  1350. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1351. flexmock(module).should_receive('expand_home_directories').and_return(())
  1352. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1353. flexmock(module.feature).should_receive('available').and_return(True)
  1354. flexmock(module).should_receive('ensure_files_readable')
  1355. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1356. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1357. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1358. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1359. )
  1360. flexmock(module.environment).should_receive('make_environment')
  1361. flexmock(module).should_receive('execute_command').with_args(
  1362. ('borg', 'create', '--progress') + REPO_ARCHIVE_WITH_PATHS,
  1363. output_log_level=logging.INFO,
  1364. output_file=module.DO_NOT_CAPTURE,
  1365. borg_local_path='borg',
  1366. working_directory=None,
  1367. extra_environment=None,
  1368. )
  1369. module.create_archive(
  1370. dry_run=False,
  1371. repository='repo',
  1372. location_config={
  1373. 'source_directories': ['foo', 'bar'],
  1374. 'repositories': ['repo'],
  1375. 'exclude_patterns': None,
  1376. },
  1377. storage_config={},
  1378. local_borg_version='1.2.3',
  1379. progress=True,
  1380. )
  1381. def test_create_archive_with_progress_and_stream_processes_calls_borg_with_progress_parameter():
  1382. processes = flexmock()
  1383. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1384. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1385. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1386. flexmock(module).should_receive('expand_directories').and_return(())
  1387. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1388. flexmock(module).should_receive('expand_home_directories').and_return(())
  1389. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1390. flexmock(module.feature).should_receive('available').and_return(True)
  1391. flexmock(module).should_receive('ensure_files_readable')
  1392. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1393. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1394. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1395. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1396. )
  1397. flexmock(module.environment).should_receive('make_environment')
  1398. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1399. ('borg', 'create', '--one-file-system', '--read-special', '--progress')
  1400. + REPO_ARCHIVE_WITH_PATHS,
  1401. processes=processes,
  1402. output_log_level=logging.INFO,
  1403. output_file=module.DO_NOT_CAPTURE,
  1404. borg_local_path='borg',
  1405. working_directory=None,
  1406. extra_environment=None,
  1407. )
  1408. module.create_archive(
  1409. dry_run=False,
  1410. repository='repo',
  1411. location_config={
  1412. 'source_directories': ['foo', 'bar'],
  1413. 'repositories': ['repo'],
  1414. 'exclude_patterns': None,
  1415. },
  1416. storage_config={},
  1417. local_borg_version='1.2.3',
  1418. progress=True,
  1419. stream_processes=processes,
  1420. )
  1421. def test_create_archive_with_json_calls_borg_with_json_parameter():
  1422. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1423. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1424. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1425. flexmock(module).should_receive('expand_directories').and_return(())
  1426. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1427. flexmock(module).should_receive('expand_home_directories').and_return(())
  1428. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1429. flexmock(module.feature).should_receive('available').and_return(True)
  1430. flexmock(module).should_receive('ensure_files_readable')
  1431. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1432. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1433. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1434. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1435. )
  1436. flexmock(module.environment).should_receive('make_environment')
  1437. flexmock(module).should_receive('execute_command').with_args(
  1438. ('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
  1439. output_log_level=None,
  1440. output_file=None,
  1441. borg_local_path='borg',
  1442. working_directory=None,
  1443. extra_environment=None,
  1444. ).and_return('[]')
  1445. json_output = module.create_archive(
  1446. dry_run=False,
  1447. repository='repo',
  1448. location_config={
  1449. 'source_directories': ['foo', 'bar'],
  1450. 'repositories': ['repo'],
  1451. 'exclude_patterns': None,
  1452. },
  1453. storage_config={},
  1454. local_borg_version='1.2.3',
  1455. json=True,
  1456. )
  1457. assert json_output == '[]'
  1458. def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter():
  1459. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1460. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1461. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1462. flexmock(module).should_receive('expand_directories').and_return(())
  1463. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1464. flexmock(module).should_receive('expand_home_directories').and_return(())
  1465. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1466. flexmock(module.feature).should_receive('available').and_return(True)
  1467. flexmock(module).should_receive('ensure_files_readable')
  1468. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1469. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1470. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1471. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1472. )
  1473. flexmock(module.environment).should_receive('make_environment')
  1474. flexmock(module).should_receive('execute_command').with_args(
  1475. ('borg', 'create', '--json') + REPO_ARCHIVE_WITH_PATHS,
  1476. output_log_level=None,
  1477. output_file=None,
  1478. borg_local_path='borg',
  1479. working_directory=None,
  1480. extra_environment=None,
  1481. ).and_return('[]')
  1482. json_output = module.create_archive(
  1483. dry_run=False,
  1484. repository='repo',
  1485. location_config={
  1486. 'source_directories': ['foo', 'bar'],
  1487. 'repositories': ['repo'],
  1488. 'exclude_patterns': None,
  1489. },
  1490. storage_config={},
  1491. local_borg_version='1.2.3',
  1492. json=True,
  1493. stats=True,
  1494. )
  1495. assert json_output == '[]'
  1496. def test_create_archive_with_source_directories_glob_expands():
  1497. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1498. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
  1499. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1500. flexmock(module).should_receive('expand_directories').and_return(())
  1501. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1502. flexmock(module).should_receive('expand_home_directories').and_return(())
  1503. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1504. flexmock(module.feature).should_receive('available').and_return(True)
  1505. flexmock(module).should_receive('ensure_files_readable')
  1506. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1507. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1508. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1509. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1510. )
  1511. flexmock(module.environment).should_receive('make_environment')
  1512. flexmock(module).should_receive('execute_command').with_args(
  1513. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  1514. output_log_level=logging.INFO,
  1515. output_file=None,
  1516. borg_local_path='borg',
  1517. working_directory=None,
  1518. extra_environment=None,
  1519. )
  1520. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return(['foo', 'food'])
  1521. module.create_archive(
  1522. dry_run=False,
  1523. repository='repo',
  1524. location_config={
  1525. 'source_directories': ['foo*'],
  1526. 'repositories': ['repo'],
  1527. 'exclude_patterns': None,
  1528. },
  1529. storage_config={},
  1530. local_borg_version='1.2.3',
  1531. )
  1532. def test_create_archive_with_non_matching_source_directories_glob_passes_through():
  1533. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1534. flexmock(module).should_receive('deduplicate_directories').and_return(('foo*',))
  1535. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1536. flexmock(module).should_receive('expand_directories').and_return(())
  1537. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1538. flexmock(module).should_receive('expand_home_directories').and_return(())
  1539. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1540. flexmock(module.feature).should_receive('available').and_return(True)
  1541. flexmock(module).should_receive('ensure_files_readable')
  1542. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1543. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1544. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1545. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1546. )
  1547. flexmock(module.environment).should_receive('make_environment')
  1548. flexmock(module).should_receive('execute_command').with_args(
  1549. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo*'),
  1550. output_log_level=logging.INFO,
  1551. output_file=None,
  1552. borg_local_path='borg',
  1553. working_directory=None,
  1554. extra_environment=None,
  1555. )
  1556. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return([])
  1557. module.create_archive(
  1558. dry_run=False,
  1559. repository='repo',
  1560. location_config={
  1561. 'source_directories': ['foo*'],
  1562. 'repositories': ['repo'],
  1563. 'exclude_patterns': None,
  1564. },
  1565. storage_config={},
  1566. local_borg_version='1.2.3',
  1567. )
  1568. def test_create_archive_with_glob_calls_borg_with_expanded_directories():
  1569. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1570. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'food'))
  1571. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1572. flexmock(module).should_receive('expand_directories').and_return(())
  1573. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1574. flexmock(module).should_receive('expand_home_directories').and_return(())
  1575. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1576. flexmock(module.feature).should_receive('available').and_return(True)
  1577. flexmock(module).should_receive('ensure_files_readable')
  1578. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1579. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1580. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1581. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1582. )
  1583. flexmock(module.environment).should_receive('make_environment')
  1584. flexmock(module).should_receive('execute_command').with_args(
  1585. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  1586. output_log_level=logging.INFO,
  1587. output_file=None,
  1588. borg_local_path='borg',
  1589. working_directory=None,
  1590. extra_environment=None,
  1591. )
  1592. module.create_archive(
  1593. dry_run=False,
  1594. repository='repo',
  1595. location_config={
  1596. 'source_directories': ['foo*'],
  1597. 'repositories': ['repo'],
  1598. 'exclude_patterns': None,
  1599. },
  1600. storage_config={},
  1601. local_borg_version='1.2.3',
  1602. )
  1603. def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
  1604. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1605. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1606. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1607. flexmock(module).should_receive('expand_directories').and_return(())
  1608. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1609. flexmock(module).should_receive('expand_home_directories').and_return(())
  1610. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1611. flexmock(module.feature).should_receive('available').and_return(True)
  1612. flexmock(module).should_receive('ensure_files_readable')
  1613. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1614. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1615. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1616. ('repo::ARCHIVE_NAME',)
  1617. )
  1618. flexmock(module.environment).should_receive('make_environment')
  1619. flexmock(module).should_receive('execute_command').with_args(
  1620. ('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar'),
  1621. output_log_level=logging.INFO,
  1622. output_file=None,
  1623. borg_local_path='borg',
  1624. working_directory=None,
  1625. extra_environment=None,
  1626. )
  1627. module.create_archive(
  1628. dry_run=False,
  1629. repository='repo',
  1630. location_config={
  1631. 'source_directories': ['foo', 'bar'],
  1632. 'repositories': ['repo'],
  1633. 'exclude_patterns': None,
  1634. },
  1635. storage_config={'archive_name_format': 'ARCHIVE_NAME'},
  1636. local_borg_version='1.2.3',
  1637. )
  1638. def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
  1639. repository_archive_pattern = 'repo::Documents_{hostname}-{now}'
  1640. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1641. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1642. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1643. flexmock(module).should_receive('expand_directories').and_return(())
  1644. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1645. flexmock(module).should_receive('expand_home_directories').and_return(())
  1646. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1647. flexmock(module.feature).should_receive('available').and_return(True)
  1648. flexmock(module).should_receive('ensure_files_readable')
  1649. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1650. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1651. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1652. (repository_archive_pattern,)
  1653. )
  1654. flexmock(module.environment).should_receive('make_environment')
  1655. flexmock(module).should_receive('execute_command').with_args(
  1656. ('borg', 'create', repository_archive_pattern, 'foo', 'bar'),
  1657. output_log_level=logging.INFO,
  1658. output_file=None,
  1659. borg_local_path='borg',
  1660. working_directory=None,
  1661. extra_environment=None,
  1662. )
  1663. module.create_archive(
  1664. dry_run=False,
  1665. repository='repo',
  1666. location_config={
  1667. 'source_directories': ['foo', 'bar'],
  1668. 'repositories': ['repo'],
  1669. 'exclude_patterns': None,
  1670. },
  1671. storage_config={'archive_name_format': 'Documents_{hostname}-{now}'},
  1672. local_borg_version='1.2.3',
  1673. )
  1674. def test_create_archive_with_repository_accepts_borg_placeholders():
  1675. repository_archive_pattern = '{fqdn}::Documents_{hostname}-{now}'
  1676. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1677. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1678. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1679. flexmock(module).should_receive('expand_directories').and_return(())
  1680. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1681. flexmock(module).should_receive('expand_home_directories').and_return(())
  1682. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1683. flexmock(module.feature).should_receive('available').and_return(True)
  1684. flexmock(module).should_receive('ensure_files_readable')
  1685. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1686. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1687. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1688. (repository_archive_pattern,)
  1689. )
  1690. flexmock(module.environment).should_receive('make_environment')
  1691. flexmock(module).should_receive('execute_command').with_args(
  1692. ('borg', 'create', repository_archive_pattern, 'foo', 'bar'),
  1693. output_log_level=logging.INFO,
  1694. output_file=None,
  1695. borg_local_path='borg',
  1696. working_directory=None,
  1697. extra_environment=None,
  1698. )
  1699. module.create_archive(
  1700. dry_run=False,
  1701. repository='{fqdn}',
  1702. location_config={
  1703. 'source_directories': ['foo', 'bar'],
  1704. 'repositories': ['{fqdn}'],
  1705. 'exclude_patterns': None,
  1706. },
  1707. storage_config={'archive_name_format': 'Documents_{hostname}-{now}'},
  1708. local_borg_version='1.2.3',
  1709. )
  1710. def test_create_archive_with_extra_borg_options_calls_borg_with_extra_options():
  1711. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1712. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1713. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1714. flexmock(module).should_receive('expand_directories').and_return(())
  1715. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1716. flexmock(module).should_receive('expand_home_directories').and_return(())
  1717. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1718. flexmock(module.feature).should_receive('available').and_return(True)
  1719. flexmock(module).should_receive('ensure_files_readable')
  1720. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1721. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1722. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1723. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1724. )
  1725. flexmock(module.environment).should_receive('make_environment')
  1726. flexmock(module).should_receive('execute_command').with_args(
  1727. ('borg', 'create', '--extra', '--options') + REPO_ARCHIVE_WITH_PATHS,
  1728. output_log_level=logging.INFO,
  1729. output_file=None,
  1730. borg_local_path='borg',
  1731. working_directory=None,
  1732. extra_environment=None,
  1733. )
  1734. module.create_archive(
  1735. dry_run=False,
  1736. repository='repo',
  1737. location_config={
  1738. 'source_directories': ['foo', 'bar'],
  1739. 'repositories': ['repo'],
  1740. 'exclude_patterns': None,
  1741. },
  1742. storage_config={'extra_borg_options': {'create': '--extra --options'}},
  1743. local_borg_version='1.2.3',
  1744. )
  1745. def test_create_archive_with_stream_processes_calls_borg_with_processes():
  1746. processes = flexmock()
  1747. flexmock(module).should_receive('borgmatic_source_directories').and_return([])
  1748. flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
  1749. flexmock(module).should_receive('map_directories_to_devices').and_return({})
  1750. flexmock(module).should_receive('expand_directories').and_return(())
  1751. flexmock(module.os.path).should_receive('expanduser').and_raise(TypeError)
  1752. flexmock(module).should_receive('expand_home_directories').and_return(())
  1753. flexmock(module).should_receive('write_pattern_file').and_return(None)
  1754. flexmock(module.feature).should_receive('available').and_return(True)
  1755. flexmock(module).should_receive('ensure_files_readable')
  1756. flexmock(module).should_receive('make_pattern_flags').and_return(())
  1757. flexmock(module).should_receive('make_exclude_flags').and_return(())
  1758. flexmock(module.flags).should_receive('make_repository_archive_flags').and_return(
  1759. (f'repo::{DEFAULT_ARCHIVE_NAME}',)
  1760. )
  1761. flexmock(module.environment).should_receive('make_environment')
  1762. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1763. ('borg', 'create', '--one-file-system', '--read-special') + REPO_ARCHIVE_WITH_PATHS,
  1764. processes=processes,
  1765. output_log_level=logging.INFO,
  1766. output_file=None,
  1767. borg_local_path='borg',
  1768. working_directory=None,
  1769. extra_environment=None,
  1770. )
  1771. module.create_archive(
  1772. dry_run=False,
  1773. repository='repo',
  1774. location_config={
  1775. 'source_directories': ['foo', 'bar'],
  1776. 'repositories': ['repo'],
  1777. 'exclude_patterns': None,
  1778. },
  1779. storage_config={},
  1780. local_borg_version='1.2.3',
  1781. stream_processes=processes,
  1782. )