mirror of
https://github.com/outbackdingo/patroni.git
synced 2026-08-31 00:29:29 +00:00
In particular, remove restore.py in favor of wale_restore.py, fix minor bugs in the latter and add unit tests.
128 lines
6.0 KiB
Python
128 lines
6.0 KiB
Python
import unittest
|
|
from mock import MagicMock, patch, PropertyMock
|
|
import os
|
|
import psycopg2
|
|
import subprocess
|
|
from patroni.scripts.wale_restore import WALERestore
|
|
|
|
|
|
def fake_cursor_fetchone(*args, **kwargs):
|
|
return ('16777216',)
|
|
|
|
|
|
def fake_call_fail_for_wal_e(*args, **kwargs):
|
|
if len(args) > 0 and 'backup-fetch' in args[0]:
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def fake_call_fail_for_base_backup(*args, **kwargs):
|
|
if len(args) > 0 and 'backup-fetch' in args[0]:
|
|
return 0
|
|
return 1
|
|
|
|
|
|
def fake_backup_data(self, *args, **kwargs):
|
|
""" return the fake result of WAL-E backup-list"""
|
|
return """name last_modified expanded_size_bytes wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop
|
|
base_00000001000000000000007F_00000040 2015-05-18T10:13:25.000Z 167772160 00000001000000000000007F 00000040 00000001000000000000007F 00000240
|
|
"""
|
|
|
|
def fake_backup_data_2(self, *args, **kwargs):
|
|
""" return the fake result of WAL-E backup-list"""
|
|
return """name last_modified expanded_size_bytes wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop """
|
|
|
|
def fake_backup_data_3(self, *args, **kwargs):
|
|
""" return the fake result of WAL-E backup-list"""
|
|
return """name last_modified expanded_size_bytes wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop
|
|
base_00000001000000000000007F_00000040 2015-05-18T10:13:25.000Z 167772160 00000001000000000000007F 00000040 00000001000000000000007F 00000240
|
|
"""
|
|
|
|
def fake_backup_data_4(self, *args, **kwargs):
|
|
""" return the fake result of WAL-E backup-list"""
|
|
return """name last_modified expanded_size_foo wal_segment_backup_start wal_segment_offset_backup_start wal_segment_backup_stop wal_segment_offset_backup_stop
|
|
base_00000001000000000000007F_00000040 2015-05-18T10:13:25.000Z 167772160 00000001000000000000007F 00000040 00000001000000000000007F 00000240
|
|
"""
|
|
|
|
|
|
@patch('os.access', MagicMock(return_value=True))
|
|
@patch('os.makedirs', MagicMock(return_value=True))
|
|
@patch('os.path.exists', MagicMock(return_value=True))
|
|
@patch('os.path.isdir', MagicMock(return_value=True))
|
|
@patch('psycopg2.extensions.cursor.fetchone', MagicMock(side_effect=fake_cursor_fetchone))
|
|
@patch('psycopg2.extensions.cursor', MagicMock(autospec=True))
|
|
@patch('psycopg2.extensions.connection', MagicMock(autospec=True))
|
|
@patch('psycopg2.connect', MagicMock(autospec=True))
|
|
@patch('subprocess.check_output', MagicMock(side_effect=fake_backup_data))
|
|
class TestWALERestore(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.wale_restore = WALERestore("batman", "/data",
|
|
"host=batman port=5432 user=batman", "/etc", 100, 100, 1)
|
|
|
|
def tearDown(self):
|
|
pass
|
|
|
|
def test_should_use_s3_to_create_replica(self):
|
|
with patch('psycopg2.connect', MagicMock(side_effect=psycopg2.Error("foo"))):
|
|
self.assertFalse(self.wale_restore.should_use_s3_to_create_replica())
|
|
with patch('subprocess.check_output', MagicMock(side_effect=subprocess.CalledProcessError(1, "cmd", "foo"))):
|
|
self.assertFalse(self.wale_restore.should_use_s3_to_create_replica())
|
|
with patch('subprocess.check_output', MagicMock(side_effect=fake_backup_data_2)):
|
|
self.assertFalse(self.wale_restore.should_use_s3_to_create_replica())
|
|
with patch('subprocess.check_output', MagicMock(side_effect=fake_backup_data_3)):
|
|
self.assertFalse(self.wale_restore.should_use_s3_to_create_replica())
|
|
with patch('subprocess.check_output', MagicMock(side_effect=fake_backup_data_4)):
|
|
self.assertFalse(self.wale_restore.should_use_s3_to_create_replica())
|
|
|
|
self.wale_restore.should_use_s3_to_create_replica()
|
|
|
|
def test_create_replica_with_s3(self):
|
|
with patch('subprocess.call', MagicMock(return_value=0)):
|
|
self.assertEqual(self.wale_restore.create_replica_with_s3(), 0)
|
|
with patch('subprocess.call', MagicMock(side_effect=Exception("foo"))):
|
|
self.assertEqual(self.wale_restore.create_replica_with_s3(), 1)
|
|
|
|
def test_run(self):
|
|
with patch.object(self.wale_restore, 'init_error', PropertyMock(return_value=True)):
|
|
self.assertEqual(self.wale_restore.run(), 2)
|
|
with patch.object(self.wale_restore, 'should_use_s3_to_create_replica', MagicMock(return_value=True)):
|
|
with patch.object(self.wale_restore, 'create_replica_with_s3', MagicMock(return_value=0)):
|
|
self.assertEqual(self.wale_restore.run(), 0)
|
|
|
|
# with patch.object(self.wale_restore, 'init_error', PropertyMock(return_value=True)):
|
|
# self.assertFalse(self.wale_restore.create_replica_with_s3())
|
|
|
|
# @patch('subprocess.call', MagicMock(return_value=0))
|
|
# def test_run(self):
|
|
# ret = self.wale_restore.run()
|
|
# self.assertEqual(ret, 0)
|
|
|
|
|
|
# The 3 tests above only differ with the mock function instead of a subprocess call
|
|
# in the first one, subprocess call should return success only for wal-e command,
|
|
# checking the primary use-case of restoring from WAL-E backup.
|
|
# In the second one, we test fallbacks by failing at WAL-E, but succeeding at
|
|
# pg_basebackup.
|
|
# Finally, the last use case is when all subprocess.call fails. resulting in a
|
|
# failure to restore from replica
|
|
# @patch('subprocess.call',
|
|
# MagicMock(side_effect=lambda *args, **kwargs: 0 if 'wal-e' in args[0] else 1))
|
|
# def test_run(self):
|
|
# self.wale_restore.setup()
|
|
# ret = self.wale_restore.run()
|
|
# self.assertEqual(ret, 0)
|
|
|
|
# @patch('subprocess.call',
|
|
# MagicMock(side_effect=lambda *args, **kwargs: 0 if 'pg_basebackup' in args[0] else 1))
|
|
# def test_run_fallback(self):
|
|
# self.wale_restore.setup()
|
|
# ret = self.wale_restore.run()
|
|
# self.assertEqual(ret, 0)
|
|
|
|
# @patch('subprocess.call', MagicMock(return_value=1))
|
|
# def test_run_all_fail(self):
|
|
# self.wale_restore.setup()
|
|
# ret = self.wale_restore.run()
|
|
# self.assertEqual(ret, 1)
|