test_mongodb.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. import logging
  2. from flexmock import flexmock
  3. from borgmatic.hooks.data_source import mongodb as module
  4. def test_use_streaming_true_for_any_non_directory_format_databases():
  5. assert module.use_streaming(
  6. databases=[{'format': 'stuff'}, {'format': 'directory'}, {}],
  7. config=flexmock(),
  8. )
  9. def test_use_streaming_false_for_all_directory_format_databases():
  10. assert not module.use_streaming(
  11. databases=[{'format': 'directory'}, {'format': 'directory'}],
  12. config=flexmock(),
  13. )
  14. def test_use_streaming_false_for_no_databases():
  15. assert not module.use_streaming(databases=[], config=flexmock())
  16. def test_dump_data_sources_runs_mongodump_for_each_database():
  17. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  18. flexmock()
  19. )
  20. databases = [{'name': 'foo'}, {'name': 'bar'}]
  21. processes = [flexmock(), flexmock()]
  22. flexmock(module).should_receive('make_dump_path').and_return('')
  23. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  24. 'databases/localhost/foo'
  25. ).and_return('databases/localhost/bar')
  26. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  27. for name, process in zip(('foo', 'bar'), processes):
  28. flexmock(module).should_receive('execute_command').with_args(
  29. ('mongodump', '--db', name, '--archive', '>', f'databases/localhost/{name}'),
  30. shell=True,
  31. run_to_completion=False,
  32. ).and_return(process).once()
  33. assert (
  34. module.dump_data_sources(
  35. databases,
  36. {},
  37. config_paths=('test.yaml',),
  38. borgmatic_runtime_directory='/run/borgmatic',
  39. patterns=[],
  40. dry_run=False,
  41. )
  42. == processes
  43. )
  44. def test_dump_data_sources_with_dry_run_skips_mongodump():
  45. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  46. flexmock()
  47. )
  48. databases = [{'name': 'foo'}, {'name': 'bar'}]
  49. flexmock(module).should_receive('make_dump_path').and_return('')
  50. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  51. 'databases/localhost/foo'
  52. ).and_return('databases/localhost/bar')
  53. flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
  54. flexmock(module).should_receive('execute_command').never()
  55. assert (
  56. module.dump_data_sources(
  57. databases,
  58. {},
  59. config_paths=('test.yaml',),
  60. borgmatic_runtime_directory='/run/borgmatic',
  61. patterns=[],
  62. dry_run=True,
  63. )
  64. == []
  65. )
  66. def test_dump_data_sources_runs_mongodump_with_hostname_and_port():
  67. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  68. flexmock()
  69. )
  70. databases = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
  71. process = flexmock()
  72. flexmock(module).should_receive('make_dump_path').and_return('')
  73. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  74. 'databases/database.example.org/foo'
  75. )
  76. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  77. flexmock(module).should_receive('execute_command').with_args(
  78. (
  79. 'mongodump',
  80. '--host',
  81. 'database.example.org',
  82. '--port',
  83. '5433',
  84. '--db',
  85. 'foo',
  86. '--archive',
  87. '>',
  88. 'databases/database.example.org/foo',
  89. ),
  90. shell=True,
  91. run_to_completion=False,
  92. ).and_return(process).once()
  93. assert module.dump_data_sources(
  94. databases,
  95. {},
  96. config_paths=('test.yaml',),
  97. borgmatic_runtime_directory='/run/borgmatic',
  98. patterns=[],
  99. dry_run=False,
  100. ) == [process]
  101. def test_dump_data_sources_runs_mongodump_with_username_and_password():
  102. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  103. flexmock()
  104. )
  105. databases = [
  106. {
  107. 'name': 'foo',
  108. 'username': 'mongo',
  109. 'password': 'trustsome1',
  110. 'authentication_database': 'admin',
  111. }
  112. ]
  113. process = flexmock()
  114. flexmock(module).should_receive('make_dump_path').and_return('')
  115. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  116. 'databases/localhost/foo'
  117. )
  118. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  119. 'resolve_credential'
  120. ).replace_with(lambda value, config: value)
  121. flexmock(module).should_receive('make_password_config_file').with_args('trustsome1').and_return(
  122. '/dev/fd/99'
  123. )
  124. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  125. flexmock(module).should_receive('execute_command').with_args(
  126. (
  127. 'mongodump',
  128. '--username',
  129. 'mongo',
  130. '--config',
  131. '/dev/fd/99',
  132. '--authenticationDatabase',
  133. 'admin',
  134. '--db',
  135. 'foo',
  136. '--archive',
  137. '>',
  138. 'databases/localhost/foo',
  139. ),
  140. shell=True,
  141. run_to_completion=False,
  142. ).and_return(process).once()
  143. assert module.dump_data_sources(
  144. databases,
  145. {},
  146. config_paths=('test.yaml',),
  147. borgmatic_runtime_directory='/run/borgmatic',
  148. patterns=[],
  149. dry_run=False,
  150. ) == [process]
  151. def test_dump_data_sources_runs_mongodump_with_directory_format():
  152. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  153. flexmock()
  154. )
  155. databases = [{'name': 'foo', 'format': 'directory'}]
  156. flexmock(module).should_receive('make_dump_path').and_return('')
  157. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  158. 'databases/localhost/foo'
  159. )
  160. flexmock(module.dump).should_receive('create_parent_directory_for_dump')
  161. flexmock(module.dump).should_receive('create_named_pipe_for_dump').never()
  162. flexmock(module).should_receive('execute_command').with_args(
  163. ('mongodump', '--out', 'databases/localhost/foo', '--db', 'foo'),
  164. shell=True,
  165. ).and_return(flexmock()).once()
  166. assert (
  167. module.dump_data_sources(
  168. databases,
  169. {},
  170. config_paths=('test.yaml',),
  171. borgmatic_runtime_directory='/run/borgmatic',
  172. patterns=[],
  173. dry_run=False,
  174. )
  175. == []
  176. )
  177. def test_dump_data_sources_runs_mongodump_with_options():
  178. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  179. flexmock()
  180. )
  181. databases = [{'name': 'foo', 'options': '--stuff=such'}]
  182. process = flexmock()
  183. flexmock(module).should_receive('make_dump_path').and_return('')
  184. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  185. 'databases/localhost/foo'
  186. )
  187. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  188. flexmock(module).should_receive('execute_command').with_args(
  189. (
  190. 'mongodump',
  191. '--db',
  192. 'foo',
  193. '--stuff=such',
  194. '--archive',
  195. '>',
  196. 'databases/localhost/foo',
  197. ),
  198. shell=True,
  199. run_to_completion=False,
  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_runs_mongodumpall_for_all_databases():
  210. flexmock(module.borgmatic.hooks.command).should_receive('Before_after_hooks').and_return(
  211. flexmock()
  212. )
  213. databases = [{'name': 'all'}]
  214. process = flexmock()
  215. flexmock(module).should_receive('make_dump_path').and_return('')
  216. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return(
  217. 'databases/localhost/all'
  218. )
  219. flexmock(module.dump).should_receive('create_named_pipe_for_dump')
  220. flexmock(module).should_receive('execute_command').with_args(
  221. ('mongodump', '--archive', '>', 'databases/localhost/all'),
  222. shell=True,
  223. run_to_completion=False,
  224. ).and_return(process).once()
  225. assert module.dump_data_sources(
  226. databases,
  227. {},
  228. config_paths=('test.yaml',),
  229. borgmatic_runtime_directory='/run/borgmatic',
  230. patterns=[],
  231. dry_run=False,
  232. ) == [process]
  233. def test_make_password_config_file_writes_password_to_pipe():
  234. read_file_descriptor = 99
  235. write_file_descriptor = flexmock()
  236. flexmock(module.os).should_receive('pipe').and_return(
  237. (read_file_descriptor, write_file_descriptor)
  238. )
  239. flexmock(module.os).should_receive('write').with_args(
  240. write_file_descriptor, b'password: trustsome1'
  241. ).once()
  242. flexmock(module.os).should_receive('close')
  243. flexmock(module.os).should_receive('set_inheritable')
  244. assert module.make_password_config_file('trustsome1') == '/dev/fd/99'
  245. def test_build_dump_command_with_username_injection_attack_gets_escaped():
  246. database = {'name': 'test', 'username': 'bob; naughty-command'}
  247. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  248. 'resolve_credential'
  249. ).replace_with(lambda value, config: value)
  250. command = module.build_dump_command(database, {}, dump_filename='test', dump_format='archive')
  251. assert "'bob; naughty-command'" in command
  252. def test_restore_data_source_dump_runs_mongorestore():
  253. hook_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}]
  254. extract_process = flexmock(stdout=flexmock())
  255. flexmock(module).should_receive('make_dump_path')
  256. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  257. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  258. 'resolve_credential'
  259. ).replace_with(lambda value, config: value)
  260. flexmock(module).should_receive('execute_command_with_processes').with_args(
  261. ['mongorestore', '--archive', '--drop'],
  262. processes=[extract_process],
  263. output_log_level=logging.DEBUG,
  264. input_file=extract_process.stdout,
  265. ).once()
  266. module.restore_data_source_dump(
  267. hook_config,
  268. {},
  269. data_source={'name': 'foo'},
  270. dry_run=False,
  271. extract_process=extract_process,
  272. connection_params={
  273. 'hostname': None,
  274. 'port': None,
  275. 'username': None,
  276. 'password': None,
  277. },
  278. borgmatic_runtime_directory='/run/borgmatic',
  279. )
  280. def test_restore_data_source_dump_runs_mongorestore_with_hostname_and_port():
  281. hook_config = [
  282. {'name': 'foo', 'hostname': 'database.example.org', 'port': 5433, 'schemas': None}
  283. ]
  284. extract_process = flexmock(stdout=flexmock())
  285. flexmock(module).should_receive('make_dump_path')
  286. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  287. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  288. 'resolve_credential'
  289. ).replace_with(lambda value, config: value)
  290. flexmock(module).should_receive('execute_command_with_processes').with_args(
  291. [
  292. 'mongorestore',
  293. '--archive',
  294. '--drop',
  295. '--host',
  296. 'database.example.org',
  297. '--port',
  298. '5433',
  299. ],
  300. processes=[extract_process],
  301. output_log_level=logging.DEBUG,
  302. input_file=extract_process.stdout,
  303. ).once()
  304. module.restore_data_source_dump(
  305. hook_config,
  306. {},
  307. data_source=hook_config[0],
  308. dry_run=False,
  309. extract_process=extract_process,
  310. connection_params={
  311. 'hostname': None,
  312. 'port': None,
  313. 'username': None,
  314. 'password': None,
  315. },
  316. borgmatic_runtime_directory='/run/borgmatic',
  317. )
  318. def test_restore_data_source_dump_runs_mongorestore_with_username_and_password():
  319. hook_config = [
  320. {
  321. 'name': 'foo',
  322. 'username': 'mongo',
  323. 'password': 'trustsome1',
  324. 'authentication_database': 'admin',
  325. 'schemas': None,
  326. }
  327. ]
  328. extract_process = flexmock(stdout=flexmock())
  329. flexmock(module).should_receive('make_dump_path')
  330. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  331. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  332. 'resolve_credential'
  333. ).replace_with(lambda value, config: value)
  334. flexmock(module).should_receive('make_password_config_file').with_args('trustsome1').and_return(
  335. '/dev/fd/99'
  336. )
  337. flexmock(module).should_receive('execute_command_with_processes').with_args(
  338. [
  339. 'mongorestore',
  340. '--archive',
  341. '--drop',
  342. '--username',
  343. 'mongo',
  344. '--config',
  345. '/dev/fd/99',
  346. '--authenticationDatabase',
  347. 'admin',
  348. ],
  349. processes=[extract_process],
  350. output_log_level=logging.DEBUG,
  351. input_file=extract_process.stdout,
  352. ).once()
  353. module.restore_data_source_dump(
  354. hook_config,
  355. {},
  356. data_source=hook_config[0],
  357. dry_run=False,
  358. extract_process=extract_process,
  359. connection_params={
  360. 'hostname': None,
  361. 'port': None,
  362. 'username': None,
  363. 'password': None,
  364. },
  365. borgmatic_runtime_directory='/run/borgmatic',
  366. )
  367. def test_restore_data_source_dump_with_connection_params_uses_connection_params_for_restore():
  368. hook_config = [
  369. {
  370. 'name': 'foo',
  371. 'username': 'mongo',
  372. 'password': 'trustsome1',
  373. 'authentication_database': 'admin',
  374. 'restore_hostname': 'restorehost',
  375. 'restore_port': 'restoreport',
  376. 'restore_username': 'restoreusername',
  377. 'restore_password': 'restorepassword',
  378. 'schemas': None,
  379. }
  380. ]
  381. extract_process = flexmock(stdout=flexmock())
  382. flexmock(module).should_receive('make_dump_path')
  383. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  384. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  385. 'resolve_credential'
  386. ).replace_with(lambda value, config: value)
  387. flexmock(module).should_receive('make_password_config_file').with_args(
  388. 'clipassword'
  389. ).and_return('/dev/fd/99')
  390. flexmock(module).should_receive('execute_command_with_processes').with_args(
  391. [
  392. 'mongorestore',
  393. '--archive',
  394. '--drop',
  395. '--host',
  396. 'clihost',
  397. '--port',
  398. 'cliport',
  399. '--username',
  400. 'cliusername',
  401. '--config',
  402. '/dev/fd/99',
  403. '--authenticationDatabase',
  404. 'admin',
  405. ],
  406. processes=[extract_process],
  407. output_log_level=logging.DEBUG,
  408. input_file=extract_process.stdout,
  409. ).once()
  410. module.restore_data_source_dump(
  411. hook_config,
  412. {},
  413. data_source=hook_config[0],
  414. dry_run=False,
  415. extract_process=extract_process,
  416. connection_params={
  417. 'hostname': 'clihost',
  418. 'port': 'cliport',
  419. 'username': 'cliusername',
  420. 'password': 'clipassword',
  421. },
  422. borgmatic_runtime_directory='/run/borgmatic',
  423. )
  424. def test_restore_data_source_dump_without_connection_params_uses_restore_params_in_config_for_restore():
  425. hook_config = [
  426. {
  427. 'name': 'foo',
  428. 'username': 'mongo',
  429. 'password': 'trustsome1',
  430. 'authentication_database': 'admin',
  431. 'schemas': None,
  432. 'restore_hostname': 'restorehost',
  433. 'restore_port': 'restoreport',
  434. 'restore_username': 'restoreuser',
  435. 'restore_password': 'restorepass',
  436. }
  437. ]
  438. extract_process = flexmock(stdout=flexmock())
  439. flexmock(module).should_receive('make_dump_path')
  440. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  441. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  442. 'resolve_credential'
  443. ).replace_with(lambda value, config: value)
  444. flexmock(module).should_receive('make_password_config_file').with_args(
  445. 'restorepass'
  446. ).and_return('/dev/fd/99')
  447. flexmock(module).should_receive('execute_command_with_processes').with_args(
  448. [
  449. 'mongorestore',
  450. '--archive',
  451. '--drop',
  452. '--host',
  453. 'restorehost',
  454. '--port',
  455. 'restoreport',
  456. '--username',
  457. 'restoreuser',
  458. '--config',
  459. '/dev/fd/99',
  460. '--authenticationDatabase',
  461. 'admin',
  462. ],
  463. processes=[extract_process],
  464. output_log_level=logging.DEBUG,
  465. input_file=extract_process.stdout,
  466. ).once()
  467. module.restore_data_source_dump(
  468. hook_config,
  469. {},
  470. data_source=hook_config[0],
  471. dry_run=False,
  472. extract_process=extract_process,
  473. connection_params={
  474. 'hostname': None,
  475. 'port': None,
  476. 'username': None,
  477. 'password': None,
  478. },
  479. borgmatic_runtime_directory='/run/borgmatic',
  480. )
  481. def test_restore_data_source_dump_runs_mongorestore_with_options():
  482. hook_config = [{'name': 'foo', 'restore_options': '--harder', 'schemas': None}]
  483. extract_process = flexmock(stdout=flexmock())
  484. flexmock(module).should_receive('make_dump_path')
  485. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  486. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  487. 'resolve_credential'
  488. ).replace_with(lambda value, config: value)
  489. flexmock(module).should_receive('execute_command_with_processes').with_args(
  490. ['mongorestore', '--archive', '--drop', '--harder'],
  491. processes=[extract_process],
  492. output_log_level=logging.DEBUG,
  493. input_file=extract_process.stdout,
  494. ).once()
  495. module.restore_data_source_dump(
  496. hook_config,
  497. {},
  498. data_source=hook_config[0],
  499. dry_run=False,
  500. extract_process=extract_process,
  501. connection_params={
  502. 'hostname': None,
  503. 'port': None,
  504. 'username': None,
  505. 'password': None,
  506. },
  507. borgmatic_runtime_directory='/run/borgmatic',
  508. )
  509. def test_restore_databases_dump_runs_mongorestore_with_schemas():
  510. hook_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}]
  511. extract_process = flexmock(stdout=flexmock())
  512. flexmock(module).should_receive('make_dump_path')
  513. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  514. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  515. 'resolve_credential'
  516. ).replace_with(lambda value, config: value)
  517. flexmock(module).should_receive('execute_command_with_processes').with_args(
  518. [
  519. 'mongorestore',
  520. '--archive',
  521. '--drop',
  522. '--nsInclude',
  523. 'bar',
  524. '--nsInclude',
  525. 'baz',
  526. ],
  527. processes=[extract_process],
  528. output_log_level=logging.DEBUG,
  529. input_file=extract_process.stdout,
  530. ).once()
  531. module.restore_data_source_dump(
  532. hook_config,
  533. {},
  534. data_source=hook_config[0],
  535. dry_run=False,
  536. extract_process=extract_process,
  537. connection_params={
  538. 'hostname': None,
  539. 'port': None,
  540. 'username': None,
  541. 'password': None,
  542. },
  543. borgmatic_runtime_directory='/run/borgmatic',
  544. )
  545. def test_restore_data_source_dump_runs_psql_for_all_database_dump():
  546. hook_config = [{'name': 'all', 'schemas': None}]
  547. extract_process = flexmock(stdout=flexmock())
  548. flexmock(module).should_receive('make_dump_path')
  549. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  550. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  551. 'resolve_credential'
  552. ).replace_with(lambda value, config: value)
  553. flexmock(module).should_receive('execute_command_with_processes').with_args(
  554. ['mongorestore', '--archive'],
  555. processes=[extract_process],
  556. output_log_level=logging.DEBUG,
  557. input_file=extract_process.stdout,
  558. ).once()
  559. module.restore_data_source_dump(
  560. hook_config,
  561. {},
  562. data_source=hook_config[0],
  563. dry_run=False,
  564. extract_process=extract_process,
  565. connection_params={
  566. 'hostname': None,
  567. 'port': None,
  568. 'username': None,
  569. 'password': None,
  570. },
  571. borgmatic_runtime_directory='/run/borgmatic',
  572. )
  573. def test_restore_data_source_dump_with_dry_run_skips_restore():
  574. hook_config = [{'name': 'foo', 'schemas': None}]
  575. flexmock(module).should_receive('make_dump_path')
  576. flexmock(module.dump).should_receive('make_data_source_dump_filename')
  577. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  578. 'resolve_credential'
  579. ).replace_with(lambda value, config: value)
  580. flexmock(module).should_receive('execute_command_with_processes').never()
  581. module.restore_data_source_dump(
  582. hook_config,
  583. {},
  584. data_source={'name': 'foo'},
  585. dry_run=True,
  586. extract_process=flexmock(),
  587. connection_params={
  588. 'hostname': None,
  589. 'port': None,
  590. 'username': None,
  591. 'password': None,
  592. },
  593. borgmatic_runtime_directory='/run/borgmatic',
  594. )
  595. def test_restore_data_source_dump_without_extract_process_restores_from_disk():
  596. hook_config = [{'name': 'foo', 'format': 'directory', 'schemas': None}]
  597. flexmock(module).should_receive('make_dump_path')
  598. flexmock(module.dump).should_receive('make_data_source_dump_filename').and_return('/dump/path')
  599. flexmock(module.borgmatic.hooks.credential.parse).should_receive(
  600. 'resolve_credential'
  601. ).replace_with(lambda value, config: value)
  602. flexmock(module).should_receive('execute_command_with_processes').with_args(
  603. ['mongorestore', '--dir', '/dump/path', '--drop'],
  604. processes=[],
  605. output_log_level=logging.DEBUG,
  606. input_file=None,
  607. ).once()
  608. module.restore_data_source_dump(
  609. hook_config,
  610. {},
  611. data_source={'name': 'foo'},
  612. dry_run=False,
  613. extract_process=None,
  614. connection_params={
  615. 'hostname': None,
  616. 'port': None,
  617. 'username': None,
  618. 'password': None,
  619. },
  620. borgmatic_runtime_directory='/run/borgmatic',
  621. )