test_create.py 75 KB

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