Skip to content

Commit

Permalink
Parsing results from backup command
Browse files Browse the repository at this point in the history
  • Loading branch information
mtlynch committed Mar 15, 2021
1 parent 20ea621 commit e8d68a8
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 2 deletions.
8 changes: 7 additions & 1 deletion e2e/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ def emit(self, record):
logger.info(restic.init())

logger.info('Backing up %s', DUMMY_DATA_PATH)
logger.info(restic.backup(paths=[DUMMY_DATA_PATH]))
backup_result = restic.backup(paths=[DUMMY_DATA_PATH])
logger.info('backup_result: %s', json.dumps(backup_summary))
if backup_result['files_new'] != 1:
logger.fatal('Expected 1 new file (got %d)', backup_result['files_new'])
if backup_result['files_changed'] != 0:
logger.fatal('Expected 0 changed files (got %d)',
backup_result['files_changed'])

RESTORE_DIR = tempfile.mkdtemp()
logger.info('Restoring to %s', RESTORE_DIR)
Expand Down
9 changes: 8 additions & 1 deletion restic/internal/backup.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json

from restic.internal import command_executor


Expand All @@ -12,4 +14,9 @@ def run(restic_base_command, paths, exclude_patterns=None, exclude_files=None):
for exclude_file in exclude_files:
cmd.extend(['--exclude-file', exclude_file])

return command_executor.execute(cmd)
result_raw = command_executor.execute(cmd)
return _parse_result(result_raw)


def _parse_result(result):
return json.loads(result.split('\n')[-1])
49 changes: 49 additions & 0 deletions restic/internal/backup_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,88 @@ class BackupTest(unittest.TestCase):

@mock.patch.object(backup.command_executor, 'execute')
def test_backup_single_path(self, mock_execute):
mock_execute.return_value = '{}'

restic.backup(['/tmp/dummy-file.txt'])

mock_execute.assert_called_with(
['restic', '--json', 'backup', '/tmp/dummy-file.txt'])

@mock.patch.object(backup.command_executor, 'execute')
def test_backup_multiple_paths(self, mock_execute):
mock_execute.return_value = '{}'

restic.backup(['/tmp/dummy-file-1.txt', '/tmp/dummy-file-2.txt'])

mock_execute.assert_called_with([
'restic', '--json', 'backup', '/tmp/dummy-file-1.txt',
'/tmp/dummy-file-2.txt'
])

@mock.patch.object(backup.command_executor, 'execute')
def test_excludes_single_pattern(self, mock_execute):
mock_execute.return_value = '{}'

restic.backup(['/data/music'], exclude_patterns=['Justin Bieber*'])

mock_execute.assert_called_with([
'restic', '--json', 'backup', '/data/music', '--exclude',
'Justin Bieber*'
])

@mock.patch.object(backup.command_executor, 'execute')
def test_excludes_multiple_patterns(self, mock_execute):
mock_execute.return_value = '{}'

restic.backup(['/data/music'],
exclude_patterns=['Justin Bieber*', 'Selena Gomez*'])

mock_execute.assert_called_with([
'restic', '--json', 'backup', '/data/music', '--exclude',
'Justin Bieber*', '--exclude', 'Selena Gomez*'
])

@mock.patch.object(backup.command_executor, 'execute')
def test_excludes_single_exclude_file(self, mock_execute):
mock_execute.return_value = '{}'

restic.backup(['/data/music'], exclude_files=['bad-songs.txt'])

mock_execute.assert_called_with([
'restic', '--json', 'backup', '/data/music', '--exclude-file',
'bad-songs.txt'
])

@mock.patch.object(backup.command_executor, 'execute')
def test_parses_result_json(self, mock_execute):
mock_execute.return_value = """
{"message_type":"status","percent_done":0,"total_files":1,"total_bytes":20}
{"message_type":"status","percent_done":0,"total_files":1,"total_bytes":20}
{"message_type":"status","percent_done":0,"total_files":1,"total_bytes":20,"current_files":["/tmp/tmpvg2jkmqw/mydata.txt"]}
{"message_type":"status","percent_done":1,"total_files":1,"total_bytes":20,"bytes_done":20,"current_files":["/tmp/tmpvg2jkmqw/mydata.txt"]}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20,"current_files":["/tmp/tmpvg2jkmqw/mydata.txt"]}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20}
{"message_type":"status","percent_done":1,"total_files":1,"files_done":1,"total_bytes":20,"bytes_done":20}
{"message_type":"summary","files_new":1,"files_changed":0,"files_unmodified":0,"dirs_new":2,"dirs_changed":0,"dirs_unmodified":0,"data_blobs":1,"tree_blobs":3,"data_added":1115,"total_files_processed":1,"total_bytes_processed":20,"total_duration":0.216764185,"snapshot_id":"01d88ea7"}
""".strip()
backup_summary = restic.backup(['/tmp/dummy-file.txt'])
self.assertEqual(
{
'message_type': 'summary',
'files_new': 1,
'files_changed': 0,
'files_unmodified': 0,
'dirs_new': 2,
'dirs_changed': 0,
'dirs_unmodified': 0,
'data_blobs': 1,
'tree_blobs': 3,
'data_added': 1115,
'total_files_processed': 1,
'total_bytes_processed': 20,
'total_duration': 0.216764185,
'snapshot_id': '01d88ea7'
}, backup_summary)

0 comments on commit e8d68a8

Please sign in to comment.