test_mysql.py 49 KB

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