test_create.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.borg import create as module
  5. from ..test_verbosity import insert_logging_mock
  6. def test_expand_directory_with_basic_path_passes_it_through():
  7. flexmock(module.os.path).should_receive('expanduser').and_return('foo')
  8. flexmock(module.glob).should_receive('glob').and_return([])
  9. paths = module._expand_directory('foo')
  10. assert paths == ['foo']
  11. def test_expand_directory_with_glob_expands():
  12. flexmock(module.os.path).should_receive('expanduser').and_return('foo*')
  13. flexmock(module.glob).should_receive('glob').and_return(['foo', 'food'])
  14. paths = module._expand_directory('foo*')
  15. assert paths == ['foo', 'food']
  16. def test_expand_directories_flattens_expanded_directories():
  17. flexmock(module).should_receive('_expand_directory').with_args('~/foo').and_return(
  18. ['/root/foo']
  19. )
  20. flexmock(module).should_receive('_expand_directory').with_args('bar*').and_return(
  21. ['bar', 'barf']
  22. )
  23. paths = module._expand_directories(('~/foo', 'bar*'))
  24. assert paths == ('/root/foo', 'bar', 'barf')
  25. def test_expand_directories_considers_none_as_no_directories():
  26. paths = module._expand_directories(None)
  27. assert paths == ()
  28. def test_expand_home_directories_expands_tildes():
  29. flexmock(module.os.path).should_receive('expanduser').with_args('~/bar').and_return('/foo/bar')
  30. flexmock(module.os.path).should_receive('expanduser').with_args('baz').and_return('baz')
  31. paths = module._expand_home_directories(('~/bar', 'baz'))
  32. assert paths == ('/foo/bar', 'baz')
  33. def test_expand_home_directories_considers_none_as_no_directories():
  34. paths = module._expand_home_directories(None)
  35. assert paths == ()
  36. def test_write_pattern_file_does_not_raise():
  37. temporary_file = flexmock(name='filename', write=lambda mode: None, flush=lambda: None)
  38. flexmock(module.tempfile).should_receive('NamedTemporaryFile').and_return(temporary_file)
  39. module._write_pattern_file(['exclude'])
  40. def test_write_pattern_file_with_empty_exclude_patterns_does_not_raise():
  41. module._write_pattern_file([])
  42. def test_make_pattern_flags_includes_pattern_filename_when_given():
  43. pattern_flags = module._make_pattern_flags(
  44. location_config={'patterns': ['R /', '- /var']}, pattern_filename='/tmp/patterns'
  45. )
  46. assert pattern_flags == ('--patterns-from', '/tmp/patterns')
  47. def test_make_pattern_flags_includes_patterns_from_filenames_when_in_config():
  48. pattern_flags = module._make_pattern_flags(
  49. location_config={'patterns_from': ['patterns', 'other']}
  50. )
  51. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', 'other')
  52. def test_make_pattern_flags_includes_both_filenames_when_patterns_given_and_patterns_from_in_config():
  53. pattern_flags = module._make_pattern_flags(
  54. location_config={'patterns_from': ['patterns']}, pattern_filename='/tmp/patterns'
  55. )
  56. assert pattern_flags == ('--patterns-from', 'patterns', '--patterns-from', '/tmp/patterns')
  57. def test_make_pattern_flags_considers_none_patterns_from_filenames_as_empty():
  58. pattern_flags = module._make_pattern_flags(location_config={'patterns_from': None})
  59. assert pattern_flags == ()
  60. def test_make_exclude_flags_includes_exclude_patterns_filename_when_given():
  61. exclude_flags = module._make_exclude_flags(
  62. location_config={'exclude_patterns': ['*.pyc', '/var']}, exclude_filename='/tmp/excludes'
  63. )
  64. assert exclude_flags == ('--exclude-from', '/tmp/excludes')
  65. def test_make_exclude_flags_includes_exclude_from_filenames_when_in_config():
  66. exclude_flags = module._make_exclude_flags(
  67. location_config={'exclude_from': ['excludes', 'other']}
  68. )
  69. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', 'other')
  70. def test_make_exclude_flags_includes_both_filenames_when_patterns_given_and_exclude_from_in_config():
  71. exclude_flags = module._make_exclude_flags(
  72. location_config={'exclude_from': ['excludes']}, exclude_filename='/tmp/excludes'
  73. )
  74. assert exclude_flags == ('--exclude-from', 'excludes', '--exclude-from', '/tmp/excludes')
  75. def test_make_exclude_flags_considers_none_exclude_from_filenames_as_empty():
  76. exclude_flags = module._make_exclude_flags(location_config={'exclude_from': None})
  77. assert exclude_flags == ()
  78. def test_make_exclude_flags_includes_exclude_caches_when_true_in_config():
  79. exclude_flags = module._make_exclude_flags(location_config={'exclude_caches': True})
  80. assert exclude_flags == ('--exclude-caches',)
  81. def test_make_exclude_flags_does_not_include_exclude_caches_when_false_in_config():
  82. exclude_flags = module._make_exclude_flags(location_config={'exclude_caches': False})
  83. assert exclude_flags == ()
  84. def test_make_exclude_flags_includes_exclude_if_present_when_in_config():
  85. exclude_flags = module._make_exclude_flags(location_config={'exclude_if_present': 'exclude_me'})
  86. assert exclude_flags == ('--exclude-if-present', 'exclude_me')
  87. def test_make_exclude_flags_is_empty_when_config_has_no_excludes():
  88. exclude_flags = module._make_exclude_flags(location_config={})
  89. assert exclude_flags == ()
  90. DEFAULT_ARCHIVE_NAME = '{hostname}-{now:%Y-%m-%dT%H:%M:%S.%f}'
  91. CREATE_COMMAND = ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'bar')
  92. def test_create_archive_calls_borg_with_parameters():
  93. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  94. flexmock(module).should_receive('_expand_home_directories').and_return(())
  95. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  96. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  97. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  98. flexmock(module).should_receive('execute_command').with_args(
  99. CREATE_COMMAND, output_log_level=logging.INFO
  100. )
  101. module.create_archive(
  102. dry_run=False,
  103. repository='repo',
  104. location_config={
  105. 'source_directories': ['foo', 'bar'],
  106. 'repositories': ['repo'],
  107. 'exclude_patterns': None,
  108. },
  109. storage_config={},
  110. )
  111. def test_create_archive_with_patterns_calls_borg_with_patterns():
  112. pattern_flags = ('--patterns-from', 'patterns')
  113. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  114. flexmock(module).should_receive('_expand_home_directories').and_return(())
  115. flexmock(module).should_receive('_write_pattern_file').and_return(
  116. flexmock(name='/tmp/patterns')
  117. ).and_return(None)
  118. flexmock(module).should_receive('_make_pattern_flags').and_return(pattern_flags)
  119. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  120. flexmock(module).should_receive('execute_command').with_args(
  121. CREATE_COMMAND + pattern_flags, output_log_level=logging.INFO
  122. )
  123. module.create_archive(
  124. dry_run=False,
  125. repository='repo',
  126. location_config={
  127. 'source_directories': ['foo', 'bar'],
  128. 'repositories': ['repo'],
  129. 'patterns': ['pattern'],
  130. },
  131. storage_config={},
  132. )
  133. def test_create_archive_with_exclude_patterns_calls_borg_with_excludes():
  134. exclude_flags = ('--exclude-from', 'excludes')
  135. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  136. flexmock(module).should_receive('_expand_home_directories').and_return(('exclude',))
  137. flexmock(module).should_receive('_write_pattern_file').and_return(None).and_return(
  138. flexmock(name='/tmp/excludes')
  139. )
  140. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  141. flexmock(module).should_receive('_make_exclude_flags').and_return(exclude_flags)
  142. flexmock(module).should_receive('execute_command').with_args(
  143. CREATE_COMMAND + exclude_flags, output_log_level=logging.INFO
  144. )
  145. module.create_archive(
  146. dry_run=False,
  147. repository='repo',
  148. location_config={
  149. 'source_directories': ['foo', 'bar'],
  150. 'repositories': ['repo'],
  151. 'exclude_patterns': ['exclude'],
  152. },
  153. storage_config={},
  154. )
  155. def test_create_archive_with_log_info_calls_borg_with_info_parameter():
  156. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  157. flexmock(module).should_receive('_expand_home_directories').and_return(())
  158. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  159. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  160. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  161. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  162. flexmock(module).should_receive('execute_command').with_args(
  163. CREATE_COMMAND + ('--list', '--filter', 'AME-', '--info', '--stats'),
  164. output_log_level=logging.INFO,
  165. )
  166. insert_logging_mock(logging.INFO)
  167. module.create_archive(
  168. dry_run=False,
  169. repository='repo',
  170. location_config={
  171. 'source_directories': ['foo', 'bar'],
  172. 'repositories': ['repo'],
  173. 'exclude_patterns': None,
  174. },
  175. storage_config={},
  176. )
  177. def test_create_archive_with_log_info_and_json_suppresses_most_borg_output():
  178. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  179. flexmock(module).should_receive('_expand_home_directories').and_return(())
  180. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  181. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  182. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  183. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  184. flexmock(module).should_receive('execute_command').with_args(
  185. CREATE_COMMAND + ('--json',), output_log_level=None
  186. )
  187. insert_logging_mock(logging.INFO)
  188. module.create_archive(
  189. dry_run=False,
  190. repository='repo',
  191. location_config={
  192. 'source_directories': ['foo', 'bar'],
  193. 'repositories': ['repo'],
  194. 'exclude_patterns': None,
  195. },
  196. storage_config={},
  197. json=True,
  198. )
  199. def test_create_archive_with_log_debug_calls_borg_with_debug_parameter():
  200. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  201. flexmock(module).should_receive('_expand_home_directories').and_return(())
  202. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  203. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  204. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  205. flexmock(module).should_receive('execute_command').with_args(
  206. CREATE_COMMAND + ('--list', '--filter', 'AME-', '--stats', '--debug', '--show-rc'),
  207. output_log_level=logging.INFO,
  208. )
  209. insert_logging_mock(logging.DEBUG)
  210. module.create_archive(
  211. dry_run=False,
  212. repository='repo',
  213. location_config={
  214. 'source_directories': ['foo', 'bar'],
  215. 'repositories': ['repo'],
  216. 'exclude_patterns': None,
  217. },
  218. storage_config={},
  219. )
  220. def test_create_archive_with_log_debug_and_json_suppresses_most_borg_output():
  221. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  222. flexmock(module).should_receive('_expand_home_directories').and_return(())
  223. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  224. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  225. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  226. flexmock(module).should_receive('execute_command').with_args(
  227. CREATE_COMMAND + ('--json',), output_log_level=None
  228. )
  229. insert_logging_mock(logging.DEBUG)
  230. module.create_archive(
  231. dry_run=False,
  232. repository='repo',
  233. location_config={
  234. 'source_directories': ['foo', 'bar'],
  235. 'repositories': ['repo'],
  236. 'exclude_patterns': None,
  237. },
  238. storage_config={},
  239. json=True,
  240. )
  241. def test_create_archive_with_dry_run_calls_borg_with_dry_run_parameter():
  242. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  243. flexmock(module).should_receive('_expand_home_directories').and_return(())
  244. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  245. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  246. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  247. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  248. flexmock(module).should_receive('execute_command').with_args(
  249. CREATE_COMMAND + ('--dry-run',), output_log_level=logging.INFO
  250. )
  251. module.create_archive(
  252. dry_run=True,
  253. repository='repo',
  254. location_config={
  255. 'source_directories': ['foo', 'bar'],
  256. 'repositories': ['repo'],
  257. 'exclude_patterns': None,
  258. },
  259. storage_config={},
  260. )
  261. def test_create_archive_with_dry_run_and_log_info_calls_borg_without_stats_parameter():
  262. # --dry-run and --stats are mutually exclusive, see:
  263. # https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
  264. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  265. flexmock(module).should_receive('_expand_home_directories').and_return(())
  266. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  267. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  268. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  269. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  270. flexmock(module).should_receive('execute_command').with_args(
  271. CREATE_COMMAND + ('--list', '--filter', 'AME-', '--info', '--dry-run'),
  272. output_log_level=logging.INFO,
  273. )
  274. insert_logging_mock(logging.INFO)
  275. module.create_archive(
  276. dry_run=True,
  277. repository='repo',
  278. location_config={
  279. 'source_directories': ['foo', 'bar'],
  280. 'repositories': ['repo'],
  281. 'exclude_patterns': None,
  282. },
  283. storage_config={},
  284. )
  285. def test_create_archive_with_dry_run_and_log_debug_calls_borg_without_stats_parameter():
  286. # --dry-run and --stats are mutually exclusive, see:
  287. # https://borgbackup.readthedocs.io/en/stable/usage/create.html#description
  288. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  289. flexmock(module).should_receive('_expand_home_directories').and_return(())
  290. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  291. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  292. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  293. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  294. flexmock(module).should_receive('execute_command').with_args(
  295. CREATE_COMMAND + ('--list', '--filter', 'AME-', '--debug', '--show-rc', '--dry-run'),
  296. output_log_level=logging.INFO,
  297. )
  298. insert_logging_mock(logging.DEBUG)
  299. module.create_archive(
  300. dry_run=True,
  301. repository='repo',
  302. location_config={
  303. 'source_directories': ['foo', 'bar'],
  304. 'repositories': ['repo'],
  305. 'exclude_patterns': None,
  306. },
  307. storage_config={},
  308. )
  309. def test_create_archive_with_checkpoint_interval_calls_borg_with_checkpoint_interval_parameters():
  310. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  311. flexmock(module).should_receive('_expand_home_directories').and_return(())
  312. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  313. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  314. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  315. flexmock(module).should_receive('execute_command').with_args(
  316. CREATE_COMMAND + ('--checkpoint-interval', '600'), output_log_level=logging.INFO
  317. )
  318. module.create_archive(
  319. dry_run=False,
  320. repository='repo',
  321. location_config={
  322. 'source_directories': ['foo', 'bar'],
  323. 'repositories': ['repo'],
  324. 'exclude_patterns': None,
  325. },
  326. storage_config={'checkpoint_interval': 600},
  327. )
  328. def test_create_archive_with_chunker_params_calls_borg_with_chunker_params_parameters():
  329. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  330. flexmock(module).should_receive('_expand_home_directories').and_return(())
  331. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  332. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  333. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  334. flexmock(module).should_receive('execute_command').with_args(
  335. CREATE_COMMAND + ('--chunker-params', '1,2,3,4'), output_log_level=logging.INFO
  336. )
  337. module.create_archive(
  338. dry_run=False,
  339. repository='repo',
  340. location_config={
  341. 'source_directories': ['foo', 'bar'],
  342. 'repositories': ['repo'],
  343. 'exclude_patterns': None,
  344. },
  345. storage_config={'chunker_params': '1,2,3,4'},
  346. )
  347. def test_create_archive_with_compression_calls_borg_with_compression_parameters():
  348. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  349. flexmock(module).should_receive('_expand_home_directories').and_return(())
  350. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  351. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  352. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  353. flexmock(module).should_receive('execute_command').with_args(
  354. CREATE_COMMAND + ('--compression', 'rle'), output_log_level=logging.INFO
  355. )
  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={'compression': 'rle'},
  365. )
  366. def test_create_archive_with_remote_rate_limit_calls_borg_with_remote_ratelimit_parameters():
  367. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  368. flexmock(module).should_receive('_expand_home_directories').and_return(())
  369. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  370. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  371. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  372. flexmock(module).should_receive('execute_command').with_args(
  373. CREATE_COMMAND + ('--remote-ratelimit', '100'), output_log_level=logging.INFO
  374. )
  375. module.create_archive(
  376. dry_run=False,
  377. repository='repo',
  378. location_config={
  379. 'source_directories': ['foo', 'bar'],
  380. 'repositories': ['repo'],
  381. 'exclude_patterns': None,
  382. },
  383. storage_config={'remote_rate_limit': 100},
  384. )
  385. def test_create_archive_with_one_file_system_calls_borg_with_one_file_system_parameter():
  386. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  387. flexmock(module).should_receive('_expand_home_directories').and_return(())
  388. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  389. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  390. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  391. flexmock(module).should_receive('execute_command').with_args(
  392. CREATE_COMMAND + ('--one-file-system',), output_log_level=logging.INFO
  393. )
  394. module.create_archive(
  395. dry_run=False,
  396. repository='repo',
  397. location_config={
  398. 'source_directories': ['foo', 'bar'],
  399. 'repositories': ['repo'],
  400. 'one_file_system': True,
  401. 'exclude_patterns': None,
  402. },
  403. storage_config={},
  404. )
  405. def test_create_archive_with_numeric_owner_calls_borg_with_numeric_owner_parameter():
  406. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  407. flexmock(module).should_receive('_expand_home_directories').and_return(())
  408. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  409. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  410. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  411. flexmock(module).should_receive('execute_command').with_args(
  412. CREATE_COMMAND + ('--numeric-owner',), output_log_level=logging.INFO
  413. )
  414. module.create_archive(
  415. dry_run=False,
  416. repository='repo',
  417. location_config={
  418. 'source_directories': ['foo', 'bar'],
  419. 'repositories': ['repo'],
  420. 'numeric_owner': True,
  421. 'exclude_patterns': None,
  422. },
  423. storage_config={},
  424. )
  425. def test_create_archive_with_read_special_calls_borg_with_read_special_parameter():
  426. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  427. flexmock(module).should_receive('_expand_home_directories').and_return(())
  428. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  429. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  430. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  431. flexmock(module).should_receive('execute_command').with_args(
  432. CREATE_COMMAND + ('--read-special',), output_log_level=logging.INFO
  433. )
  434. module.create_archive(
  435. dry_run=False,
  436. repository='repo',
  437. location_config={
  438. 'source_directories': ['foo', 'bar'],
  439. 'repositories': ['repo'],
  440. 'read_special': True,
  441. 'exclude_patterns': None,
  442. },
  443. storage_config={},
  444. )
  445. @pytest.mark.parametrize('option_name', ('atime', 'ctime', 'birthtime', 'bsd_flags'))
  446. def test_create_archive_with_option_true_calls_borg_without_corresponding_parameter(option_name):
  447. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  448. flexmock(module).should_receive('_expand_home_directories').and_return(())
  449. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  450. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  451. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  452. flexmock(module).should_receive('execute_command').with_args(
  453. CREATE_COMMAND, output_log_level=logging.INFO
  454. )
  455. module.create_archive(
  456. dry_run=False,
  457. repository='repo',
  458. location_config={
  459. 'source_directories': ['foo', 'bar'],
  460. 'repositories': ['repo'],
  461. option_name: True,
  462. 'exclude_patterns': None,
  463. },
  464. storage_config={},
  465. )
  466. @pytest.mark.parametrize('option_name', ('atime', 'ctime', 'birthtime', 'bsd_flags'))
  467. def test_create_archive_with_option_false_calls_borg_with_corresponding_parameter(option_name):
  468. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  469. flexmock(module).should_receive('_expand_home_directories').and_return(())
  470. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  471. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  472. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  473. flexmock(module).should_receive('execute_command').with_args(
  474. CREATE_COMMAND + ('--no' + option_name.replace('_', ''),), output_log_level=logging.INFO
  475. )
  476. module.create_archive(
  477. dry_run=False,
  478. repository='repo',
  479. location_config={
  480. 'source_directories': ['foo', 'bar'],
  481. 'repositories': ['repo'],
  482. option_name: False,
  483. 'exclude_patterns': None,
  484. },
  485. storage_config={},
  486. )
  487. def test_create_archive_with_files_cache_calls_borg_with_files_cache_parameters():
  488. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  489. flexmock(module).should_receive('_expand_home_directories').and_return(())
  490. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  491. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  492. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  493. flexmock(module).should_receive('execute_command').with_args(
  494. CREATE_COMMAND + ('--files-cache', 'ctime,size'), output_log_level=logging.INFO
  495. )
  496. module.create_archive(
  497. dry_run=False,
  498. repository='repo',
  499. location_config={
  500. 'source_directories': ['foo', 'bar'],
  501. 'repositories': ['repo'],
  502. 'files_cache': 'ctime,size',
  503. 'exclude_patterns': None,
  504. },
  505. storage_config={},
  506. )
  507. def test_create_archive_with_local_path_calls_borg_via_local_path():
  508. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  509. flexmock(module).should_receive('_expand_home_directories').and_return(())
  510. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  511. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  512. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  513. flexmock(module).should_receive('execute_command').with_args(
  514. ('borg1',) + CREATE_COMMAND[1:], output_log_level=logging.INFO
  515. )
  516. module.create_archive(
  517. dry_run=False,
  518. repository='repo',
  519. location_config={
  520. 'source_directories': ['foo', 'bar'],
  521. 'repositories': ['repo'],
  522. 'exclude_patterns': None,
  523. },
  524. storage_config={},
  525. local_path='borg1',
  526. )
  527. def test_create_archive_with_remote_path_calls_borg_with_remote_path_parameters():
  528. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  529. flexmock(module).should_receive('_expand_home_directories').and_return(())
  530. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  531. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  532. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  533. flexmock(module).should_receive('execute_command').with_args(
  534. CREATE_COMMAND + ('--remote-path', 'borg1'), output_log_level=logging.INFO
  535. )
  536. module.create_archive(
  537. dry_run=False,
  538. repository='repo',
  539. location_config={
  540. 'source_directories': ['foo', 'bar'],
  541. 'repositories': ['repo'],
  542. 'exclude_patterns': None,
  543. },
  544. storage_config={},
  545. remote_path='borg1',
  546. )
  547. def test_create_archive_with_umask_calls_borg_with_umask_parameters():
  548. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  549. flexmock(module).should_receive('_expand_home_directories').and_return(())
  550. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  551. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  552. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  553. flexmock(module).should_receive('execute_command').with_args(
  554. CREATE_COMMAND + ('--umask', '740'), output_log_level=logging.INFO
  555. )
  556. module.create_archive(
  557. dry_run=False,
  558. repository='repo',
  559. location_config={
  560. 'source_directories': ['foo', 'bar'],
  561. 'repositories': ['repo'],
  562. 'exclude_patterns': None,
  563. },
  564. storage_config={'umask': 740},
  565. )
  566. def test_create_archive_with_lock_wait_calls_borg_with_lock_wait_parameters():
  567. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  568. flexmock(module).should_receive('_expand_home_directories').and_return(())
  569. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  570. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  571. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  572. flexmock(module).should_receive('execute_command').with_args(
  573. CREATE_COMMAND + ('--lock-wait', '5'), output_log_level=logging.INFO
  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={'lock_wait': 5},
  584. )
  585. def test_create_archive_with_stats_calls_borg_with_stats_parameter():
  586. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  587. flexmock(module).should_receive('_expand_home_directories').and_return(())
  588. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  589. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  590. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  591. flexmock(module).should_receive('execute_command').with_args(
  592. CREATE_COMMAND + ('--stats',), output_log_level=logging.WARNING
  593. )
  594. module.create_archive(
  595. dry_run=False,
  596. repository='repo',
  597. location_config={
  598. 'source_directories': ['foo', 'bar'],
  599. 'repositories': ['repo'],
  600. 'exclude_patterns': None,
  601. },
  602. storage_config={},
  603. stats=True,
  604. )
  605. def test_create_archive_with_json_calls_borg_with_json_parameter():
  606. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  607. flexmock(module).should_receive('_expand_home_directories').and_return(())
  608. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  609. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  610. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  611. flexmock(module).should_receive('execute_command').with_args(
  612. CREATE_COMMAND + ('--json',), output_log_level=None
  613. ).and_return('[]')
  614. json_output = module.create_archive(
  615. dry_run=False,
  616. repository='repo',
  617. location_config={
  618. 'source_directories': ['foo', 'bar'],
  619. 'repositories': ['repo'],
  620. 'exclude_patterns': None,
  621. },
  622. storage_config={},
  623. json=True,
  624. )
  625. assert json_output == '[]'
  626. def test_create_archive_with_stats_and_json_calls_borg_without_stats_parameter():
  627. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  628. flexmock(module).should_receive('_expand_home_directories').and_return(())
  629. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  630. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  631. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  632. flexmock(module).should_receive('execute_command').with_args(
  633. CREATE_COMMAND + ('--json',), output_log_level=None
  634. ).and_return('[]')
  635. json_output = module.create_archive(
  636. dry_run=False,
  637. repository='repo',
  638. location_config={
  639. 'source_directories': ['foo', 'bar'],
  640. 'repositories': ['repo'],
  641. 'exclude_patterns': None,
  642. },
  643. storage_config={},
  644. json=True,
  645. stats=True,
  646. )
  647. assert json_output == '[]'
  648. def test_create_archive_with_source_directories_glob_expands():
  649. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food'))
  650. flexmock(module).should_receive('_expand_home_directories').and_return(())
  651. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  652. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  653. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  654. flexmock(module).should_receive('execute_command').with_args(
  655. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  656. output_log_level=logging.INFO,
  657. )
  658. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return(['foo', 'food'])
  659. module.create_archive(
  660. dry_run=False,
  661. repository='repo',
  662. location_config={
  663. 'source_directories': ['foo*'],
  664. 'repositories': ['repo'],
  665. 'exclude_patterns': None,
  666. },
  667. storage_config={},
  668. )
  669. def test_create_archive_with_non_matching_source_directories_glob_passes_through():
  670. flexmock(module).should_receive('_expand_directories').and_return(('foo*',))
  671. flexmock(module).should_receive('_expand_home_directories').and_return(())
  672. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  673. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  674. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  675. flexmock(module).should_receive('execute_command').with_args(
  676. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo*'),
  677. output_log_level=logging.INFO,
  678. )
  679. flexmock(module.glob).should_receive('glob').with_args('foo*').and_return([])
  680. module.create_archive(
  681. dry_run=False,
  682. repository='repo',
  683. location_config={
  684. 'source_directories': ['foo*'],
  685. 'repositories': ['repo'],
  686. 'exclude_patterns': None,
  687. },
  688. storage_config={},
  689. )
  690. def test_create_archive_with_glob_calls_borg_with_expanded_directories():
  691. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'food'))
  692. flexmock(module).should_receive('_expand_home_directories').and_return(())
  693. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  694. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  695. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  696. flexmock(module).should_receive('execute_command').with_args(
  697. ('borg', 'create', 'repo::{}'.format(DEFAULT_ARCHIVE_NAME), 'foo', 'food'),
  698. output_log_level=logging.INFO,
  699. )
  700. module.create_archive(
  701. dry_run=False,
  702. repository='repo',
  703. location_config={
  704. 'source_directories': ['foo*'],
  705. 'repositories': ['repo'],
  706. 'exclude_patterns': None,
  707. },
  708. storage_config={},
  709. )
  710. def test_create_archive_with_archive_name_format_calls_borg_with_archive_name():
  711. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  712. flexmock(module).should_receive('_expand_home_directories').and_return(())
  713. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  714. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  715. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  716. flexmock(module).should_receive('execute_command').with_args(
  717. ('borg', 'create', 'repo::ARCHIVE_NAME', 'foo', 'bar'), output_log_level=logging.INFO
  718. )
  719. module.create_archive(
  720. dry_run=False,
  721. repository='repo',
  722. location_config={
  723. 'source_directories': ['foo', 'bar'],
  724. 'repositories': ['repo'],
  725. 'exclude_patterns': None,
  726. },
  727. storage_config={'archive_name_format': 'ARCHIVE_NAME'},
  728. )
  729. def test_create_archive_with_archive_name_format_accepts_borg_placeholders():
  730. flexmock(module).should_receive('_expand_directories').and_return(('foo', 'bar'))
  731. flexmock(module).should_receive('_expand_home_directories').and_return(())
  732. flexmock(module).should_receive('_write_pattern_file').and_return(None)
  733. flexmock(module).should_receive('_make_pattern_flags').and_return(())
  734. flexmock(module).should_receive('_make_exclude_flags').and_return(())
  735. flexmock(module).should_receive('execute_command').with_args(
  736. ('borg', 'create', 'repo::Documents_{hostname}-{now}', 'foo', 'bar'),
  737. output_log_level=logging.INFO,
  738. )
  739. module.create_archive(
  740. dry_run=False,
  741. repository='repo',
  742. location_config={
  743. 'source_directories': ['foo', 'bar'],
  744. 'repositories': ['repo'],
  745. 'exclude_patterns': None,
  746. },
  747. storage_config={'archive_name_format': 'Documents_{hostname}-{now}'},
  748. )