test_prune.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import logging
  2. from collections import OrderedDict
  3. from flexmock import flexmock
  4. from borgmatic.borg import prune as module
  5. from ..test_verbosity import insert_logging_mock
  6. def insert_execute_command_mock(prune_command, output_log_level):
  7. flexmock(module.environment).should_receive('make_environment')
  8. flexmock(module).should_receive('execute_command').with_args(
  9. prune_command,
  10. output_log_level=output_log_level,
  11. borg_local_path=prune_command[0],
  12. extra_environment=None,
  13. ).once()
  14. BASE_PRUNE_FLAGS = ('--keep-daily', '1', '--keep-weekly', '2', '--keep-monthly', '3')
  15. def test_make_prune_flags_returns_flags_from_config():
  16. retention_config = OrderedDict((('keep_daily', 1), ('keep_weekly', 2), ('keep_monthly', 3)))
  17. flexmock(module.feature).should_receive('available').and_return(True)
  18. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  19. result = module.make_prune_flags({}, retention_config, local_borg_version='1.2.3')
  20. assert result == BASE_PRUNE_FLAGS
  21. def test_make_prune_flags_accepts_prefix_with_placeholders():
  22. retention_config = OrderedDict(
  23. (('keep_daily', 1), ('prefix', 'Documents_{hostname}-{now}')) # noqa: FS003
  24. )
  25. flexmock(module.feature).should_receive('available').and_return(True)
  26. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  27. result = module.make_prune_flags({}, retention_config, local_borg_version='1.2.3')
  28. expected = (
  29. '--keep-daily',
  30. '1',
  31. '--match-archives',
  32. 'sh:Documents_{hostname}-{now}*', # noqa: FS003
  33. )
  34. assert result == expected
  35. def test_make_prune_flags_with_prefix_without_borg_features_uses_glob_archives():
  36. retention_config = OrderedDict(
  37. (('keep_daily', 1), ('prefix', 'Documents_{hostname}-{now}')) # noqa: FS003
  38. )
  39. flexmock(module.feature).should_receive('available').and_return(False)
  40. flexmock(module.flags).should_receive('make_match_archives_flags').and_return(())
  41. result = module.make_prune_flags({}, retention_config, local_borg_version='1.2.3')
  42. expected = (
  43. '--keep-daily',
  44. '1',
  45. '--glob-archives',
  46. 'Documents_{hostname}-{now}*', # noqa: FS003
  47. )
  48. assert result == expected
  49. def test_make_prune_flags_without_prefix_uses_archive_name_format_instead():
  50. storage_config = {'archive_name_format': 'bar-{now}'} # noqa: FS003
  51. retention_config = OrderedDict((('keep_daily', 1), ('prefix', None)))
  52. flexmock(module.feature).should_receive('available').and_return(True)
  53. flexmock(module.flags).should_receive('make_match_archives_flags').with_args(
  54. None, 'bar-{now}', '1.2.3' # noqa: FS003
  55. ).and_return(('--match-archives', 'sh:bar-*'))
  56. result = module.make_prune_flags(storage_config, retention_config, local_borg_version='1.2.3')
  57. expected = (
  58. '--keep-daily',
  59. '1',
  60. '--match-archives',
  61. 'sh:bar-*', # noqa: FS003
  62. )
  63. assert result == expected
  64. PRUNE_COMMAND = ('borg', 'prune', '--keep-daily', '1', '--keep-weekly', '2', '--keep-monthly', '3')
  65. def test_prune_archives_calls_borg_with_parameters():
  66. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  67. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  68. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  69. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  70. insert_execute_command_mock(PRUNE_COMMAND + ('repo',), logging.INFO)
  71. module.prune_archives(
  72. dry_run=False,
  73. repository_path='repo',
  74. storage_config={},
  75. retention_config=flexmock(),
  76. local_borg_version='1.2.3',
  77. )
  78. def test_prune_archives_with_log_info_calls_borg_with_info_parameter():
  79. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  80. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  81. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  82. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  83. insert_execute_command_mock(PRUNE_COMMAND + ('--info', 'repo'), logging.INFO)
  84. insert_logging_mock(logging.INFO)
  85. module.prune_archives(
  86. repository_path='repo',
  87. storage_config={},
  88. dry_run=False,
  89. retention_config=flexmock(),
  90. local_borg_version='1.2.3',
  91. )
  92. def test_prune_archives_with_log_debug_calls_borg_with_debug_parameter():
  93. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  94. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  95. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  96. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  97. insert_execute_command_mock(PRUNE_COMMAND + ('--debug', '--show-rc', 'repo'), logging.INFO)
  98. insert_logging_mock(logging.DEBUG)
  99. module.prune_archives(
  100. repository_path='repo',
  101. storage_config={},
  102. dry_run=False,
  103. retention_config=flexmock(),
  104. local_borg_version='1.2.3',
  105. )
  106. def test_prune_archives_with_dry_run_calls_borg_with_dry_run_parameter():
  107. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  108. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  109. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  110. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  111. insert_execute_command_mock(PRUNE_COMMAND + ('--dry-run', 'repo'), logging.INFO)
  112. module.prune_archives(
  113. repository_path='repo',
  114. storage_config={},
  115. dry_run=True,
  116. retention_config=flexmock(),
  117. local_borg_version='1.2.3',
  118. )
  119. def test_prune_archives_with_local_path_calls_borg_via_local_path():
  120. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  121. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  122. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  123. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  124. insert_execute_command_mock(('borg1',) + PRUNE_COMMAND[1:] + ('repo',), logging.INFO)
  125. module.prune_archives(
  126. dry_run=False,
  127. repository_path='repo',
  128. storage_config={},
  129. retention_config=flexmock(),
  130. local_borg_version='1.2.3',
  131. local_path='borg1',
  132. )
  133. def test_prune_archives_with_remote_path_calls_borg_with_remote_path_parameters():
  134. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  135. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  136. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  137. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  138. insert_execute_command_mock(PRUNE_COMMAND + ('--remote-path', 'borg1', 'repo'), logging.INFO)
  139. module.prune_archives(
  140. dry_run=False,
  141. repository_path='repo',
  142. storage_config={},
  143. retention_config=flexmock(),
  144. local_borg_version='1.2.3',
  145. remote_path='borg1',
  146. )
  147. def test_prune_archives_with_stats_calls_borg_with_stats_parameter_and_answer_output_log_level():
  148. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  149. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  150. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  151. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  152. insert_execute_command_mock(PRUNE_COMMAND + ('--stats', 'repo'), module.borgmatic.logger.ANSWER)
  153. module.prune_archives(
  154. dry_run=False,
  155. repository_path='repo',
  156. storage_config={},
  157. retention_config=flexmock(),
  158. local_borg_version='1.2.3',
  159. stats=True,
  160. )
  161. def test_prune_archives_with_files_calls_borg_with_list_parameter_and_answer_output_log_level():
  162. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  163. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  164. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  165. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  166. insert_execute_command_mock(PRUNE_COMMAND + ('--list', 'repo'), module.borgmatic.logger.ANSWER)
  167. module.prune_archives(
  168. dry_run=False,
  169. repository_path='repo',
  170. storage_config={},
  171. retention_config=flexmock(),
  172. local_borg_version='1.2.3',
  173. list_archives=True,
  174. )
  175. def test_prune_archives_with_umask_calls_borg_with_umask_parameters():
  176. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  177. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  178. storage_config = {'umask': '077'}
  179. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  180. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  181. insert_execute_command_mock(PRUNE_COMMAND + ('--umask', '077', 'repo'), logging.INFO)
  182. module.prune_archives(
  183. dry_run=False,
  184. repository_path='repo',
  185. storage_config=storage_config,
  186. retention_config=flexmock(),
  187. local_borg_version='1.2.3',
  188. )
  189. def test_prune_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
  190. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  191. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  192. storage_config = {'lock_wait': 5}
  193. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  194. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  195. insert_execute_command_mock(PRUNE_COMMAND + ('--lock-wait', '5', 'repo'), logging.INFO)
  196. module.prune_archives(
  197. dry_run=False,
  198. repository_path='repo',
  199. storage_config=storage_config,
  200. retention_config=flexmock(),
  201. local_borg_version='1.2.3',
  202. )
  203. def test_prune_archives_with_extra_borg_options_calls_borg_with_extra_options():
  204. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  205. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  206. flexmock(module).should_receive('make_prune_flags').and_return(BASE_PRUNE_FLAGS)
  207. flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',))
  208. insert_execute_command_mock(PRUNE_COMMAND + ('--extra', '--options', 'repo'), logging.INFO)
  209. module.prune_archives(
  210. dry_run=False,
  211. repository_path='repo',
  212. storage_config={'extra_borg_options': {'prune': '--extra --options'}},
  213. retention_config=flexmock(),
  214. local_borg_version='1.2.3',
  215. )