test_arguments.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. import pytest
  2. from flexmock import flexmock
  3. from borgmatic.commands import arguments as module
  4. def test_make_argument_description_with_array_adds_example():
  5. assert (
  6. module.make_argument_description(
  7. schema={
  8. 'description': 'Thing.',
  9. 'type': 'array',
  10. 'example': [1, '- foo', {'bar': 'baz'}],
  11. },
  12. flag_name='flag',
  13. )
  14. == 'Thing. Example value: "[1, \'- foo\', bar: baz]"'
  15. )
  16. def test_add_array_element_arguments_adds_arguments_for_array_index_flags():
  17. parser = module.ArgumentParser(allow_abbrev=False, add_help=False)
  18. arguments_group = parser.add_argument_group('arguments')
  19. arguments_group.add_argument(
  20. '--foo[0].val',
  21. action='store_true',
  22. dest='--foo[0].val',
  23. )
  24. flexmock(arguments_group).should_receive('add_argument').with_args(
  25. '--foo[25].val',
  26. action='store_true',
  27. choices=object,
  28. default=object,
  29. dest='foo[25].val',
  30. nargs=object,
  31. required=object,
  32. type=object,
  33. ).once()
  34. module.add_array_element_arguments(
  35. arguments_group=arguments_group,
  36. unparsed_arguments=('--foo[25].val', 'fooval', '--bar[1].val', 'barval'),
  37. flag_name='foo[0].val',
  38. )
  39. def test_add_arguments_from_schema_with_nested_object_adds_flag_for_each_option():
  40. parser = module.ArgumentParser(allow_abbrev=False, add_help=False)
  41. arguments_group = parser.add_argument_group('arguments')
  42. flexmock(arguments_group).should_receive('add_argument').with_args(
  43. '--foo.bar',
  44. type=int,
  45. metavar='BAR',
  46. help='help 1',
  47. ).once()
  48. flexmock(arguments_group).should_receive('add_argument').with_args(
  49. '--foo.baz',
  50. type=str,
  51. metavar='BAZ',
  52. help='help 2',
  53. ).once()
  54. module.add_arguments_from_schema(
  55. arguments_group=arguments_group,
  56. schema={
  57. 'type': 'object',
  58. 'properties': {
  59. 'foo': {
  60. 'type': 'object',
  61. 'properties': {
  62. 'bar': {'type': 'integer', 'description': 'help 1'},
  63. 'baz': {'type': 'string', 'description': 'help 2'},
  64. }
  65. }
  66. }
  67. },
  68. unparsed_arguments=(),
  69. )
  70. def test_add_arguments_from_schema_with_array_and_nested_object_adds_multiple_flags():
  71. parser = module.ArgumentParser(allow_abbrev=False, add_help=False)
  72. arguments_group = parser.add_argument_group('arguments')
  73. flexmock(arguments_group).should_receive('add_argument').with_args(
  74. '--foo[0].bar',
  75. type=int,
  76. metavar='BAR',
  77. help=object,
  78. ).once()
  79. flexmock(arguments_group).should_receive('add_argument').with_args(
  80. '--foo',
  81. type=str,
  82. metavar='FOO',
  83. help='help 2',
  84. ).once()
  85. module.add_arguments_from_schema(
  86. arguments_group=arguments_group,
  87. schema={
  88. 'type': 'object',
  89. 'properties': {
  90. 'foo': {
  91. 'type': 'array',
  92. 'items': {
  93. 'type': 'object',
  94. 'properties': {
  95. 'bar': {
  96. 'type': 'integer',
  97. 'description': 'help 1',
  98. }
  99. }
  100. },
  101. 'description': 'help 2',
  102. }
  103. }
  104. },
  105. unparsed_arguments=(),
  106. )
  107. def test_parse_arguments_with_no_arguments_uses_defaults():
  108. config_paths = ['default']
  109. flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
  110. arguments = module.parse_arguments({})
  111. global_arguments = arguments['global']
  112. assert global_arguments.config_paths == config_paths
  113. assert global_arguments.verbosity == 0
  114. assert global_arguments.syslog_verbosity == -2
  115. assert global_arguments.log_file_verbosity == 1
  116. assert global_arguments.monitoring_verbosity == 1
  117. def test_parse_arguments_with_multiple_config_flags_parses_as_list():
  118. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  119. arguments = module.parse_arguments({}, '--config', 'myconfig', '--config', 'otherconfig')
  120. global_arguments = arguments['global']
  121. assert global_arguments.config_paths == ['myconfig', 'otherconfig']
  122. assert global_arguments.verbosity == 0
  123. assert global_arguments.syslog_verbosity == -2
  124. assert global_arguments.log_file_verbosity == 1
  125. assert global_arguments.monitoring_verbosity == 1
  126. def test_parse_arguments_with_action_after_config_path_omits_action():
  127. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  128. arguments = module.parse_arguments({}, '--config', 'myconfig', 'list', '--json')
  129. global_arguments = arguments['global']
  130. assert global_arguments.config_paths == ['myconfig']
  131. assert 'list' in arguments
  132. assert arguments['list'].json
  133. def test_parse_arguments_with_action_after_config_path_omits_aliased_action():
  134. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  135. arguments = module.parse_arguments(
  136. {}, '--config', 'myconfig', 'init', '--encryption', 'repokey'
  137. )
  138. global_arguments = arguments['global']
  139. assert global_arguments.config_paths == ['myconfig']
  140. assert 'repo-create' in arguments
  141. assert arguments['repo-create'].encryption_mode == 'repokey'
  142. def test_parse_arguments_with_action_and_positional_arguments_after_config_path_omits_action_and_arguments():
  143. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  144. arguments = module.parse_arguments({}, '--config', 'myconfig', 'borg', 'key', 'export')
  145. global_arguments = arguments['global']
  146. assert global_arguments.config_paths == ['myconfig']
  147. assert 'borg' in arguments
  148. assert arguments['borg'].options == ['key', 'export']
  149. def test_parse_arguments_with_verbosity_overrides_default():
  150. config_paths = ['default']
  151. flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
  152. arguments = module.parse_arguments({}, '--verbosity', '1')
  153. global_arguments = arguments['global']
  154. assert global_arguments.config_paths == config_paths
  155. assert global_arguments.verbosity == 1
  156. assert global_arguments.syslog_verbosity == -2
  157. assert global_arguments.log_file_verbosity == 1
  158. assert global_arguments.monitoring_verbosity == 1
  159. def test_parse_arguments_with_syslog_verbosity_overrides_default():
  160. config_paths = ['default']
  161. flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
  162. arguments = module.parse_arguments({}, '--syslog-verbosity', '2')
  163. global_arguments = arguments['global']
  164. assert global_arguments.config_paths == config_paths
  165. assert global_arguments.verbosity == 0
  166. assert global_arguments.syslog_verbosity == 2
  167. assert global_arguments.log_file_verbosity == 1
  168. assert global_arguments.monitoring_verbosity == 1
  169. def test_parse_arguments_with_log_file_verbosity_overrides_default():
  170. config_paths = ['default']
  171. flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths)
  172. arguments = module.parse_arguments({}, '--log-file-verbosity', '-1')
  173. global_arguments = arguments['global']
  174. assert global_arguments.config_paths == config_paths
  175. assert global_arguments.verbosity == 0
  176. assert global_arguments.syslog_verbosity == -2
  177. assert global_arguments.log_file_verbosity == -1
  178. assert global_arguments.monitoring_verbosity == 1
  179. def test_parse_arguments_with_single_override_parses():
  180. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  181. arguments = module.parse_arguments({}, '--override', 'foo.bar=baz')
  182. global_arguments = arguments['global']
  183. assert global_arguments.overrides == ['foo.bar=baz']
  184. def test_parse_arguments_with_multiple_overrides_flags_parses():
  185. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  186. arguments = module.parse_arguments(
  187. {}, '--override', 'foo.bar=baz', '--override', 'foo.quux=7', '--override', 'this.that=8'
  188. )
  189. global_arguments = arguments['global']
  190. assert global_arguments.overrides == ['foo.bar=baz', 'foo.quux=7', 'this.that=8']
  191. def test_parse_arguments_with_list_json_overrides_default():
  192. arguments = module.parse_arguments({}, 'list', '--json')
  193. assert 'list' in arguments
  194. assert arguments['list'].json is True
  195. def test_parse_arguments_with_no_actions_defaults_to_all_actions_enabled():
  196. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  197. arguments = module.parse_arguments({})
  198. assert 'prune' in arguments
  199. assert 'create' in arguments
  200. assert 'check' in arguments
  201. def test_parse_arguments_with_no_actions_passes_argument_to_relevant_actions():
  202. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  203. arguments = module.parse_arguments({}, '--stats', '--list')
  204. assert 'prune' in arguments
  205. assert arguments['prune'].stats
  206. assert arguments['prune'].list_archives
  207. assert 'create' in arguments
  208. assert arguments['create'].stats
  209. assert arguments['create'].list_files
  210. assert 'check' in arguments
  211. def test_parse_arguments_with_help_and_no_actions_shows_global_help(capsys):
  212. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  213. with pytest.raises(SystemExit) as exit:
  214. module.parse_arguments({}, '--help')
  215. assert exit.value.code == 0
  216. captured = capsys.readouterr()
  217. assert 'global arguments:' in captured.out
  218. assert 'actions:' in captured.out
  219. def test_parse_arguments_with_help_and_action_shows_action_help(capsys):
  220. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  221. with pytest.raises(SystemExit) as exit:
  222. module.parse_arguments({}, 'create', '--help')
  223. assert exit.value.code == 0
  224. captured = capsys.readouterr()
  225. assert 'global arguments:' not in captured.out
  226. assert 'actions:' not in captured.out
  227. assert 'create arguments:' in captured.out
  228. def test_parse_arguments_with_action_before_global_options_parses_options():
  229. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  230. arguments = module.parse_arguments({}, 'prune', '--verbosity', '2')
  231. assert 'prune' in arguments
  232. assert arguments['global'].verbosity == 2
  233. def test_parse_arguments_with_global_options_before_action_parses_options():
  234. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  235. arguments = module.parse_arguments({}, '--verbosity', '2', 'prune')
  236. assert 'prune' in arguments
  237. assert arguments['global'].verbosity == 2
  238. def test_parse_arguments_with_prune_action_leaves_other_actions_disabled():
  239. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  240. arguments = module.parse_arguments({}, 'prune')
  241. assert 'prune' in arguments
  242. assert 'create' not in arguments
  243. assert 'check' not in arguments
  244. def test_parse_arguments_with_multiple_actions_leaves_other_action_disabled():
  245. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  246. arguments = module.parse_arguments({}, 'create', 'check')
  247. assert 'prune' not in arguments
  248. assert 'create' in arguments
  249. assert 'check' in arguments
  250. def test_parse_arguments_disallows_invalid_argument():
  251. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  252. with pytest.raises(ValueError):
  253. module.parse_arguments({}, '--posix-me-harder')
  254. def test_parse_arguments_disallows_encryption_mode_without_init():
  255. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  256. with pytest.raises(ValueError):
  257. module.parse_arguments({}, '--config', 'myconfig', '--encryption', 'repokey')
  258. def test_parse_arguments_allows_encryption_mode_with_init():
  259. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  260. module.parse_arguments({}, '--config', 'myconfig', 'init', '--encryption', 'repokey')
  261. def test_parse_arguments_disallows_append_only_without_init():
  262. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  263. with pytest.raises(ValueError):
  264. module.parse_arguments({}, '--config', 'myconfig', '--append-only')
  265. def test_parse_arguments_disallows_storage_quota_without_init():
  266. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  267. with pytest.raises(ValueError):
  268. module.parse_arguments({}, '--config', 'myconfig', '--storage-quota', '5G')
  269. def test_parse_arguments_allows_init_and_prune():
  270. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  271. module.parse_arguments({}, '--config', 'myconfig', 'init', '--encryption', 'repokey', 'prune')
  272. def test_parse_arguments_allows_init_and_create():
  273. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  274. module.parse_arguments({}, '--config', 'myconfig', 'init', '--encryption', 'repokey', 'create')
  275. def test_parse_arguments_allows_repository_with_extract():
  276. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  277. module.parse_arguments(
  278. {}, '--config', 'myconfig', 'extract', '--repository', 'test.borg', '--archive', 'test'
  279. )
  280. def test_parse_arguments_allows_repository_with_mount():
  281. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  282. module.parse_arguments(
  283. {},
  284. '--config',
  285. 'myconfig',
  286. 'mount',
  287. '--repository',
  288. 'test.borg',
  289. '--archive',
  290. 'test',
  291. '--mount-point',
  292. '/mnt',
  293. )
  294. def test_parse_arguments_allows_repository_with_list():
  295. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  296. module.parse_arguments({}, '--config', 'myconfig', 'list', '--repository', 'test.borg')
  297. def test_parse_arguments_disallows_archive_unless_action_consumes_it():
  298. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  299. with pytest.raises(ValueError):
  300. module.parse_arguments({}, '--config', 'myconfig', '--archive', 'test')
  301. def test_parse_arguments_disallows_paths_unless_action_consumes_it():
  302. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  303. with pytest.raises(ValueError):
  304. module.parse_arguments({}, '--config', 'myconfig', '--path', 'test')
  305. def test_parse_arguments_disallows_other_actions_with_config_bootstrap():
  306. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  307. with pytest.raises(ValueError):
  308. module.parse_arguments({}, 'config', 'bootstrap', '--repository', 'test.borg', 'list')
  309. def test_parse_arguments_allows_archive_with_extract():
  310. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  311. module.parse_arguments({}, '--config', 'myconfig', 'extract', '--archive', 'test')
  312. def test_parse_arguments_allows_archive_with_mount():
  313. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  314. module.parse_arguments(
  315. {}, '--config', 'myconfig', 'mount', '--archive', 'test', '--mount-point', '/mnt'
  316. )
  317. def test_parse_arguments_allows_archive_with_restore():
  318. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  319. module.parse_arguments({}, '--config', 'myconfig', 'restore', '--archive', 'test')
  320. def test_parse_arguments_allows_archive_with_list():
  321. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  322. module.parse_arguments({}, '--config', 'myconfig', 'list', '--archive', 'test')
  323. def test_parse_arguments_requires_archive_with_extract():
  324. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  325. with pytest.raises(SystemExit):
  326. module.parse_arguments({}, '--config', 'myconfig', 'extract')
  327. def test_parse_arguments_requires_archive_with_restore():
  328. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  329. with pytest.raises(SystemExit):
  330. module.parse_arguments({}, '--config', 'myconfig', 'restore')
  331. def test_parse_arguments_requires_mount_point_with_mount():
  332. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  333. with pytest.raises(SystemExit):
  334. module.parse_arguments({}, '--config', 'myconfig', 'mount', '--archive', 'test')
  335. def test_parse_arguments_requires_mount_point_with_umount():
  336. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  337. with pytest.raises(SystemExit):
  338. module.parse_arguments({}, '--config', 'myconfig', 'umount')
  339. def test_parse_arguments_allows_progress_before_create():
  340. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  341. module.parse_arguments({}, '--progress', 'create', 'list')
  342. def test_parse_arguments_allows_progress_after_create():
  343. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  344. module.parse_arguments({}, 'create', '--progress', 'list')
  345. def test_parse_arguments_allows_progress_and_extract():
  346. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  347. module.parse_arguments({}, '--progress', 'extract', '--archive', 'test', 'list')
  348. def test_parse_arguments_disallows_progress_without_create():
  349. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  350. with pytest.raises(ValueError):
  351. module.parse_arguments({}, '--progress', 'list')
  352. def test_parse_arguments_with_stats_and_create_flags_does_not_raise():
  353. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  354. module.parse_arguments({}, '--stats', 'create', 'list')
  355. def test_parse_arguments_with_stats_and_prune_flags_does_not_raise():
  356. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  357. module.parse_arguments({}, '--stats', 'prune', 'list')
  358. def test_parse_arguments_with_stats_flag_but_no_create_or_prune_flag_raises_value_error():
  359. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  360. with pytest.raises(ValueError):
  361. module.parse_arguments({}, '--stats', 'list')
  362. def test_parse_arguments_with_list_and_create_flags_does_not_raise():
  363. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  364. module.parse_arguments({}, '--list', 'create')
  365. def test_parse_arguments_with_list_and_prune_flags_does_not_raise():
  366. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  367. module.parse_arguments({}, '--list', 'prune')
  368. def test_parse_arguments_with_list_flag_but_no_relevant_action_raises_value_error():
  369. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  370. with pytest.raises(ValueError):
  371. module.parse_arguments({}, '--list', 'repo-create')
  372. def test_parse_arguments_disallows_list_with_progress_for_create_action():
  373. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  374. with pytest.raises(ValueError):
  375. module.parse_arguments({}, 'create', '--list', '--progress')
  376. def test_parse_arguments_disallows_list_with_json_for_create_action():
  377. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  378. with pytest.raises(ValueError):
  379. module.parse_arguments({}, 'create', '--list', '--json')
  380. def test_parse_arguments_allows_json_with_list_or_info():
  381. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  382. module.parse_arguments({}, 'list', '--json')
  383. module.parse_arguments({}, 'info', '--json')
  384. def test_parse_arguments_disallows_json_with_both_list_and_info():
  385. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  386. with pytest.raises(ValueError):
  387. module.parse_arguments({}, 'list', 'info', '--json')
  388. def test_parse_arguments_disallows_json_with_both_list_and_repo_info():
  389. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  390. with pytest.raises(ValueError):
  391. module.parse_arguments({}, 'list', 'repo-info', '--json')
  392. def test_parse_arguments_disallows_json_with_both_repo_info_and_info():
  393. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  394. with pytest.raises(ValueError):
  395. module.parse_arguments({}, 'repo-info', 'info', '--json')
  396. def test_parse_arguments_disallows_transfer_with_both_archive_and_match_archives():
  397. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  398. with pytest.raises(ValueError):
  399. module.parse_arguments(
  400. {},
  401. 'transfer',
  402. '--source-repository',
  403. 'source.borg',
  404. '--archive',
  405. 'foo',
  406. '--match-archives',
  407. 'sh:*bar',
  408. )
  409. def test_parse_arguments_disallows_list_with_both_prefix_and_match_archives():
  410. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  411. with pytest.raises(ValueError):
  412. module.parse_arguments({}, 'list', '--prefix', 'foo', '--match-archives', 'sh:*bar')
  413. def test_parse_arguments_disallows_repo_list_with_both_prefix_and_match_archives():
  414. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  415. with pytest.raises(ValueError):
  416. module.parse_arguments({}, 'repo-list', '--prefix', 'foo', '--match-archives', 'sh:*bar')
  417. def test_parse_arguments_disallows_info_with_both_archive_and_match_archives():
  418. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  419. with pytest.raises(ValueError):
  420. module.parse_arguments({}, 'info', '--archive', 'foo', '--match-archives', 'sh:*bar')
  421. def test_parse_arguments_disallows_info_with_both_archive_and_prefix():
  422. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  423. with pytest.raises(ValueError):
  424. module.parse_arguments({}, 'info', '--archive', 'foo', '--prefix', 'bar')
  425. def test_parse_arguments_disallows_info_with_both_prefix_and_match_archives():
  426. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  427. with pytest.raises(ValueError):
  428. module.parse_arguments({}, 'info', '--prefix', 'foo', '--match-archives', 'sh:*bar')
  429. def test_parse_arguments_check_only_extract_does_not_raise_extract_subparser_error():
  430. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  431. module.parse_arguments({}, 'check', '--only', 'extract')
  432. def test_parse_arguments_extract_archive_check_does_not_raise_check_subparser_error():
  433. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  434. module.parse_arguments({}, 'extract', '--archive', 'check')
  435. def test_parse_arguments_extract_with_check_only_extract_does_not_raise():
  436. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  437. module.parse_arguments({}, 'extract', '--archive', 'name', 'check', '--only', 'extract')
  438. def test_parse_arguments_bootstrap_without_config_errors():
  439. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  440. with pytest.raises(ValueError):
  441. module.parse_arguments({}, 'bootstrap')
  442. def test_parse_arguments_config_with_no_subaction_errors():
  443. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  444. with pytest.raises(ValueError):
  445. module.parse_arguments({}, 'config')
  446. def test_parse_arguments_config_with_help_shows_config_help(capsys):
  447. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  448. with pytest.raises(SystemExit) as exit:
  449. module.parse_arguments({}, 'config', '--help')
  450. assert exit.value.code == 0
  451. captured = capsys.readouterr()
  452. assert 'global arguments:' not in captured.out
  453. assert 'config arguments:' in captured.out
  454. assert 'config sub-actions:' in captured.out
  455. def test_parse_arguments_config_with_subaction_but_missing_flags_errors():
  456. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  457. with pytest.raises(SystemExit) as exit:
  458. module.parse_arguments({}, 'config', 'bootstrap')
  459. assert exit.value.code == 2
  460. def test_parse_arguments_config_with_subaction_and_help_shows_subaction_help(capsys):
  461. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  462. with pytest.raises(SystemExit) as exit:
  463. module.parse_arguments({}, 'config', 'bootstrap', '--help')
  464. assert exit.value.code == 0
  465. captured = capsys.readouterr()
  466. assert 'config bootstrap arguments:' in captured.out
  467. def test_parse_arguments_config_with_subaction_and_required_flags_does_not_raise():
  468. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  469. module.parse_arguments({}, 'config', 'bootstrap', '--repository', 'repo.borg')
  470. def test_parse_arguments_config_with_subaction_and_global_flags_at_start_does_not_raise():
  471. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  472. module.parse_arguments(
  473. {}, '--verbosity', '1', 'config', 'bootstrap', '--repository', 'repo.borg'
  474. )
  475. def test_parse_arguments_config_with_subaction_and_global_flags_at_end_does_not_raise():
  476. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  477. module.parse_arguments(
  478. {}, 'config', 'bootstrap', '--repository', 'repo.borg', '--verbosity', '1'
  479. )
  480. def test_parse_arguments_config_with_subaction_and_explicit_config_file_does_not_raise():
  481. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  482. module.parse_arguments(
  483. {}, 'config', 'bootstrap', '--repository', 'repo.borg', '--config', 'test.yaml'
  484. )
  485. def test_parse_arguments_with_borg_action_and_dry_run_raises():
  486. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  487. with pytest.raises(ValueError):
  488. module.parse_arguments({}, '--dry-run', 'borg', 'list')
  489. def test_parse_arguments_with_borg_action_and_no_dry_run_does_not_raise():
  490. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  491. module.parse_arguments({}, 'borg', 'list')
  492. def test_parse_arguments_with_argument_from_schema_does_not_raise():
  493. flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
  494. module.parse_arguments(
  495. {
  496. 'type': 'object',
  497. 'properties': {'foo': {'type': 'object', 'properties': {'bar': {'type': 'integer'}}}},
  498. },
  499. '--foo.bar',
  500. '3',
  501. )