test_mysql.py 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  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. environment = flexmock()
  7. names = module.database_names_to_dump(
  8. {'name': 'foo'},
  9. {},
  10. 'root',
  11. 'trustsome1',
  12. environment,
  13. dry_run=False,
  14. )
  15. assert names == ('foo',)
  16. def test_database_names_to_dump_bails_for_dry_run():
  17. environment = flexmock()
  18. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  19. 'resolve_credential',
  20. ).replace_with(lambda value, config: value)
  21. flexmock(module).should_receive('execute_command_and_capture_output').never()
  22. names = module.database_names_to_dump(
  23. {'name': 'all'},
  24. {},
  25. 'root',
  26. 'trustsome1',
  27. environment,
  28. dry_run=True,
  29. )
  30. assert names == ()
  31. def test_database_names_to_dump_queries_mysql_for_database_names():
  32. environment = flexmock()
  33. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  34. 'resolve_credential',
  35. ).replace_with(lambda value, config: value)
  36. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  37. 'parse_extra_options',
  38. ).and_return((), None)
  39. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  40. 'make_defaults_file_options',
  41. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  42. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  43. (
  44. 'mysql',
  45. '--defaults-extra-file=/dev/fd/99',
  46. '--skip-column-names',
  47. '--batch',
  48. '--execute',
  49. 'show schemas',
  50. ),
  51. environment=environment,
  52. ).and_return('foo\nbar\nmysql\n').once()
  53. names = module.database_names_to_dump(
  54. {'name': 'all'},
  55. {},
  56. 'root',
  57. 'trustsome1',
  58. environment,
  59. dry_run=False,
  60. )
  61. assert names == ('foo', 'bar')
  62. def test_database_names_to_dump_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  63. environment = flexmock()
  64. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  65. 'resolve_credential',
  66. ).replace_with(lambda value, config: value)
  67. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  68. 'parse_extra_options',
  69. ).and_return((), None)
  70. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  71. 'make_defaults_file_options',
  72. ).never()
  73. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  74. (
  75. 'mysql',
  76. '--user',
  77. 'root',
  78. '--skip-column-names',
  79. '--batch',
  80. '--execute',
  81. 'show schemas',
  82. ),
  83. environment=environment,
  84. ).and_return('foo\nbar\nmysql\n').once()
  85. names = module.database_names_to_dump(
  86. {'name': 'all', 'password_transport': 'environment'},
  87. {},
  88. 'root',
  89. 'trustsome1',
  90. environment,
  91. dry_run=False,
  92. )
  93. assert names == ('foo', 'bar')
  94. def test_database_names_to_dump_runs_mysql_with_tls():
  95. environment = flexmock()
  96. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  97. 'resolve_credential',
  98. ).replace_with(lambda value, config: value)
  99. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  100. 'parse_extra_options',
  101. ).and_return((), None)
  102. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  103. 'make_defaults_file_options',
  104. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  105. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  106. (
  107. 'mysql',
  108. '--defaults-extra-file=/dev/fd/99',
  109. '--ssl',
  110. '--skip-column-names',
  111. '--batch',
  112. '--execute',
  113. 'show schemas',
  114. ),
  115. environment=environment,
  116. ).and_return('foo\nbar\nmysql\n').once()
  117. names = module.database_names_to_dump(
  118. {'name': 'all', 'tls': True},
  119. {},
  120. 'root',
  121. 'trustsome1',
  122. environment,
  123. dry_run=False,
  124. )
  125. assert names == ('foo', 'bar')
  126. def test_database_names_to_dump_runs_mysql_without_tls():
  127. environment = flexmock()
  128. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  129. 'resolve_credential',
  130. ).replace_with(lambda value, config: value)
  131. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  132. 'parse_extra_options',
  133. ).and_return((), None)
  134. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  135. 'make_defaults_file_options',
  136. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  137. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  138. (
  139. 'mysql',
  140. '--defaults-extra-file=/dev/fd/99',
  141. '--skip-ssl',
  142. '--skip-column-names',
  143. '--batch',
  144. '--execute',
  145. 'show schemas',
  146. ),
  147. environment=environment,
  148. ).and_return('foo\nbar\nmysql\n').once()
  149. names = module.database_names_to_dump(
  150. {'name': 'all', 'tls': False},
  151. {},
  152. 'root',
  153. 'trustsome1',
  154. environment,
  155. dry_run=False,
  156. )
  157. assert names == ('foo', 'bar')
  158. def test_use_streaming_true_for_any_databases():
  159. assert module.use_streaming(
  160. databases=[flexmock(), flexmock()],
  161. config=flexmock(),
  162. )
  163. def test_use_streaming_false_for_no_databases():
  164. assert not module.use_streaming(databases=[], config=flexmock())
  165. def test_dump_data_sources_dumps_each_database():
  166. databases = [{'name': 'foo'}, {'name': 'bar'}]
  167. processes = [flexmock(), flexmock()]
  168. flexmock(module).should_receive('make_dump_path').and_return('')
  169. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  170. 'resolve_credential',
  171. ).and_return(None)
  172. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  173. flexmock(module).should_receive('database_names_to_dump').with_args(
  174. database=databases[0],
  175. config={},
  176. username=None,
  177. password=None,
  178. environment={'USER': 'root'},
  179. dry_run=False,
  180. ).and_return(('foo',))
  181. flexmock(module).should_receive('database_names_to_dump').with_args(
  182. database=databases[1],
  183. config={},
  184. username=None,
  185. password=None,
  186. environment={'USER': 'root'},
  187. dry_run=False,
  188. ).and_return(('bar',))
  189. for name, process in zip(('foo', 'bar'), processes):
  190. flexmock(module).should_receive('execute_dump_command').with_args(
  191. database={'name': name},
  192. config={},
  193. username=None,
  194. password=None,
  195. dump_path=object,
  196. database_names=(name,),
  197. environment={'USER': 'root'},
  198. dry_run=object,
  199. dry_run_label=object,
  200. ).and_return(process).once()
  201. assert (
  202. module.dump_data_sources(
  203. databases,
  204. {},
  205. config_paths=('test.yaml',),
  206. borgmatic_runtime_directory='/run/borgmatic',
  207. patterns=[],
  208. dry_run=False,
  209. )
  210. == processes
  211. )
  212. def test_dump_data_sources_dumps_with_password():
  213. database = {'name': 'foo', 'username': 'root', 'password': 'trustsome1'}
  214. process = flexmock()
  215. flexmock(module).should_receive('make_dump_path').and_return('')
  216. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  217. 'resolve_credential',
  218. ).replace_with(lambda value, config: value)
  219. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  220. flexmock(module).should_receive('database_names_to_dump').with_args(
  221. database=database,
  222. config={},
  223. username='root',
  224. password='trustsome1',
  225. environment={'USER': 'root'},
  226. dry_run=False,
  227. ).and_return(('foo',))
  228. flexmock(module).should_receive('execute_dump_command').with_args(
  229. database=database,
  230. config={},
  231. username='root',
  232. password='trustsome1',
  233. dump_path=object,
  234. database_names=('foo',),
  235. environment={'USER': 'root'},
  236. dry_run=object,
  237. dry_run_label=object,
  238. ).and_return(process).once()
  239. assert module.dump_data_sources(
  240. [database],
  241. {},
  242. config_paths=('test.yaml',),
  243. borgmatic_runtime_directory='/run/borgmatic',
  244. patterns=[],
  245. dry_run=False,
  246. ) == [process]
  247. def test_dump_data_sources_dumps_with_environment_password_transport_passes_password_environment_variable():
  248. database = {
  249. 'name': 'foo',
  250. 'username': 'root',
  251. 'password': 'trustsome1',
  252. 'password_transport': 'environment',
  253. }
  254. process = flexmock()
  255. flexmock(module).should_receive('make_dump_path').and_return('')
  256. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  257. 'resolve_credential',
  258. ).replace_with(lambda value, config: value)
  259. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  260. flexmock(module).should_receive('database_names_to_dump').with_args(
  261. database=database,
  262. config={},
  263. username='root',
  264. password='trustsome1',
  265. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  266. dry_run=False,
  267. ).and_return(('foo',))
  268. flexmock(module).should_receive('execute_dump_command').with_args(
  269. database=database,
  270. config={},
  271. username='root',
  272. password='trustsome1',
  273. dump_path=object,
  274. database_names=('foo',),
  275. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  276. dry_run=object,
  277. dry_run_label=object,
  278. ).and_return(process).once()
  279. assert module.dump_data_sources(
  280. [database],
  281. {},
  282. config_paths=('test.yaml',),
  283. borgmatic_runtime_directory='/run/borgmatic',
  284. patterns=[],
  285. dry_run=False,
  286. ) == [process]
  287. def test_dump_data_sources_dumps_all_databases_at_once():
  288. databases = [{'name': 'all'}]
  289. process = flexmock()
  290. flexmock(module).should_receive('make_dump_path').and_return('')
  291. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  292. 'resolve_credential',
  293. ).and_return(None)
  294. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  295. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  296. flexmock(module).should_receive('execute_dump_command').with_args(
  297. database={'name': 'all'},
  298. config={},
  299. username=None,
  300. password=None,
  301. dump_path=object,
  302. database_names=('foo', 'bar'),
  303. environment={'USER': 'root'},
  304. dry_run=object,
  305. dry_run_label=object,
  306. ).and_return(process).once()
  307. assert module.dump_data_sources(
  308. databases,
  309. {},
  310. config_paths=('test.yaml',),
  311. borgmatic_runtime_directory='/run/borgmatic',
  312. patterns=[],
  313. dry_run=False,
  314. ) == [process]
  315. def test_dump_data_sources_dumps_all_databases_separately_when_format_configured():
  316. databases = [{'name': 'all', 'format': 'sql'}]
  317. processes = [flexmock(), flexmock()]
  318. flexmock(module).should_receive('make_dump_path').and_return('')
  319. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  320. 'resolve_credential',
  321. ).and_return(None)
  322. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  323. flexmock(module).should_receive('database_names_to_dump').and_return(('foo', 'bar'))
  324. for name, process in zip(('foo', 'bar'), processes):
  325. flexmock(module).should_receive('execute_dump_command').with_args(
  326. database={'name': name, 'format': 'sql'},
  327. config={},
  328. username=None,
  329. password=None,
  330. dump_path=object,
  331. database_names=(name,),
  332. environment={'USER': 'root'},
  333. dry_run=object,
  334. dry_run_label=object,
  335. ).and_return(process).once()
  336. assert (
  337. module.dump_data_sources(
  338. databases,
  339. {},
  340. config_paths=('test.yaml',),
  341. borgmatic_runtime_directory='/run/borgmatic',
  342. patterns=[],
  343. dry_run=False,
  344. )
  345. == processes
  346. )
  347. def test_dump_data_sources_errors_for_missing_all_databases():
  348. databases = [{'name': 'all'}]
  349. flexmock(module).should_receive('make_dump_path').and_return('')
  350. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  351. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  352. 'resolve_credential',
  353. ).replace_with(lambda value, config: value)
  354. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  355. 'databases/localhost/all',
  356. )
  357. flexmock(module).should_receive('database_names_to_dump').and_return(())
  358. with pytest.raises(ValueError):
  359. assert module.dump_data_sources(
  360. databases,
  361. {},
  362. config_paths=('test.yaml',),
  363. borgmatic_runtime_directory='/run/borgmatic',
  364. patterns=[],
  365. dry_run=False,
  366. )
  367. def test_dump_data_sources_does_not_error_for_missing_all_databases_with_dry_run():
  368. databases = [{'name': 'all'}]
  369. flexmock(module).should_receive('make_dump_path').and_return('')
  370. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  371. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  372. 'resolve_credential',
  373. ).replace_with(lambda value, config: value)
  374. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  375. 'databases/localhost/all',
  376. )
  377. flexmock(module).should_receive('database_names_to_dump').and_return(())
  378. assert (
  379. module.dump_data_sources(
  380. databases,
  381. {},
  382. config_paths=('test.yaml',),
  383. borgmatic_runtime_directory='/run/borgmatic',
  384. patterns=[],
  385. dry_run=True,
  386. )
  387. == []
  388. )
  389. def test_database_names_to_dump_runs_mysql_with_list_options():
  390. database = {'name': 'all', 'list_options': '--defaults-extra-file=my.cnf --skip-ssl'}
  391. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  392. 'parse_extra_options',
  393. ).and_return(('--skip-ssl',), 'my.cnf')
  394. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  395. 'make_defaults_file_options',
  396. ).with_args('root', 'trustsome1', 'my.cnf').and_return(('--defaults-extra-file=/dev/fd/99',))
  397. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  398. (
  399. 'mysql',
  400. '--defaults-extra-file=/dev/fd/99',
  401. '--skip-ssl',
  402. '--skip-column-names',
  403. '--batch',
  404. '--execute',
  405. 'show schemas',
  406. ),
  407. environment=None,
  408. ).and_return('foo\nbar').once()
  409. assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
  410. 'foo',
  411. 'bar',
  412. )
  413. def test_database_names_to_dump_runs_non_default_mysql_with_list_options():
  414. database = {
  415. 'name': 'all',
  416. 'list_options': '--defaults-extra-file=my.cnf --skip-ssl',
  417. 'mysql_command': 'custom_mysql',
  418. }
  419. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  420. 'parse_extra_options',
  421. ).and_return(('--skip-ssl',), 'my.cnf')
  422. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  423. 'make_defaults_file_options',
  424. ).with_args('root', 'trustsome1', 'my.cnf').and_return(('--defaults-extra-file=/dev/fd/99',))
  425. flexmock(module).should_receive('execute_command_and_capture_output').with_args(
  426. environment=None,
  427. full_command=(
  428. 'custom_mysql', # Custom MySQL command
  429. '--defaults-extra-file=/dev/fd/99',
  430. '--skip-ssl',
  431. '--skip-column-names',
  432. '--batch',
  433. '--execute',
  434. 'show schemas',
  435. ),
  436. ).and_return('foo\nbar').once()
  437. assert module.database_names_to_dump(database, {}, 'root', 'trustsome1', None, '') == (
  438. 'foo',
  439. 'bar',
  440. )
  441. def test_execute_dump_command_runs_mysqldump():
  442. process = flexmock()
  443. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  444. flexmock(module.os.path).should_receive('exists').and_return(False)
  445. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  446. 'resolve_credential',
  447. ).replace_with(lambda value, config: value)
  448. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  449. 'parse_extra_options',
  450. ).and_return((), None)
  451. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  452. 'make_defaults_file_options',
  453. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  454. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  455. flexmock(module).should_receive('execute_command').with_args(
  456. (
  457. 'mysqldump',
  458. '--defaults-extra-file=/dev/fd/99',
  459. '--add-drop-database',
  460. '--databases',
  461. 'foo',
  462. '--result-file',
  463. 'dump',
  464. ),
  465. environment=None,
  466. run_to_completion=False,
  467. ).and_return(process).once()
  468. assert (
  469. module.execute_dump_command(
  470. database={'name': 'foo'},
  471. config={},
  472. username='root',
  473. password='trustsome1',
  474. dump_path=flexmock(),
  475. database_names=('foo',),
  476. environment=None,
  477. dry_run=False,
  478. dry_run_label='',
  479. )
  480. == process
  481. )
  482. def test_execute_dump_command_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  483. process = flexmock()
  484. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  485. flexmock(module.os.path).should_receive('exists').and_return(False)
  486. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  487. 'resolve_credential',
  488. ).replace_with(lambda value, config: value)
  489. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  490. 'parse_extra_options',
  491. ).and_return((), None)
  492. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  493. 'make_defaults_file_options',
  494. ).never()
  495. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  496. flexmock(module).should_receive('execute_command').with_args(
  497. (
  498. 'mysqldump',
  499. '--add-drop-database',
  500. '--user',
  501. 'root',
  502. '--databases',
  503. 'foo',
  504. '--result-file',
  505. 'dump',
  506. ),
  507. environment=None,
  508. run_to_completion=False,
  509. ).and_return(process).once()
  510. assert (
  511. module.execute_dump_command(
  512. database={'name': 'foo', 'password_transport': 'environment'},
  513. config={},
  514. username='root',
  515. password='trustsome1',
  516. dump_path=flexmock(),
  517. database_names=('foo',),
  518. environment=None,
  519. dry_run=False,
  520. dry_run_label='',
  521. )
  522. == process
  523. )
  524. def test_execute_dump_command_runs_mysqldump_without_add_drop_database():
  525. process = flexmock()
  526. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  527. flexmock(module.os.path).should_receive('exists').and_return(False)
  528. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  529. 'resolve_credential',
  530. ).replace_with(lambda value, config: value)
  531. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  532. 'parse_extra_options',
  533. ).and_return((), None)
  534. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  535. 'make_defaults_file_options',
  536. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  537. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  538. flexmock(module).should_receive('execute_command').with_args(
  539. (
  540. 'mysqldump',
  541. '--defaults-extra-file=/dev/fd/99',
  542. '--databases',
  543. 'foo',
  544. '--result-file',
  545. 'dump',
  546. ),
  547. environment=None,
  548. run_to_completion=False,
  549. ).and_return(process).once()
  550. assert (
  551. module.execute_dump_command(
  552. database={'name': 'foo', 'add_drop_database': False},
  553. config={},
  554. username='root',
  555. password='trustsome1',
  556. dump_path=flexmock(),
  557. database_names=('foo',),
  558. environment=None,
  559. dry_run=False,
  560. dry_run_label='',
  561. )
  562. == process
  563. )
  564. def test_execute_dump_command_runs_mysqldump_with_hostname_and_port():
  565. process = flexmock()
  566. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  567. flexmock(module.os.path).should_receive('exists').and_return(False)
  568. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  569. 'resolve_credential',
  570. ).replace_with(lambda value, config: value)
  571. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  572. 'parse_extra_options',
  573. ).and_return((), None)
  574. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  575. 'make_defaults_file_options',
  576. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  577. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  578. flexmock(module).should_receive('execute_command').with_args(
  579. (
  580. 'mysqldump',
  581. '--defaults-extra-file=/dev/fd/99',
  582. '--add-drop-database',
  583. '--host',
  584. 'database.example.org',
  585. '--port',
  586. '5433',
  587. '--protocol',
  588. 'tcp',
  589. '--databases',
  590. 'foo',
  591. '--result-file',
  592. 'dump',
  593. ),
  594. environment=None,
  595. run_to_completion=False,
  596. ).and_return(process).once()
  597. assert (
  598. module.execute_dump_command(
  599. database={'name': 'foo', 'hostname': 'database.example.org', 'port': 5433},
  600. config={},
  601. username='root',
  602. password='trustsome1',
  603. dump_path=flexmock(),
  604. database_names=('foo',),
  605. environment=None,
  606. dry_run=False,
  607. dry_run_label='',
  608. )
  609. == process
  610. )
  611. def test_execute_dump_command_runs_mysqldump_with_tls():
  612. process = flexmock()
  613. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  614. flexmock(module.os.path).should_receive('exists').and_return(False)
  615. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  616. 'resolve_credential',
  617. ).replace_with(lambda value, config: value)
  618. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  619. 'parse_extra_options',
  620. ).and_return((), None)
  621. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  622. 'make_defaults_file_options',
  623. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  624. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  625. flexmock(module).should_receive('execute_command').with_args(
  626. (
  627. 'mysqldump',
  628. '--defaults-extra-file=/dev/fd/99',
  629. '--add-drop-database',
  630. '--ssl',
  631. '--databases',
  632. 'foo',
  633. '--result-file',
  634. 'dump',
  635. ),
  636. environment=None,
  637. run_to_completion=False,
  638. ).and_return(process).once()
  639. assert (
  640. module.execute_dump_command(
  641. database={'name': 'foo', 'tls': True},
  642. config={},
  643. username='root',
  644. password='trustsome1',
  645. dump_path=flexmock(),
  646. database_names=('foo',),
  647. environment=None,
  648. dry_run=False,
  649. dry_run_label='',
  650. )
  651. == process
  652. )
  653. def test_execute_dump_command_runs_mysqldump_without_tls():
  654. process = flexmock()
  655. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  656. flexmock(module.os.path).should_receive('exists').and_return(False)
  657. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  658. 'resolve_credential',
  659. ).replace_with(lambda value, config: value)
  660. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  661. 'parse_extra_options',
  662. ).and_return((), None)
  663. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  664. 'make_defaults_file_options',
  665. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  666. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  667. flexmock(module).should_receive('execute_command').with_args(
  668. (
  669. 'mysqldump',
  670. '--defaults-extra-file=/dev/fd/99',
  671. '--add-drop-database',
  672. '--skip-ssl',
  673. '--databases',
  674. 'foo',
  675. '--result-file',
  676. 'dump',
  677. ),
  678. environment=None,
  679. run_to_completion=False,
  680. ).and_return(process).once()
  681. assert (
  682. module.execute_dump_command(
  683. database={'name': 'foo', 'tls': False},
  684. config={},
  685. username='root',
  686. password='trustsome1',
  687. dump_path=flexmock(),
  688. database_names=('foo',),
  689. environment=None,
  690. dry_run=False,
  691. dry_run_label='',
  692. )
  693. == process
  694. )
  695. def test_execute_dump_command_runs_mysqldump_with_username_and_password():
  696. process = flexmock()
  697. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  698. flexmock(module.os.path).should_receive('exists').and_return(False)
  699. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  700. 'resolve_credential',
  701. ).replace_with(lambda value, config: value)
  702. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  703. 'parse_extra_options',
  704. ).and_return((), None)
  705. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  706. 'make_defaults_file_options',
  707. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  708. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  709. flexmock(module).should_receive('execute_command').with_args(
  710. (
  711. 'mysqldump',
  712. '--defaults-extra-file=/dev/fd/99',
  713. '--add-drop-database',
  714. '--databases',
  715. 'foo',
  716. '--result-file',
  717. 'dump',
  718. ),
  719. environment={},
  720. run_to_completion=False,
  721. ).and_return(process).once()
  722. assert (
  723. module.execute_dump_command(
  724. database={'name': 'foo', 'username': 'root', 'password': 'trustsome1'},
  725. config={},
  726. username='root',
  727. password='trustsome1',
  728. dump_path=flexmock(),
  729. database_names=('foo',),
  730. environment={},
  731. dry_run=False,
  732. dry_run_label='',
  733. )
  734. == process
  735. )
  736. def test_execute_dump_command_runs_mysqldump_with_options():
  737. process = flexmock()
  738. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  739. flexmock(module.os.path).should_receive('exists').and_return(False)
  740. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  741. 'resolve_credential',
  742. ).replace_with(lambda value, config: value)
  743. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  744. 'parse_extra_options',
  745. ).and_return(('--stuff=such',), None)
  746. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  747. 'make_defaults_file_options',
  748. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  749. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  750. flexmock(module).should_receive('execute_command').with_args(
  751. (
  752. 'mysqldump',
  753. '--defaults-extra-file=/dev/fd/99',
  754. '--stuff=such',
  755. '--add-drop-database',
  756. '--databases',
  757. 'foo',
  758. '--result-file',
  759. 'dump',
  760. ),
  761. environment=None,
  762. run_to_completion=False,
  763. ).and_return(process).once()
  764. assert (
  765. module.execute_dump_command(
  766. database={'name': 'foo', 'options': '--stuff=such'},
  767. config={},
  768. username='root',
  769. password='trustsome1',
  770. dump_path=flexmock(),
  771. database_names=('foo',),
  772. environment=None,
  773. dry_run=False,
  774. dry_run_label='',
  775. )
  776. == process
  777. )
  778. def test_execute_dump_command_runs_non_default_mysqldump():
  779. process = flexmock()
  780. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  781. flexmock(module.os.path).should_receive('exists').and_return(False)
  782. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  783. 'resolve_credential',
  784. ).replace_with(lambda value, config: value)
  785. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  786. 'parse_extra_options',
  787. ).and_return((), None)
  788. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  789. 'make_defaults_file_options',
  790. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  791. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  792. flexmock(module).should_receive('execute_command').with_args(
  793. (
  794. 'custom_mysqldump', # Custom MySQL dump command
  795. '--defaults-extra-file=/dev/fd/99',
  796. '--add-drop-database',
  797. '--databases',
  798. 'foo',
  799. '--result-file',
  800. 'dump',
  801. ),
  802. environment=None,
  803. run_to_completion=False,
  804. ).and_return(process).once()
  805. assert (
  806. module.execute_dump_command(
  807. database={
  808. 'name': 'foo',
  809. 'mysql_dump_command': 'custom_mysqldump',
  810. }, # Custom MySQL dump command specified
  811. config={},
  812. username='root',
  813. password='trustsome1',
  814. dump_path=flexmock(),
  815. database_names=('foo',),
  816. environment=None,
  817. dry_run=False,
  818. dry_run_label='',
  819. )
  820. == process
  821. )
  822. def test_execute_dump_command_with_duplicate_dump_skips_mysqldump():
  823. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  824. flexmock(module.os.path).should_receive('exists').and_return(True)
  825. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  826. 'parse_extra_options',
  827. ).and_return((), None)
  828. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  829. 'make_defaults_file_options',
  830. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  831. flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
  832. flexmock(module).should_receive('execute_command').never()
  833. assert (
  834. module.execute_dump_command(
  835. database={'name': 'foo'},
  836. config={},
  837. username='root',
  838. password='trustsome1',
  839. dump_path=flexmock(),
  840. database_names=('foo',),
  841. environment=None,
  842. dry_run=True,
  843. dry_run_label='SO DRY',
  844. )
  845. is None
  846. )
  847. def test_execute_dump_command_with_dry_run_skips_mysqldump():
  848. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('dump')
  849. flexmock(module.os.path).should_receive('exists').and_return(False)
  850. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  851. 'resolve_credential',
  852. ).replace_with(lambda value, config: value)
  853. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  854. 'parse_extra_options',
  855. ).and_return((), None)
  856. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  857. 'make_defaults_file_options',
  858. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  859. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  860. flexmock(module).should_receive('execute_command').never()
  861. assert (
  862. module.execute_dump_command(
  863. database={'name': 'foo'},
  864. config={},
  865. username='root',
  866. password='trustsome1',
  867. dump_path=flexmock(),
  868. database_names=('foo',),
  869. environment=None,
  870. dry_run=True,
  871. dry_run_label='SO DRY',
  872. )
  873. is None
  874. )
  875. def test_restore_data_source_dump_runs_mysql_to_restore():
  876. hook_config = [{'name': 'foo'}, {'name': 'bar'}]
  877. extract_process = flexmock(stdout=flexmock())
  878. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  879. 'resolve_credential',
  880. ).replace_with(lambda value, config: value)
  881. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  882. 'parse_extra_options',
  883. ).and_return((), None)
  884. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  885. 'make_defaults_file_options',
  886. ).with_args(None, None, None).and_return(())
  887. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  888. flexmock(module).should_receive('execute_command_with_processes').with_args(
  889. ('mysql', '--batch'),
  890. processes=[extract_process],
  891. output_log_level=logging.DEBUG,
  892. input_file=extract_process.stdout,
  893. environment={'USER': 'root'},
  894. ).once()
  895. module.restore_data_source_dump(
  896. hook_config,
  897. {},
  898. data_source={'name': 'foo'},
  899. dry_run=False,
  900. extract_process=extract_process,
  901. connection_params={
  902. 'hostname': None,
  903. 'port': None,
  904. 'username': None,
  905. 'password': None,
  906. },
  907. borgmatic_runtime_directory='/run/borgmatic',
  908. )
  909. def test_restore_data_source_dump_runs_mysql_with_options():
  910. hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
  911. extract_process = flexmock(stdout=flexmock())
  912. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  913. 'resolve_credential',
  914. ).replace_with(lambda value, config: value)
  915. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  916. 'parse_extra_options',
  917. ).and_return(('--harder',), None)
  918. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  919. 'make_defaults_file_options',
  920. ).with_args(None, None, None).and_return(())
  921. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  922. flexmock(module).should_receive('execute_command_with_processes').with_args(
  923. ('mysql', '--harder', '--batch'),
  924. processes=[extract_process],
  925. output_log_level=logging.DEBUG,
  926. input_file=extract_process.stdout,
  927. environment={'USER': 'root'},
  928. ).once()
  929. module.restore_data_source_dump(
  930. hook_config,
  931. {},
  932. data_source=hook_config[0],
  933. dry_run=False,
  934. extract_process=extract_process,
  935. connection_params={
  936. 'hostname': None,
  937. 'port': None,
  938. 'username': None,
  939. 'password': None,
  940. },
  941. borgmatic_runtime_directory='/run/borgmatic',
  942. )
  943. def test_restore_data_source_dump_runs_non_default_mysql_with_options():
  944. hook_config = [{'name': 'foo', 'mysql_command': 'custom_mysql', 'restore_options': '--harder'}]
  945. extract_process = flexmock(stdout=flexmock())
  946. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  947. 'resolve_credential',
  948. ).replace_with(lambda value, config: value)
  949. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  950. 'parse_extra_options',
  951. ).and_return(('--harder',), None)
  952. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  953. 'make_defaults_file_options',
  954. ).with_args(None, None, None).and_return(())
  955. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  956. flexmock(module).should_receive('execute_command_with_processes').with_args(
  957. ('custom_mysql', '--harder', '--batch'),
  958. processes=[extract_process],
  959. output_log_level=logging.DEBUG,
  960. input_file=extract_process.stdout,
  961. environment={'USER': 'root'},
  962. ).once()
  963. module.restore_data_source_dump(
  964. hook_config,
  965. {},
  966. data_source=hook_config[0],
  967. dry_run=False,
  968. extract_process=extract_process,
  969. connection_params={
  970. 'hostname': None,
  971. 'port': None,
  972. 'username': None,
  973. 'password': None,
  974. },
  975. borgmatic_runtime_directory='/run/borgmatic',
  976. )
  977. def test_restore_data_source_dump_runs_mysql_with_hostname_and_port():
  978. hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
  979. extract_process = flexmock(stdout=flexmock())
  980. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  981. 'resolve_credential',
  982. ).replace_with(lambda value, config: value)
  983. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  984. 'parse_extra_options',
  985. ).and_return((), None)
  986. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  987. 'make_defaults_file_options',
  988. ).with_args(None, None, None).and_return(())
  989. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  990. flexmock(module).should_receive('execute_command_with_processes').with_args(
  991. (
  992. 'mysql',
  993. '--batch',
  994. '--host',
  995. 'database.example.org',
  996. '--port',
  997. '5433',
  998. '--protocol',
  999. 'tcp',
  1000. ),
  1001. processes=[extract_process],
  1002. output_log_level=logging.DEBUG,
  1003. input_file=extract_process.stdout,
  1004. environment={'USER': 'root'},
  1005. ).once()
  1006. module.restore_data_source_dump(
  1007. hook_config,
  1008. {},
  1009. data_source=hook_config[0],
  1010. dry_run=False,
  1011. extract_process=extract_process,
  1012. connection_params={
  1013. 'hostname': None,
  1014. 'port': None,
  1015. 'username': None,
  1016. 'password': None,
  1017. },
  1018. borgmatic_runtime_directory='/run/borgmatic',
  1019. )
  1020. def test_restore_data_source_dump_runs_mysql_with_tls():
  1021. hook_config = [{'name': 'foo', 'tls': True}]
  1022. extract_process = flexmock(stdout=flexmock())
  1023. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1024. 'resolve_credential',
  1025. ).replace_with(lambda value, config: value)
  1026. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1027. 'parse_extra_options',
  1028. ).and_return((), None)
  1029. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1030. 'make_defaults_file_options',
  1031. ).with_args(None, None, None).and_return(())
  1032. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1033. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1034. (
  1035. 'mysql',
  1036. '--batch',
  1037. '--ssl',
  1038. ),
  1039. processes=[extract_process],
  1040. output_log_level=logging.DEBUG,
  1041. input_file=extract_process.stdout,
  1042. environment={'USER': 'root'},
  1043. ).once()
  1044. module.restore_data_source_dump(
  1045. hook_config,
  1046. {},
  1047. data_source=hook_config[0],
  1048. dry_run=False,
  1049. extract_process=extract_process,
  1050. connection_params={
  1051. 'hostname': None,
  1052. 'port': None,
  1053. 'username': None,
  1054. 'password': None,
  1055. },
  1056. borgmatic_runtime_directory='/run/borgmatic',
  1057. )
  1058. def test_restore_data_source_dump_runs_mysql_without_tls():
  1059. hook_config = [{'name': 'foo', 'tls': False}]
  1060. extract_process = flexmock(stdout=flexmock())
  1061. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1062. 'resolve_credential',
  1063. ).replace_with(lambda value, config: value)
  1064. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1065. 'parse_extra_options',
  1066. ).and_return((), None)
  1067. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1068. 'make_defaults_file_options',
  1069. ).with_args(None, None, None).and_return(())
  1070. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1071. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1072. (
  1073. 'mysql',
  1074. '--batch',
  1075. '--skip-ssl',
  1076. ),
  1077. processes=[extract_process],
  1078. output_log_level=logging.DEBUG,
  1079. input_file=extract_process.stdout,
  1080. environment={'USER': 'root'},
  1081. ).once()
  1082. module.restore_data_source_dump(
  1083. hook_config,
  1084. {},
  1085. data_source=hook_config[0],
  1086. dry_run=False,
  1087. extract_process=extract_process,
  1088. connection_params={
  1089. 'hostname': None,
  1090. 'port': None,
  1091. 'username': None,
  1092. 'password': None,
  1093. },
  1094. borgmatic_runtime_directory='/run/borgmatic',
  1095. )
  1096. def test_restore_data_source_dump_runs_mysql_with_username_and_password():
  1097. hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
  1098. extract_process = flexmock(stdout=flexmock())
  1099. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1100. 'resolve_credential',
  1101. ).replace_with(lambda value, config: value)
  1102. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1103. 'parse_extra_options',
  1104. ).and_return((), None)
  1105. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1106. 'make_defaults_file_options',
  1107. ).with_args('root', 'trustsome1', None).and_return(('--defaults-extra-file=/dev/fd/99',))
  1108. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1109. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1110. ('mysql', '--defaults-extra-file=/dev/fd/99', '--batch'),
  1111. processes=[extract_process],
  1112. output_log_level=logging.DEBUG,
  1113. input_file=extract_process.stdout,
  1114. environment={'USER': 'root'},
  1115. ).once()
  1116. module.restore_data_source_dump(
  1117. hook_config,
  1118. {},
  1119. data_source=hook_config[0],
  1120. dry_run=False,
  1121. extract_process=extract_process,
  1122. connection_params={
  1123. 'hostname': None,
  1124. 'port': None,
  1125. 'username': None,
  1126. 'password': None,
  1127. },
  1128. borgmatic_runtime_directory='/run/borgmatic',
  1129. )
  1130. def test_restore_data_source_with_environment_password_transport_skips_defaults_file_and_passes_user_flag():
  1131. hook_config = [
  1132. {
  1133. 'name': 'foo',
  1134. 'username': 'root',
  1135. 'password': 'trustsome1',
  1136. 'password_transport': 'environment',
  1137. },
  1138. ]
  1139. extract_process = flexmock(stdout=flexmock())
  1140. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1141. 'resolve_credential',
  1142. ).replace_with(lambda value, config: value)
  1143. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1144. 'parse_extra_options',
  1145. ).and_return((), None)
  1146. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1147. 'make_defaults_file_options',
  1148. ).never()
  1149. flexmock(module.os).should_receive('environ').and_return(
  1150. {'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  1151. )
  1152. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1153. ('mysql', '--batch', '--user', 'root'),
  1154. processes=[extract_process],
  1155. output_log_level=logging.DEBUG,
  1156. input_file=extract_process.stdout,
  1157. environment={'USER': 'root', 'MYSQL_PWD': 'trustsome1'},
  1158. ).once()
  1159. module.restore_data_source_dump(
  1160. hook_config,
  1161. {},
  1162. data_source=hook_config[0],
  1163. dry_run=False,
  1164. extract_process=extract_process,
  1165. connection_params={
  1166. 'hostname': None,
  1167. 'port': None,
  1168. 'username': None,
  1169. 'password': None,
  1170. },
  1171. borgmatic_runtime_directory='/run/borgmatic',
  1172. )
  1173. def test_restore_data_source_dump_with_connection_params_uses_connection_params_for_restore():
  1174. hook_config = [
  1175. {
  1176. 'name': 'foo',
  1177. 'username': 'root',
  1178. 'password': 'trustsome1',
  1179. 'restore_hostname': 'restorehost',
  1180. 'restore_port': 'restoreport',
  1181. 'restore_username': 'restoreusername',
  1182. 'restore_password': 'restorepassword',
  1183. },
  1184. ]
  1185. extract_process = flexmock(stdout=flexmock())
  1186. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1187. 'resolve_credential',
  1188. ).replace_with(lambda value, config: value)
  1189. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1190. 'parse_extra_options',
  1191. ).and_return((), None)
  1192. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1193. 'make_defaults_file_options',
  1194. ).with_args('cliusername', 'clipassword', None).and_return(
  1195. ('--defaults-extra-file=/dev/fd/99',),
  1196. )
  1197. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1198. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1199. (
  1200. 'mysql',
  1201. '--defaults-extra-file=/dev/fd/99',
  1202. '--batch',
  1203. '--host',
  1204. 'clihost',
  1205. '--port',
  1206. 'cliport',
  1207. '--protocol',
  1208. 'tcp',
  1209. ),
  1210. processes=[extract_process],
  1211. output_log_level=logging.DEBUG,
  1212. input_file=extract_process.stdout,
  1213. environment={'USER': 'root'},
  1214. ).once()
  1215. module.restore_data_source_dump(
  1216. hook_config,
  1217. {},
  1218. data_source={'name': 'foo'},
  1219. dry_run=False,
  1220. extract_process=extract_process,
  1221. connection_params={
  1222. 'hostname': 'clihost',
  1223. 'port': 'cliport',
  1224. 'username': 'cliusername',
  1225. 'password': 'clipassword',
  1226. },
  1227. borgmatic_runtime_directory='/run/borgmatic',
  1228. )
  1229. def test_restore_data_source_dump_without_connection_params_uses_restore_params_in_config_for_restore():
  1230. hook_config = [
  1231. {
  1232. 'name': 'foo',
  1233. 'username': 'root',
  1234. 'password': 'trustsome1',
  1235. 'hostname': 'dbhost',
  1236. 'port': 'dbport',
  1237. 'tls': True,
  1238. 'restore_username': 'restoreuser',
  1239. 'restore_password': 'restorepass',
  1240. 'restore_hostname': 'restorehost',
  1241. 'restore_port': 'restoreport',
  1242. 'restore_tls': False,
  1243. },
  1244. ]
  1245. extract_process = flexmock(stdout=flexmock())
  1246. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1247. 'resolve_credential',
  1248. ).replace_with(lambda value, config: value)
  1249. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1250. 'parse_extra_options',
  1251. ).and_return((), None)
  1252. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1253. 'make_defaults_file_options',
  1254. ).with_args('restoreuser', 'restorepass', None).and_return(
  1255. ('--defaults-extra-file=/dev/fd/99',),
  1256. )
  1257. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1258. flexmock(module).should_receive('execute_command_with_processes').with_args(
  1259. (
  1260. 'mysql',
  1261. '--defaults-extra-file=/dev/fd/99',
  1262. '--batch',
  1263. '--host',
  1264. 'restorehost',
  1265. '--port',
  1266. 'restoreport',
  1267. '--protocol',
  1268. 'tcp',
  1269. '--skip-ssl',
  1270. ),
  1271. processes=[extract_process],
  1272. output_log_level=logging.DEBUG,
  1273. input_file=extract_process.stdout,
  1274. environment={'USER': 'root'},
  1275. ).once()
  1276. module.restore_data_source_dump(
  1277. hook_config,
  1278. {},
  1279. data_source=hook_config[0],
  1280. dry_run=False,
  1281. extract_process=extract_process,
  1282. connection_params={
  1283. 'hostname': None,
  1284. 'port': None,
  1285. 'username': None,
  1286. 'password': None,
  1287. },
  1288. borgmatic_runtime_directory='/run/borgmatic',
  1289. )
  1290. def test_restore_data_source_dump_with_dry_run_skips_restore():
  1291. hook_config = [{'name': 'foo'}]
  1292. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  1293. 'resolve_credential',
  1294. ).replace_with(lambda value, config: value)
  1295. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1296. 'parse_extra_options',
  1297. ).and_return((), None)
  1298. flexmock(module.borgmatic.hooks.data_source.mariadb).should_receive(
  1299. 'make_defaults_file_options',
  1300. ).with_args(None, None, None).and_return(())
  1301. flexmock(module.os).should_receive('environ').and_return({'USER': 'root'})
  1302. flexmock(module).should_receive('execute_command_with_processes').never()
  1303. module.restore_data_source_dump(
  1304. hook_config,
  1305. {},
  1306. data_source={'name': 'foo'},
  1307. dry_run=True,
  1308. extract_process=flexmock(),
  1309. connection_params={
  1310. 'hostname': None,
  1311. 'port': None,
  1312. 'username': None,
  1313. 'password': None,
  1314. },
  1315. borgmatic_runtime_directory='/run/borgmatic',
  1316. )