From 9f821862b74e29a41f20ed6d0a39a4cb859d3267 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Tue, 10 Dec 2019 16:41:01 -0800 Subject: [PATCH] End-to-end tests for database dump and restore. --- .drone.yml | 45 ++++++++++++++++++ tests/end-to-end/test_borgmatic.py | 8 ++-- tests/end-to-end/test_database.py | 76 ++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 tests/end-to-end/test_database.py diff --git a/.drone.yml b/.drone.yml index 81377208f..a7fa332de 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,6 +2,15 @@ kind: pipeline name: python-3-5-alpine-3-10 +services: + database: + image: postgres:11.5 + ports: + - "5432:5432" + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: test + steps: - name: build image: python:3.5-alpine3.10 @@ -12,6 +21,15 @@ steps: kind: pipeline name: python-3-6-alpine-3-10 +services: + database: + image: postgres:11.5 + ports: + - "5432:5432" + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: test + steps: - name: build image: python:3.6-alpine3.10 @@ -22,6 +40,15 @@ steps: kind: pipeline name: python-3-7-alpine-3-10 +services: + database: + image: postgres:11.5 + ports: + - "5432:5432" + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: test + steps: - name: build image: python:3.7-alpine3.10 @@ -32,6 +59,15 @@ steps: kind: pipeline name: python-3-7-alpine-3-7 +services: + database: + image: postgres:11.5 + ports: + - "5432:5432" + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: test + steps: - name: build image: python:3.7-alpine3.7 @@ -42,6 +78,15 @@ steps: kind: pipeline name: python-3-8-alpine-3-10 +services: + database: + image: postgres:11.5 + ports: + - "5432:5432" + environment: + POSTGRES_PASSWORD: test + POSTGRES_DB: test + steps: - name: build image: python:3.8-alpine3.10 diff --git a/tests/end-to-end/test_borgmatic.py b/tests/end-to-end/test_borgmatic.py index 620e67a96..0bfe7b7b5 100644 --- a/tests/end-to-end/test_borgmatic.py +++ b/tests/end-to-end/test_borgmatic.py @@ -44,13 +44,13 @@ def test_borgmatic_command(): generate_configuration(config_path, repository_path) subprocess.check_call( - 'borgmatic -v 2 --config {} --init --encryption repokey'.format(config_path).split(' ') + 'borgmatic -v 2 --config {} init --encryption repokey'.format(config_path).split(' ') ) # Run borgmatic to generate a backup archive, and then list it to make sure it exists. subprocess.check_call('borgmatic --config {}'.format(config_path).split(' ')) output = subprocess.check_output( - 'borgmatic --config {} --list --json'.format(config_path).split(' ') + 'borgmatic --config {} list --json'.format(config_path).split(' ') ).decode(sys.stdout.encoding) parsed_output = json.loads(output) @@ -61,7 +61,7 @@ def test_borgmatic_command(): # Extract the created archive into the current (temporary) directory, and confirm that the # extracted file looks right. output = subprocess.check_output( - 'borgmatic --config {} --extract --archive {}'.format(config_path, archive_name).split( + 'borgmatic --config {} extract --archive {}'.format(config_path, archive_name).split( ' ' ) ).decode(sys.stdout.encoding) @@ -70,7 +70,7 @@ def test_borgmatic_command(): # Exercise the info flag. output = subprocess.check_output( - 'borgmatic --config {} --info --json'.format(config_path).split(' ') + 'borgmatic --config {} info --json'.format(config_path).split(' ') ).decode(sys.stdout.encoding) parsed_output = json.loads(output) diff --git a/tests/end-to-end/test_database.py b/tests/end-to-end/test_database.py new file mode 100644 index 000000000..b5a341358 --- /dev/null +++ b/tests/end-to-end/test_database.py @@ -0,0 +1,76 @@ +import json +import os +import shutil +import subprocess +import sys +import tempfile + + +def write_configuration(config_path, repository_path, borgmatic_source_directory): + ''' + Write out borgmatic configuration into a file at the config path. Set the options so as to work + for testing. This includes injecting the given repository path, borgmatic source directory for + storing database dumps, and encryption passphrase. + ''' + config = ''' +location: + source_directories: + - {} + repositories: + - {} + borgmatic_source_directory: {} + +storage: + encryption_passphrase: "test" + +hooks: + postgresql_databases: + - name: test + hostname: localhost + username: postgres + password: test +'''.format(config_path, repository_path, borgmatic_source_directory) + + config_file = open(config_path, 'w') + config_file.write(config) + config_file.close() + + +def test_database_dump_and_restore(): + # Create a Borg repository. + temporary_directory = tempfile.mkdtemp() + repository_path = os.path.join(temporary_directory, 'test.borg') + borgmatic_source_directory = os.path.join(temporary_directory, '.borgmatic') + + original_working_directory = os.getcwd() + + try: + config_path = os.path.join(temporary_directory, 'test.yaml') + write_configuration(config_path, repository_path, borgmatic_source_directory) + + subprocess.check_call( + 'borgmatic -v 2 --config {} init --encryption repokey'.format(config_path).split(' ') + ) + + # Run borgmatic to generate a backup archive including a database dump + subprocess.check_call('borgmatic create --config {} -v 2'.format(config_path).split(' ')) + + # Get the created archive name. + output = subprocess.check_output( + 'borgmatic --config {} list --json'.format(config_path).split(' ') + ).decode(sys.stdout.encoding) + parsed_output = json.loads(output) + + assert len(parsed_output) == 1 + assert len(parsed_output[0]['archives']) == 1 + archive_name = parsed_output[0]['archives'][0]['archive'] + + # Restore the database from the archive. + subprocess.check_call( + 'borgmatic --config {} restore --archive {}'.format(config_path, archive_name).split( + ' ' + ) + ) + finally: + os.chdir(original_working_directory) + shutil.rmtree(temporary_directory)