1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2024-11-28 09:33:54 +02:00

TESTS: false_positive added, pgpro-560 added, validate redesign

This commit is contained in:
Grigory Smolkin 2017-05-22 14:17:43 +03:00
parent 134c9390b2
commit 0f212e0455
27 changed files with 550 additions and 485 deletions

View File

@ -5,16 +5,16 @@ from . import init_test, option_test, show_test, \
retention_test, ptrack_clean, ptrack_cluster, \ retention_test, ptrack_clean, ptrack_cluster, \
ptrack_move_to_tablespace, ptrack_recovery, ptrack_vacuum, \ ptrack_move_to_tablespace, ptrack_recovery, ptrack_vacuum, \
ptrack_vacuum_bits_frozen, ptrack_vacuum_bits_visibility, \ ptrack_vacuum_bits_frozen, ptrack_vacuum_bits_visibility, \
ptrack_vacuum_full, ptrack_vacuum_truncate, common_archive_test, \ ptrack_vacuum_full, ptrack_vacuum_truncate, pgpro560, pgpro589, \
pgpro561, pgpro688, pgpro702, pgpro589 false_positive, replica
def load_tests(loader, tests, pattern): def load_tests(loader, tests, pattern):
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTests(loader.loadTestsFromModule(pgpro561)) suite.addTests(loader.loadTestsFromModule(replica))
suite.addTests(loader.loadTestsFromModule(pgpro560))
suite.addTests(loader.loadTestsFromModule(pgpro589)) suite.addTests(loader.loadTestsFromModule(pgpro589))
suite.addTests(loader.loadTestsFromModule(pgpro688)) suite.addTests(loader.loadTestsFromModule(false_positive))
suite.addTests(loader.loadTestsFromModule(pgpro702))
suite.addTests(loader.loadTestsFromModule(init_test)) suite.addTests(loader.loadTestsFromModule(init_test))
suite.addTests(loader.loadTestsFromModule(option_test)) suite.addTests(loader.loadTestsFromModule(option_test))
suite.addTests(loader.loadTestsFromModule(show_test)) suite.addTests(loader.loadTestsFromModule(show_test))
@ -34,3 +34,6 @@ def load_tests(loader, tests, pattern):
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_truncate)) suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_truncate))
return suite return suite
# ExpectedFailures are bugs, which should be fixed

View File

@ -10,10 +10,12 @@ class BackupTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(BackupTest, self).__init__(*args, **kwargs) super(BackupTest, self).__init__(*args, **kwargs)
# @classmethod @classmethod
# def tearDownClass(cls): def tearDownClass(cls):
# stop_all() stop_all()
# @unittest.skip("123")
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_backup_modes_archive(self): def test_backup_modes_archive(self):
"""standart backup modes with ARCHIVE WAL method""" """standart backup modes with ARCHIVE WAL method"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -26,8 +28,10 @@ class BackupTest(ProbackupTest, unittest.TestCase):
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
# full backup mode # full backup mode
with open(path.join(node.logs_dir, "backup_full.log"), "wb") as backup_log: #with open(path.join(node.logs_dir, "backup_full.log"), "wb") as backup_log:
backup_log.write(self.backup_pb(node, options=["--verbose"])) # backup_log.write(self.backup_pb(node, options=["--verbose"]))
self.backup_pb(node)
show_backup = self.show_pb(node)[0] show_backup = self.show_pb(node)[0]
full_backup_id = show_backup['ID'] full_backup_id = show_backup['ID']
@ -46,8 +50,7 @@ class BackupTest(ProbackupTest, unittest.TestCase):
self.assertEqual(excluded, True) self.assertEqual(excluded, True)
# page backup mode # page backup mode
with open(path.join(node.logs_dir, "backup_page.log"), "wb") as backup_log: self.backup_pb(node, backup_type="page")
backup_log.write(self.backup_pb(node, backup_type="page", options=["--verbose"]))
# print self.show_pb(node) # print self.show_pb(node)
show_backup = self.show_pb(node)[1] show_backup = self.show_pb(node)[1]
@ -60,8 +63,7 @@ class BackupTest(ProbackupTest, unittest.TestCase):
self.show_pb(node, id=show_backup['ID'])["parent-backup-id"]) self.show_pb(node, id=show_backup['ID'])["parent-backup-id"])
# ptrack backup mode # ptrack backup mode
with open(path.join(node.logs_dir, "backup_ptrack.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack")
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose"]))
show_backup = self.show_pb(node)[2] show_backup = self.show_pb(node)[2]
self.assertEqual(show_backup['Status'], six.b("OK")) self.assertEqual(show_backup['Status'], six.b("OK"))
@ -69,7 +71,6 @@ class BackupTest(ProbackupTest, unittest.TestCase):
node.stop() node.stop()
# @unittest.skip("123")
def test_smooth_checkpoint(self): def test_smooth_checkpoint(self):
"""full backup with smooth checkpoint""" """full backup with smooth checkpoint"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -81,14 +82,12 @@ class BackupTest(ProbackupTest, unittest.TestCase):
node.start() node.start()
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
with open(path.join(node.logs_dir, "backup.log"), "wb") as backup_log: self.backup_pb(node, options=["-C"])
backup_log.write(self.backup_pb(node, options=["--verbose", "-C"]))
self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK")) self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK"))
node.stop() node.stop()
# @unittest.skip("123")
def test_page_backup_without_full(self): def test_page_backup_without_full(self):
"""page-level backup without validated full backup""" """page-level backup without validated full backup"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -101,14 +100,13 @@ class BackupTest(ProbackupTest, unittest.TestCase):
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
try: try:
self.backup_pb(node, backup_type="page", options=["--verbose"]) self.backup_pb(node, backup_type="page")
except ProbackupException, e: except ProbackupException, e:
pass pass
self.assertEqual(self.show_pb(node)[0]['Status'], six.b("ERROR")) self.assertEqual(self.show_pb(node)[0]['Status'], six.b("ERROR"))
node.stop() node.stop()
# @unittest.skip("123")
def test_ptrack_threads(self): def test_ptrack_threads(self):
"""ptrack multi thread backup mode""" """ptrack multi thread backup mode"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -120,19 +118,17 @@ class BackupTest(ProbackupTest, unittest.TestCase):
node.start() node.start()
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
with open(path.join(node.logs_dir, "backup_full.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full", options=["-j", "4"])
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose", "-j", "4"]))
self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK")) self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK"))
with open(path.join(node.logs_dir, "backup_ptrack.log"), "wb") as backup_log: with open(path.join(node.logs_dir, "backup_ptrack.log"), "wb") as backup_log:
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose", "-j", "4"])) backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["-j", "4"]))
self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK")) self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK"))
node.stop() node.stop()
# @unittest.skip("123")
def test_ptrack_threads_stream(self): def test_ptrack_threads_stream(self):
"""ptrack multi thread backup mode and stream""" """ptrack multi thread backup mode and stream"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -144,21 +140,11 @@ class BackupTest(ProbackupTest, unittest.TestCase):
node.start() node.start()
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
with open(path.join(node.logs_dir, "backup_full.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full", options=["-j", "4", "--stream"])
backup_log.write(self.backup_pb(
node,
backup_type="full",
options=["--verbose", "-j", "4", "--stream"]
))
self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK")) self.assertEqual(self.show_pb(node)[0]['Status'], six.b("OK"))
with open(path.join(node.logs_dir, "backup_ptrack.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack", options=["-j", "4", "--stream"])
backup_log.write(self.backup_pb(
node,
backup_type="ptrack",
options=["--verbose", "-j", "4", "--stream"]
))
self.assertEqual(self.show_pb(node)[1]['Status'], six.b("OK")) self.assertEqual(self.show_pb(node)[1]['Status'], six.b("OK"))
node.stop() node.stop()

View File

@ -11,10 +11,12 @@ class DeleteTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(DeleteTest, self).__init__(*args, **kwargs) super(DeleteTest, self).__init__(*args, **kwargs)
# @classmethod @classmethod
# def tearDownClass(cls): def tearDownClass(cls):
# stop_all() stop_all()
# @unittest.skip("123")
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_delete_full_backups(self): def test_delete_full_backups(self):
"""delete full backups""" """delete full backups"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -28,22 +30,19 @@ class DeleteTest(ProbackupTest, unittest.TestCase):
node.pgbench_init() node.pgbench_init()
# full backup mode # full backup mode
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_3.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
show_backups = self.show_pb(node) show_backups = self.show_pb(node)
id_1 = show_backups[0]['ID'] id_1 = show_backups[0]['ID']
@ -55,7 +54,6 @@ class DeleteTest(ProbackupTest, unittest.TestCase):
node.stop() node.stop()
# @unittest.skip("123")
def test_delete_increment(self): def test_delete_increment(self):
"""delete increment and all after him""" """delete increment and all after him"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -68,16 +66,13 @@ class DeleteTest(ProbackupTest, unittest.TestCase):
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
# full backup mode # full backup mode
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
# page backup mode # page backup mode
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="page")
backup_log.write(self.backup_pb(node, backup_type="page", options=["--verbose"]))
# page backup mode # page backup mode
with open(path.join(node.logs_dir, "backup_3.log"), "wb") as backup_log: self.backup_pb(node, backup_type="page")
backup_log.write(self.backup_pb(node, backup_type="page", options=["--verbose"]))
# full backup mode # full backup mode
self.backup_pb(node) self.backup_pb(node)

View File

@ -9,7 +9,13 @@ pg_probackup - utility to manage backup/recovery of PostgreSQL database.
pg_probackup set-config -B backup-dir pg_probackup set-config -B backup-dir
[-d dbname] [-h host] [-p port] [-U username] [-d dbname] [-h host] [-p port] [-U username]
[--retention-redundancy=retention-redundancy]] [--log-level=log-level]
[--log-filename=log-filename]
[--error-log-filename=error-log-filename]
[--log-directory=log-directory]
[--log-rotation-size=log-rotation-size]
[--log-rotation-age=log-rotation-age]
[--retention-redundancy=retention-redundancy]
[--retention-window=retention-window] [--retention-window=retention-window]
pg_probackup show-config -B backup-dir pg_probackup show-config -B backup-dir
@ -17,16 +23,16 @@ pg_probackup - utility to manage backup/recovery of PostgreSQL database.
pg_probackup backup -B backup-path -b backup-mode pg_probackup backup -B backup-path -b backup-mode
[-D pgdata-dir] [-C] [--stream [-S slot-name]] [--backup-pg-log] [-D pgdata-dir] [-C] [--stream [-S slot-name]] [--backup-pg-log]
[-j num-threads] [--archive-timeout=archive-timeout] [-j num-threads] [--archive-timeout=archive-timeout]
[--progress] [-q] [-v] [--delete-expired] [--progress] [--delete-expired]
[-d dbname] [-h host] [-p port] [-U username] [-d dbname] [-h host] [-p port] [-U username]
pg_probackup restore -B backup-dir pg_probackup restore -B backup-dir
[-D pgdata-dir] [-i backup-id] [--progress] [-q] [-v] [-D pgdata-dir] [-i backup-id] [--progress]
[--time=time|--xid=xid [--inclusive=boolean]] [--time=time|--xid=xid [--inclusive=boolean]]
[--timeline=timeline] [-T OLDDIR=NEWDIR] [--timeline=timeline] [-T OLDDIR=NEWDIR]
pg_probackup validate -B backup-dir pg_probackup validate -B backup-dir
[-D pgdata-dir] [-i backup-id] [--progress] [-q] [-v] [-D pgdata-dir] [-i backup-id] [--progress]
[--time=time|--xid=xid [--inclusive=boolean]] [--time=time|--xid=xid [--inclusive=boolean]]
[--timeline=timeline] [--timeline=timeline]

154
tests/false_positive.py Normal file
View File

@ -0,0 +1,154 @@
import unittest
import os
import six
from .ptrack_helpers import ProbackupTest, ProbackupException
from datetime import datetime, timedelta
from testgres import stop_all
import subprocess
from sys import exit
class FalsePositive(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs):
super(FalsePositive, self).__init__(*args, **kwargs)
@classmethod
def tearDownClass(cls):
stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_pgpro561(self):
"""
make node with archiving, make stream backup, restore it to node1,
check that archiving is not successful on node1
"""
fname = self.id().split('.')[3]
master = self.make_simple_node(base_dir="tmp_dirs/false_positive/{0}/master".format(fname),
set_archiving=True,
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
master.start()
self.assertEqual(self.init_pb(master), six.b(""))
id = self.backup_pb(master, backup_type='full', options=["--stream"])
node1 = self.make_simple_node(base_dir="tmp_dirs/false_positive/{0}/node1".format(fname))
node1.cleanup()
master.psql(
"postgres",
"create table t_heap as select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,256) i")
self.backup_pb(master, backup_type='page', options=["--stream"])
self.restore_pb(backup_dir=self.backup_dir(master), data_dir=node1.data_dir)
node1.append_conf('postgresql.auto.conf', 'port = {0}'.format(node1.port))
node1.start({"-t": "600"})
timeline_master = master.get_control_data()["Latest checkpoint's TimeLineID"]
timeline_node1 = node1.get_control_data()["Latest checkpoint's TimeLineID"]
self.assertEqual(timeline_master, timeline_node1, "Timelines on Master and Node1 should be equal. This is unexpected")
archive_command_master = master.safe_psql("postgres", "show archive_command")
archive_command_node1 = node1.safe_psql("postgres", "show archive_command")
self.assertEqual(archive_command_master, archive_command_node1, "Archive command on Master and Node should be equal. This is unexpected")
res = node1.safe_psql("postgres", "select last_failed_wal from pg_stat_get_archiver() where last_failed_wal is not NULL")
# self.assertEqual(res, six.b(""), 'Restored Node1 failed to archive segment {0} due to having the same archive command as Master'.format(res.rstrip()))
if res == six.b(""):
self.assertEqual(1, 0, 'Error is expected due to Master and Node1 having the common archive and archive_command')
master.stop()
node1.stop()
def pgpro688(self):
"""
make node with archiving, make backup,
get Recovery Time, validate to Recovery Time
Waiting PGPRO-688
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/false_positive/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
id = self.backup_pb(node, backup_type='full')
recovery_time = self.show_pb(node, id=id)['recovery-time']
# Uncommenting this section will make this test True Positive
#node.psql("postgres", "select pg_create_restore_point('123')")
#node.psql("postgres", "select txid_current()")
#node.psql("postgres", "select pg_switch_xlog()")
####
try:
self.validate_pb(node, options=["--time='{0}'".format(recovery_time)])
self.assertEqual(1, 0, 'Error is expected because We should not be able safely validate "Recovery Time" without wal record with timestamp')
except ProbackupException, e:
self.assertTrue('WARNING: recovery can be done up to time {0}'.format(recovery_time) in e.message)
node.stop()
def pgpro702_688(self):
"""
make node without archiving, make stream backup,
get Recovery Time, validate to Recovery Time
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/false_positive/{0}".format(fname),
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
id = self.backup_pb(node, backup_type='full', options=["--stream"])
recovery_time = self.show_pb(node, id=id)['recovery-time']
self.assertIn(six.b("INFO: backup validation completed successfully on"),
self.validate_pb(node, options=["--time='{0}'".format(recovery_time)]))
def test_validate_wal_lost_segment(self):
"""Loose segment located between backups. ExpectedFailure. This is BUG """
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/false_positive/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
self.backup_pb(node, backup_type='full')
# make some wals
node.pgbench_init(scale=2)
pgbench = node.pgbench(
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
options=["-c", "4", "-T", "10"]
)
pgbench.wait()
pgbench.stdout.close()
# delete last wal segment
wals_dir = os.path.join(self.backup_dir(node), "wal")
wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')]
wals = map(int, wals)
os.remove(os.path.join(self.backup_dir(node), "wal", '0000000' + str(max(wals))))
##### Hole Smokes, Batman! We just lost a wal segment and know nothing about it
##### We need archive-push ASAP
self.backup_pb(node, backup_type='full')
self.assertTrue('validation completed successfully' in self.validate_pb(node))
########
node.stop()

View File

@ -12,6 +12,8 @@ class InitTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(InitTest, self).__init__(*args, **kwargs) super(InitTest, self).__init__(*args, **kwargs)
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_success_1(self): def test_success_1(self):
"""Success normal init""" """Success normal init"""
fname = self.id().split(".")[3] fname = self.id().split(".")[3]

View File

@ -14,6 +14,8 @@ class OptionTest(ProbackupTest, unittest.TestCase):
def tearDownClass(cls): def tearDownClass(cls):
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_help_1(self): def test_help_1(self):
"""help options""" """help options"""
fname = self.id().split(".")[3] fname = self.id().split(".")[3]

78
tests/pgpro560.py Normal file
View File

@ -0,0 +1,78 @@
import unittest
import os
import six
from .ptrack_helpers import ProbackupTest, ProbackupException, idx_ptrack
from datetime import datetime, timedelta
from testgres import stop_all
import subprocess
from sys import exit
class CheckSystemID(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs):
super(CheckSystemID, self).__init__(*args, **kwargs)
@classmethod
def tearDownClass(cls):
stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_pgpro560_control_file_loss(self):
"""
https://jira.postgrespro.ru/browse/PGPRO-560
make node with stream support, delete control file
make backup
check that backup failed
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/pgpro560/{0}/node".format(fname),
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
file = os.path.join(node.base_dir,'data', 'global', 'pg_control')
os.remove(file)
try:
self.backup_pb(node, backup_type='full', options=['--stream'])
assertEqual(1, 0, 'Error is expected because of control file loss')
except ProbackupException, e:
self.assertTrue(
'ERROR: could not open file' and 'pg_control' in e.message,
'Expected error is about control file loss')
def test_pgpro560_systemid_mismatch(self):
"""
https://jira.postgrespro.ru/browse/PGPRO-560
make node1 and node2
feed to backup PGDATA from node1 and PGPORT from node2
check that backup failed
"""
fname = self.id().split('.')[3]
node1 = self.make_simple_node(base_dir="tmp_dirs/pgpro560/{0}/node1".format(fname),
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node1.start()
node2 = self.make_simple_node(base_dir="tmp_dirs/pgpro560/{0}/node2".format(fname),
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node2.start()
self.assertEqual(self.init_pb(node1), six.b(""))
try:
self.backup_pb(node1, data_dir=node2.data_dir, backup_type='full', options=['--stream'])
assertEqual(1, 0, 'Error is expected because of SYSTEM ID mismatch')
except ProbackupException, e:
self.assertTrue(
'ERROR: Backup data directory was initialized for system id' and
'but target backup directory system id is' in e.message,
'Expected error is about SYSTEM ID mismatch')

View File

@ -1,62 +0,0 @@
import unittest
import os
import six
from .ptrack_helpers import ProbackupTest, ProbackupException, idx_ptrack
from datetime import datetime, timedelta
from testgres import stop_all
import subprocess
from sys import exit
class CommonArchiveDir(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs):
super(CommonArchiveDir, self).__init__(*args, **kwargs)
# @classmethod
# def tearDownClass(cls):
# stop_all()
def test_pgpro561(self):
"""
EXPECTED TO FAIL
make node with archiving, make stream backup, restore it to node1,
check that archiving is not successful on node1
"""
fname = self.id().split('.')[3]
master = self.make_simple_node(base_dir="tmp_dirs/pgpro561/{0}/master".format(fname),
set_archiving=True,
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
master.start()
self.assertEqual(self.init_pb(master), six.b(""))
id = self.backup_pb(master, backup_type='full', options=["--stream"])
node1 = self.make_simple_node(base_dir="tmp_dirs/pgpro561/{0}/node1".format(fname))
node1.cleanup()
master.psql(
"postgres",
"create table t_heap as select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,256) i")
self.backup_pb(master, backup_type='page', options=["--stream"])
self.restore_pb(backup_dir=self.backup_dir(master), data_dir=node1.data_dir)
node1.append_conf('postgresql.auto.conf', 'port = {0}'.format(node1.port))
node1.start({"-t": "600"})
timeline_master = master.get_control_data()["Latest checkpoint's TimeLineID"]
timeline_node1 = node1.get_control_data()["Latest checkpoint's TimeLineID"]
self.assertEqual(timeline_master, timeline_node1, "Timelines on Master and Node1 should be equal. This is unexpected")
archive_command_master = master.safe_psql("postgres", "show archive_command")
archive_command_node1 = node1.safe_psql("postgres", "show archive_command")
self.assertEqual(archive_command_master, archive_command_node1, "Archive command on Master and Node should be equal. This is unexpected")
res = node1.safe_psql("postgres", "select last_failed_wal from pg_stat_get_archiver() where last_failed_wal is not NULL")
self.assertEqual(res, six.b(""), 'Restored Node1 failed to archive segment {0} due to having the same archive command as Master'.format(res.rstrip()))
master.stop()
node1.stop()

View File

@ -8,21 +8,22 @@ import subprocess
from sys import exit from sys import exit
class LsnCheck(ProbackupTest, unittest.TestCase): class ArchiveCheck(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(LsnCheck, self).__init__(*args, **kwargs) super(ArchiveCheck, self).__init__(*args, **kwargs)
# @classmethod @classmethod
# def tearDownClass(cls): def tearDownClass(cls):
# stop_all() stop_all()
# @unittest.expectedFailure
def test_pgpro589(self): # @unittest.skip("skip")
# @unittest.expectedFailure
def test_archive_mode(self):
""" """
https://jira.postgrespro.ru/browse/PGPRO-589 https://jira.postgrespro.ru/browse/PGPRO-589
make node without archive support, make backup which should fail make node without archive support, make backup which should fail
check that no files where copied to backup catalogue check ERROR text
EXPECTED TO FAIL
""" """
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/pgpro589/{0}/node".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/pgpro589/{0}/node".format(fname),
@ -43,18 +44,54 @@ class LsnCheck(ProbackupTest, unittest.TestCase):
path = node.safe_psql("postgres", "select pg_relation_filepath('pgbench_accounts')").rstrip() path = node.safe_psql("postgres", "select pg_relation_filepath('pgbench_accounts')").rstrip()
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
proc = self.backup_pb(
node, backup_type='full', options=['--archive-timeout=1'], async=True)
content = proc.stderr.read() try:
self.assertEqual(True, 'wait for LSN' in repr(content), self.backup_pb(node, backup_type='full', options=['--archive-timeout=10'])
'No Wait for LSN') assertEqual(1, 0, 'Error is expected because of disabled archive_mode')
self.assertEqual(True, 'could not be archived' in repr(content), except ProbackupException, e:
'No Fail Archiving Message') self.assertEqual(e.message, 'ERROR: Archiving must be enabled for archive backup\n')
def test_pgpro589(self):
"""
https://jira.postgrespro.ru/browse/PGPRO-589
make node without archive support, make backup which should fail
check that backup status equal to ERROR
check that no files where copied to backup catalogue
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/pgpro589/{0}/node".format(fname),
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.append_conf("postgresql.auto.conf", "archive_mode = on")
node.append_conf("postgresql.auto.conf", "wal_level = archive")
node.append_conf("postgresql.auto.conf", "archive_command = 'exit 0'")
node.start()
node.pgbench_init(scale=5)
pgbench = node.pgbench(
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
options=["-c", "4", "-T", "10"]
)
pgbench.wait()
pgbench.stdout.close()
path = node.safe_psql("postgres", "select pg_relation_filepath('pgbench_accounts')").rstrip()
self.assertEqual(self.init_pb(node), six.b(""))
try:
self.backup_pb(
node, backup_type='full', options=['--archive-timeout=10'])
assertEqual(1, 0, 'Error is expected because of missing archive wal segment with start_backup() LSN')
except ProbackupException, e:
self.assertTrue('INFO: wait for LSN' in e.message, "Expecting 'INFO: wait for LSN'")
self.assertTrue('ERROR: switched WAL segment' and 'could not be archived' in e.message,
"Expecting 'ERROR: switched WAL segment could not be archived'")
id = self.show_pb(node)[0]['ID'] id = self.show_pb(node)[0]['ID']
self.assertEqual('ERROR', self.show_pb(node, id=id)['status'], 'Backup should have ERROR status') self.assertEqual('ERROR', self.show_pb(node, id=id)['status'], 'Backup should have ERROR status')
#print self.backup_dir(node) #print self.backup_dir(node)
file = os.path.join(self.backup_dir(node), 'backups', id, 'database', path) file = os.path.join(self.backup_dir(node), 'backups', id, 'database', path)
self.assertEqual(False, os.path.isfile(file), self.assertFalse(os.path.isfile(file),
'\n Start LSN was not found in archive but datafiles where copied to backup catalogue.\n For example: {0}\n It is not optimal'.format(file)) '\n Start LSN was not found in archive but datafiles where copied to backup catalogue.\n For example: {0}\n It is not optimal'.format(file))

View File

@ -1,45 +0,0 @@
import unittest
import os
import six
from .ptrack_helpers import ProbackupTest, ProbackupException
from datetime import datetime, timedelta
from testgres import stop_all
import subprocess
from sys import exit
class ValidateTime(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs):
super(ValidateTime, self).__init__(*args, **kwargs)
# @classmethod
# def tearDownClass(cls):
# stop_all()
def test_validate_recovery_time(self):
"""
make node with archiving, make backup,
get Recovery Time, validate to Recovery Time
EXPECT VALIDATE TO FAIL
Waiting PGPRO-688
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/pgpro668/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
id = self.backup_pb(node, backup_type='full')
recovery_time = self.show_pb(node, id=id)['recovery-time']
# Optional
#node.psql("postgres", "select pg_create_restore_point('123')")
#node.psql("postgres", "select txid_current()")
#node.psql("postgres", "select pg_switch_xlog()")
self.assertIn(six.b("INFO: backup validation completed successfully on"),
self.validate_pb(node, options=["--time='{0}'".format(recovery_time)]))
####

View File

@ -1,39 +0,0 @@
import unittest
import os
import six
from .ptrack_helpers import ProbackupTest, ProbackupException
from datetime import datetime, timedelta
from testgres import stop_all
import subprocess
from sys import exit
class ValidateTime(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs):
super(ValidateTime, self).__init__(*args, **kwargs)
# @classmethod
# def tearDownClass(cls):
# stop_all()
def test_validate_recovery_time(self):
"""
make node without archiving, make stream backup,
get Recovery Time, validate to Recovery Time
EXPECT VALIDATE TO FAIL
"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/pgpro702/{0}".format(fname),
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
id = self.backup_pb(node, backup_type='full', options=["--stream"])
recovery_time = self.show_pb(node, id=id)['recovery-time']
self.assertIn(six.b("INFO: backup validation completed successfully on"),
self.validate_pb(node, options=["--time='{0}'".format(recovery_time)]))

View File

@ -9,10 +9,10 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
super(SimpleTest, self).__init__(*args, **kwargs) super(SimpleTest, self).__init__(*args, **kwargs)
def teardown(self): def teardown(self):
# clean_all()
stop_all() stop_all()
# @unittest.skip("123") # @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_clean(self): def test_ptrack_clean(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),

View File

@ -12,7 +12,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("123") # @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_cluster_btree(self): def test_ptrack_cluster_btree(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname),

View File

@ -161,6 +161,7 @@ class ProbackupTest(object):
node.init(initdb_params=initdb_params) node.init(initdb_params=initdb_params)
# Sane default parameters, not a shit with fsync = off from testgres # Sane default parameters, not a shit with fsync = off from testgres
node.append_conf("postgresql.auto.conf", "{0} = {1}".format('shared_buffers', '10MB'))
node.append_conf("postgresql.auto.conf", "{0} = {1}".format('fsync', 'on')) node.append_conf("postgresql.auto.conf", "{0} = {1}".format('fsync', 'on'))
node.append_conf("postgresql.auto.conf", "{0} = {1}".format('wal_level', 'minimal')) node.append_conf("postgresql.auto.conf", "{0} = {1}".format('wal_level', 'minimal'))
@ -294,7 +295,7 @@ class ProbackupTest(object):
def run_pb(self, command, async=False): def run_pb(self, command, async=False):
try: try:
# print [self.probackup_path] + command #print [self.probackup_path] + command
if async is True: if async is True:
return subprocess.Popen( return subprocess.Popen(
[self.probackup_path] + command, [self.probackup_path] + command,
@ -315,7 +316,9 @@ class ProbackupTest(object):
return output return output
else: else:
# return backup ID # return backup ID
return output.split()[2] for line in output.splitlines():
if 'INFO: Backup' and 'completed' in line:
return line.split()[2]
else: else:
return output return output
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
@ -391,13 +394,17 @@ class ProbackupTest(object):
body = body[::-1] body = body[::-1]
# split string in list with string for every header element # split string in list with string for every header element
header_split = re.split(" +", header) header_split = re.split(" +", header)
# CRUNCH, remove last item, because it`s empty, like that '' # Remove empty items
header_split.pop() for i in header_split:
if i == '':
header_split.remove(i)
for backup_record in body: for backup_record in body:
# split string in list with string for every backup record element # split string in list with string for every backup record element
backup_record_split = re.split(" +", backup_record) backup_record_split = re.split(" +", backup_record)
# CRUNCH, remove last item, because it`s empty, like that '' # Remove empty items
backup_record_split.pop() for i in backup_record_split:
if i == '':
backup_record_split.remove(i)
if len(header_split) != len(backup_record_split): if len(header_split) != len(backup_record_split):
print warning.format( print warning.format(
header=header, body=body, header=header, body=body,

View File

@ -15,6 +15,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_recovery(self): def test_ptrack_recovery(self):
fname = self.id().split(".")[3] fname = self.id().split(".")[3]
node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname),

View File

@ -15,6 +15,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_recovery(self): def test_ptrack_recovery(self):
fname = self.id().split(".")[3] fname = self.id().split(".")[3]
node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/ptrack/{0}".format(fname),

View File

@ -12,7 +12,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("123") # @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_vacuum(self): def test_ptrack_vacuum(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),

View File

@ -13,6 +13,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_vacuum_bits_frozen(self): def test_ptrack_vacuum_bits_frozen(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),

View File

@ -13,6 +13,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_vacuum_bits_visibility(self): def test_ptrack_vacuum_bits_visibility(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),

View File

@ -5,17 +5,6 @@ from testgres import get_new_node, stop_all
from os import path, open, lseek, read, close, O_RDONLY from os import path, open, lseek, read, close, O_RDONLY
from .ptrack_helpers import ProbackupTest, idx_ptrack from .ptrack_helpers import ProbackupTest, idx_ptrack
# res = node.execute('postgres', 'show fsync')
# print res[0][0]
# res = node.execute('postgres', 'show wal_level')
# print res[0][0]
# a = ProbackupTest
# res = node.execute('postgres', 'select 1')`
# self.assertEqual(len(res), 1)
# self.assertEqual(res[0][0], 1)
# node.stop()
# a = self.backup_dir(node)
class SimpleTest(ProbackupTest, unittest.TestCase): class SimpleTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -25,9 +14,10 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_vacuum_full(self): def test_ptrack_vacuum_full(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
print '{0} started'.format(fname)
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),
set_replication=True, set_replication=True,
initdb_params=['--data-checksums', '-A trust'], initdb_params=['--data-checksums', '-A trust'],

View File

@ -13,6 +13,8 @@ class SimpleTest(ProbackupTest, unittest.TestCase):
# clean_all() # clean_all()
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_ptrack_vacuum_truncate(self): def test_ptrack_vacuum_truncate(self):
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname), node = self.make_simple_node(base_dir='tmp_dirs/ptrack/{0}'.format(fname),

View File

@ -11,19 +11,21 @@ from sys import exit
class ReplicaTest(ProbackupTest, unittest.TestCase): class ReplicaTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(SomeTest, self).__init__(*args, **kwargs) super(ReplicaTest, self).__init__(*args, **kwargs)
@classmethod @classmethod
def tearDownClass(cls): def tearDownClass(cls):
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def test_make_simple_replica(self): def test_make_simple_replica(self):
""" """
make node with archiving, make stream backup, make node with archiving, make stream backup,
get Recovery Time, try to make pitr to Recovery Time get Recovery Time, try to make pitr to Recovery Time
""" """
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
master = self.make_simple_node(base_dir="tmp_dirs/pgpro561/{0}/master".format(fname), master = self.make_simple_node(base_dir="tmp_dirs/replica/{0}/master".format(fname),
set_archiving=True, set_archiving=True,
set_replication=True, set_replication=True,
initdb_params=['--data-checksums'], initdb_params=['--data-checksums'],
@ -31,30 +33,20 @@ class ReplicaTest(ProbackupTest, unittest.TestCase):
) )
master.start() master.start()
slave = self.make_simple_node(base_dir="tmp_dirs/pgpro561/{0}/replica".format(fname), slave = self.make_simple_node(base_dir="tmp_dirs/replica/{0}/slave".format(fname))
set_archiving=True,
set_replication=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica', 'max_wal_senders': '2'}
)
slave_port = slave.port slave_port = slave.port
slave.cleanup() slave.cleanup()
self.assertEqual(self.init_pb(master), six.b("")) self.assertEqual(self.init_pb(master), six.b(""))
self.backup_pb(master, backup_type='full') self.backup_pb(master, backup_type='full', options=['--stream'])
master.psql( master.psql(
"postgres", "postgres",
"create table t_heap as select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,256) i") "create table t_heap as select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,256) i")
# for i in idx_ptrack:
# if idx_ptrack[i]['type'] == 'heap':
# continue
# master.psql("postgres", "create index {0} on {1} using {2}({3})".format(
# i, idx_ptrack[i]['relation'], idx_ptrack[i]['type'], idx_ptrack[i]['column']))
before = master.execute("postgres", "SELECT * FROM t_heap") before = master.execute("postgres", "SELECT * FROM t_heap")
id = self.backup_pb(master, backup_type='page') id = self.backup_pb(master, backup_type='page', options=['--stream'])
self.restore_pb(backup_dir=self.backup_dir(master), data_dir=slave.data_dir) self.restore_pb(backup_dir=self.backup_dir(master), data_dir=slave.data_dir)
slave.append_conf('postgresql.auto.conf', 'port = {0}'.format(slave.port)) slave.append_conf('postgresql.auto.conf', 'port = {0}'.format(slave.port))
slave.append_conf('postgresql.auto.conf', 'hot_standby = on') slave.append_conf('postgresql.auto.conf', 'hot_standby = on')
@ -66,3 +58,6 @@ class ReplicaTest(ProbackupTest, unittest.TestCase):
after = slave.execute("postgres", "SELECT * FROM t_heap") after = slave.execute("postgres", "SELECT * FROM t_heap")
self.assertEqual(before, after) self.assertEqual(before, after)
self.assertEqual(self.init_pb(slave), six.b(""))
self.backup_pb(slave, backup_type='full', options=['--stream'])

View File

@ -18,7 +18,8 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
def tearDownClass(cls): def tearDownClass(cls):
stop_all() stop_all()
# @unittest.skip("123") # @unittest.skip("skip")
# @unittest.expectedFailure
def test_restore_full_to_latest(self): def test_restore_full_to_latest(self):
"""recovery to latest from full backup""" """recovery to latest from full backup"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -34,17 +35,14 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# 1 - Test recovery from latest # 1 - Test recovery from latest
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
# 2 - Test that recovery.conf was created # 2 - Test that recovery.conf was created
recovery_conf = path.join(node.data_dir, "recovery.conf") recovery_conf = path.join(node.data_dir, "recovery.conf")
@ -70,24 +68,21 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.pgbench_init(scale=2) node.pgbench_init(scale=2)
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log:
backup_log.write(self.backup_pb(node, options=["--verbose"])) backup_log.write(self.backup_pb(node))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="page")
backup_log.write(self.backup_pb(node, backup_type="page", options=["--verbose"]))
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -110,17 +105,14 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
target_tli = int(node.get_control_data()[six.b("Latest checkpoint's TimeLineID")]) target_tli = int(node.get_control_data()[six.b("Latest checkpoint's TimeLineID")])
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -128,17 +120,14 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node, options=["-j", "4", "--timeline=%i" % target_tli]))
options=["-j", "4", "--verbose", "--timeline=%i" % target_tli])
# )
recovery_target_timeline = self.get_recovery_conf(node)["recovery_target_timeline"] recovery_target_timeline = self.get_recovery_conf(node)["recovery_target_timeline"]
self.assertEqual(int(recovery_target_timeline), target_tli) self.assertEqual(int(recovery_target_timeline), target_tli)
@ -164,8 +153,7 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
target_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") target_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@ -175,11 +163,9 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node, options=["-j", "4", '--time="%s"' % target_time]))
options=["-j", "4", "--verbose", '--time="%s"' % target_time])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -203,8 +189,7 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
con.execute("CREATE TABLE tbl0005 (a text)") con.execute("CREATE TABLE tbl0005 (a text)")
con.commit() con.commit()
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
@ -228,11 +213,9 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.stop({"-m": "fast"}) node.stop({"-m": "fast"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node, options=["-j", "4", '--xid=%s' % target_xid]))
options=["-j", "4", "--verbose", '--xid=%s' % target_xid])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -261,25 +244,21 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.append_conf("postgresql.conf", "ptrack_enable = on") node.append_conf("postgresql.conf", "ptrack_enable = on")
node.restart() node.restart()
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack")
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose"]))
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -308,32 +287,27 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.append_conf("postgresql.conf", "ptrack_enable = on") node.append_conf("postgresql.conf", "ptrack_enable = on")
node.restart() node.restart()
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack")
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_3.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack")
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose"]))
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -359,25 +333,21 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
self.skipTest("ptrack not supported") self.skipTest("ptrack not supported")
return return
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full", options=["--stream"])
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose", "--stream"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack", options=["--stream"])
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose", "--stream"]))
before = node.execute("postgres", "SELECT * FROM pgbench_branches") before = node.execute("postgres", "SELECT * FROM pgbench_branches")
node.stop({"-m": "immediate"}) node.stop({"-m": "immediate"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -406,8 +376,7 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
return return
node.restart() node.restart()
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench = node.pgbench( pgbench = node.pgbench(
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
@ -415,8 +384,7 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
options=["-c", "4", "-T", "8"] options=["-c", "4", "-T", "8"]
) )
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack", options=["--stream"])
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose", "--stream"]))
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
@ -430,10 +398,8 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
self.wrong_wal_clean(node, wal_segment_size) self.wrong_wal_clean(node, wal_segment_size)
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -471,14 +437,12 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
options=["-c", "4", "-T", "8"] options=["-c", "4", "-T", "8"]
) )
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
with open(path.join(node.logs_dir, "backup_2.log"), "wb") as backup_log: self.backup_pb(node, backup_type="ptrack", options=["--stream"])
backup_log.write(self.backup_pb(node, backup_type="ptrack", options=["--verbose", "--stream"]))
bbalance = node.execute("postgres", "SELECT sum(bbalance) FROM pgbench_branches") bbalance = node.execute("postgres", "SELECT sum(bbalance) FROM pgbench_branches")
delta = node.execute("postgres", "SELECT sum(delta) FROM pgbench_history") delta = node.execute("postgres", "SELECT sum(delta) FROM pgbench_history")
@ -489,10 +453,8 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.cleanup() node.cleanup()
self.wrong_wal_clean(node, wal_segment_size) self.wrong_wal_clean(node, wal_segment_size)
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node, options=["-j", "4"]))
self.restore_pb(node, options=["-j", "4", "--verbose"])
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -518,8 +480,7 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
con.execute("CREATE TABLE tbl0005 (a text)") con.execute("CREATE TABLE tbl0005 (a text)")
con.commit() con.commit()
with open(path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node, backup_type="full")
backup_log.write(self.backup_pb(node, backup_type="full", options=["--verbose"]))
pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) pgbench = node.pgbench(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
pgbench.wait() pgbench.wait()
@ -543,15 +504,12 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.stop({"-m": "fast"}) node.stop({"-m": "fast"})
node.cleanup() node.cleanup()
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete"), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node,
options=[ options=[
"-j", "4", "-j", "4",
"--verbose",
'--xid=%s' % target_xid, '--xid=%s' % target_xid,
"--inclusive=false"]) "--inclusive=false"]))
# )
node.start({"-t": "600"}) node.start({"-t": "600"})
@ -590,33 +548,27 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.stop() node.stop()
try: try:
self.restore_pb(node) self.restore_pb(node)
# we should die here because exception is what we expect to happen assertEqual(1, 0, 'Error is expected because restore destination is not empty')
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(
e.message, e.message,
'ERROR: restore destination is not empty: "{0}"\n'.format(node.data_dir) 'ERROR: restore destination is not empty: "{0}"\n'.format(node.data_dir))
)
# 2 - Try to restore to existing tablespace directory # 2 - Try to restore to existing tablespace directory
shutil.rmtree(node.data_dir) shutil.rmtree(node.data_dir)
try: try:
self.restore_pb(node) self.restore_pb(node)
# we should die here because exception is what we expect to happen assertEqual(1, 0, 'Error is expected because restore tablespace destination is not empty')
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(
e.message, e.message,
'ERROR: restore tablespace destination is not empty: "{0}"\n'.format(tblspc_path) 'ERROR: restore tablespace destination is not empty: "{0}"\n'.format(tblspc_path))
)
# 3 - Restore using tablespace-mapping # 3 - Restore using tablespace-mapping
tblspc_path_new = path.join(node.base_dir, "tblspc_new") tblspc_path_new = path.join(node.base_dir, "tblspc_new")
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete."), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node, options=["-T", "%s=%s" % (tblspc_path, tblspc_path_new)]))
options=["-T", "%s=%s" % (tblspc_path, tblspc_path_new)])
# )
node.start() node.start()
id = node.execute("postgres", "SELECT id FROM test") id = node.execute("postgres", "SELECT id FROM test")
@ -636,11 +588,10 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.stop() node.stop()
node.cleanup() node.cleanup()
tblspc_path_page = path.join(node.base_dir, "tblspc_page") tblspc_path_page = path.join(node.base_dir, "tblspc_page")
# TODO WAITING FIX FOR RESTORE
# self.assertIn(six.b("INFO: restore complete."), self.assertTrue(six.b("INFO: Restore of backup") and
self.restore_pb(node, six.b("completed.") in self.restore_pb(node,
options=["-T", "%s=%s" % (tblspc_path_new, tblspc_path_page)]) options=["-T", "%s=%s" % (tblspc_path_new, tblspc_path_page)]))
# )
node.start() node.start()
id = node.execute("postgres", "SELECT id FROM test OFFSET 1") id = node.execute("postgres", "SELECT id FROM test OFFSET 1")
@ -696,13 +647,10 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.cleanup() node.cleanup()
tblspc_path_new = path.join(node.base_dir, "tblspc_new") tblspc_path_new = path.join(node.base_dir, "tblspc_new")
# exit(1)
# TODO WAITING FIX FOR RESTORE self.assertTrue(six.b("INFO: Restore of backup") and
# self.assertIn(six.b("INFO: restore complete."), six.b("completed.") in self.restore_pb(node,
self.restore_pb(node, options=["-T", "%s=%s" % (tblspc_path, tblspc_path_new)]))
options=["-T", "%s=%s" % (tblspc_path, tblspc_path_new)])
# )
# Check tables
node.start() node.start()
count = node.execute("postgres", "SELECT count(*) FROM tbl") count = node.execute("postgres", "SELECT count(*) FROM tbl")
@ -732,7 +680,10 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.pg_ctl('stop', {'-m': 'immediate', '-D': '{0}'.format(node.data_dir)}) node.pg_ctl('stop', {'-m': 'immediate', '-D': '{0}'.format(node.data_dir)})
node.cleanup() node.cleanup()
self.restore_pb(node, options=['--time="{0}"'.format(recovery_time)]) self.assertTrue(six.b("INFO: Restore of backup") and
six.b("completed.") in self.restore_pb(
node, options=['--time="{0}"'.format(recovery_time)]))
node.start({"-t": "600"}) node.start({"-t": "600"})
self.assertEqual(True, node.status()) self.assertEqual(True, node.status())
node.stop() node.stop()
@ -757,9 +708,11 @@ class RestoreTest(ProbackupTest, unittest.TestCase):
node.pg_ctl('stop', {'-m': 'immediate', '-D': '{0}'.format(node.data_dir)}) node.pg_ctl('stop', {'-m': 'immediate', '-D': '{0}'.format(node.data_dir)})
node.cleanup() node.cleanup()
recovery_time = self.show_pb(node, id=id)['recovery-time'] recovery_time = self.show_pb(node, id=id)['recovery-time']
self.restore_pb(node,
options=["-j", "4", '--time="{0}"'.format(recovery_time)] self.assertTrue(six.b("INFO: Restore of backup") and
) six.b("completed.") in self.restore_pb(node,
options=["-j", "4", '--time="{0}"'.format(recovery_time)]))
node.start({"-t": "600"}) node.start({"-t": "600"})
res = node.psql("postgres", 'select * from t_heap') res = node.psql("postgres", 'select * from t_heap')

View File

@ -15,7 +15,8 @@ class RetentionTest(ProbackupTest, unittest.TestCase):
def tearDownClass(cls): def tearDownClass(cls):
stop_all() stop_all()
# @unittest.skip("123") # @unittest.skip("skip")
# @unittest.expectedFailure
def test_retention_redundancy_1(self): def test_retention_redundancy_1(self):
"""purge backups using redundancy-based retention policy""" """purge backups using redundancy-based retention policy"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]

View File

@ -15,6 +15,8 @@ class OptionTest(ProbackupTest, unittest.TestCase):
def tearDownClass(cls): def tearDownClass(cls):
stop_all() stop_all()
# @unittest.skip("skip")
# @unittest.expectedFailure
def show_test_1(self): def show_test_1(self):
"""Status DONE and OK""" """Status DONE and OK"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]

View File

@ -13,43 +13,13 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ValidateTest, self).__init__(*args, **kwargs) super(ValidateTest, self).__init__(*args, **kwargs)
# @classmethod @classmethod
# def tearDownClass(cls): def tearDownClass(cls):
# try: stop_all()
# stop_all()
# except:
# pass
# @unittest.skip("123") # @unittest.skip("skip")
def test_validate_time(self): # @unittest.expectedFailure
"""recovery to latest from full backup. Expect to Fail""" def test_validate_wal_unreal_values(self):
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.start()
node.pgbench_init(scale=2)
pgbench = node.pgbench(
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
options=["-c", "4", "-T", "10"]
)
pgbench.wait()
pgbench.stdout.close()
self.assertEqual(self.init_pb(node), six.b(""))
id = self.backup_pb(node)
recovery_time = self.show_pb(node, id=id)['recovery-time']
self.assertIn(six.b("INFO: backup validation completed successfully on"),
self.validate_pb(node, options=["--time='{0}'".format(recovery_time)]))
node.stop()
# @unittest.skip("123")
def test_validate_wal_1(self):
"""recovery to latest from full backup""" """recovery to latest from full backup"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname),
@ -65,8 +35,7 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
con.execute("CREATE TABLE tbl0005 (a text)") con.execute("CREATE TABLE tbl0005 (a text)")
con.commit() con.commit()
with open(os.path.join(node.logs_dir, "backup_1.log"), "wb") as backup_log: self.backup_pb(node)
backup_log.write(self.backup_pb(node, options=["--verbose"]))
node.pgbench_init(scale=2) node.pgbench_init(scale=2)
pgbench = node.pgbench( pgbench = node.pgbench(
@ -78,7 +47,7 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
id_backup = self.show_pb(node)[0]['ID'] backup_id = self.show_pb(node)[0]['ID']
target_time = self.show_pb(node)[0]['Recovery time'] target_time = self.show_pb(node)[0]['Recovery time']
after_backup_time = datetime.now() after_backup_time = datetime.now()
@ -91,24 +60,19 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
self.validate_pb(node, options=["--time='{:%Y-%m-%d %H:%M:%S}'".format( self.validate_pb(node, options=["--time='{:%Y-%m-%d %H:%M:%S}'".format(
after_backup_time - timedelta(days=2))]) after_backup_time - timedelta(days=2))])
# we should die here because exception is what we expect to happen # we should die here because exception is what we expect to happen
exit(1) self.assertEqual(1, 0, "Error in validation is expected because of validation of unreal time")
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(
e.message, e.message,
'ERROR: Full backup satisfying target options is not found.\n' 'ERROR: Full backup satisfying target options is not found.\n')
)
# Validate to unreal time #2 # Validate to unreal time #2
try: try:
self.validate_pb(node, options=["--time='{:%Y-%m-%d %H:%M:%S}'".format( self.validate_pb(node, options=["--time='{:%Y-%m-%d %H:%M:%S}'".format(
after_backup_time + timedelta(days=2))]) after_backup_time + timedelta(days=2))])
# we should die here because exception is what we expect to happen self.assertEqual(1, 0, "Error in validation is expected because of validation unreal time")
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(True, 'ERROR: not enough WAL records to time' in e.message)
True,
'ERROR: not enough WAL records to time' in e.message
)
# Validate to real xid # Validate to real xid
target_xid = None target_xid = None
@ -124,19 +88,32 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
# Validate to unreal xid # Validate to unreal xid
try: try:
self.validate_pb(node, options=["--xid=%d" % (int(target_xid) + 1000)]) self.validate_pb(node, options=["--xid=%d" % (int(target_xid) + 1000)])
# we should die here because exception is what we expect to happen self.assertEqual(1, 0, "Error in validation is expected because of validation of unreal xid")
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(True, 'ERROR: not enough WAL records to xid' in e.message)
True,
'ERROR: not enough WAL records to xid' in e.message
)
# Validate with backup ID # Validate with backup ID
self.assertIn(six.b("INFO: backup validation completed successfully on"), self.assertIn(six.b("INFO: backup validation completed successfully on"),
self.validate_pb(node, id_backup)) self.validate_pb(node, backup_id))
# Validate broken WAL def test_validate_broken_wal_1(self):
"""recovery to latest from full backup"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
with node.connect("postgres") as con:
con.execute("CREATE TABLE tbl0005 (a text)")
con.commit()
backup_id = self.backup_pb(node)
# Corrupt WAL
wals_dir = os.path.join(self.backup_dir(node), "wal") wals_dir = os.path.join(self.backup_dir(node), "wal")
wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')] wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')]
wals.sort() wals.sort()
@ -146,29 +123,60 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
f.write(six.b("blablabla")) f.write(six.b("blablabla"))
f.close f.close
try: # Simple validate
self.validate_pb(node, id_backup, options=['--xid=%s' % target_xid])
# we should die here because exception is what we expect to happen
exit(1)
except ProbackupException, e:
self.assertEqual(
True,
'Possible WAL CORRUPTION' in e.message
)
try: try:
self.validate_pb(node) self.validate_pb(node)
# we should die here because exception is what we expect to happen self.assertEqual(1, 0, "Expecting Error because of wal corruption. THIS IS BAD")
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(True, 'Possible WAL CORRUPTION' in e.message)
True,
'Possible WAL CORRUPTION' in e.message self.assertEqual('CORRUPT', self.show_pb(node, id=backup_id)['status'], 'Backup STATUS should be "CORRUPT"')
)
node.stop() node.stop()
# @unittest.skip("123") def test_validate_broken_wal_2(self):
"""recovery to latest from full backup"""
fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname),
set_archiving=True,
initdb_params=['--data-checksums'],
pg_options={'wal_level': 'replica'}
)
node.start()
self.assertEqual(self.init_pb(node), six.b(""))
with node.connect("postgres") as con:
con.execute("CREATE TABLE tbl0005 (a text)")
con.commit()
backup_id = self.backup_pb(node)
target_xid = None
with node.connect("postgres") as con:
res = con.execute("INSERT INTO tbl0005 VALUES ('inserted') RETURNING (xmin)")
con.commit()
target_xid = res[0][0]
node.execute("postgres", "SELECT pg_switch_xlog()")
# Corrupt WAL
wals_dir = os.path.join(self.backup_dir(node), "wal")
wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')]
wals.sort()
for wal in wals:
f = open(os.path.join(wals_dir, wal), "rb+")
f.seek(256)
f.write(six.b("blablabla"))
f.close
# Simple validate
try:
self.validate_pb(node, backup_id, options=['--xid=%s' % target_xid])
self.assertEqual(1, 0, "Expecting Error because of wal corruption. THIS IS BAD")
except ProbackupException, e:
self.assertEqual(True, 'Possible WAL CORRUPTION' in e.message)
self.assertEqual('CORRUPT', self.show_pb(node, id=backup_id)['status'], 'Backup STATUS should be "CORRUPT"')
node.stop()
def test_validate_wal_lost_segment_1(self): def test_validate_wal_lost_segment_1(self):
"""Loose segment which belong to some backup""" """Loose segment which belong to some backup"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
@ -188,25 +196,23 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
) )
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
self.backup_pb(node, backup_type='full') backup_id = self.backup_pb(node, backup_type='full')
# Delete wal segment
wals_dir = os.path.join(self.backup_dir(node), "wal") wals_dir = os.path.join(self.backup_dir(node), "wal")
wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')] wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')]
os.remove(os.path.join(self.backup_dir(node), "wal", wals[1])) os.remove(os.path.join(self.backup_dir(node), "wal", wals[1]))
try: try:
self.validate_pb(node) self.validate_pb(node)
# we should die here because exception is what we expect to happen self.assertEqual(1, 0, "Expecting Error because of wal segment disappearance")
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(True, 'is absent' in e.message)
True,
'is absent' in e.message self.assertEqual('CORRUPT', self.show_pb(node, id=backup_id)['status'], 'Backup STATUS should be "CORRUPT"')
)
node.stop() node.stop()
# @unittest.skip("123")
def test_validate_wal_lost_segment_2(self): def test_validate_wal_lost_segment_2(self):
"""Loose segment located between backups. Expect to fail """ """Loose segment located between backups"""
fname = self.id().split('.')[3] fname = self.id().split('.')[3]
node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname), node = self.make_simple_node(base_dir="tmp_dirs/validate/{0}".format(fname),
set_archiving=True, set_archiving=True,
@ -216,6 +222,9 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
node.start() node.start()
self.assertEqual(self.init_pb(node), six.b("")) self.assertEqual(self.init_pb(node), six.b(""))
self.backup_pb(node, backup_type='full')
# make some wals
node.pgbench_init(scale=2) node.pgbench_init(scale=2)
pgbench = node.pgbench( pgbench = node.pgbench(
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
@ -224,38 +233,17 @@ class ValidateTest(ProbackupTest, unittest.TestCase):
) )
pgbench.wait() pgbench.wait()
pgbench.stdout.close() pgbench.stdout.close()
self.backup_pb(node, backup_type='full')
# need to do that to find segment between(!) backups
node.psql("postgres", "CREATE TABLE t1(a int)")
node.psql("postgres", "SELECT pg_switch_xlog()")
node.psql("postgres", "CREATE TABLE t2(a int)")
node.psql("postgres", "SELECT pg_switch_xlog()")
# delete last wal segment
wals_dir = os.path.join(self.backup_dir(node), "wal") wals_dir = os.path.join(self.backup_dir(node), "wal")
wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')] wals = [f for f in os.listdir(wals_dir) if os.path.isfile(os.path.join(wals_dir, f)) and not f.endswith('.backup')]
wals = map(int, wals) wals = map(int, wals)
# delete last wal segment
#print os.path.join(self.backup_dir(node), "wal", '0000000' + str(max(wals)))
os.remove(os.path.join(self.backup_dir(node), "wal", '0000000' + str(max(wals)))) os.remove(os.path.join(self.backup_dir(node), "wal", '0000000' + str(max(wals))))
# Need more accurate error message about loosing wal segment between backups # Need more accurate error message about loosing wal segment between backups
try: try:
self.backup_pb(node, backup_type='page') self.backup_pb(node, backup_type='page')
# we should die here because exception is what we expect to happen self.assertEqual(1, 0, "Expecting Error in PAGE backup because of wal segment disappearance")
exit(1)
except ProbackupException, e: except ProbackupException, e:
self.assertEqual( self.assertEqual(True, 'could not read WAL record' in e.message)
True,
'could not read WAL record' in e.message
)
self.delete_pb(node, id=self.show_pb(node)[1]['ID'])
##### Hole Smokes, Batman! We just lost a wal segment and know nothing about it
##### We need archive-push ASAP
self.backup_pb(node, backup_type='full')
self.assertEqual(False, 'validation completed successfully' in self.validate_pb(node))
########
node.stop() node.stop()