test_prune.py 10 KB

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