test_borg.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. import logging
  2. from flexmock import flexmock
  3. from borgmatic.borg import borg as module
  4. from ..test_verbosity import insert_logging_mock
  5. def test_run_arbitrary_borg_calls_borg_with_flags():
  6. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  7. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  8. flexmock(module.flags).should_receive('make_flags').and_return(())
  9. flexmock(module.environment).should_receive('make_environment')
  10. flexmock(module).should_receive('execute_command').with_args(
  11. ('borg', 'break-lock', '::'),
  12. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  13. borg_local_path='borg',
  14. borg_exit_codes=None,
  15. shell=True,
  16. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  17. )
  18. module.run_arbitrary_borg(
  19. repository_path='repo',
  20. config={},
  21. local_borg_version='1.2.3',
  22. options=['break-lock', '::'],
  23. )
  24. def test_run_arbitrary_borg_with_log_info_calls_borg_with_info_flag():
  25. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  26. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  27. flexmock(module.flags).should_receive('make_flags').and_return(())
  28. flexmock(module.environment).should_receive('make_environment')
  29. flexmock(module).should_receive('execute_command').with_args(
  30. ('borg', 'break-lock', '--info', '::'),
  31. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  32. borg_local_path='borg',
  33. borg_exit_codes=None,
  34. shell=True,
  35. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  36. )
  37. insert_logging_mock(logging.INFO)
  38. module.run_arbitrary_borg(
  39. repository_path='repo',
  40. config={},
  41. local_borg_version='1.2.3',
  42. options=['break-lock', '::'],
  43. )
  44. def test_run_arbitrary_borg_with_log_debug_calls_borg_with_debug_flag():
  45. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  46. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  47. flexmock(module.flags).should_receive('make_flags').and_return(())
  48. flexmock(module.environment).should_receive('make_environment')
  49. flexmock(module).should_receive('execute_command').with_args(
  50. ('borg', 'break-lock', '--debug', '--show-rc', '::'),
  51. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  52. borg_local_path='borg',
  53. borg_exit_codes=None,
  54. shell=True,
  55. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  56. )
  57. insert_logging_mock(logging.DEBUG)
  58. module.run_arbitrary_borg(
  59. repository_path='repo',
  60. config={},
  61. local_borg_version='1.2.3',
  62. options=['break-lock', '::'],
  63. )
  64. def test_run_arbitrary_borg_with_lock_wait_calls_borg_with_lock_wait_flags():
  65. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  66. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  67. config = {'lock_wait': 5}
  68. flexmock(module.flags).should_receive('make_flags').and_return(()).and_return(
  69. ('--lock-wait', '5')
  70. )
  71. flexmock(module.environment).should_receive('make_environment')
  72. flexmock(module).should_receive('execute_command').with_args(
  73. ('borg', 'break-lock', '--lock-wait', '5', '::'),
  74. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  75. borg_local_path='borg',
  76. borg_exit_codes=None,
  77. shell=True,
  78. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  79. )
  80. module.run_arbitrary_borg(
  81. repository_path='repo',
  82. config=config,
  83. local_borg_version='1.2.3',
  84. options=['break-lock', '::'],
  85. )
  86. def test_run_arbitrary_borg_with_archive_calls_borg_with_archive_flag():
  87. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  88. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  89. flexmock(module.flags).should_receive('make_flags').and_return(())
  90. flexmock(module.environment).should_receive('make_environment')
  91. flexmock(module).should_receive('execute_command').with_args(
  92. ('borg', 'break-lock', "'::$ARCHIVE'"),
  93. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  94. borg_local_path='borg',
  95. borg_exit_codes=None,
  96. shell=True,
  97. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': 'archive'},
  98. )
  99. module.run_arbitrary_borg(
  100. repository_path='repo',
  101. config={},
  102. local_borg_version='1.2.3',
  103. options=['break-lock', '::$ARCHIVE'],
  104. archive='archive',
  105. )
  106. def test_run_arbitrary_borg_with_local_path_calls_borg_via_local_path():
  107. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  108. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  109. flexmock(module.flags).should_receive('make_flags').and_return(())
  110. flexmock(module.environment).should_receive('make_environment')
  111. flexmock(module).should_receive('execute_command').with_args(
  112. ('borg1', 'break-lock', '::'),
  113. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  114. borg_local_path='borg1',
  115. borg_exit_codes=None,
  116. shell=True,
  117. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  118. )
  119. module.run_arbitrary_borg(
  120. repository_path='repo',
  121. config={},
  122. local_borg_version='1.2.3',
  123. options=['break-lock', '::'],
  124. local_path='borg1',
  125. )
  126. def test_run_arbitrary_borg_with_exit_codes_calls_borg_using_them():
  127. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  128. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  129. flexmock(module.flags).should_receive('make_flags').and_return(())
  130. flexmock(module.environment).should_receive('make_environment')
  131. borg_exit_codes = flexmock()
  132. flexmock(module).should_receive('execute_command').with_args(
  133. ('borg', 'break-lock', '::'),
  134. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  135. borg_local_path='borg',
  136. borg_exit_codes=borg_exit_codes,
  137. shell=True,
  138. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  139. )
  140. module.run_arbitrary_borg(
  141. repository_path='repo',
  142. config={'borg_exit_codes': borg_exit_codes},
  143. local_borg_version='1.2.3',
  144. options=['break-lock', '::'],
  145. )
  146. def test_run_arbitrary_borg_with_remote_path_calls_borg_with_remote_path_flags():
  147. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  148. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  149. flexmock(module.flags).should_receive('make_flags').and_return(
  150. ('--remote-path', 'borg1')
  151. ).and_return(())
  152. flexmock(module.environment).should_receive('make_environment')
  153. flexmock(module).should_receive('execute_command').with_args(
  154. ('borg', 'break-lock', '--remote-path', 'borg1', '::'),
  155. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  156. borg_local_path='borg',
  157. borg_exit_codes=None,
  158. shell=True,
  159. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  160. )
  161. module.run_arbitrary_borg(
  162. repository_path='repo',
  163. config={},
  164. local_borg_version='1.2.3',
  165. options=['break-lock', '::'],
  166. remote_path='borg1',
  167. )
  168. def test_run_arbitrary_borg_with_remote_path_injection_attack_gets_escaped():
  169. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  170. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  171. flexmock(module.flags).should_receive('make_flags').and_return(
  172. ('--remote-path', 'borg1; naughty-command')
  173. ).and_return(())
  174. flexmock(module.environment).should_receive('make_environment')
  175. flexmock(module).should_receive('execute_command').with_args(
  176. ('borg', 'break-lock', '--remote-path', "'borg1; naughty-command'", '::'),
  177. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  178. borg_local_path='borg',
  179. borg_exit_codes=None,
  180. shell=True,
  181. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  182. )
  183. module.run_arbitrary_borg(
  184. repository_path='repo',
  185. config={},
  186. local_borg_version='1.2.3',
  187. options=['break-lock', '::'],
  188. remote_path='borg1',
  189. )
  190. def test_run_arbitrary_borg_passes_borg_specific_flags_to_borg():
  191. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  192. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  193. flexmock(module.flags).should_receive('make_flags').and_return(())
  194. flexmock(module.environment).should_receive('make_environment')
  195. flexmock(module).should_receive('execute_command').with_args(
  196. ('borg', 'list', '--progress', '::'),
  197. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  198. borg_local_path='borg',
  199. borg_exit_codes=None,
  200. shell=True,
  201. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  202. )
  203. module.run_arbitrary_borg(
  204. repository_path='repo',
  205. config={},
  206. local_borg_version='1.2.3',
  207. options=['list', '--progress', '::'],
  208. )
  209. def test_run_arbitrary_borg_omits_dash_dash_in_flags_passed_to_borg():
  210. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  211. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  212. flexmock(module.flags).should_receive('make_flags').and_return(())
  213. flexmock(module.environment).should_receive('make_environment')
  214. flexmock(module).should_receive('execute_command').with_args(
  215. ('borg', 'break-lock', '::'),
  216. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  217. borg_local_path='borg',
  218. borg_exit_codes=None,
  219. shell=True,
  220. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  221. )
  222. module.run_arbitrary_borg(
  223. repository_path='repo',
  224. config={},
  225. local_borg_version='1.2.3',
  226. options=['--', 'break-lock', '::'],
  227. )
  228. def test_run_arbitrary_borg_without_borg_specific_flags_does_not_raise():
  229. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  230. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  231. flexmock(module.flags).should_receive('make_flags').and_return(())
  232. flexmock(module.environment).should_receive('make_environment')
  233. flexmock(module).should_receive('execute_command').with_args(
  234. ('borg',),
  235. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  236. borg_local_path='borg',
  237. borg_exit_codes=None,
  238. shell=True,
  239. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  240. )
  241. module.run_arbitrary_borg(
  242. repository_path='repo',
  243. config={},
  244. local_borg_version='1.2.3',
  245. options=[],
  246. )
  247. def test_run_arbitrary_borg_passes_key_sub_command_to_borg_before_injected_flags():
  248. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  249. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  250. flexmock(module.flags).should_receive('make_flags').and_return(())
  251. flexmock(module.environment).should_receive('make_environment')
  252. flexmock(module).should_receive('execute_command').with_args(
  253. ('borg', 'key', 'export', '--info', '::'),
  254. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  255. borg_local_path='borg',
  256. borg_exit_codes=None,
  257. shell=True,
  258. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  259. )
  260. insert_logging_mock(logging.INFO)
  261. module.run_arbitrary_borg(
  262. repository_path='repo',
  263. config={},
  264. local_borg_version='1.2.3',
  265. options=['key', 'export', '::'],
  266. )
  267. def test_run_arbitrary_borg_passes_debug_sub_command_to_borg_before_injected_flags():
  268. flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels')
  269. flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER
  270. flexmock(module.flags).should_receive('make_flags').and_return(())
  271. flexmock(module.environment).should_receive('make_environment')
  272. flexmock(module).should_receive('execute_command').with_args(
  273. ('borg', 'debug', 'dump-manifest', '--info', '::', 'path'),
  274. output_file=module.borgmatic.execute.DO_NOT_CAPTURE,
  275. borg_local_path='borg',
  276. borg_exit_codes=None,
  277. shell=True,
  278. extra_environment={'BORG_REPO': 'repo', 'ARCHIVE': ''},
  279. )
  280. insert_logging_mock(logging.INFO)
  281. module.run_arbitrary_borg(
  282. repository_path='repo',
  283. config={},
  284. local_borg_version='1.2.3',
  285. options=['debug', 'dump-manifest', '::', 'path'],
  286. )