test_flags.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. import pytest
  2. from flexmock import flexmock
  3. from borgmatic.borg import flags as module
  4. def test_make_flags_formats_string_value():
  5. assert module.make_flags('foo', 'bar') == ('--foo', 'bar')
  6. def test_make_flags_formats_integer_value():
  7. assert module.make_flags('foo', 3) == ('--foo', '3')
  8. def test_make_flags_formats_true_value():
  9. assert module.make_flags('foo', True) == ('--foo',)
  10. def test_make_flags_omits_false_value():
  11. assert module.make_flags('foo', False) == ()
  12. def test_make_flags_formats_name_with_underscore():
  13. assert module.make_flags('posix_me_harder', 'okay') == ('--posix-me-harder', 'okay')
  14. def test_make_flags_from_arguments_flattens_and_sorts_multiple_arguments():
  15. flexmock(module).should_receive('make_flags').with_args('foo', 'bar').and_return(('foo', 'bar'))
  16. flexmock(module).should_receive('make_flags').with_args('baz', 'quux').and_return(
  17. ('baz', 'quux')
  18. )
  19. arguments = flexmock(foo='bar', baz='quux')
  20. assert module.make_flags_from_arguments(arguments) == ('baz', 'quux', 'foo', 'bar')
  21. def test_make_flags_from_arguments_excludes_underscored_argument_names():
  22. flexmock(module).should_receive('make_flags').with_args('foo', 'bar').and_return(('foo', 'bar'))
  23. arguments = flexmock(foo='bar', _baz='quux')
  24. assert module.make_flags_from_arguments(arguments) == ('foo', 'bar')
  25. def test_make_flags_from_arguments_omits_excludes():
  26. flexmock(module).should_receive('make_flags').with_args('foo', 'bar').and_return(('foo', 'bar'))
  27. arguments = flexmock(foo='bar', baz='quux')
  28. assert module.make_flags_from_arguments(arguments, excludes=('baz', 'other')) == ('foo', 'bar')
  29. def test_make_repository_flags_with_borg_features_includes_repo_flag():
  30. flexmock(module.feature).should_receive('available').and_return(True)
  31. assert module.make_repository_flags(repository_path='repo', local_borg_version='1.2.3') == (
  32. '--repo',
  33. 'repo',
  34. )
  35. def test_make_repository_flags_without_borg_features_includes_omits_flag():
  36. flexmock(module.feature).should_receive('available').and_return(False)
  37. assert module.make_repository_flags(repository_path='repo', local_borg_version='1.2.3') == (
  38. 'repo',
  39. )
  40. def test_make_repository_archive_flags_with_borg_features_separates_repository_and_archive():
  41. flexmock(module.feature).should_receive('available').and_return(True)
  42. assert module.make_repository_archive_flags(
  43. repository_path='repo', archive='archive', local_borg_version='1.2.3'
  44. ) == (
  45. '--repo',
  46. 'repo',
  47. 'archive',
  48. )
  49. def test_make_repository_archive_flags_with_borg_features_joins_repository_and_archive():
  50. flexmock(module.feature).should_receive('available').and_return(False)
  51. assert module.make_repository_archive_flags(
  52. repository_path='repo', archive='archive', local_borg_version='1.2.3'
  53. ) == ('repo::archive',)
  54. def test_get_default_archive_name_format_with_archive_series_feature_uses_series_archive_name_format():
  55. flexmock(module.feature).should_receive('available').and_return(True)
  56. assert (
  57. module.get_default_archive_name_format(local_borg_version='1.2.3')
  58. == module.DEFAULT_ARCHIVE_NAME_FORMAT_WITH_SERIES
  59. )
  60. def test_get_default_archive_name_format_without_archive_series_feature_uses_non_series_archive_name_format():
  61. flexmock(module.feature).should_receive('available').and_return(False)
  62. assert (
  63. module.get_default_archive_name_format(local_borg_version='1.2.3')
  64. == module.DEFAULT_ARCHIVE_NAME_FORMAT_WITHOUT_SERIES
  65. )
  66. @pytest.mark.parametrize(
  67. 'match_archives,archive_name_format,feature_available,expected_result',
  68. (
  69. (None, None, True, ('--match-archives', 'sh:{hostname}-*')), # noqa: FS003
  70. (None, '', True, ('--match-archives', 'sh:{hostname}-*')), # noqa: FS003
  71. (
  72. 're:foo-.*',
  73. '{hostname}-{now}', # noqa: FS003
  74. True,
  75. ('--match-archives', 're:foo-.*'),
  76. ),
  77. (
  78. 'sh:foo-*',
  79. '{hostname}-{now}', # noqa: FS003
  80. False,
  81. ('--glob-archives', 'foo-*'),
  82. ),
  83. (
  84. 'foo-*',
  85. '{hostname}-{now}', # noqa: FS003
  86. False,
  87. ('--glob-archives', 'foo-*'),
  88. ),
  89. (
  90. None,
  91. '{hostname}-docs-{now}', # noqa: FS003
  92. True,
  93. ('--match-archives', 'sh:{hostname}-docs-*'), # noqa: FS003
  94. ),
  95. (
  96. None,
  97. '{utcnow}-docs-{user}', # noqa: FS003
  98. True,
  99. ('--match-archives', 'sh:*-docs-{user}'), # noqa: FS003
  100. ),
  101. (None, '{fqdn}-{pid}', True, ('--match-archives', 'sh:{fqdn}-*')), # noqa: FS003
  102. (
  103. None,
  104. 'stuff-{now:%Y-%m-%dT%H:%M:%S.%f}', # noqa: FS003
  105. True,
  106. ('--match-archives', 'sh:stuff-*'),
  107. ),
  108. (
  109. None,
  110. '{hostname}-docs-{now}', # noqa: FS003
  111. False,
  112. ('--glob-archives', '{hostname}-docs-*'), # noqa: FS003
  113. ),
  114. (
  115. None,
  116. '{now}', # noqa: FS003
  117. False,
  118. (),
  119. ),
  120. (
  121. None,
  122. '{now}', # noqa: FS003
  123. True,
  124. (),
  125. ),
  126. (
  127. None,
  128. '{utcnow}-docs-{user}', # noqa: FS003
  129. False,
  130. ('--glob-archives', '*-docs-{user}'), # noqa: FS003
  131. ),
  132. (
  133. '*',
  134. '{now}', # noqa: FS003
  135. True,
  136. (),
  137. ),
  138. (
  139. '*',
  140. '{now}', # noqa: FS003
  141. False,
  142. (),
  143. ),
  144. (
  145. 're:.*',
  146. '{now}', # noqa: FS003
  147. True,
  148. (),
  149. ),
  150. (
  151. 'sh:*',
  152. '{now}', # noqa: FS003
  153. True,
  154. (),
  155. ),
  156. (
  157. 'abcdefabcdef',
  158. None,
  159. True,
  160. ('--match-archives', 'aid:abcdefabcdef'),
  161. ),
  162. (
  163. 'aid:abcdefabcdef',
  164. None,
  165. True,
  166. ('--match-archives', 'aid:abcdefabcdef'),
  167. ),
  168. ),
  169. )
  170. def test_make_match_archives_flags_makes_flags_with_globs(
  171. match_archives, archive_name_format, feature_available, expected_result
  172. ):
  173. flexmock(module.feature).should_receive('available').and_return(feature_available)
  174. flexmock(module).should_receive('get_default_archive_name_format').and_return(
  175. module.DEFAULT_ARCHIVE_NAME_FORMAT_WITHOUT_SERIES
  176. )
  177. assert (
  178. module.make_match_archives_flags(
  179. match_archives, archive_name_format, local_borg_version=flexmock()
  180. )
  181. == expected_result
  182. )
  183. def test_make_match_archives_flags_accepts_default_archive_name_format():
  184. flexmock(module.feature).should_receive('available').and_return(True)
  185. assert (
  186. module.make_match_archives_flags(
  187. match_archives=None,
  188. archive_name_format=None,
  189. local_borg_version=flexmock(),
  190. default_archive_name_format='*',
  191. )
  192. == ()
  193. )
  194. def test_warn_for_aggressive_archive_flags_without_archive_flags_bails():
  195. flexmock(module.logger).should_receive('warning').never()
  196. module.warn_for_aggressive_archive_flags(('borg', '--do-stuff'), '{}')
  197. def test_warn_for_aggressive_archive_flags_with_glob_archives_and_zero_archives_warns():
  198. flexmock(module.logger).should_receive('warning').twice()
  199. module.warn_for_aggressive_archive_flags(
  200. ('borg', '--glob-archives', 'foo*'), '{"archives": []}'
  201. )
  202. def test_warn_for_aggressive_archive_flags_with_match_archives_and_zero_archives_warns():
  203. flexmock(module.logger).should_receive('warning').twice()
  204. module.warn_for_aggressive_archive_flags(
  205. ('borg', '--match-archives', 'foo*'), '{"archives": []}'
  206. )
  207. def test_warn_for_aggressive_archive_flags_with_glob_archives_and_one_archive_does_not_warn():
  208. flexmock(module.logger).should_receive('warning').never()
  209. module.warn_for_aggressive_archive_flags(
  210. ('borg', '--glob-archives', 'foo*'), '{"archives": [{"name": "foo"]}'
  211. )
  212. def test_warn_for_aggressive_archive_flags_with_match_archives_and_one_archive_does_not_warn():
  213. flexmock(module.logger).should_receive('warning').never()
  214. module.warn_for_aggressive_archive_flags(
  215. ('borg', '--match-archives', 'foo*'), '{"archives": [{"name": "foo"]}'
  216. )
  217. def test_warn_for_aggressive_archive_flags_with_glob_archives_and_invalid_json_does_not_warn():
  218. flexmock(module.logger).should_receive('warning').never()
  219. module.warn_for_aggressive_archive_flags(('borg', '--glob-archives', 'foo*'), '{"archives": [}')
  220. def test_warn_for_aggressive_archive_flags_with_glob_archives_and_json_missing_archives_does_not_warn():
  221. flexmock(module.logger).should_receive('warning').never()
  222. module.warn_for_aggressive_archive_flags(('borg', '--glob-archives', 'foo*'), '{}')
  223. def test_omit_flag_removes_flag_from_arguments():
  224. assert module.omit_flag(('borg', 'create', '--flag', '--other'), '--flag') == (
  225. 'borg',
  226. 'create',
  227. '--other',
  228. )
  229. def test_omit_flag_without_flag_present_passes_through_arguments():
  230. assert module.omit_flag(('borg', 'create', '--other'), '--flag') == (
  231. 'borg',
  232. 'create',
  233. '--other',
  234. )
  235. def test_omit_flag_and_value_removes_flag_and_value_from_arguments():
  236. assert module.omit_flag_and_value(
  237. ('borg', 'create', '--flag', 'value', '--other'), '--flag'
  238. ) == (
  239. 'borg',
  240. 'create',
  241. '--other',
  242. )
  243. def test_omit_flag_and_value_with_equals_sign_removes_flag_and_value_from_arguments():
  244. assert module.omit_flag_and_value(('borg', 'create', '--flag=value', '--other'), '--flag') == (
  245. 'borg',
  246. 'create',
  247. '--other',
  248. )
  249. def test_omit_flag_and_value_without_flag_present_passes_through_arguments():
  250. assert module.omit_flag_and_value(('borg', 'create', '--other'), '--flag') == (
  251. 'borg',
  252. 'create',
  253. '--other',
  254. )
  255. def test_make_exclude_flags_includes_exclude_caches_when_true_in_config():
  256. exclude_flags = module.make_exclude_flags(config={'exclude_caches': True})
  257. assert exclude_flags == ('--exclude-caches',)
  258. def test_make_exclude_flags_does_not_include_exclude_caches_when_false_in_config():
  259. exclude_flags = module.make_exclude_flags(config={'exclude_caches': False})
  260. assert exclude_flags == ()
  261. def test_make_exclude_flags_includes_exclude_if_present_when_in_config():
  262. exclude_flags = module.make_exclude_flags(
  263. config={'exclude_if_present': ['exclude_me', 'also_me']}
  264. )
  265. assert exclude_flags == (
  266. '--exclude-if-present',
  267. 'exclude_me',
  268. '--exclude-if-present',
  269. 'also_me',
  270. )
  271. def test_make_exclude_flags_includes_keep_exclude_tags_when_true_in_config():
  272. exclude_flags = module.make_exclude_flags(config={'keep_exclude_tags': True})
  273. assert exclude_flags == ('--keep-exclude-tags',)
  274. def test_make_exclude_flags_does_not_include_keep_exclude_tags_when_false_in_config():
  275. exclude_flags = module.make_exclude_flags(config={'keep_exclude_tags': False})
  276. assert exclude_flags == ()
  277. def test_make_exclude_flags_includes_exclude_nodump_when_true_in_config():
  278. exclude_flags = module.make_exclude_flags(config={'exclude_nodump': True})
  279. assert exclude_flags == ('--exclude-nodump',)
  280. def test_make_exclude_flags_does_not_include_exclude_nodump_when_false_in_config():
  281. exclude_flags = module.make_exclude_flags(config={'exclude_nodump': False})
  282. assert exclude_flags == ()
  283. def test_make_exclude_flags_is_empty_when_config_has_no_excludes():
  284. exclude_flags = module.make_exclude_flags(config={})
  285. assert exclude_flags == ()
  286. def test_make_list_filter_flags_with_debug_and_feature_available_includes_plus_and_minus():
  287. flexmock(module.logger).should_receive('isEnabledFor').and_return(True)
  288. flexmock(module.feature).should_receive('available').and_return(True)
  289. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=False) == 'AME+-'
  290. def test_make_list_filter_flags_with_info_and_feature_available_omits_plus_and_minus():
  291. flexmock(module.logger).should_receive('isEnabledFor').and_return(False)
  292. flexmock(module.feature).should_receive('available').and_return(True)
  293. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=False) == 'AME'
  294. def test_make_list_filter_flags_with_debug_and_feature_available_and_dry_run_includes_plus_and_minus():
  295. flexmock(module.logger).should_receive('isEnabledFor').and_return(True)
  296. flexmock(module.feature).should_receive('available').and_return(True)
  297. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=True) == 'AME+-'
  298. def test_make_list_filter_flags_with_info_and_feature_available_and_dry_run_includes_plus_and_minus():
  299. flexmock(module.logger).should_receive('isEnabledFor').and_return(False)
  300. flexmock(module.feature).should_receive('available').and_return(True)
  301. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=True) == 'AME+-'
  302. def test_make_list_filter_flags_with_debug_and_feature_not_available_includes_x():
  303. flexmock(module.logger).should_receive('isEnabledFor').and_return(True)
  304. flexmock(module.feature).should_receive('available').and_return(False)
  305. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=False) == 'AMEx-'
  306. def test_make_list_filter_flags_with_info_and_feature_not_available_omits_x():
  307. flexmock(module.logger).should_receive('isEnabledFor').and_return(False)
  308. flexmock(module.feature).should_receive('available').and_return(False)
  309. assert module.make_list_filter_flags(local_borg_version=flexmock(), dry_run=False) == 'AME-'