test_database.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import json
  2. import os
  3. import shutil
  4. import subprocess
  5. import sys
  6. import tempfile
  7. import pytest
  8. def write_configuration(
  9. config_path, repository_path, borgmatic_source_directory, postgresql_dump_format='custom'
  10. ):
  11. '''
  12. Write out borgmatic configuration into a file at the config path. Set the options so as to work
  13. for testing. This includes injecting the given repository path, borgmatic source directory for
  14. storing database dumps, dump format (for PostgreSQL), and encryption passphrase.
  15. '''
  16. config = '''
  17. location:
  18. source_directories:
  19. - {}
  20. repositories:
  21. - {}
  22. borgmatic_source_directory: {}
  23. storage:
  24. encryption_passphrase: "test"
  25. hooks:
  26. postgresql_databases:
  27. - name: test
  28. hostname: postgresql
  29. username: postgres
  30. password: test
  31. format: {}
  32. - name: all
  33. hostname: postgresql
  34. username: postgres
  35. password: test
  36. mysql_databases:
  37. - name: test
  38. hostname: mysql
  39. username: root
  40. password: test
  41. - name: all
  42. hostname: mysql
  43. username: root
  44. password: test
  45. mongodb_databases:
  46. - name: test
  47. hostname: mongodb
  48. username: root
  49. password: test
  50. authentication_database: admin
  51. - name: all
  52. hostname: mongodb
  53. username: root
  54. password: test
  55. '''.format(
  56. config_path, repository_path, borgmatic_source_directory, postgresql_dump_format
  57. )
  58. with open(config_path, 'w') as config_file:
  59. config_file.write(config)
  60. def test_database_dump_and_restore():
  61. # Create a Borg repository.
  62. temporary_directory = tempfile.mkdtemp()
  63. repository_path = os.path.join(temporary_directory, 'test.borg')
  64. borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic')
  65. original_working_directory = os.getcwd()
  66. try:
  67. config_path = os.path.join(temporary_directory, 'test.yaml')
  68. write_configuration(config_path, repository_path, borgmatic_source_directory)
  69. subprocess.check_call(
  70. ['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
  71. )
  72. # Run borgmatic to generate a backup archive including a database dump.
  73. subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2'])
  74. # Get the created archive name.
  75. output = subprocess.check_output(
  76. ['borgmatic', '--config', config_path, 'list', '--json']
  77. ).decode(sys.stdout.encoding)
  78. parsed_output = json.loads(output)
  79. assert len(parsed_output) == 1
  80. assert len(parsed_output[0]['archives']) == 1
  81. archive_name = parsed_output[0]['archives'][0]['archive']
  82. # Restore the database from the archive.
  83. subprocess.check_call(
  84. ['borgmatic', '--config', config_path, 'restore', '--archive', archive_name]
  85. )
  86. finally:
  87. os.chdir(original_working_directory)
  88. shutil.rmtree(temporary_directory)
  89. def test_database_dump_and_restore_with_directory_format():
  90. # Create a Borg repository.
  91. temporary_directory = tempfile.mkdtemp()
  92. repository_path = os.path.join(temporary_directory, 'test.borg')
  93. borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic')
  94. original_working_directory = os.getcwd()
  95. try:
  96. config_path = os.path.join(temporary_directory, 'test.yaml')
  97. write_configuration(
  98. config_path,
  99. repository_path,
  100. borgmatic_source_directory,
  101. postgresql_dump_format='directory',
  102. )
  103. subprocess.check_call(
  104. ['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
  105. )
  106. # Run borgmatic to generate a backup archive including a database dump.
  107. subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2'])
  108. # Restore the database from the archive.
  109. subprocess.check_call(
  110. ['borgmatic', '--config', config_path, 'restore', '--archive', 'latest']
  111. )
  112. finally:
  113. os.chdir(original_working_directory)
  114. shutil.rmtree(temporary_directory)
  115. def test_database_dump_with_error_causes_borgmatic_to_exit():
  116. # Create a Borg repository.
  117. temporary_directory = tempfile.mkdtemp()
  118. repository_path = os.path.join(temporary_directory, 'test.borg')
  119. borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic')
  120. original_working_directory = os.getcwd()
  121. try:
  122. config_path = os.path.join(temporary_directory, 'test.yaml')
  123. write_configuration(config_path, repository_path, borgmatic_source_directory)
  124. subprocess.check_call(
  125. ['borgmatic', '-v', '2', '--config', config_path, 'init', '--encryption', 'repokey']
  126. )
  127. # Run borgmatic with a config override such that the database dump fails.
  128. with pytest.raises(subprocess.CalledProcessError):
  129. subprocess.check_call(
  130. [
  131. 'borgmatic',
  132. 'create',
  133. '--config',
  134. config_path,
  135. '-v',
  136. '2',
  137. '--override',
  138. "hooks.postgresql_databases=[{'name': 'nope'}]",
  139. ]
  140. )
  141. finally:
  142. os.chdir(original_working_directory)
  143. shutil.rmtree(temporary_directory)