Skip to content

Commit f051755

Browse files
committed
draft start for the plugin Testgres.probackup
1 parent 934f540 commit f051755

File tree

4 files changed

+145
-34
lines changed

4 files changed

+145
-34
lines changed

‎setup.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from distutils.core import setup
77

88
# Basic dependencies
9-
install_requires = ["pg8000", "port-for>=0.4", "six>=1.9.0", "psutil"]
9+
install_requires = ["pg8000", "port-for>=0.4", "six>=1.9.0", "psutil", "tox", "termcolor"]
1010

1111
# Add compatibility enum class
1212
if sys.version_info < (3, 4):
@@ -21,7 +21,7 @@
2121
readme = f.read()
2222

2323
setup(
24-
version='1.8.5',
24+
version='1.9.0',
2525
name='testgres',
2626
packages=['testgres'],
2727
description='Testing utility for PostgreSQL and its extensions',

‎testgres/node.py

+35
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,41 @@ def promote(self, dbname=None, username=None):
772772

773773
return self
774774

775+
def slow_start(self, replica=False):
776+
777+
# wait for https://.com/postgrespro/testgres/pull/50
778+
# self.start()
779+
# self.poll_query_until(
780+
# "postgres",
781+
# "SELECT not pg_is_in_recovery()",
782+
# suppress={testgres.NodeConnection})
783+
784+
if replica:
785+
query = 'SELECT pg_is_in_recovery()'
786+
else:
787+
query = 'SELECT not pg_is_in_recovery()'
788+
789+
self.start()
790+
while True:
791+
try:
792+
output = self.safe_psql('template1', query).decode("utf-8").rstrip()
793+
794+
if output == 't':
795+
break
796+
797+
except testgres.QueryException as e:
798+
if 'database system is starting up' in e.message:
799+
pass
800+
elif 'FATAL: the database system is not accepting connections' in e.message:
801+
pass
802+
elif replica and 'Hot standby mode is disabled' in e.message:
803+
raise e
804+
else:
805+
raise e
806+
807+
sleep(0.5)
808+
809+
775810
def pg_ctl(self, params):
776811
"""
777812
Invoke pg_ctl with params.

‎testgres/probackup.py

+99-32
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,23 @@
1212
import re
1313
import json
1414

15+
import errno
16+
import unittest
17+
from termcolor import colored
18+
19+
1520
from time import sleep
1621
from sys import exit, argv, version_info
1722

1823
#from testgres.utils import get_pg_edition
1924
from testgres.utils import is_enterprise, is_nls_enabled
2025

21-
class ProbackupException(Exception):
26+
27+
# move to the settings.py with other global configurations
28+
TEST_DIR = 'tmp_dirs'
29+
30+
31+
class PGProbackupException(Exception):
2232
def __init__(self, message, cmd):
2333
self.message = message
2434
self.cmd = cmd
@@ -27,21 +37,60 @@ def __str__(self):
2737
return '\n ERROR: {0}\n CMD: {1}'.format(repr(self.message), self.cmd)
2838

2939

40+
class PGProbackupApp(object):
41+
IS_ENTERPRISE = False
42+
43+
settings = dict()
44+
host = 'localhost'
45+
tests_full_path = TEST_DIR # tmp_test_dirs
46+
47+
48+
#def __new__(self, *args, **kwargs):
49+
# pass
50+
51+
def __init__(
52+
self, tests_path='.', test_dir=TEST_DIR,
53+
*args, **kwargs):
54+
pass
3055

3156

32-
class ProbackupTest(object):
57+
class PGProbackupTestCaseMixin(unittest.TestCase):
58+
def setUp(self):
59+
pass
60+
61+
def tearDown(self):
62+
pass
63+
64+
65+
66+
class PGProbackupPackageCompTestCaseMixin(PGProbackupTestCaseMixin):
67+
current_version = None
68+
previous_version = None
69+
70+
def setUp(self):
71+
pass
72+
73+
def tearDown(self):
74+
pass
75+
76+
77+
78+
79+
class ProbackupTest(object):
3380
# Class attributes
3481
enterprise = is_enterprise()
3582
enable_nls = is_nls_enabled()
3683

3784
def __init__(self, *args, **kwargs):
3885
super(ProbackupTest, self).__init__(*args, **kwargs)
86+
87+
self.verbose = False
3988
if '-v' in argv or '--verbose' in argv:
4089
self.verbose = True
41-
else:
42-
self.verbose = False
90+
4391

4492
self.test_env = os.environ.copy()
93+
4594
envs_list = [
4695
'LANGUAGE',
4796
'LC_ALL',
@@ -75,28 +124,32 @@ def __init__(self, *args, **kwargs):
75124
self.archive_compress = 'ARCHIVE_COMPRESSION' in self.test_env and \
76125
self.test_env['ARCHIVE_COMPRESSION'] == 'ON'
77126

78-
try:
79-
testgres.configure_testgres(
80-
cache_initdb=False,
81-
cached_initdb_dir=False,
82-
cache_pg_config=False,
83-
node_cleanup_full=False)
84-
except:
85-
pass
86-
87-
self.helpers_path = os.path.dirname(os.path.realpath(__file__))
88-
self.dir_path = os.path.abspath(
89-
os.path.join(self.helpers_path, os.pardir)
90-
)
91-
self.tmp_path = os.path.abspath(
92-
os.path.join(self.dir_path, 'tmp_dirs')
93-
)
94-
try:
95-
os.makedirs(os.path.join(self.dir_path, 'tmp_dirs'))
96-
except:
97-
pass
98127

128+
testgres.configure_testgres(
129+
cache_initdb=False,
130+
cached_initdb_dir=False,
131+
cache_pg_config=False,
132+
node_cleanup_full=False)
133+
134+
135+
# Choose path for the tests artifacts
136+
self.tests_path =os.path.join(os.path.abspath('.'), TEST_DIR)
137+
try:
138+
os.makedirs(os.path.join(self.tests_path))
139+
log.info('Artefacts from the tests are stored in the direcotry: %s'%self.tests_path)
140+
except OSError as e:
141+
if e.errno == errno.EEXIST:
142+
pass
143+
else:
144+
# print(
145+
# colored('Please choose directory for the tests artefacts with 777 chmod. [%s]'%self.tests_path, 'red'))
146+
raise
147+
148+
149+
# XXX dont work with
99150
self.user = self.get_username()
151+
152+
100153
self.probackup_path = None
101154
if 'PGPROBACKUPBIN' in self.test_env:
102155
if (
@@ -108,6 +161,7 @@ def __init__(self, *args, **kwargs):
108161
if self.verbose:
109162
print('PGPROBACKUPBIN is not an executable file')
110163

164+
# XXX
111165
print('@@@', self.probackup_path)
112166

113167
if not self.probackup_path:
@@ -162,18 +216,22 @@ def __init__(self, *args, **kwargs):
162216
self.old_probackup_version = None
163217

164218
try:
219+
165220
self.probackup_version_output = subprocess.check_output(
166221
[self.probackup_path, "--version"],
167222
stderr=subprocess.STDOUT,
168223
).decode('utf-8')
224+
169225
except subprocess.CalledProcessError as e:
170-
raise ProbackupException(e.output.decode('utf-8'))
226+
raise PGProbackupException(e.output.decode('utf-8'))
171227

172228
if self.probackup_old_path:
229+
173230
old_probackup_version_output = subprocess.check_output(
174231
[self.probackup_old_path, "--version"],
175232
stderr=subprocess.STDOUT,
176233
).decode('utf-8')
234+
177235
self.old_probackup_version = re.search(
178236
r"\d+\.\d+\.\d+",
179237
subprocess.check_output(
@@ -224,19 +282,26 @@ def pg_config_version(self):
224282
# print('PGPROBACKUP_SSH_USER is not set')
225283
# exit(1)
226284

285+
286+
# XXX move to the node.PostgresNode
227287
def make_empty_node(
228288
self,
229289
base_dir=None):
230-
real_base_dir = os.path.join(self.tmp_path, base_dir)
290+
291+
real_base_dir = os.path.join(self.tests_path, base_dir)
231292
shutil.rmtree(real_base_dir, ignore_errors=True)
232293
os.makedirs(real_base_dir)
233294

234295
node = testgres.get_new_node('test', base_dir=real_base_dir)
296+
235297
# bound method slow_start() to 'node' class instance
236-
node.slow_start = slow_start.__get__(node)
298+
#node.slow_start = slow_start.__get__(node)
299+
237300
node.should_rm_dirs = True
238301
return node
239302

303+
304+
# XXX preconfigured Node for the pg_probackup app
240305
def make_simple_node(
241306
self,
242307
base_dir=None,
@@ -254,6 +319,8 @@ def make_simple_node(
254319
node.major_version_str = str(f.read().rstrip())
255320
node.major_version = float(node.major_version_str)
256321

322+
# XXX move it to the ProbackupTestCaseMixin class setUp
323+
257324
# Sane default parameters
258325
options = {}
259326
options['max_connections'] = 100
@@ -405,7 +472,7 @@ def get_md5_per_page_for_fork(self, file, size_in_pages):
405472

406473
size = size_in_pages
407474
for segment_number in range(nsegments):
408-
if size - 131072 > 0:
475+
if size - 131072 > 0: # XXX make global static config PARAM
409476
pages_per_segment[segment_number] = 131072
410477
else:
411478
pages_per_segment[segment_number] = size
@@ -427,7 +494,7 @@ def get_md5_per_page_for_fork(self, file, size_in_pages):
427494
for page in range(start_page, end_page):
428495
md5_per_page[page] = hashlib.md5(
429496
os.read(file_desc, 8192)).hexdigest()
430-
offset += 8192
497+
offset += 8192 # XXX make global static config PARAM
431498
os.lseek(file_desc, offset, 0)
432499
os.close(file_desc)
433500

@@ -683,7 +750,7 @@ def run_pb(self, command, asynchronous=False, gdb=False, old_binary=False, retur
683750
else:
684751
return self.output
685752
except subprocess.CalledProcessError as e:
686-
raise ProbackupException(e.output.decode('utf-8'), self.cmd)
753+
raise PGProbackupException(e.output.decode('utf-8'), self.cmd)
687754

688755
def run_binary(self, command, asynchronous=False, env=None):
689756

@@ -709,7 +776,7 @@ def run_binary(self, command, asynchronous=False, env=None):
709776
).decode('utf-8')
710777
return self.output
711778
except subprocess.CalledProcessError as e:
712-
raise ProbackupException(e.output.decode('utf-8'), command)
779+
raise PGProbackupException(e.output.decode('utf-8'), command)
713780

714781
def init_pb(self, backup_dir, options=[], old_binary=False):
715782

@@ -1455,7 +1522,7 @@ def del_test_dir(self, module_name, fname):
14551522

14561523
shutil.rmtree(
14571524
os.path.join(
1458-
self.tmp_path,
1525+
self.tests_path,
14591526
module_name,
14601527
fname
14611528
),

‎tox.ini

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[tox]
2+
envlist = py27,py36
3+
4+
[testenv]
5+
# install pytest in the virtualenv where commands will be executed
6+
deps = pytest
7+
commands =
8+
# NOTE: you can run any command line tool here - not just tests
9+
make

0 commit comments

Comments
 (0)