test_borg.py 15 KB

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