Skip to content

Commit d60cdcb

Browse files
committed
Merge branch 'master' into logical
2 parents 4b279ef + 221df4f commit d60cdcb

File tree

6 files changed

+116
-31
lines changed

6 files changed

+116
-31
lines changed

hooks/pre-commit

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
#!/bin/bash
22

3+
set -e
4+
35
# capture the changed files that have been staged
46
changed_files=$(git diff --staged --name-only)
57

68
for file in ${changed_files}
79
do
810
if [[ "${file##*.}" == "py" ]]; then
9-
echo "Yapfing ${file}"
10-
yapf ${file} -i
11-
git add ${file}
11+
if command -v yapf > /dev/null; then
12+
echo "Run yapf on ${file}"
13+
yapf ${file} -i
14+
git add ${file}
15+
fi
16+
17+
if command -v flake8 > /dev/null; then
18+
echo "Run flake8 on ${file}"
19+
flake8 ${file}
20+
fi
1221
fi
1322
done
23+

setup.py

100644100755
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,18 @@
1616
if sys.version_info < (3, 3):
1717
install_requires.append("ipaddress")
1818

19+
# Get contents of README file
20+
with open('README.md', 'r') as f:
21+
readme = f.read()
22+
1923
setup(
20-
version='1.6.0',
24+
version='1.7.0',
2125
name='testgres',
2226
packages=['testgres'],
2327
description='Testing utility for PostgreSQL and its extensions',
2428
url='https://github.com/postgrespro/testgres',
29+
long_description=readme,
30+
long_description_content_type='text/markdown',
2531
license='PostgreSQL',
2632
author='Ildar Musin',
2733
author_email='zildermann@gmail.com',

testgres/enums.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,14 @@ def from_process(process):
8585

8686
# default
8787
return ProcessType.Unknown
88+
89+
90+
class DumpFormat(Enum):
91+
"""
92+
Available dump formats
93+
"""
94+
95+
Plain = 'plain'
96+
Custom = 'custom'
97+
Directory = 'directory'
98+
Tar = 'tar'

testgres/node.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
from six import raise_from, iteritems
1111
from tempfile import mkstemp, mkdtemp
1212

13-
from .enums import NodeStatus, ProcessType
13+
from .enums import \
14+
NodeStatus, \
15+
ProcessType, \
16+
DumpFormat
1417

1518
from .cache import cached_initdb
1619

@@ -55,7 +58,8 @@
5558
StartNodeException, \
5659
TimeoutException, \
5760
InitNodeException, \
58-
TestgresException
61+
TestgresException, \
62+
BackupException
5963

6064
from .logger import TestgresLogger
6165

@@ -577,12 +581,13 @@ def get_control_data(self):
577581

578582
return out_dict
579583

580-
def start(self, params=[]):
584+
def start(self, params=[], wait=True):
581585
"""
582586
Start this node using pg_ctl.
583587
584588
Args:
585589
params: additional arguments for pg_ctl.
590+
wait: wait until operation completes.
586591
587592
Returns:
588593
This instance of :class:`.PostgresNode`.
@@ -592,7 +597,7 @@ def start(self, params=[]):
592597
get_bin_path("pg_ctl"),
593598
"-D", self.data_dir,
594599
"-l", self.pg_log_file,
595-
"-w", # wait
600+
"-w" if wait else '-W', # --wait or --no-wait
596601
"start"
597602
] + params # yapf: disable
598603

@@ -607,12 +612,13 @@ def start(self, params=[]):
607612

608613
return self
609614

610-
def stop(self, params=[]):
615+
def stop(self, params=[], wait=True):
611616
"""
612617
Stop this node using pg_ctl.
613618
614619
Args:
615620
params: additional arguments for pg_ctl.
621+
wait: wait until operation completes.
616622
617623
Returns:
618624
This instance of :class:`.PostgresNode`.
@@ -621,7 +627,7 @@ def stop(self, params=[]):
621627
_params = [
622628
get_bin_path("pg_ctl"),
623629
"-D", self.data_dir,
624-
"-w", # wait
630+
"-w" if wait else '-W', # --wait or --no-wait
625631
"stop"
626632
] + params # yapf: disable
627633

@@ -681,6 +687,8 @@ def reload(self, params=[]):
681687

682688
execute_utility(_params, self.utils_log_file)
683689

690+
return self
691+
684692
def pg_ctl(self, params):
685693
"""
686694
Invoke pg_ctl with params.
@@ -812,7 +820,11 @@ def safe_psql(self, query=None, **kwargs):
812820

813821
return out
814822

815-
def dump(self, filename=None, dbname=None, username=None):
823+
def dump(self,
824+
filename=None,
825+
dbname=None,
826+
username=None,
827+
format=DumpFormat.Plain):
816828
"""
817829
Dump database into a file using pg_dump.
818830
NOTE: the file is not removed automatically.
@@ -821,14 +833,27 @@ def dump(self, filename=None, dbname=None, username=None):
821833
filename: database dump taken by pg_dump.
822834
dbname: database name to connect to.
823835
username: database user name.
836+
format: format argument plain/custom/directory/tar.
824837
825838
Returns:
826839
Path to a file containing dump.
827840
"""
828841

842+
# Check arguments
843+
if not isinstance(format, DumpFormat):
844+
try:
845+
format = DumpFormat(format)
846+
except ValueError:
847+
msg = 'Invalid format "{}"'.format(format)
848+
raise BackupException(msg)
849+
850+
# Generate tmpfile or tmpdir
829851
def tmpfile():
830-
fd, fname = mkstemp(prefix=TMP_DUMP)
831-
os.close(fd)
852+
if format == DumpFormat.Directory:
853+
fname = mkdtemp(prefix=TMP_DUMP)
854+
else:
855+
fd, fname = mkstemp(prefix=TMP_DUMP)
856+
os.close(fd)
832857
return fname
833858

834859
# Set default arguments
@@ -842,7 +867,8 @@ def tmpfile():
842867
"-h", self.host,
843868
"-f", filename,
844869
"-U", username,
845-
"-d", dbname
870+
"-d", dbname,
871+
"-F", format.value
846872
] # yapf: disable
847873

848874
execute_utility(_params, self.utils_log_file)
@@ -854,12 +880,29 @@ def restore(self, filename, dbname=None, username=None):
854880
Restore database from pg_dump's file.
855881
856882
Args:
857-
filename: database dump taken by pg_dump.
883+
filename: database dump taken by pg_dump in custom/directory/tar formats.
858884
dbname: database name to connect to.
859885
username: database user name.
860886
"""
861887

862-
self.psql(filename=filename, dbname=dbname, username=username)
888+
# Set default arguments
889+
dbname = dbname or default_dbname()
890+
username = username or default_username()
891+
892+
_params = [
893+
get_bin_path("pg_restore"),
894+
"-p", str(self.port),
895+
"-h", self.host,
896+
"-U", username,
897+
"-d", dbname,
898+
filename
899+
] # yapf: disable
900+
901+
# try pg_restore if dump is binary formate, and psql if not
902+
try:
903+
execute_utility(_params, self.utils_log_name)
904+
except ExecUtilException:
905+
self.psql(filename=filename, dbname=dbname, username=username)
863906

864907
@method_decorator(positional_args_hack(['dbname', 'query']))
865908
def poll_query_until(self,

testgres/pubsub.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ def add_tables(self, tables, dbname=None, username=None):
102102

103103
class Subscription(object):
104104
def __init__(self,
105-
name,
106105
node,
107106
publication,
107+
name=None,
108108
dbname=None,
109109
username=None,
110110
**params):

tests/test_simple.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646

4747
def util_exists(util):
4848
def good_properties(f):
49-
return (os.path.exists(f) and
50-
os.path.isfile(f) and
49+
return (os.path.exists(f) and # noqa: W504
50+
os.path.isfile(f) and # noqa: W504
5151
os.access(f, os.X_OK)) # yapf: disable
5252

5353
# try to resolve it
@@ -67,12 +67,14 @@ def removing(f):
6767
finally:
6868
if os.path.isfile(f):
6969
os.remove(f)
70+
elif os.path.isdir(f):
71+
rmtree(f, ignore_errors=True)
7072

7173

7274
class TestgresTests(unittest.TestCase):
7375
def test_node_repr(self):
7476
with get_new_node() as node:
75-
pattern = 'PostgresNode\(name=\'.+\', port=.+, base_dir=\'.+\'\)'
77+
pattern = r"PostgresNode\(name='.+', port=.+, base_dir='.+'\)"
7678
self.assertIsNotNone(re.match(pattern, str(node)))
7779

7880
def test_custom_init(self):
@@ -263,7 +265,7 @@ def test_psql(self):
263265
# check feeding input
264266
node.safe_psql('create table horns (w int)')
265267
node.safe_psql(
266-
'copy horns from stdin (format csv)', input=b"1\n2\n3\n\.\n")
268+
'copy horns from stdin (format csv)', input=b"1\n2\n3\n\\.\n")
267269
_sum = node.safe_psql('select sum(w) from horns')
268270
self.assertEqual(_sum, b'6\n')
269271

@@ -373,6 +375,18 @@ def test_backup_wrong_xlog_method(self):
373375
BackupException, msg='Invalid xlog_method "wrong"'):
374376
node.backup(xlog_method='wrong')
375377

378+
def test_pg_ctl_wait_option(self):
379+
with get_new_node() as node:
380+
node.init().start(wait=False)
381+
while True:
382+
try:
383+
node.stop(wait=False)
384+
break
385+
except ExecUtilException:
386+
# it's ok to get this exception here since node
387+
# could be not started yet
388+
pass
389+
376390
def test_replicate(self):
377391
with get_new_node() as node:
378392
node.init(allow_streaming=True).start()
@@ -515,16 +529,17 @@ def test_dump(self):
515529
with get_new_node().init().start() as node1:
516530

517531
node1.execute(query_create)
518-
519-
# take a new dump
520-
with removing(node1.dump()) as dump:
521-
with get_new_node().init().start() as node2:
522-
# restore dump
523-
self.assertTrue(os.path.isfile(dump))
524-
node2.restore(filename=dump)
525-
526-
res = node2.execute(query_select)
527-
self.assertListEqual(res, [(1, ), (2, )])
532+
for format in ['plain', 'custom', 'directory', 'tar']:
533+
with removing(node1.dump(format=format)) as dump:
534+
with get_new_node().init().start() as node3:
535+
if format == 'directory':
536+
self.assertTrue(os.path.isdir(dump))
537+
else:
538+
self.assertTrue(os.path.isfile(dump))
539+
# restore dump
540+
node3.restore(filename=dump)
541+
res = node3.execute(query_select)
542+
self.assertListEqual(res, [(1, ), (2, )])
528543

529544
def test_users(self):
530545
with get_new_node().init().start() as node:

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy