Skip to content

Commit dc297ec

Browse files
committed
tests: compatibility module added
1 parent 77c36ee commit dc297ec

File tree

4 files changed

+171
-34
lines changed

4 files changed

+171
-34
lines changed

tests/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import unittest
22

3-
from . import init_test, merge, option_test, show_test, \
3+
from . import init_test, merge, option_test, show_test, compatibility, \
44
backup_test, delete_test, delta, restore_test, validate_test, \
55
retention_test, ptrack_clean, ptrack_cluster, \
6-
ptrack_move_to_tablespace, ptrack_recovery, ptrack_truncate, ptrack_vacuum, \
7-
ptrack_vacuum_bits_frozen, ptrack_vacuum_bits_visibility, \
6+
ptrack_move_to_tablespace, ptrack_recovery, ptrack_truncate, \
7+
ptrack_vacuum, ptrack_vacuum_bits_frozen, ptrack_vacuum_bits_visibility, \
88
ptrack_vacuum_full, ptrack_vacuum_truncate, pgpro560, pgpro589, \
99
false_positive, replica, compression, page, ptrack, archive, \
1010
exclude, cfs_backup, cfs_restore, cfs_validate_backup, auth_test
@@ -15,6 +15,7 @@ def load_tests(loader, tests, pattern):
1515
# suite.addTests(loader.loadTestsFromModule(auth_test))
1616
suite.addTests(loader.loadTestsFromModule(archive))
1717
suite.addTests(loader.loadTestsFromModule(backup_test))
18+
suite.addTests(loader.loadTestsFromModule(compatibility))
1819
suite.addTests(loader.loadTestsFromModule(cfs_backup))
1920
suite.addTests(loader.loadTestsFromModule(cfs_restore))
2021
# suite.addTests(loader.loadTestsFromModule(cfs_validate_backup))

tests/compatibility.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import unittest
2+
import subprocess
3+
import os
4+
from .helpers.ptrack_helpers import ProbackupTest, ProbackupException, archive_script
5+
from sys import exit
6+
7+
module_name = 'compatibility'
8+
9+
10+
class CompatibilityTest(ProbackupTest, unittest.TestCase):
11+
12+
# @unittest.expectedFailure
13+
# @unittest.skip("skip")
14+
def test_show_previous_version_catalog(self):
15+
"""Description in jira issue PGPRO-434"""
16+
fname = self.id().split('.')[3]
17+
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
18+
node = self.make_simple_node(
19+
base_dir="{0}/{1}/node".format(module_name, fname),
20+
set_replication=True,
21+
initdb_params=['--data-checksums'],
22+
pg_options={
23+
'max_wal_senders': '2',
24+
'checkpoint_timeout': '30s'}
25+
)
26+
self.init_pb(backup_dir, old_binary=True)
27+
self.show_pb(backup_dir)
28+
29+
self.add_instance(backup_dir, 'node', node, old_binary=True)
30+
self.show_pb(backup_dir)
31+
32+
self.set_archiving(backup_dir, 'node', node, old_binary=True)
33+
node.slow_start()
34+
35+
node.pgbench_init(scale=10)
36+
37+
# FULL backup
38+
self.backup_node(
39+
backup_dir, 'node', node, old_binary=True)
40+
41+
if self.paranoia:
42+
pgdata = self.pgdata_content(node.data_dir)
43+
44+
self.show_pb(backup_dir)
45+
self.validate_pb(backup_dir)
46+
47+
# RESTORE
48+
node_restored = self.make_simple_node(
49+
base_dir="{0}/{1}/node_restored".format(module_name, fname))
50+
51+
node_restored.cleanup()
52+
53+
self.restore_node(
54+
backup_dir, 'node', node_restored,
55+
options=["-j", "4", "--recovery-target-action=promote"])
56+
57+
if self.paranoia:
58+
pgdata_restored = self.pgdata_content(node_restored.data_dir)
59+
self.compare_pgdata(pgdata, pgdata_restored)
60+
61+
# Incremental BACKUP
62+
pgbench = node.pgbench(
63+
stdout=subprocess.PIPE,
64+
stderr=subprocess.STDOUT,
65+
options=["-c", "4", "-T", "10"]
66+
)
67+
68+
self.backup_node(
69+
backup_dir, 'node', node, backup_type='page',
70+
old_binary=True)
71+
72+
if self.paranoia:
73+
pgdata = self.pgdata_content(node.data_dir)
74+
75+
node_restored.cleanup()
76+
self.restore_node(
77+
backup_dir, 'node', node_restored,
78+
options=["-j", "4", "--recovery-target-action=promote"])
79+
80+
if self.paranoia:
81+
pgdata_restored = self.pgdata_content(node_restored.data_dir)
82+
self.compare_pgdata(pgdata, pgdata_restored)
83+
84+
# Incremental BACKUP with new binary
85+
pgbench = node.pgbench(
86+
stdout=subprocess.PIPE,
87+
stderr=subprocess.STDOUT,
88+
options=["-c", "4", "-T", "10"]
89+
)
90+
91+
self.backup_node(
92+
backup_dir, 'node', node,
93+
backup_type='page')
94+
95+
if self.paranoia:
96+
pgdata = self.pgdata_content(node.data_dir)
97+
98+
node_restored.cleanup()
99+
self.restore_node(
100+
backup_dir, 'node', node_restored,
101+
options=["-j", "4", "--recovery-target-action=promote"])
102+
103+
if self.paranoia:
104+
pgdata_restored = self.pgdata_content(node_restored.data_dir)
105+
self.compare_pgdata(pgdata, pgdata_restored)

tests/helpers/ptrack_helpers.py

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,16 @@ def __init__(self, *args, **kwargs):
252252
os.environ['PATH'] = os.path.dirname(
253253
self.probackup_path) + ":" + os.environ['PATH']
254254

255+
if "PGPROBACKUPBIN_OLD" in self.test_env:
256+
if (
257+
os.path.isfile(self.test_env["PGPROBACKUPBIN_OLD"]) and
258+
os.access(self.test_env["PGPROBACKUPBIN_OLD"], os.X_OK)
259+
):
260+
self.probackup_old_path = self.test_env["PGPROBACKUPBIN_OLD"]
261+
else:
262+
if self.verbose:
263+
print('PGPROBACKUPBIN_OLD is not an executable file')
264+
255265
def make_simple_node(
256266
self,
257267
base_dir=None,
@@ -534,13 +544,22 @@ def check_ptrack_clean(self, idx_dict, size):
534544
)
535545
)
536546

537-
def run_pb(self, command, async=False, gdb=False):
547+
def run_pb(self, command, async=False, gdb=False, old_binary=False):
548+
if not self.probackup_old_path and old_binary:
549+
print("PGPROBACKUPBIN_OLD is not set")
550+
exit(1)
551+
552+
if old_binary:
553+
binary_path = self.probackup_old_path
554+
else:
555+
binary_path = self.probackup_path
556+
538557
try:
539-
self.cmd = [' '.join(map(str, [self.probackup_path] + command))]
558+
self.cmd = [' '.join(map(str, [binary_path] + command))]
540559
if self.verbose:
541560
print(self.cmd)
542561
if gdb:
543-
return GDBobj([self.probackup_path] + command, self.verbose)
562+
return GDBobj([binary_path] + command, self.verbose)
544563
if async:
545564
return subprocess.Popen(
546565
self.cmd,
@@ -550,7 +569,7 @@ def run_pb(self, command, async=False, gdb=False):
550569
)
551570
else:
552571
self.output = subprocess.check_output(
553-
[self.probackup_path] + command,
572+
[binary_path] + command,
554573
stderr=subprocess.STDOUT,
555574
env=self.test_env
556575
).decode("utf-8")
@@ -586,37 +605,45 @@ def run_binary(self, command, async=False):
586605
except subprocess.CalledProcessError as e:
587606
raise ProbackupException(e.output.decode("utf-8"), command)
588607

589-
def init_pb(self, backup_dir):
608+
def init_pb(self, backup_dir, old_binary=False):
590609

591610
shutil.rmtree(backup_dir, ignore_errors=True)
611+
592612
return self.run_pb([
593613
"init",
594614
"-B", backup_dir
595-
])
615+
],
616+
old_binary=old_binary
617+
)
596618

597-
def add_instance(self, backup_dir, instance, node):
619+
def add_instance(self, backup_dir, instance, node, old_binary=False):
598620

599621
return self.run_pb([
600622
"add-instance",
601623
"--instance={0}".format(instance),
602624
"-B", backup_dir,
603625
"-D", node.data_dir
604-
])
626+
],
627+
old_binary=old_binary
628+
)
605629

606-
def del_instance(self, backup_dir, instance):
630+
def del_instance(self, backup_dir, instance, old_binary=False):
607631

608632
return self.run_pb([
609633
"del-instance",
610634
"--instance={0}".format(instance),
611635
"-B", backup_dir
612-
])
636+
],
637+
old_binary=old_binary
638+
)
613639

614640
def clean_pb(self, backup_dir):
615641
shutil.rmtree(backup_dir, ignore_errors=True)
616642

617643
def backup_node(
618644
self, backup_dir, instance, node, data_dir=False,
619-
backup_type="full", options=[], async=False, gdb=False
645+
backup_type="full", options=[], async=False, gdb=False,
646+
old_binary=False
620647
):
621648
if not node and not data_dir:
622649
print('You must provide ether node or data_dir for backup')
@@ -639,23 +666,23 @@ def backup_node(
639666
if backup_type:
640667
cmd_list += ["-b", backup_type]
641668

642-
return self.run_pb(cmd_list + options, async, gdb)
669+
return self.run_pb(cmd_list + options, async, gdb, old_binary)
643670

644671
def merge_backup(
645672
self, backup_dir, instance, backup_id, async=False,
646-
gdb=False, options=[]):
673+
gdb=False, old_binary=False, options=[]):
647674
cmd_list = [
648675
"merge",
649676
"-B", backup_dir,
650677
"--instance={0}".format(instance),
651678
"-i", backup_id
652679
]
653680

654-
return self.run_pb(cmd_list + options, async, gdb)
681+
return self.run_pb(cmd_list + options, async, gdb, old_binary)
655682

656683
def restore_node(
657684
self, backup_dir, instance, node=False,
658-
data_dir=None, backup_id=None, options=[]
685+
data_dir=None, backup_id=None, old_binary=False, options=[]
659686
):
660687
if data_dir is None:
661688
data_dir = node.data_dir
@@ -669,11 +696,11 @@ def restore_node(
669696
if backup_id:
670697
cmd_list += ["-i", backup_id]
671698

672-
return self.run_pb(cmd_list + options)
699+
return self.run_pb(cmd_list + options, old_binary=old_binary)
673700

674701
def show_pb(
675702
self, backup_dir, instance=None, backup_id=None,
676-
options=[], as_text=False, as_json=True
703+
options=[], as_text=False, as_json=True, old_binary=False
677704
):
678705

679706
backup_list = []
@@ -693,11 +720,11 @@ def show_pb(
693720

694721
if as_text:
695722
# You should print it when calling as_text=true
696-
return self.run_pb(cmd_list + options)
723+
return self.run_pb(cmd_list + options, old_binary=old_binary)
697724

698725
# get show result as list of lines
699726
if as_json:
700-
data = json.loads(self.run_pb(cmd_list + options))
727+
data = json.loads(self.run_pb(cmd_list + options, old_binary=old_binary))
701728
# print(data)
702729
for instance_data in data:
703730
# find specific instance if requested
@@ -713,7 +740,8 @@ def show_pb(
713740
backup_list.append(backup)
714741
return backup_list
715742
else:
716-
show_splitted = self.run_pb(cmd_list + options).splitlines()
743+
show_splitted = self.run_pb(
744+
cmd_list + options, old_binary=old_binary).splitlines()
717745
if instance is not None and backup_id is None:
718746
# cut header(ID, Mode, etc) from show as single string
719747
header = show_splitted[1:2][0]
@@ -768,7 +796,7 @@ def show_pb(
768796

769797
def validate_pb(
770798
self, backup_dir, instance=None,
771-
backup_id=None, options=[]
799+
backup_id=None, options=[], old_binary=False
772800
):
773801

774802
cmd_list = [
@@ -780,9 +808,11 @@ def validate_pb(
780808
if backup_id:
781809
cmd_list += ["-i", backup_id]
782810

783-
return self.run_pb(cmd_list + options)
811+
return self.run_pb(cmd_list + options, old_binary=old_binary)
784812

785-
def delete_pb(self, backup_dir, instance, backup_id=None, options=[]):
813+
def delete_pb(
814+
self, backup_dir, instance,
815+
backup_id=None, options=[], old_binary=False):
786816
cmd_list = [
787817
"delete",
788818
"-B", backup_dir
@@ -792,24 +822,25 @@ def delete_pb(self, backup_dir, instance, backup_id=None, options=[]):
792822
if backup_id:
793823
cmd_list += ["-i", backup_id]
794824

795-
return self.run_pb(cmd_list + options)
825+
return self.run_pb(cmd_list + options, old_binary=old_binary)
796826

797-
def delete_expired(self, backup_dir, instance, options=[]):
827+
def delete_expired(
828+
self, backup_dir, instance, options=[], old_binary=False):
798829
cmd_list = [
799830
"delete", "--expired", "--wal",
800831
"-B", backup_dir,
801832
"--instance={0}".format(instance)
802833
]
803-
return self.run_pb(cmd_list + options)
834+
return self.run_pb(cmd_list + options, old_binary=old_binary)
804835

805-
def show_config(self, backup_dir, instance):
836+
def show_config(self, backup_dir, instance, old_binary=False):
806837
out_dict = {}
807838
cmd_list = [
808839
"show-config",
809840
"-B", backup_dir,
810841
"--instance={0}".format(instance)
811842
]
812-
res = self.run_pb(cmd_list).splitlines()
843+
res = self.run_pb(cmd_list, old_binary=old_binary).splitlines()
813844
for line in res:
814845
if not line.startswith('#'):
815846
name, var = line.partition(" = ")[::2]
@@ -830,7 +861,8 @@ def get_recovery_conf(self, node):
830861
return out_dict
831862

832863
def set_archiving(
833-
self, backup_dir, instance, node, replica=False, overwrite=False):
864+
self, backup_dir, instance, node, replica=False, overwrite=False,
865+
old_binary=False):
834866

835867
if replica:
836868
archive_mode = 'always'
@@ -966,7 +998,6 @@ def switch_wal_segment(self, node):
966998
node.execute("select pg_switch_wal()")
967999
else:
9681000
node.execute("select pg_switch_xlog()")
969-
sleep(1)
9701001

9711002
def get_version(self, node):
9721003
return self.version_to_num(

tests/restore_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1330,7 +1330,7 @@ def test_zags_block_corrupt_1(self):
13301330
pg_options={
13311331
'wal_level': 'replica',
13321332
'autovacuum': 'off',
1333-
'full_page_write': 'on'}
1333+
'full_page_writes': 'on'}
13341334
)
13351335
backup_dir = os.path.join(self.tmp_path, module_name, fname, 'backup')
13361336
self.init_pb(backup_dir)

0 commit comments

Comments
 (0)