test_restore.py 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  1. import pytest
  2. from flexmock import flexmock
  3. import borgmatic.actions.restore as module
  4. @pytest.mark.parametrize(
  5. 'first_dump,second_dump,expected_result',
  6. (
  7. (
  8. module.Dump('postgresql_databases', 'foo'),
  9. module.Dump('postgresql_databases', 'foo'),
  10. True,
  11. ),
  12. (
  13. module.Dump('postgresql_databases', 'foo'),
  14. module.Dump('postgresql_databases', 'bar'),
  15. False,
  16. ),
  17. (
  18. module.Dump('postgresql_databases', 'foo'),
  19. module.Dump('mariadb_databases', 'foo'),
  20. False,
  21. ),
  22. (module.Dump('postgresql_databases', 'foo'), module.Dump(module.UNSPECIFIED, 'foo'), True),
  23. (module.Dump('postgresql_databases', 'foo'), module.Dump(module.UNSPECIFIED, 'bar'), False),
  24. (
  25. module.Dump('postgresql_databases', module.UNSPECIFIED),
  26. module.Dump('postgresql_databases', 'foo'),
  27. True,
  28. ),
  29. (
  30. module.Dump('postgresql_databases', module.UNSPECIFIED),
  31. module.Dump('mariadb_databases', 'foo'),
  32. False,
  33. ),
  34. (
  35. module.Dump('postgresql_databases', 'foo', 'myhost'),
  36. module.Dump('postgresql_databases', 'foo', 'myhost'),
  37. True,
  38. ),
  39. (
  40. module.Dump('postgresql_databases', 'foo', 'myhost'),
  41. module.Dump('postgresql_databases', 'foo', 'otherhost'),
  42. False,
  43. ),
  44. (
  45. module.Dump('postgresql_databases', 'foo', 'myhost'),
  46. module.Dump('postgresql_databases', 'foo', module.UNSPECIFIED),
  47. True,
  48. ),
  49. (
  50. module.Dump('postgresql_databases', 'foo', 'myhost'),
  51. module.Dump('postgresql_databases', 'bar', module.UNSPECIFIED),
  52. False,
  53. ),
  54. (
  55. module.Dump('postgresql_databases', 'foo', 'myhost', 1234),
  56. module.Dump('postgresql_databases', 'foo', 'myhost', 1234),
  57. True,
  58. ),
  59. (
  60. module.Dump('postgresql_databases', 'foo', 'myhost', 1234),
  61. module.Dump('postgresql_databases', 'foo', 'myhost', 4321),
  62. False,
  63. ),
  64. (
  65. module.Dump('postgresql_databases', 'foo', 'myhost', module.UNSPECIFIED),
  66. module.Dump('postgresql_databases', 'foo', 'myhost', 1234),
  67. True,
  68. ),
  69. (
  70. module.Dump('postgresql_databases', 'foo', 'myhost', module.UNSPECIFIED),
  71. module.Dump('postgresql_databases', 'foo', 'otherhost', 1234),
  72. False,
  73. ),
  74. (
  75. module.Dump(
  76. module.UNSPECIFIED, module.UNSPECIFIED, module.UNSPECIFIED, module.UNSPECIFIED
  77. ),
  78. module.Dump('postgresql_databases', 'foo', 'myhost', 1234),
  79. True,
  80. ),
  81. ),
  82. )
  83. def test_dumps_match_compares_two_dumps_while_respecting_unspecified_values(
  84. first_dump, second_dump, expected_result
  85. ):
  86. assert module.dumps_match(first_dump, second_dump) == expected_result
  87. @pytest.mark.parametrize(
  88. 'dump,expected_result',
  89. (
  90. (
  91. module.Dump('postgresql_databases', 'foo'),
  92. 'foo@localhost (postgresql_databases)',
  93. ),
  94. (
  95. module.Dump(module.UNSPECIFIED, 'foo'),
  96. 'foo@localhost',
  97. ),
  98. (
  99. module.Dump('postgresql_databases', module.UNSPECIFIED),
  100. 'unspecified@localhost (postgresql_databases)',
  101. ),
  102. (
  103. module.Dump('postgresql_databases', 'foo', 'host'),
  104. 'foo@host (postgresql_databases)',
  105. ),
  106. (
  107. module.Dump('postgresql_databases', 'foo', module.UNSPECIFIED),
  108. 'foo (postgresql_databases)',
  109. ),
  110. (
  111. module.Dump('postgresql_databases', 'foo', 'host', 1234),
  112. 'foo@host:1234 (postgresql_databases)',
  113. ),
  114. (
  115. module.Dump('postgresql_databases', 'foo', module.UNSPECIFIED, 1234),
  116. 'foo@:1234 (postgresql_databases)',
  117. ),
  118. (
  119. module.Dump('postgresql_databases', 'foo', 'host', module.UNSPECIFIED),
  120. 'foo@host (postgresql_databases)',
  121. ),
  122. (
  123. module.Dump(
  124. module.UNSPECIFIED, module.UNSPECIFIED, module.UNSPECIFIED, module.UNSPECIFIED
  125. ),
  126. 'unspecified',
  127. ),
  128. ),
  129. )
  130. def test_render_dump_metadata_renders_dump_values_into_string(dump, expected_result):
  131. assert module.render_dump_metadata(dump) == expected_result
  132. def test_get_configured_data_source_matches_data_source_with_restore_dump():
  133. flexmock(module).should_receive('dumps_match').and_return(False)
  134. flexmock(module).should_receive('dumps_match').with_args(
  135. module.Dump('postgresql_databases', 'bar'),
  136. module.Dump('postgresql_databases', 'bar'),
  137. ).and_return(True)
  138. assert module.get_configured_data_source(
  139. config={
  140. 'other_databases': [{'name': 'other'}],
  141. 'postgresql_databases': [{'name': 'foo'}, {'name': 'bar'}],
  142. },
  143. restore_dump=module.Dump('postgresql_databases', 'bar'),
  144. ) == {'name': 'bar'}
  145. def test_get_configured_data_source_matches_nothing_when_nothing_configured():
  146. flexmock(module).should_receive('dumps_match').and_return(False)
  147. assert (
  148. module.get_configured_data_source(
  149. config={},
  150. restore_dump=module.Dump('postgresql_databases', 'quux'),
  151. )
  152. is None
  153. )
  154. def test_get_configured_data_source_matches_nothing_when_restore_dump_does_not_match_configuration():
  155. flexmock(module).should_receive('dumps_match').and_return(False)
  156. assert (
  157. module.get_configured_data_source(
  158. config={
  159. 'postgresql_databases': [{'name': 'foo'}],
  160. },
  161. restore_dump=module.Dump('postgresql_databases', 'quux'),
  162. )
  163. is None
  164. )
  165. def test_get_configured_data_source_with_multiple_matching_data_sources_errors():
  166. flexmock(module).should_receive('dumps_match').and_return(False)
  167. flexmock(module).should_receive('dumps_match').with_args(
  168. module.Dump('postgresql_databases', 'bar'),
  169. module.Dump('postgresql_databases', 'bar'),
  170. ).and_return(True)
  171. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  172. with pytest.raises(ValueError):
  173. module.get_configured_data_source(
  174. config={
  175. 'other_databases': [{'name': 'other'}],
  176. 'postgresql_databases': [
  177. {'name': 'foo'},
  178. {'name': 'bar'},
  179. {'name': 'bar', 'format': 'directory'},
  180. ],
  181. },
  182. restore_dump=module.Dump('postgresql_databases', 'bar'),
  183. )
  184. def test_strip_path_prefix_from_extracted_dump_destination_renames_first_matching_databases_subdirectory():
  185. flexmock(module.os).should_receive('walk').and_return(
  186. [
  187. ('/foo', flexmock(), flexmock()),
  188. ('/foo/bar', flexmock(), flexmock()),
  189. ('/foo/bar/postgresql_databases', flexmock(), flexmock()),
  190. ('/foo/bar/mariadb_databases', flexmock(), flexmock()),
  191. ]
  192. )
  193. flexmock(module.shutil).should_receive('move').with_args(
  194. '/foo/bar/postgresql_databases', '/run/user/0/borgmatic/postgresql_databases'
  195. ).once()
  196. flexmock(module.shutil).should_receive('move').with_args(
  197. '/foo/bar/mariadb_databases', '/run/user/0/borgmatic/mariadb_databases'
  198. ).never()
  199. module.strip_path_prefix_from_extracted_dump_destination('/foo', '/run/user/0/borgmatic')
  200. def test_restore_single_dump_extracts_and_restores_single_file_dump():
  201. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  202. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').with_args(
  203. 'make_data_source_dump_patterns', object, object, object, object, object
  204. ).and_return({'postgresql': flexmock()})
  205. flexmock(module.tempfile).should_receive('mkdtemp').never()
  206. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  207. 'convert_glob_patterns_to_borg_pattern'
  208. ).and_return(flexmock())
  209. flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
  210. flexmock()
  211. ).once()
  212. flexmock(module).should_receive('strip_path_prefix_from_extracted_dump_destination').never()
  213. flexmock(module.shutil).should_receive('rmtree').never()
  214. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').with_args(
  215. function_name='restore_data_source_dump',
  216. config=object,
  217. log_prefix=object,
  218. hook_name=object,
  219. data_source=object,
  220. dry_run=object,
  221. extract_process=object,
  222. connection_params=object,
  223. borgmatic_runtime_directory=object,
  224. ).once()
  225. module.restore_single_dump(
  226. repository={'path': 'test.borg'},
  227. config=flexmock(),
  228. local_borg_version=flexmock(),
  229. global_arguments=flexmock(dry_run=False),
  230. local_path=None,
  231. remote_path=None,
  232. archive_name=flexmock(),
  233. hook_name='postgresql',
  234. data_source={'name': 'test', 'format': 'plain'},
  235. connection_params=flexmock(),
  236. borgmatic_runtime_directory='/run/borgmatic',
  237. )
  238. def test_restore_single_dump_extracts_and_restores_directory_dump():
  239. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  240. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').with_args(
  241. 'make_data_source_dump_patterns', object, object, object, object, object
  242. ).and_return({'postgresql': flexmock()})
  243. flexmock(module.tempfile).should_receive('mkdtemp').once().and_return(
  244. '/run/user/0/borgmatic/tmp1234'
  245. )
  246. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  247. 'convert_glob_patterns_to_borg_pattern'
  248. ).and_return(flexmock())
  249. flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
  250. flexmock()
  251. ).once()
  252. flexmock(module).should_receive('strip_path_prefix_from_extracted_dump_destination').once()
  253. flexmock(module.shutil).should_receive('rmtree').once()
  254. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').with_args(
  255. function_name='restore_data_source_dump',
  256. config=object,
  257. log_prefix=object,
  258. hook_name=object,
  259. data_source=object,
  260. dry_run=object,
  261. extract_process=object,
  262. connection_params=object,
  263. borgmatic_runtime_directory='/run/borgmatic',
  264. ).once()
  265. module.restore_single_dump(
  266. repository={'path': 'test.borg'},
  267. config=flexmock(),
  268. local_borg_version=flexmock(),
  269. global_arguments=flexmock(dry_run=False),
  270. local_path=None,
  271. remote_path=None,
  272. archive_name=flexmock(),
  273. hook_name='postgresql',
  274. data_source={'name': 'test', 'format': 'directory'},
  275. connection_params=flexmock(),
  276. borgmatic_runtime_directory='/run/borgmatic',
  277. )
  278. def test_restore_single_dump_with_directory_dump_error_cleans_up_temporary_directory():
  279. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  280. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').with_args(
  281. 'make_data_source_dump_patterns', object, object, object, object, object
  282. ).and_return({'postgresql': flexmock()})
  283. flexmock(module.tempfile).should_receive('mkdtemp').once().and_return(
  284. '/run/user/0/borgmatic/tmp1234'
  285. )
  286. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  287. 'convert_glob_patterns_to_borg_pattern'
  288. ).and_return(flexmock())
  289. flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_raise(
  290. ValueError
  291. ).once()
  292. flexmock(module).should_receive('strip_path_prefix_from_extracted_dump_destination').never()
  293. flexmock(module.shutil).should_receive('rmtree').once()
  294. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').with_args(
  295. function_name='restore_data_source_dump',
  296. config=object,
  297. log_prefix=object,
  298. hook_name=object,
  299. data_source=object,
  300. dry_run=object,
  301. extract_process=object,
  302. connection_params=object,
  303. borgmatic_runtime_directory='/run/user/0/borgmatic/tmp1234',
  304. ).never()
  305. with pytest.raises(ValueError):
  306. module.restore_single_dump(
  307. repository={'path': 'test.borg'},
  308. config=flexmock(),
  309. local_borg_version=flexmock(),
  310. global_arguments=flexmock(dry_run=False),
  311. local_path=None,
  312. remote_path=None,
  313. archive_name=flexmock(),
  314. hook_name='postgresql',
  315. data_source={'name': 'test', 'format': 'directory'},
  316. connection_params=flexmock(),
  317. borgmatic_runtime_directory='/run/borgmatic',
  318. )
  319. def test_restore_single_dump_with_directory_dump_and_dry_run_skips_directory_move_and_cleanup():
  320. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  321. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks').with_args(
  322. 'make_data_source_dump_patterns', object, object, object, object, object
  323. ).and_return({'postgresql': flexmock()})
  324. flexmock(module.tempfile).should_receive('mkdtemp').once().and_return('/run/borgmatic/tmp1234')
  325. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  326. 'convert_glob_patterns_to_borg_pattern'
  327. ).and_return(flexmock())
  328. flexmock(module.borgmatic.borg.extract).should_receive('extract_archive').and_return(
  329. flexmock()
  330. ).once()
  331. flexmock(module).should_receive('strip_path_prefix_from_extracted_dump_destination').never()
  332. flexmock(module.shutil).should_receive('rmtree').never()
  333. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hook').with_args(
  334. function_name='restore_data_source_dump',
  335. config=object,
  336. log_prefix=object,
  337. hook_name=object,
  338. data_source=object,
  339. dry_run=object,
  340. extract_process=object,
  341. connection_params=object,
  342. borgmatic_runtime_directory='/run/borgmatic',
  343. ).once()
  344. module.restore_single_dump(
  345. repository={'path': 'test.borg'},
  346. config=flexmock(),
  347. local_borg_version=flexmock(),
  348. global_arguments=flexmock(dry_run=True),
  349. local_path=None,
  350. remote_path=None,
  351. archive_name=flexmock(),
  352. hook_name='postgresql',
  353. data_source={'name': 'test', 'format': 'directory'},
  354. connection_params=flexmock(),
  355. borgmatic_runtime_directory='/run/borgmatic',
  356. )
  357. def test_collect_dumps_from_archive_parses_archive_paths():
  358. flexmock(module.borgmatic.config.paths).should_receive(
  359. 'get_borgmatic_source_directory'
  360. ).and_return('/root/.borgmatic')
  361. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  362. 'make_data_source_dump_path'
  363. ).and_return('')
  364. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  365. [
  366. 'borgmatic/postgresql_databases/localhost/foo',
  367. 'borgmatic/postgresql_databases/host:1234/bar',
  368. 'borgmatic/mysql_databases/localhost/quux',
  369. ]
  370. )
  371. archive_dumps = module.collect_dumps_from_archive(
  372. repository={'path': 'repo'},
  373. archive='archive',
  374. config={},
  375. local_borg_version=flexmock(),
  376. global_arguments=flexmock(log_json=False),
  377. local_path=flexmock(),
  378. remote_path=flexmock(),
  379. borgmatic_runtime_directory='/run/borgmatic',
  380. )
  381. assert archive_dumps == {
  382. module.Dump('postgresql_databases', 'foo'),
  383. module.Dump('postgresql_databases', 'bar', 'host', 1234),
  384. module.Dump('mysql_databases', 'quux'),
  385. }
  386. def test_collect_dumps_from_archive_parses_archive_paths_with_different_base_directories():
  387. flexmock(module.borgmatic.config.paths).should_receive(
  388. 'get_borgmatic_source_directory'
  389. ).and_return('/root/.borgmatic')
  390. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  391. 'make_data_source_dump_path'
  392. ).and_return('')
  393. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  394. [
  395. 'borgmatic/postgresql_databases/localhost/foo',
  396. '.borgmatic/postgresql_databases/localhost/bar',
  397. '/root/.borgmatic/postgresql_databases/localhost/baz',
  398. '/var/run/0/borgmatic/mysql_databases/localhost/quux',
  399. ]
  400. )
  401. archive_dumps = module.collect_dumps_from_archive(
  402. repository={'path': 'repo'},
  403. archive='archive',
  404. config={},
  405. local_borg_version=flexmock(),
  406. global_arguments=flexmock(log_json=False),
  407. local_path=flexmock(),
  408. remote_path=flexmock(),
  409. borgmatic_runtime_directory='/run/borgmatic',
  410. )
  411. assert archive_dumps == {
  412. module.Dump('postgresql_databases', 'foo'),
  413. module.Dump('postgresql_databases', 'bar'),
  414. module.Dump('postgresql_databases', 'baz'),
  415. module.Dump('mysql_databases', 'quux'),
  416. }
  417. def test_collect_dumps_from_archive_parses_directory_format_archive_paths():
  418. flexmock(module.borgmatic.config.paths).should_receive(
  419. 'get_borgmatic_source_directory'
  420. ).and_return('/root/.borgmatic')
  421. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  422. 'make_data_source_dump_path'
  423. ).and_return('')
  424. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  425. [
  426. 'borgmatic/postgresql_databases/localhost/foo/table1',
  427. 'borgmatic/postgresql_databases/localhost/foo/table2',
  428. ]
  429. )
  430. archive_dumps = module.collect_dumps_from_archive(
  431. repository={'path': 'repo'},
  432. archive='archive',
  433. config={},
  434. local_borg_version=flexmock(),
  435. global_arguments=flexmock(log_json=False),
  436. local_path=flexmock(),
  437. remote_path=flexmock(),
  438. borgmatic_runtime_directory='/run/borgmatic',
  439. )
  440. assert archive_dumps == {
  441. module.Dump('postgresql_databases', 'foo'),
  442. }
  443. def test_collect_dumps_from_archive_skips_bad_archive_paths_or_bad_path_components():
  444. flexmock(module.borgmatic.config.paths).should_receive(
  445. 'get_borgmatic_source_directory'
  446. ).and_return('/root/.borgmatic')
  447. flexmock(module.borgmatic.hooks.data_source.dump).should_receive(
  448. 'make_data_source_dump_path'
  449. ).and_return('')
  450. flexmock(module.borgmatic.borg.list).should_receive('capture_archive_listing').and_return(
  451. [
  452. 'borgmatic/postgresql_databases/localhost/foo',
  453. 'borgmatic/postgresql_databases/localhost:abcd/bar',
  454. 'borgmatic/invalid',
  455. 'invalid/as/well',
  456. '',
  457. ]
  458. )
  459. archive_dumps = module.collect_dumps_from_archive(
  460. repository={'path': 'repo'},
  461. archive='archive',
  462. config={},
  463. local_borg_version=flexmock(),
  464. global_arguments=flexmock(log_json=False),
  465. local_path=flexmock(),
  466. remote_path=flexmock(),
  467. borgmatic_runtime_directory='/run/borgmatic',
  468. )
  469. assert archive_dumps == {
  470. module.Dump('postgresql_databases', 'foo'),
  471. module.Dump('postgresql_databases', 'bar'),
  472. }
  473. def test_get_dumps_to_restore_gets_requested_dumps_found_in_archive():
  474. dumps_from_archive = {
  475. module.Dump('postgresql_databases', 'foo'),
  476. module.Dump('postgresql_databases', 'bar'),
  477. module.Dump('postgresql_databases', 'baz'),
  478. }
  479. flexmock(module).should_receive('dumps_match').and_return(False)
  480. flexmock(module).should_receive('dumps_match').with_args(
  481. module.Dump(module.UNSPECIFIED, 'foo'),
  482. module.Dump('postgresql_databases', 'foo'),
  483. ).and_return(True)
  484. flexmock(module).should_receive('dumps_match').with_args(
  485. module.Dump(module.UNSPECIFIED, 'bar'),
  486. module.Dump('postgresql_databases', 'bar'),
  487. ).and_return(True)
  488. assert module.get_dumps_to_restore(
  489. restore_arguments=flexmock(
  490. hook=None,
  491. data_sources=['foo', 'bar'],
  492. original_hostname=None,
  493. original_port=None,
  494. ),
  495. dumps_from_archive=dumps_from_archive,
  496. ) == {
  497. module.Dump('postgresql_databases', 'foo'),
  498. module.Dump('postgresql_databases', 'bar'),
  499. }
  500. def test_get_dumps_to_restore_raises_for_requested_dumps_missing_from_archive():
  501. dumps_from_archive = {
  502. module.Dump('postgresql_databases', 'foo'),
  503. }
  504. flexmock(module).should_receive('dumps_match').and_return(False)
  505. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  506. with pytest.raises(ValueError):
  507. module.get_dumps_to_restore(
  508. restore_arguments=flexmock(
  509. hook=None,
  510. data_sources=['foo', 'bar'],
  511. original_hostname=None,
  512. original_port=None,
  513. ),
  514. dumps_from_archive=dumps_from_archive,
  515. )
  516. def test_get_dumps_to_restore_without_requested_dumps_finds_all_archive_dumps():
  517. dumps_from_archive = {
  518. module.Dump('postgresql_databases', 'foo'),
  519. module.Dump('postgresql_databases', 'bar'),
  520. }
  521. flexmock(module).should_receive('dumps_match').and_return(False)
  522. assert (
  523. module.get_dumps_to_restore(
  524. restore_arguments=flexmock(
  525. hook=None,
  526. data_sources=[],
  527. original_hostname=None,
  528. original_port=None,
  529. ),
  530. dumps_from_archive=dumps_from_archive,
  531. )
  532. == dumps_from_archive
  533. )
  534. def test_get_dumps_to_restore_with_all_in_requested_dumps_finds_all_archive_dumps():
  535. dumps_from_archive = {
  536. module.Dump('postgresql_databases', 'foo'),
  537. module.Dump('postgresql_databases', 'bar'),
  538. }
  539. flexmock(module).should_receive('dumps_match').and_return(False)
  540. flexmock(module).should_receive('dumps_match').with_args(
  541. module.Dump(module.UNSPECIFIED, 'foo'),
  542. module.Dump('postgresql_databases', 'foo'),
  543. ).and_return(True)
  544. flexmock(module).should_receive('dumps_match').with_args(
  545. module.Dump(module.UNSPECIFIED, 'bar'),
  546. module.Dump('postgresql_databases', 'bar'),
  547. ).and_return(True)
  548. assert (
  549. module.get_dumps_to_restore(
  550. restore_arguments=flexmock(
  551. hook=None,
  552. data_sources=['all'],
  553. original_hostname=None,
  554. original_port=None,
  555. ),
  556. dumps_from_archive=dumps_from_archive,
  557. )
  558. == dumps_from_archive
  559. )
  560. def test_get_dumps_to_restore_with_all_in_requested_dumps_plus_additional_requested_dumps_omits_duplicates():
  561. dumps_from_archive = {
  562. module.Dump('postgresql_databases', 'foo'),
  563. module.Dump('postgresql_databases', 'bar'),
  564. }
  565. flexmock(module).should_receive('dumps_match').and_return(False)
  566. flexmock(module).should_receive('dumps_match').with_args(
  567. module.Dump(module.UNSPECIFIED, 'foo'),
  568. module.Dump('postgresql_databases', 'foo'),
  569. ).and_return(True)
  570. flexmock(module).should_receive('dumps_match').with_args(
  571. module.Dump(module.UNSPECIFIED, 'bar'),
  572. module.Dump('postgresql_databases', 'bar'),
  573. ).and_return(True)
  574. assert (
  575. module.get_dumps_to_restore(
  576. restore_arguments=flexmock(
  577. hook=None,
  578. data_sources=['all', 'foo', 'bar'],
  579. original_hostname=None,
  580. original_port=None,
  581. ),
  582. dumps_from_archive=dumps_from_archive,
  583. )
  584. == dumps_from_archive
  585. )
  586. def test_get_dumps_to_restore_raises_for_multiple_matching_dumps_in_archive():
  587. flexmock(module).should_receive('dumps_match').and_return(False)
  588. flexmock(module).should_receive('dumps_match').with_args(
  589. module.Dump(module.UNSPECIFIED, 'foo'),
  590. module.Dump('postgresql_databases', 'foo'),
  591. ).and_return(True)
  592. flexmock(module).should_receive('dumps_match').with_args(
  593. module.Dump(module.UNSPECIFIED, 'foo'),
  594. module.Dump('mariadb_databases', 'foo'),
  595. ).and_return(True)
  596. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  597. with pytest.raises(ValueError):
  598. module.get_dumps_to_restore(
  599. restore_arguments=flexmock(
  600. hook=None,
  601. data_sources=['foo'],
  602. original_hostname=None,
  603. original_port=None,
  604. ),
  605. dumps_from_archive={
  606. module.Dump('postgresql_databases', 'foo'),
  607. module.Dump('mariadb_databases', 'foo'),
  608. },
  609. )
  610. def test_get_dumps_to_restore_raises_for_all_in_requested_dumps_and_requested_dumps_missing_from_archive():
  611. flexmock(module).should_receive('dumps_match').and_return(False)
  612. flexmock(module).should_receive('dumps_match').with_args(
  613. module.Dump(module.UNSPECIFIED, 'foo'),
  614. module.Dump('postgresql_databases', 'foo'),
  615. ).and_return(True)
  616. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  617. with pytest.raises(ValueError):
  618. module.get_dumps_to_restore(
  619. restore_arguments=flexmock(
  620. hook=None,
  621. data_sources=['all', 'foo', 'bar'],
  622. original_hostname=None,
  623. original_port=None,
  624. ),
  625. dumps_from_archive={module.Dump('postresql_databases', 'foo')},
  626. )
  627. def test_get_dumps_to_restore_with_requested_hook_name_filters_dumps_found_in_archive():
  628. dumps_from_archive = {
  629. module.Dump('mariadb_databases', 'foo'),
  630. module.Dump('postgresql_databases', 'foo'),
  631. module.Dump('sqlite_databases', 'bar'),
  632. }
  633. flexmock(module).should_receive('dumps_match').and_return(False)
  634. flexmock(module).should_receive('dumps_match').with_args(
  635. module.Dump('postgresql_databases', 'foo'),
  636. module.Dump('postgresql_databases', 'foo'),
  637. ).and_return(True)
  638. assert module.get_dumps_to_restore(
  639. restore_arguments=flexmock(
  640. hook='postgresql_databases',
  641. data_sources=['foo'],
  642. original_hostname=None,
  643. original_port=None,
  644. ),
  645. dumps_from_archive=dumps_from_archive,
  646. ) == {
  647. module.Dump('postgresql_databases', 'foo'),
  648. }
  649. def test_get_dumps_to_restore_with_requested_shortened_hook_name_filters_dumps_found_in_archive():
  650. dumps_from_archive = {
  651. module.Dump('mariadb_databases', 'foo'),
  652. module.Dump('postgresql_databases', 'foo'),
  653. module.Dump('sqlite_databases', 'bar'),
  654. }
  655. flexmock(module).should_receive('dumps_match').and_return(False)
  656. flexmock(module).should_receive('dumps_match').with_args(
  657. module.Dump('postgresql_databases', 'foo'),
  658. module.Dump('postgresql_databases', 'foo'),
  659. ).and_return(True)
  660. assert module.get_dumps_to_restore(
  661. restore_arguments=flexmock(
  662. hook='postgresql',
  663. data_sources=['foo'],
  664. original_hostname=None,
  665. original_port=None,
  666. ),
  667. dumps_from_archive=dumps_from_archive,
  668. ) == {
  669. module.Dump('postgresql_databases', 'foo'),
  670. }
  671. def test_get_dumps_to_restore_with_requested_hostname_filters_dumps_found_in_archive():
  672. dumps_from_archive = {
  673. module.Dump('postgresql_databases', 'foo'),
  674. module.Dump('postgresql_databases', 'foo', 'host'),
  675. module.Dump('postgresql_databases', 'bar'),
  676. }
  677. flexmock(module).should_receive('dumps_match').and_return(False)
  678. flexmock(module).should_receive('dumps_match').with_args(
  679. module.Dump('postgresql_databases', 'foo', 'host'),
  680. module.Dump('postgresql_databases', 'foo', 'host'),
  681. ).and_return(True)
  682. assert module.get_dumps_to_restore(
  683. restore_arguments=flexmock(
  684. hook='postgresql_databases',
  685. data_sources=['foo'],
  686. original_hostname='host',
  687. original_port=None,
  688. ),
  689. dumps_from_archive=dumps_from_archive,
  690. ) == {
  691. module.Dump('postgresql_databases', 'foo', 'host'),
  692. }
  693. def test_get_dumps_to_restore_with_requested_port_filters_dumps_found_in_archive():
  694. dumps_from_archive = {
  695. module.Dump('postgresql_databases', 'foo', 'host'),
  696. module.Dump('postgresql_databases', 'foo', 'host', 1234),
  697. module.Dump('postgresql_databases', 'bar'),
  698. }
  699. flexmock(module).should_receive('dumps_match').and_return(False)
  700. flexmock(module).should_receive('dumps_match').with_args(
  701. module.Dump('postgresql_databases', 'foo', 'host', 1234),
  702. module.Dump('postgresql_databases', 'foo', 'host', 1234),
  703. ).and_return(True)
  704. assert module.get_dumps_to_restore(
  705. restore_arguments=flexmock(
  706. hook='postgresql_databases',
  707. data_sources=['foo'],
  708. original_hostname='host',
  709. original_port=1234,
  710. ),
  711. dumps_from_archive=dumps_from_archive,
  712. ) == {
  713. module.Dump('postgresql_databases', 'foo', 'host', 1234),
  714. }
  715. def test_ensure_requested_dumps_restored_with_all_dumps_restored_does_not_raise():
  716. module.ensure_requested_dumps_restored(
  717. dumps_to_restore={
  718. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  719. module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  720. },
  721. dumps_actually_restored={
  722. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  723. module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  724. },
  725. )
  726. def test_ensure_requested_dumps_restored_with_no_dumps_raises():
  727. with pytest.raises(ValueError):
  728. module.ensure_requested_dumps_restored(
  729. dumps_to_restore={},
  730. dumps_actually_restored={},
  731. )
  732. def test_ensure_requested_dumps_restored_with_missing_dumps_raises():
  733. flexmock(module).should_receive('render_dump_metadata').and_return('test')
  734. with pytest.raises(ValueError):
  735. module.ensure_requested_dumps_restored(
  736. dumps_to_restore={
  737. module.Dump(hook_name='postgresql_databases', data_source_name='foo')
  738. },
  739. dumps_actually_restored={
  740. module.Dump(hook_name='postgresql_databases', data_source_name='bar')
  741. },
  742. )
  743. def test_run_restore_restores_each_data_source():
  744. dumps_to_restore = {
  745. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  746. module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  747. }
  748. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
  749. borgmatic_runtime_directory = flexmock()
  750. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  751. borgmatic_runtime_directory
  752. )
  753. flexmock(module.borgmatic.config.paths).should_receive(
  754. 'make_runtime_directory_glob'
  755. ).replace_with(lambda path: path)
  756. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks_even_if_unconfigured')
  757. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  758. flexmock()
  759. )
  760. flexmock(module).should_receive('collect_dumps_from_archive').and_return(flexmock())
  761. flexmock(module).should_receive('get_dumps_to_restore').and_return(dumps_to_restore)
  762. flexmock(module).should_receive('get_configured_data_source').and_return(
  763. {'name': 'foo'}
  764. ).and_return({'name': 'bar'})
  765. flexmock(module).should_receive('restore_single_dump').with_args(
  766. repository=object,
  767. config=object,
  768. local_borg_version=object,
  769. global_arguments=object,
  770. local_path=object,
  771. remote_path=object,
  772. archive_name=object,
  773. hook_name='postgresql_databases',
  774. data_source={'name': 'foo', 'schemas': None},
  775. connection_params=object,
  776. borgmatic_runtime_directory=borgmatic_runtime_directory,
  777. ).once()
  778. flexmock(module).should_receive('restore_single_dump').with_args(
  779. repository=object,
  780. config=object,
  781. local_borg_version=object,
  782. global_arguments=object,
  783. local_path=object,
  784. remote_path=object,
  785. archive_name=object,
  786. hook_name='postgresql_databases',
  787. data_source={'name': 'bar', 'schemas': None},
  788. connection_params=object,
  789. borgmatic_runtime_directory=borgmatic_runtime_directory,
  790. ).once()
  791. flexmock(module).should_receive('ensure_requested_dumps_restored')
  792. module.run_restore(
  793. repository={'path': 'repo'},
  794. config=flexmock(),
  795. local_borg_version=flexmock(),
  796. restore_arguments=flexmock(
  797. repository='repo',
  798. archive='archive',
  799. data_sources=flexmock(),
  800. schemas=None,
  801. hostname=None,
  802. port=None,
  803. username=None,
  804. password=None,
  805. restore_path=None,
  806. ),
  807. global_arguments=flexmock(dry_run=False),
  808. local_path=flexmock(),
  809. remote_path=flexmock(),
  810. )
  811. def test_run_restore_bails_for_non_matching_repository():
  812. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(
  813. False
  814. )
  815. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  816. flexmock()
  817. )
  818. flexmock(module.borgmatic.config.paths).should_receive(
  819. 'make_runtime_directory_glob'
  820. ).replace_with(lambda path: path)
  821. flexmock(module.borgmatic.hooks.dispatch).should_receive(
  822. 'call_hooks_even_if_unconfigured'
  823. ).never()
  824. flexmock(module).should_receive('restore_single_dump').never()
  825. module.run_restore(
  826. repository={'path': 'repo'},
  827. config=flexmock(),
  828. local_borg_version=flexmock(),
  829. restore_arguments=flexmock(repository='repo', archive='archive', data_sources=flexmock()),
  830. global_arguments=flexmock(dry_run=False),
  831. local_path=flexmock(),
  832. remote_path=flexmock(),
  833. )
  834. def test_run_restore_restores_data_source_by_falling_back_to_all_name():
  835. dumps_to_restore = {
  836. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  837. }
  838. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
  839. borgmatic_runtime_directory = flexmock()
  840. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  841. borgmatic_runtime_directory
  842. )
  843. flexmock(module.borgmatic.config.paths).should_receive(
  844. 'make_runtime_directory_glob'
  845. ).replace_with(lambda path: path)
  846. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks_even_if_unconfigured')
  847. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  848. flexmock()
  849. )
  850. flexmock(module).should_receive('collect_dumps_from_archive').and_return(flexmock())
  851. flexmock(module).should_receive('get_dumps_to_restore').and_return(dumps_to_restore)
  852. flexmock(module).should_receive('get_configured_data_source').and_return(
  853. {'name': 'foo'}
  854. ).and_return({'name': 'all'})
  855. flexmock(module).should_receive('restore_single_dump').with_args(
  856. repository=object,
  857. config=object,
  858. local_borg_version=object,
  859. global_arguments=object,
  860. local_path=object,
  861. remote_path=object,
  862. archive_name=object,
  863. hook_name='postgresql_databases',
  864. data_source={'name': 'foo', 'schemas': None},
  865. connection_params=object,
  866. borgmatic_runtime_directory=borgmatic_runtime_directory,
  867. ).once()
  868. flexmock(module).should_receive('ensure_requested_dumps_restored')
  869. module.run_restore(
  870. repository={'path': 'repo'},
  871. config=flexmock(),
  872. local_borg_version=flexmock(),
  873. restore_arguments=flexmock(
  874. repository='repo',
  875. archive='archive',
  876. data_sources=flexmock(),
  877. schemas=None,
  878. hostname=None,
  879. port=None,
  880. username=None,
  881. password=None,
  882. restore_path=None,
  883. ),
  884. global_arguments=flexmock(dry_run=False),
  885. local_path=flexmock(),
  886. remote_path=flexmock(),
  887. )
  888. def test_run_restore_restores_data_source_configured_with_all_name():
  889. dumps_to_restore = {
  890. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  891. module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  892. }
  893. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
  894. borgmatic_runtime_directory = flexmock()
  895. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  896. borgmatic_runtime_directory
  897. )
  898. flexmock(module.borgmatic.config.paths).should_receive(
  899. 'make_runtime_directory_glob'
  900. ).replace_with(lambda path: path)
  901. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks_even_if_unconfigured')
  902. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  903. flexmock()
  904. )
  905. flexmock(module).should_receive('collect_dumps_from_archive').and_return(flexmock())
  906. flexmock(module).should_receive('get_dumps_to_restore').and_return(dumps_to_restore)
  907. flexmock(module).should_receive('get_configured_data_source').with_args(
  908. config=object,
  909. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  910. ).and_return({'name': 'foo'})
  911. flexmock(module).should_receive('get_configured_data_source').with_args(
  912. config=object,
  913. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  914. ).and_return(None)
  915. flexmock(module).should_receive('get_configured_data_source').with_args(
  916. config=object,
  917. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='all'),
  918. ).and_return({'name': 'bar'})
  919. flexmock(module).should_receive('restore_single_dump').with_args(
  920. repository=object,
  921. config=object,
  922. local_borg_version=object,
  923. global_arguments=object,
  924. local_path=object,
  925. remote_path=object,
  926. archive_name=object,
  927. hook_name='postgresql_databases',
  928. data_source={'name': 'foo', 'schemas': None},
  929. connection_params=object,
  930. borgmatic_runtime_directory=borgmatic_runtime_directory,
  931. ).once()
  932. flexmock(module).should_receive('restore_single_dump').with_args(
  933. repository=object,
  934. config=object,
  935. local_borg_version=object,
  936. global_arguments=object,
  937. local_path=object,
  938. remote_path=object,
  939. archive_name=object,
  940. hook_name='postgresql_databases',
  941. data_source={'name': 'bar', 'schemas': None},
  942. connection_params=object,
  943. borgmatic_runtime_directory=borgmatic_runtime_directory,
  944. ).once()
  945. flexmock(module).should_receive('ensure_requested_dumps_restored')
  946. module.run_restore(
  947. repository={'path': 'repo'},
  948. config=flexmock(),
  949. local_borg_version=flexmock(),
  950. restore_arguments=flexmock(
  951. repository='repo',
  952. archive='archive',
  953. data_sources=flexmock(),
  954. schemas=None,
  955. hostname=None,
  956. port=None,
  957. username=None,
  958. password=None,
  959. restore_path=None,
  960. ),
  961. global_arguments=flexmock(dry_run=False),
  962. local_path=flexmock(),
  963. remote_path=flexmock(),
  964. )
  965. def test_run_restore_skips_missing_data_source():
  966. dumps_to_restore = {
  967. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  968. module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  969. }
  970. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
  971. borgmatic_runtime_directory = flexmock()
  972. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  973. borgmatic_runtime_directory
  974. )
  975. flexmock(module.borgmatic.config.paths).should_receive(
  976. 'make_runtime_directory_glob'
  977. ).replace_with(lambda path: path)
  978. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks_even_if_unconfigured')
  979. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  980. flexmock()
  981. )
  982. flexmock(module).should_receive('collect_dumps_from_archive').and_return(flexmock())
  983. flexmock(module).should_receive('get_dumps_to_restore').and_return(dumps_to_restore)
  984. flexmock(module).should_receive('get_configured_data_source').with_args(
  985. config=object,
  986. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  987. ).and_return({'name': 'foo'})
  988. flexmock(module).should_receive('get_configured_data_source').with_args(
  989. config=object,
  990. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='bar'),
  991. ).and_return(None)
  992. flexmock(module).should_receive('get_configured_data_source').with_args(
  993. config=object,
  994. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='all'),
  995. ).and_return(None)
  996. flexmock(module).should_receive('restore_single_dump').with_args(
  997. repository=object,
  998. config=object,
  999. local_borg_version=object,
  1000. global_arguments=object,
  1001. local_path=object,
  1002. remote_path=object,
  1003. archive_name=object,
  1004. hook_name='postgresql_databases',
  1005. data_source={'name': 'foo', 'schemas': None},
  1006. connection_params=object,
  1007. borgmatic_runtime_directory=borgmatic_runtime_directory,
  1008. ).once()
  1009. flexmock(module).should_receive('restore_single_dump').with_args(
  1010. repository=object,
  1011. config=object,
  1012. local_borg_version=object,
  1013. global_arguments=object,
  1014. local_path=object,
  1015. remote_path=object,
  1016. archive_name=object,
  1017. hook_name='postgresql_databases',
  1018. data_source={'name': 'bar', 'schemas': None},
  1019. connection_params=object,
  1020. borgmatic_runtime_directory=borgmatic_runtime_directory,
  1021. ).never()
  1022. flexmock(module).should_receive('ensure_requested_dumps_restored')
  1023. module.run_restore(
  1024. repository={'path': 'repo'},
  1025. config=flexmock(),
  1026. local_borg_version=flexmock(),
  1027. restore_arguments=flexmock(
  1028. repository='repo',
  1029. archive='archive',
  1030. data_sources=flexmock(),
  1031. schemas=None,
  1032. hostname=None,
  1033. port=None,
  1034. username=None,
  1035. password=None,
  1036. restore_path=None,
  1037. ),
  1038. global_arguments=flexmock(dry_run=False),
  1039. local_path=flexmock(),
  1040. remote_path=flexmock(),
  1041. )
  1042. def test_run_restore_restores_data_sources_from_different_hooks():
  1043. dumps_to_restore = {
  1044. module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  1045. module.Dump(hook_name='mysql_databases', data_source_name='foo'),
  1046. }
  1047. flexmock(module.borgmatic.config.validate).should_receive('repositories_match').and_return(True)
  1048. borgmatic_runtime_directory = flexmock()
  1049. flexmock(module.borgmatic.config.paths).should_receive('Runtime_directory').and_return(
  1050. borgmatic_runtime_directory
  1051. )
  1052. flexmock(module.borgmatic.config.paths).should_receive(
  1053. 'make_runtime_directory_glob'
  1054. ).replace_with(lambda path: path)
  1055. flexmock(module.borgmatic.hooks.dispatch).should_receive('call_hooks_even_if_unconfigured')
  1056. flexmock(module.borgmatic.borg.repo_list).should_receive('resolve_archive_name').and_return(
  1057. flexmock()
  1058. )
  1059. flexmock(module).should_receive('collect_dumps_from_archive').and_return(flexmock())
  1060. flexmock(module).should_receive('get_dumps_to_restore').and_return(dumps_to_restore)
  1061. flexmock(module).should_receive('get_configured_data_source').with_args(
  1062. config=object,
  1063. restore_dump=module.Dump(hook_name='postgresql_databases', data_source_name='foo'),
  1064. ).and_return({'name': 'foo'})
  1065. flexmock(module).should_receive('get_configured_data_source').with_args(
  1066. config=object,
  1067. restore_dump=module.Dump(hook_name='mysql_databases', data_source_name='foo'),
  1068. ).and_return({'name': 'bar'})
  1069. flexmock(module).should_receive('restore_single_dump').with_args(
  1070. repository=object,
  1071. config=object,
  1072. local_borg_version=object,
  1073. global_arguments=object,
  1074. local_path=object,
  1075. remote_path=object,
  1076. archive_name=object,
  1077. hook_name='postgresql_databases',
  1078. data_source={'name': 'foo', 'schemas': None},
  1079. connection_params=object,
  1080. borgmatic_runtime_directory=borgmatic_runtime_directory,
  1081. ).once()
  1082. flexmock(module).should_receive('restore_single_dump').with_args(
  1083. repository=object,
  1084. config=object,
  1085. local_borg_version=object,
  1086. global_arguments=object,
  1087. local_path=object,
  1088. remote_path=object,
  1089. archive_name=object,
  1090. hook_name='mysql_databases',
  1091. data_source={'name': 'bar', 'schemas': None},
  1092. connection_params=object,
  1093. borgmatic_runtime_directory=borgmatic_runtime_directory,
  1094. ).once()
  1095. flexmock(module).should_receive('ensure_requested_dumps_restored')
  1096. module.run_restore(
  1097. repository={'path': 'repo'},
  1098. config=flexmock(),
  1099. local_borg_version=flexmock(),
  1100. restore_arguments=flexmock(
  1101. repository='repo',
  1102. archive='archive',
  1103. data_sources=flexmock(),
  1104. schemas=None,
  1105. hostname=None,
  1106. port=None,
  1107. username=None,
  1108. password=None,
  1109. restore_path=None,
  1110. ),
  1111. global_arguments=flexmock(dry_run=False),
  1112. local_path=flexmock(),
  1113. remote_path=flexmock(),
  1114. )