test_mysql.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. import logging
  2. import pytest
  3. from flexmock import flexmock
  4. from borgmatic.hooks.data_source import mysql as module
  5. def test_database_names_to_dump_passes_through_name():
  6. extra_environment = flexmock()
  7. names = module.database_names_to_dump({'name': 'foo'}, {}, extra_environment, dry_run=False)
  8. assert names == ('foo',)
  9. def test_database_names_to_dump_bails_for_dry_run():
  10. extra_environment = flexmock()
  11. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  12. 'resolve_credential'
  13. ).replace_with(lambda value, config: value)
  14. flexmock(module).should_receive('execute_command_and_capture_output').never()
  15. names = module.database_names_to_dump({'name': 'all'}, {}, extra_environment, dry_run=True)
  16. assert names == ()
  17. def test_database_names_to_dump_queries_mysql_for_database_names():
  18. extra_environment = flexmock()
  19. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  20. 'resolve_credential'
  21. ).replace_with(lambda value, config: value)
  22. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  23. ('mysql', '--skip-column-names', '--batch', '--execute', 'show schemas'),
  24. extra_environment=extra_environment,
  25. ).and_return('foo\nbar\nmysql\n').once()
  26. names = module.database_names_to_dump({'name': 'all'}, {}, extra_environment, dry_run=False)
  27. assert names == ('foo', 'bar')
  28. def test_use_streaming_true_for_any_databases():
  29. assert module.use_streaming(
  30. databases=[flexmock(), flexmock()],
  31. config=flexmock(),
  32. )
  33. def test_use_streaming_false_for_no_databases():
  34. assert not module.use_streaming(databases=[], config=flexmock())
  35. def test_dump_data_sources_dumps_each_database():
  36. databases = [{'name': 'foo'}, {'name': 'bar'}]
  37. processes = [flexmock(), flexmock()]
  38. flexmock(module).should_receive('make_dump_path').and_return('')
  39. flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
  40. ('bar',)
  41. )
  42. for name, process in zip(('foo', 'bar'), processes):
  43. flexmock(module).should_receive('execute_dump_command').with_args(
  44. database={'name': name},
  45. config={},
  46. dump_path=object,
  47. database_names=(name,),
  48. extra_environment=object,
  49. dry_run=object,
  50. dry_run_label=object,
  51. ).and_return(process).once()
  52. assert (
  53. module.dump_data_sources(
  54. databases,
  55. {},
  56. config_paths=('test.yaml',),
  57. borgmatic_runtime_directory='/run/borgmatic',
  58. patterns=[],
  59. dry_run=False,
  60. )
  61. == processes
  62. )
  63. def test_dump_data_sources_dumps_with_password():
  64. database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
  65. process = flexmock()
  66. flexmock(module).should_receive('make_dump_path').and_return('')
  67. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  68. 'resolve_credential'
  69. ).replace_with(lambda value, config: value)
  70. flexmock(module).should_receive('database_names_to_dump').and_return(('foo',)).and_return(
  71. ('bar',)
  72. )
  73. flexmock(module).should_receive('execute_dump_command').with_args(
  74. database=database,
  75. config={},
  76. dump_path=object,
  77. database_names=('foo',),
  78. extra_environment={'MYSQL_PWD': 'trustsome1'},
  79. dry_run=object,
  80. dry_run_label=object,
  81. ).and_return(process).once()
  82. assert module.dump_data_sources(
  83. [database],
  84. {},
  85. config_paths=('test.yaml',),
  86. borgmatic_runtime_directory='/run/borgmatic',
  87. patterns=[],
  88. dry_run=False,
  89. ) == [process]
  90. def test_dump_data_sources_dumps_all_databases_at_once():
  91. databases = [{'name': 'all'}]
  92. process = flexmock()
  93. flexmock(module).should_receive('make_dump_path').and_return('')
  94. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  95. flexmock(module).should_receive('execute_dump_command').with_args(
  96. database={'name': 'all'},
  97. config={},
  98. dump_path=object,
  99. database_names=('foo', 'bar'),
  100. extra_environment=object,
  101. dry_run=object,
  102. dry_run_label=object,
  103. ).and_return(process).once()
  104. assert module.dump_data_sources(
  105. databases,
  106. {},
  107. config_paths=('test.yaml',),
  108. borgmatic_runtime_directory='/run/borgmatic',
  109. patterns=[],
  110. dry_run=False,
  111. ) == [process]
  112. def test_dump_data_sources_dumps_all_databases_separately_when_format_configured():
  113. databases = [{'name': 'all', 'format': 'sql'}]
  114. processes = [flexmock(), flexmock()]
  115. flexmock(module).should_receive('make_dump_path').and_return('')
  116. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  117. for name, process in zip(('foo', 'bar'), processes):
  118. flexmock(module).should_receive('execute_dump_command').with_args(
  119. database={'name': name, 'format': 'sql'},
  120. config={},
  121. dump_path=object,
  122. database_names=(name,),
  123. extra_environment=object,
  124. dry_run=object,
  125. dry_run_label=object,
  126. ).and_return(process).once()
  127. assert (
  128. module.dump_data_sources(
  129. databases,
  130. {},
  131. config_paths=('test.yaml',),
  132. borgmatic_runtime_directory='/run/borgmatic',
  133. patterns=[],
  134. dry_run=False,
  135. )
  136. == processes
  137. )
  138. def test_database_names_to_dump_runs_mysql_with_list_options():
  139. database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf'}
  140. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  141. (
  142. 'mysql',
  143. '--defaults-extra-file=my.cnf',
  144. '--skip-column-names',
  145. '--batch',
  146. '--execute',
  147. 'show schemas',
  148. ),
  149. extra_environment=None,
  150. ).and_return(('foo\nbar')).once()
  151. assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
  152. def test_database_names_to_dump_runs_non_default_mysql_with_list_options():
  153. database = {
  154. 'name': 'all',
  155. 'list_options': '--defaults-extra-file=my.cnf',
  156. 'mysql_command': 'custom_mysql',
  157. }
  158. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  159. extra_environment=None,
  160. full_command=(
  161. 'custom_mysql', # Custom MySQL command
  162. '--defaults-extra-file=my.cnf',
  163. '--skip-column-names',
  164. '--batch',
  165. '--execute',
  166. 'show schemas',
  167. ),
  168. ).and_return(('foo\nbar')).once()
  169. assert module.database_names_to_dump(database, {}, None, '') == ('foo', 'bar')
  170. def test_execute_dump_command_runs_mysqldump():
  171. process = flexmock()
  172. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  173. flexmock(module.os.path).should_receive('exists').and_return(False)
  174. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  175. 'resolve_credential'
  176. ).replace_with(lambda value, config: value)
  177. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  178. flexmock(module).should_receive('execute_command').with_args(
  179. (
  180. 'mysqldump',
  181. '--add-drop-database',
  182. '--databases',
  183. 'foo',
  184. '--result-file',
  185. 'dump',
  186. ),
  187. extra_environment=None,
  188. run_to_completion=False,
  189. ).and_return(process).once()
  190. assert (
  191. module.execute_dump_command(
  192. database={'name': 'foo'},
  193. config={},
  194. dump_path=flexmock(),
  195. database_names=('foo',),
  196. extra_environment=None,
  197. dry_run=False,
  198. dry_run_label='',
  199. )
  200. == process
  201. )
  202. def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
  203. process = flexmock()
  204. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  205. flexmock(module.os.path).should_receive('exists').and_return(False)
  206. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  207. 'resolve_credential'
  208. ).replace_with(lambda value, config: value)
  209. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  210. flexmock(module).should_receive('execute_command').with_args(
  211. (
  212. 'mysqldump',
  213. '--databases',
  214. 'foo',
  215. '--result-file',
  216. 'dump',
  217. ),
  218. extra_environment=None,
  219. run_to_completion=False,
  220. ).and_return(process).once()
  221. assert (
  222. module.execute_dump_command(
  223. database={'name': 'foo', 'add_drop_database': False},
  224. config={},
  225. dump_path=flexmock(),
  226. database_names=('foo',),
  227. extra_environment=None,
  228. dry_run=False,
  229. dry_run_label='',
  230. )
  231. == process
  232. )
  233. def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
  234. process = flexmock()
  235. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  236. flexmock(module.os.path).should_receive('exists').and_return(False)
  237. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  238. 'resolve_credential'
  239. ).replace_with(lambda value, config: value)
  240. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  241. flexmock(module).should_receive('execute_command').with_args(
  242. (
  243. 'mysqldump',
  244. '--add-drop-database',
  245. '--host',
  246. 'database.example.org',
  247. '--port',
  248. '5433',
  249. '--protocol',
  250. 'tcp',
  251. '--databases',
  252. 'foo',
  253. '--result-file',
  254. 'dump',
  255. ),
  256. extra_environment=None,
  257. run_to_completion=False,
  258. ).and_return(process).once()
  259. assert (
  260. module.execute_dump_command(
  261. database={'name': 'foo', 'hostname': 'database.example.org', 'port': 5433},
  262. config={},
  263. dump_path=flexmock(),
  264. database_names=('foo',),
  265. extra_environment=None,
  266. dry_run=False,
  267. dry_run_label='',
  268. )
  269. == process
  270. )
  271. def test_execute_dump_command_runs_mysqldump_with_username_and_password():
  272. process = flexmock()
  273. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  274. flexmock(module.os.path).should_receive('exists').and_return(False)
  275. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  276. 'resolve_credential'
  277. ).replace_with(lambda value, config: value)
  278. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  279. flexmock(module).should_receive('execute_command').with_args(
  280. (
  281. 'mysqldump',
  282. '--add-drop-database',
  283. '--user',
  284. 'root',
  285. '--databases',
  286. 'foo',
  287. '--result-file',
  288. 'dump',
  289. ),
  290. extra_environment={'MYSQL_PWD': 'trustsome1'},
  291. run_to_completion=False,
  292. ).and_return(process).once()
  293. assert (
  294. module.execute_dump_command(
  295. database={'name': 'foo', 'username': 'root', 'password': 'trustsome1'},
  296. config={},
  297. dump_path=flexmock(),
  298. database_names=('foo',),
  299. extra_environment={'MYSQL_PWD': 'trustsome1'},
  300. dry_run=False,
  301. dry_run_label='',
  302. )
  303. == process
  304. )
  305. def test_execute_dump_command_runs_mysqldump_with_options():
  306. process = flexmock()
  307. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  308. flexmock(module.os.path).should_receive('exists').and_return(False)
  309. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  310. 'resolve_credential'
  311. ).replace_with(lambda value, config: value)
  312. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  313. flexmock(module).should_receive('execute_command').with_args(
  314. (
  315. 'mysqldump',
  316. '--stuff=such',
  317. '--add-drop-database',
  318. '--databases',
  319. 'foo',
  320. '--result-file',
  321. 'dump',
  322. ),
  323. extra_environment=None,
  324. run_to_completion=False,
  325. ).and_return(process).once()
  326. assert (
  327. module.execute_dump_command(
  328. database={'name': 'foo', 'options': '--stuff=such'},
  329. config={},
  330. dump_path=flexmock(),
  331. database_names=('foo',),
  332. extra_environment=None,
  333. dry_run=False,
  334. dry_run_label='',
  335. )
  336. == process
  337. )
  338. def test_execute_dump_command_runs_non_default_mysqldump():
  339. process = flexmock()
  340. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  341. flexmock(module.os.path).should_receive('exists').and_return(False)
  342. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  343. 'resolve_credential'
  344. ).replace_with(lambda value, config: value)
  345. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  346. flexmock(module).should_receive('execute_command').with_args(
  347. (
  348. 'custom_mysqldump', # Custom MySQL dump command
  349. '--add-drop-database',
  350. '--databases',
  351. 'foo',
  352. '--result-file',
  353. 'dump',
  354. ),
  355. extra_environment=None,
  356. run_to_completion=False,
  357. ).and_return(process).once()
  358. assert (
  359. module.execute_dump_command(
  360. database={
  361. 'name': 'foo',
  362. 'mysql_dump_command': 'custom_mysqldump',
  363. }, # Custom MySQL dump command specified
  364. config={},
  365. dump_path=flexmock(),
  366. database_names=('foo',),
  367. extra_environment=None,
  368. dry_run=False,
  369. dry_run_label='',
  370. )
  371. == process
  372. )
  373. def test_execute_dump_command_with_duplicate_dump_skips_mysqldump():
  374. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  375. flexmock(module.os.path).should_receive('exists').and_return(True)
  376. flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
  377. flexmock(module).should_receive('execute_command').never()
  378. assert (
  379. module.execute_dump_command(
  380. database={'name': 'foo'},
  381. config={},
  382. dump_path=flexmock(),
  383. database_names=('foo',),
  384. extra_environment=None,
  385. dry_run=True,
  386. dry_run_label='SO DRY',
  387. )
  388. is None
  389. )
  390. def test_execute_dump_command_with_dry_run_skips_mysqldump():
  391. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  392. flexmock(module.os.path).should_receive('exists').and_return(False)
  393. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  394. 'resolve_credential'
  395. ).replace_with(lambda value, config: value)
  396. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  397. flexmock(module).should_receive('execute_command').never()
  398. assert (
  399. module.execute_dump_command(
  400. database={'name': 'foo'},
  401. config={},
  402. dump_path=flexmock(),
  403. database_names=('foo',),
  404. extra_environment=None,
  405. dry_run=True,
  406. dry_run_label='SO DRY',
  407. )
  408. is None
  409. )
  410. def test_dump_data_sources_errors_for_missing_all_databases():
  411. databases = [{'name': 'all'}]
  412. flexmock(module).should_receive('make_dump_path').and_return('')
  413. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  414. 'resolve_credential'
  415. ).replace_with(lambda value, config: value)
  416. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  417. 'databases/localhost/all'
  418. )
  419. flexmock(module).should_receive('database_names_to_dump').and_return(())
  420. with pytest.raises(ValueError):
  421. assert module.dump_data_sources(
  422. databases,
  423. {},
  424. config_paths=('test.yaml',),
  425. borgmatic_runtime_directory='/run/borgmatic',
  426. patterns=[],
  427. dry_run=False,
  428. )
  429. def test_dump_data_sources_does_not_error_for_missing_all_databases_with_dry_run():
  430. databases = [{'name': 'all'}]
  431. flexmock(module).should_receive('make_dump_path').and_return('')
  432. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  433. 'resolve_credential'
  434. ).replace_with(lambda value, config: value)
  435. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  436. 'databases/localhost/all'
  437. )
  438. flexmock(module).should_receive('database_names_to_dump').and_return(())
  439. assert (
  440. module.dump_data_sources(
  441. databases,
  442. {},
  443. config_paths=('test.yaml',),
  444. borgmatic_runtime_directory='/run/borgmatic',
  445. patterns=[],
  446. dry_run=True,
  447. )
  448. == []
  449. )
  450. def test_restore_data_source_dump_runs_mysql_to_restore():
  451. hook_config = [{'name': 'foo'}, {'name': 'bar'}]
  452. extract_process = flexmock(stdout=flexmock())
  453. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  454. 'resolve_credential'
  455. ).replace_with(lambda value, config: value)
  456. flexmock(module).should_receive('execute_command_with_processes').with_args(
  457. ('mysql', '--batch'),
  458. processes=[extract_process],
  459. output_log_level=logging.DEBUG,
  460. input_file=extract_process.stdout,
  461. extra_environment=None,
  462. ).once()
  463. module.restore_data_source_dump(
  464. hook_config,
  465. {},
  466. data_source={'name': 'foo'},
  467. dry_run=False,
  468. extract_process=extract_process,
  469. connection_params={
  470. 'hostname': None,
  471. 'port': None,
  472. 'username': None,
  473. 'password': None,
  474. },
  475. borgmatic_runtime_directory='/run/borgmatic',
  476. )
  477. def test_restore_data_source_dump_runs_mysql_with_options():
  478. hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
  479. extract_process = flexmock(stdout=flexmock())
  480. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  481. 'resolve_credential'
  482. ).replace_with(lambda value, config: value)
  483. flexmock(module).should_receive('execute_command_with_processes').with_args(
  484. ('mysql', '--batch', '--harder'),
  485. processes=[extract_process],
  486. output_log_level=logging.DEBUG,
  487. input_file=extract_process.stdout,
  488. extra_environment=None,
  489. ).once()
  490. module.restore_data_source_dump(
  491. hook_config,
  492. {},
  493. data_source=hook_config[0],
  494. dry_run=False,
  495. extract_process=extract_process,
  496. connection_params={
  497. 'hostname': None,
  498. 'port': None,
  499. 'username': None,
  500. 'password': None,
  501. },
  502. borgmatic_runtime_directory='/run/borgmatic',
  503. )
  504. def test_restore_data_source_dump_runs_non_default_mysql_with_options():
  505. hook_config = [{'name': 'foo', 'mysql_command': 'custom_mysql', 'restore_options': '--harder'}]
  506. extract_process = flexmock(stdout=flexmock())
  507. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  508. 'resolve_credential'
  509. ).replace_with(lambda value, config: value)
  510. flexmock(module).should_receive('execute_command_with_processes').with_args(
  511. ('custom_mysql', '--batch', '--harder'),
  512. processes=[extract_process],
  513. output_log_level=logging.DEBUG,
  514. input_file=extract_process.stdout,
  515. extra_environment=None,
  516. ).once()
  517. module.restore_data_source_dump(
  518. hook_config,
  519. {},
  520. data_source=hook_config[0],
  521. dry_run=False,
  522. extract_process=extract_process,
  523. connection_params={
  524. 'hostname': None,
  525. 'port': None,
  526. 'username': None,
  527. 'password': None,
  528. },
  529. borgmatic_runtime_directory='/run/borgmatic',
  530. )
  531. def test_restore_data_source_dump_runs_mysql_with_hostname_and_port():
  532. hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
  533. extract_process = flexmock(stdout=flexmock())
  534. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  535. 'resolve_credential'
  536. ).replace_with(lambda value, config: value)
  537. flexmock(module).should_receive('execute_command_with_processes').with_args(
  538. (
  539. 'mysql',
  540. '--batch',
  541. '--host',
  542. 'database.example.org',
  543. '--port',
  544. '5433',
  545. '--protocol',
  546. 'tcp',
  547. ),
  548. processes=[extract_process],
  549. output_log_level=logging.DEBUG,
  550. input_file=extract_process.stdout,
  551. extra_environment=None,
  552. ).once()
  553. module.restore_data_source_dump(
  554. hook_config,
  555. {},
  556. data_source=hook_config[0],
  557. dry_run=False,
  558. extract_process=extract_process,
  559. connection_params={
  560. 'hostname': None,
  561. 'port': None,
  562. 'username': None,
  563. 'password': None,
  564. },
  565. borgmatic_runtime_directory='/run/borgmatic',
  566. )
  567. def test_restore_data_source_dump_runs_mysql_with_username_and_password():
  568. hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
  569. extract_process = flexmock(stdout=flexmock())
  570. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  571. 'resolve_credential'
  572. ).replace_with(lambda value, config: value)
  573. flexmock(module).should_receive('execute_command_with_processes').with_args(
  574. ('mysql', '--batch', '--user', 'root'),
  575. processes=[extract_process],
  576. output_log_level=logging.DEBUG,
  577. input_file=extract_process.stdout,
  578. extra_environment={'MYSQL_PWD': 'trustsome1'},
  579. ).once()
  580. module.restore_data_source_dump(
  581. hook_config,
  582. {},
  583. data_source=hook_config[0],
  584. dry_run=False,
  585. extract_process=extract_process,
  586. connection_params={
  587. 'hostname': None,
  588. 'port': None,
  589. 'username': None,
  590. 'password': None,
  591. },
  592. borgmatic_runtime_directory='/run/borgmatic',
  593. )
  594. def test_restore_data_source_dump_with_connection_params_uses_connection_params_for_restore():
  595. hook_config = [
  596. {
  597. 'name': 'foo',
  598. 'username': 'root',
  599. 'password': 'trustsome1',
  600. 'restore_hostname': 'restorehost',
  601. 'restore_port': 'restoreport',
  602. 'restore_username': 'restoreusername',
  603. 'restore_password': 'restorepassword',
  604. }
  605. ]
  606. extract_process = flexmock(stdout=flexmock())
  607. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  608. 'resolve_credential'
  609. ).replace_with(lambda value, config: value)
  610. flexmock(module).should_receive('execute_command_with_processes').with_args(
  611. (
  612. 'mysql',
  613. '--batch',
  614. '--host',
  615. 'clihost',
  616. '--port',
  617. 'cliport',
  618. '--protocol',
  619. 'tcp',
  620. '--user',
  621. 'cliusername',
  622. ),
  623. processes=[extract_process],
  624. output_log_level=logging.DEBUG,
  625. input_file=extract_process.stdout,
  626. extra_environment={'MYSQL_PWD': 'clipassword'},
  627. ).once()
  628. module.restore_data_source_dump(
  629. hook_config,
  630. {},
  631. data_source={'name': 'foo'},
  632. dry_run=False,
  633. extract_process=extract_process,
  634. connection_params={
  635. 'hostname': 'clihost',
  636. 'port': 'cliport',
  637. 'username': 'cliusername',
  638. 'password': 'clipassword',
  639. },
  640. borgmatic_runtime_directory='/run/borgmatic',
  641. )
  642. def test_restore_data_source_dump_without_connection_params_uses_restore_params_in_config_for_restore():
  643. hook_config = [
  644. {
  645. 'name': 'foo',
  646. 'username': 'root',
  647. 'password': 'trustsome1',
  648. 'hostname': 'dbhost',
  649. 'port': 'dbport',
  650. 'restore_username': 'restoreuser',
  651. 'restore_password': 'restorepass',
  652. 'restore_hostname': 'restorehost',
  653. 'restore_port': 'restoreport',
  654. }
  655. ]
  656. extract_process = flexmock(stdout=flexmock())
  657. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  658. 'resolve_credential'
  659. ).replace_with(lambda value, config: value)
  660. flexmock(module).should_receive('execute_command_with_processes').with_args(
  661. (
  662. 'mysql',
  663. '--batch',
  664. '--host',
  665. 'restorehost',
  666. '--port',
  667. 'restoreport',
  668. '--protocol',
  669. 'tcp',
  670. '--user',
  671. 'restoreuser',
  672. ),
  673. processes=[extract_process],
  674. output_log_level=logging.DEBUG,
  675. input_file=extract_process.stdout,
  676. extra_environment={'MYSQL_PWD': 'restorepass'},
  677. ).once()
  678. module.restore_data_source_dump(
  679. hook_config,
  680. {},
  681. data_source=hook_config[0],
  682. dry_run=False,
  683. extract_process=extract_process,
  684. connection_params={
  685. 'hostname': None,
  686. 'port': None,
  687. 'username': None,
  688. 'password': None,
  689. },
  690. borgmatic_runtime_directory='/run/borgmatic',
  691. )
  692. def test_restore_data_source_dump_with_dry_run_skips_restore():
  693. hook_config = [{'name': 'foo'}]
  694. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  695. 'resolve_credential'
  696. ).replace_with(lambda value, config: value)
  697. flexmock(module).should_receive('execute_command_with_processes').never()
  698. module.restore_data_source_dump(
  699. hook_config,
  700. {},
  701. data_source={'name': 'foo'},
  702. dry_run=True,
  703. extract_process=flexmock(),
  704. connection_params={
  705. 'hostname': None,
  706. 'port': None,
  707. 'username': None,
  708. 'password': None,
  709. },
  710. borgmatic_runtime_directory='/run/borgmatic',
  711. )