test_dump.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import io
  2. import sys
  3. import pytest
  4. from flexmock import flexmock
  5. from borgmatic.hooks.data_source import dump as module
  6. def test_make_data_source_dump_path_joins_arguments():
  7. assert module.make_data_source_dump_path('/tmp', 'super_databases') == '/tmp/super_databases'
  8. def test_make_data_source_dump_filename_uses_name_and_hostname():
  9. assert (
  10. module.make_data_source_dump_filename('databases', 'test', 'hostname')
  11. == 'databases/hostname/test'
  12. )
  13. def test_make_data_source_dump_filename_uses_name_and_hostname_and_port():
  14. assert (
  15. module.make_data_source_dump_filename('databases', 'test', 'hostname', 1234)
  16. == 'databases/hostname:1234/test'
  17. )
  18. def test_make_data_source_dump_filename_uses_label():
  19. assert (
  20. module.make_data_source_dump_filename(
  21. 'databases', 'test', 'hostname', 1234, label='custom_label'
  22. )
  23. == 'databases/custom_label/test'
  24. )
  25. def test_make_data_source_dump_filename_uses_container():
  26. assert (
  27. module.make_data_source_dump_filename(
  28. 'databases', 'test', 'hostname', 1234, container='container'
  29. )
  30. == 'databases/container:1234/test'
  31. )
  32. def test_make_data_source_dump_filename_without_hostname_defaults_to_localhost():
  33. assert module.make_data_source_dump_filename('databases', 'test') == 'databases/localhost/test'
  34. def test_make_data_source_dump_filename_with_invalid_name_raises():
  35. with pytest.raises(ValueError):
  36. module.make_data_source_dump_filename('databases', 'invalid/name')
  37. def test_write_data_source_dumps_metadata_writes_json_to_file():
  38. dumps_metadata = [
  39. module.borgmatic.actions.restore.Dump('databases', 'foo'),
  40. module.borgmatic.actions.restore.Dump('databases', 'bar'),
  41. ]
  42. dumps_stream = io.StringIO('password')
  43. dumps_stream.name = '/run/borgmatic/databases/dumps.json'
  44. builtins = flexmock(sys.modules['builtins'])
  45. builtins.should_receive('open').with_args(dumps_stream.name, 'w', encoding='utf-8').and_return(
  46. dumps_stream
  47. )
  48. flexmock(dumps_stream).should_receive('close') # Prevent close() so getvalue() below works.
  49. module.write_data_source_dumps_metadata('/run/borgmatic', 'databases', dumps_metadata)
  50. assert (
  51. dumps_stream.getvalue()
  52. == '{"dumps": [{"container": null, "data_source_name": "foo", "hook_name": "databases", "hostname": null, "label": null, "port": null}, {"container": null, "data_source_name": "bar", "hook_name": "databases", "hostname": null, "label": null, "port": null}]}'
  53. )
  54. def test_write_data_source_dumps_metadata_with_operating_system_error_raises():
  55. dumps_metadata = [
  56. module.borgmatic.actions.restore.Dump('databases', 'foo'),
  57. module.borgmatic.actions.restore.Dump('databases', 'bar'),
  58. ]
  59. dumps_stream = io.StringIO('password')
  60. dumps_stream.name = '/run/borgmatic/databases/dumps.json'
  61. builtins = flexmock(sys.modules['builtins'])
  62. builtins.should_receive('open').with_args(dumps_stream.name, 'w', encoding='utf-8').and_raise(
  63. OSError
  64. )
  65. with pytest.raises(ValueError):
  66. module.write_data_source_dumps_metadata('/run/borgmatic', 'databases', dumps_metadata)
  67. def test_parse_data_source_dumps_metadata_converts_json_to_dump_instances():
  68. dumps_json = '{"dumps": [{"data_source_name": "foo", "hook_name": "databases", "hostname": null, "port": null}, {"data_source_name": "bar", "hook_name": "databases", "hostname": "example.org", "port": 1234}]}'
  69. assert module.parse_data_source_dumps_metadata(
  70. dumps_json, 'borgmatic/databases/dumps.json'
  71. ) == (
  72. module.borgmatic.actions.restore.Dump('databases', 'foo'),
  73. module.borgmatic.actions.restore.Dump('databases', 'bar', 'example.org', 1234),
  74. )
  75. def test_parse_data_source_dumps_metadata_with_invalid_json_raises():
  76. with pytest.raises(ValueError):
  77. module.parse_data_source_dumps_metadata('[{', 'borgmatic/databases/dumps.json')
  78. def test_parse_data_source_dumps_metadata_with_unknown_keys_raises():
  79. dumps_json = (
  80. '{"dumps": [{"data_source_name": "foo", "hook_name": "databases", "wtf": "is this"}]}'
  81. )
  82. with pytest.raises(ValueError):
  83. module.parse_data_source_dumps_metadata(dumps_json, 'borgmatic/databases/dumps.json')
  84. def test_parse_data_source_dumps_metadata_with_missing_dumps_key_raises():
  85. dumps_json = '{"not": "what we are looking for"}'
  86. with pytest.raises(ValueError):
  87. module.parse_data_source_dumps_metadata(dumps_json, 'borgmatic/databases/dumps.json')
  88. def test_create_parent_directory_for_dump_does_not_raise():
  89. flexmock(module.os).should_receive('makedirs')
  90. module.create_parent_directory_for_dump('/path/to/parent')
  91. def test_create_named_pipe_for_dump_does_not_raise():
  92. flexmock(module).should_receive('create_parent_directory_for_dump')
  93. flexmock(module.os).should_receive('mkfifo')
  94. module.create_named_pipe_for_dump('/path/to/pipe')
  95. def test_remove_data_source_dumps_removes_dump_path():
  96. flexmock(module.os.path).should_receive('exists').and_return(True)
  97. flexmock(module.shutil).should_receive('rmtree').with_args('databases').once()
  98. module.remove_data_source_dumps('databases', 'SuperDB', dry_run=False)
  99. def test_remove_data_source_dumps_with_dry_run_skips_removal():
  100. flexmock(module.os.path).should_receive('exists').never()
  101. flexmock(module.shutil).should_receive('rmtree').never()
  102. module.remove_data_source_dumps('databases', 'SuperDB', dry_run=True)
  103. def test_remove_data_source_dumps_without_dump_path_present_skips_removal():
  104. flexmock(module.os.path).should_receive('exists').and_return(False)
  105. flexmock(module.shutil).should_receive('rmtree').never()
  106. module.remove_data_source_dumps('databases', 'SuperDB', dry_run=False)
  107. def test_convert_glob_patterns_to_borg_pattern_makes_multipart_regular_expression():
  108. assert (
  109. module.convert_glob_patterns_to_borg_pattern(('/etc/foo/bar', '/bar/*/baz'))
  110. == 're:(?s:etc/foo/bar)|(?s:bar/.*/baz)'
  111. )