2
0

test_borg.py 15 KB

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