test_mysql.py 43 KB

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