testgres 1.15.1__tar.gz → 1.16.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {testgres-1.15.1/testgres.egg-info → testgres-1.16.0}/PKG-INFO +2 -2
- {testgres-1.15.1 → testgres-1.16.0}/pyproject.toml +1 -1
- {testgres-1.15.1 → testgres-1.16.0}/src/__init__.py +8 -3
- {testgres-1.15.1 → testgres-1.16.0}/src/backup.py +9 -2
- {testgres-1.15.1 → testgres-1.16.0}/src/cache.py +14 -7
- {testgres-1.15.1 → testgres-1.16.0}/src/exceptions.py +2 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/platforms/linux/internal_platform_utils.py +15 -18
- {testgres-1.15.1 → testgres-1.16.0}/src/logger.py +1 -1
- {testgres-1.15.1 → testgres-1.16.0}/src/node.py +130 -40
- {testgres-1.15.1 → testgres-1.16.0}/src/utils.py +92 -40
- {testgres-1.15.1 → testgres-1.16.0/testgres.egg-info}/PKG-INFO +2 -2
- {testgres-1.15.1 → testgres-1.16.0}/testgres.egg-info/requires.txt +1 -1
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_os_ops_common.py +2697 -30
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_os_ops_local.py +3 -3
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_os_ops_remote.py +28 -5
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_testgres_common.py +2 -2
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_utils.py +3 -3
- {testgres-1.15.1 → testgres-1.16.0}/LICENSE +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/README.md +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/setup.cfg +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/api.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/config.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/connection.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/consts.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/decorators.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/defaults.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/enums.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/file_line_reader.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/internal_utils.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/platforms/internal_platform_utils.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/platforms/internal_platform_utils_factory.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/platforms/win32/internal_platform_utils.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/port_manager__generic.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/port_manager__generic2.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/impl/port_manager__this_host.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/node_app.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/port_manager.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/pubsub.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/raise_error.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/src/standby.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/testgres.egg-info/SOURCES.txt +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/testgres.egg-info/dependency_links.txt +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/testgres.egg-info/top_level.txt +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_api.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_config.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_raise_error.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_testgres_local.py +0 -0
- {testgres-1.15.1 → testgres-1.16.0}/tests/test_testgres_remote.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testgres
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0
|
|
4
4
|
Summary: Testing utility for PostgreSQL and its extensions
|
|
5
5
|
Author-email: Postgres Professional <testgres@postgrespro.ru>
|
|
6
6
|
License: PostgreSQL
|
|
@@ -27,7 +27,7 @@ Requires-Dist: port-for>=0.4
|
|
|
27
27
|
Requires-Dist: six>=1.9.0
|
|
28
28
|
Requires-Dist: psutil
|
|
29
29
|
Requires-Dist: packaging
|
|
30
|
-
Requires-Dist: testgres.os_ops<4.0.0,>=3.
|
|
30
|
+
Requires-Dist: testgres.os_ops<4.0.0,>=3.3.0
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
33
33
|
[](https://github.com/postgrespro/testgres/actions/workflows/ci.yml)
|
|
@@ -18,6 +18,7 @@ from .connection import \
|
|
|
18
18
|
from .exceptions import \
|
|
19
19
|
TestgresException, \
|
|
20
20
|
ExecUtilException, \
|
|
21
|
+
ExecTimeoutException, \
|
|
21
22
|
QueryException, \
|
|
22
23
|
QueryTimeoutException, \
|
|
23
24
|
TimeoutException, \
|
|
@@ -53,11 +54,13 @@ from .standby import \
|
|
|
53
54
|
|
|
54
55
|
from .config import testgres_config
|
|
55
56
|
|
|
56
|
-
from testgres.operations.os_ops import OsOperations
|
|
57
|
+
from testgres.operations.os_ops import OsOperations
|
|
58
|
+
from testgres.operations.os_ops import ConnectionParams
|
|
59
|
+
from testgres.operations.os_ops import OsProcessController
|
|
57
60
|
from testgres.operations.local_ops import LocalOperations
|
|
58
61
|
from testgres.operations.remote_ops import RemoteOperations
|
|
59
62
|
|
|
60
|
-
__version__ = "1.
|
|
63
|
+
__version__ = "1.16.0"
|
|
61
64
|
|
|
62
65
|
__all__ = [
|
|
63
66
|
"get_new_node",
|
|
@@ -66,6 +69,7 @@ __all__ = [
|
|
|
66
69
|
"TestgresConfig", "configure_testgres", "scoped_config", "push_config", "pop_config",
|
|
67
70
|
"NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
|
|
68
71
|
"TestgresException", "ExecUtilException", "QueryException",
|
|
72
|
+
"ExecTimeoutException",
|
|
69
73
|
"QueryTimeoutException",
|
|
70
74
|
"TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
|
|
71
75
|
"XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
|
|
@@ -74,5 +78,6 @@ __all__ = [
|
|
|
74
78
|
"PortManager",
|
|
75
79
|
"reserve_port", "release_port", "get_bin_path", "get_bin_dir", "get_pg_config", "get_pg_version", "parse_pg_version",
|
|
76
80
|
"First", "Any",
|
|
77
|
-
"OsOperations", "LocalOperations", "RemoteOperations", "ConnectionParams"
|
|
81
|
+
"OsOperations", "LocalOperations", "RemoteOperations", "ConnectionParams",
|
|
82
|
+
"OsProcessController",
|
|
78
83
|
]
|
|
@@ -15,9 +15,10 @@ from .exceptions import BackupException
|
|
|
15
15
|
|
|
16
16
|
from testgres.operations.os_ops import OsOperations
|
|
17
17
|
|
|
18
|
+
from . import utils
|
|
19
|
+
|
|
18
20
|
from .utils import \
|
|
19
21
|
get_bin_path2, \
|
|
20
|
-
execute_utility2, \
|
|
21
22
|
clean_on_error
|
|
22
23
|
|
|
23
24
|
|
|
@@ -86,7 +87,13 @@ class NodeBackup(object):
|
|
|
86
87
|
"-X", xlog_method.value
|
|
87
88
|
] # yapf: disable
|
|
88
89
|
_params += options
|
|
89
|
-
|
|
90
|
+
|
|
91
|
+
utils.execute_utility3(
|
|
92
|
+
self.os_ops,
|
|
93
|
+
_params,
|
|
94
|
+
self.log_file,
|
|
95
|
+
)
|
|
96
|
+
return
|
|
90
97
|
|
|
91
98
|
def __enter__(self):
|
|
92
99
|
return self
|
|
@@ -8,14 +8,12 @@ from .consts import XLOG_CONTROL_FILE
|
|
|
8
8
|
|
|
9
9
|
from .defaults import generate_system_id
|
|
10
10
|
|
|
11
|
+
from . import utils
|
|
12
|
+
|
|
11
13
|
from .exceptions import \
|
|
12
14
|
InitNodeException, \
|
|
13
15
|
ExecUtilException
|
|
14
16
|
|
|
15
|
-
from .utils import \
|
|
16
|
-
get_bin_path2, \
|
|
17
|
-
execute_utility2
|
|
18
|
-
|
|
19
17
|
from testgres.operations.local_ops import LocalOperations
|
|
20
18
|
from testgres.operations.os_ops import OsOperations
|
|
21
19
|
|
|
@@ -39,13 +37,17 @@ def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = No
|
|
|
39
37
|
if bin_path:
|
|
40
38
|
return os_ops.build_path(bin_path, name)
|
|
41
39
|
|
|
42
|
-
return get_bin_path2(os_ops, name)
|
|
40
|
+
return utils.get_bin_path2(os_ops, name)
|
|
43
41
|
|
|
44
42
|
def call_initdb(initdb_dir, log=logfile):
|
|
45
43
|
try:
|
|
46
44
|
initdb_path = make_utility_path("initdb")
|
|
47
45
|
_params = [initdb_path, "-D", initdb_dir, "-N"]
|
|
48
|
-
|
|
46
|
+
utils.execute_utility3(
|
|
47
|
+
os_ops,
|
|
48
|
+
_params + (params or []),
|
|
49
|
+
log,
|
|
50
|
+
)
|
|
49
51
|
except ExecUtilException as e:
|
|
50
52
|
raise_from(InitNodeException("Failed to run initdb"), e)
|
|
51
53
|
|
|
@@ -78,7 +80,12 @@ def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = No
|
|
|
78
80
|
|
|
79
81
|
# XXX: build new WAL segment with our system id
|
|
80
82
|
_params = [make_utility_path("pg_resetwal"), "-D", data_dir, "-f"]
|
|
81
|
-
|
|
83
|
+
|
|
84
|
+
utils.execute_utility3(
|
|
85
|
+
os_ops,
|
|
86
|
+
_params,
|
|
87
|
+
logfile,
|
|
88
|
+
)
|
|
82
89
|
|
|
83
90
|
except ExecUtilException as e:
|
|
84
91
|
msg = "Failed to reset WAL for system id"
|
|
@@ -6,6 +6,7 @@ import typing
|
|
|
6
6
|
from testgres.operations.exceptions import TestgresException
|
|
7
7
|
from testgres.operations.exceptions import ExecUtilException
|
|
8
8
|
from testgres.operations.exceptions import InvalidOperationException
|
|
9
|
+
from testgres.operations.exceptions import ExecTimeoutException
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class PortForException(TestgresException):
|
|
@@ -298,3 +299,4 @@ class BackupException(TestgresException):
|
|
|
298
299
|
|
|
299
300
|
assert ExecUtilException.__name__ == "ExecUtilException"
|
|
300
301
|
assert InvalidOperationException.__name__ == "InvalidOperationException"
|
|
302
|
+
assert ExecTimeoutException.__name__ == "ExecTimeoutException"
|
|
@@ -5,7 +5,9 @@ from ... import internal_utils
|
|
|
5
5
|
from ....raise_error import RaiseError
|
|
6
6
|
|
|
7
7
|
from testgres.operations.os_ops import OsOperations
|
|
8
|
+
from testgres.operations.os_ops import OsCommandResult
|
|
8
9
|
from testgres.operations.exceptions import ExecUtilException
|
|
10
|
+
from testgres.operations.types import T_OS_EXEC_ENV
|
|
9
11
|
|
|
10
12
|
import re
|
|
11
13
|
import shlex
|
|
@@ -17,7 +19,7 @@ class InternalPlatformUtils(base.InternalPlatformUtils):
|
|
|
17
19
|
C_MAX_FIND_POSTMASTER_ATTEMPTS = 5
|
|
18
20
|
C_BASH_EXE = "/bin/bash"
|
|
19
21
|
|
|
20
|
-
sm_exec_env = {
|
|
22
|
+
sm_exec_env: T_OS_EXEC_ENV = {
|
|
21
23
|
"LANG": "en_US.UTF-8",
|
|
22
24
|
"LC_ALL": "en_US.UTF-8",
|
|
23
25
|
}
|
|
@@ -113,37 +115,32 @@ class InternalPlatformUtils(base.InternalPlatformUtils):
|
|
|
113
115
|
"ps -ewwo \"pid=,ppid=,args=\" | grep -E " + shlex.quote(regexp),
|
|
114
116
|
]
|
|
115
117
|
|
|
116
|
-
exec_r = os_ops.
|
|
118
|
+
exec_r = os_ops.run(
|
|
117
119
|
cmd=cmd,
|
|
118
|
-
|
|
119
|
-
verbose=True,
|
|
120
|
+
check=False,
|
|
120
121
|
exec_env=__class__.sm_exec_env,
|
|
121
122
|
)
|
|
122
123
|
|
|
123
|
-
assert type(exec_r) is
|
|
124
|
-
assert
|
|
124
|
+
assert type(exec_r) is OsCommandResult
|
|
125
|
+
assert type(exec_r.returncode) is int
|
|
126
|
+
assert type(exec_r.stdout) is bytes
|
|
127
|
+
assert type(exec_r.stderr) is bytes
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
assert type(exit_status) is int
|
|
129
|
-
assert type(output_b) is bytes
|
|
130
|
-
assert type(error_b) is bytes
|
|
131
|
-
|
|
132
|
-
if exit_status == 1:
|
|
129
|
+
if exec_r.returncode == 1:
|
|
133
130
|
return None
|
|
134
131
|
|
|
135
|
-
output =
|
|
136
|
-
error =
|
|
132
|
+
output = exec_r.stdout.decode("utf-8")
|
|
133
|
+
error = exec_r.stderr.decode("utf-8")
|
|
137
134
|
|
|
138
135
|
assert type(output) is str
|
|
139
136
|
assert type(error) is str
|
|
140
137
|
|
|
141
|
-
if
|
|
142
|
-
errMsg = f"test command returned an unexpected exit code: {
|
|
138
|
+
if exec_r.returncode != 0:
|
|
139
|
+
errMsg = f"test command returned an unexpected exit code: {exec_r.returncode}"
|
|
143
140
|
raise ExecUtilException(
|
|
144
141
|
message=errMsg,
|
|
145
142
|
command=cmd,
|
|
146
|
-
exit_code=
|
|
143
|
+
exit_code=exec_r.returncode,
|
|
147
144
|
out=output,
|
|
148
145
|
error=error,
|
|
149
146
|
)
|
|
@@ -31,7 +31,7 @@ class TestgresLogger(threading.Thread):
|
|
|
31
31
|
assert type(log_file_encoding) is str
|
|
32
32
|
assert os_ops is None or isinstance(os_ops, OsOperations)
|
|
33
33
|
|
|
34
|
-
threading.Thread.__init__(self)
|
|
34
|
+
threading.Thread.__init__(self, daemon=True)
|
|
35
35
|
|
|
36
36
|
if os_ops is None:
|
|
37
37
|
os_ops = tconf.os_ops
|
|
@@ -92,7 +92,6 @@ from .utils import \
|
|
|
92
92
|
PgVer, \
|
|
93
93
|
eprint, \
|
|
94
94
|
get_pg_version2, \
|
|
95
|
-
execute_utility2, \
|
|
96
95
|
options_string, \
|
|
97
96
|
clean_on_error
|
|
98
97
|
|
|
@@ -101,6 +100,8 @@ from .raise_error import RaiseError
|
|
|
101
100
|
from .backup import NodeBackup
|
|
102
101
|
|
|
103
102
|
from testgres.operations.os_ops import OsOperations
|
|
103
|
+
from testgres.operations.os_ops import OsCommandResult
|
|
104
|
+
from testgres.operations.os_ops import OsProcessController
|
|
104
105
|
from testgres.operations.local_ops import LocalOperations
|
|
105
106
|
|
|
106
107
|
InternalError = pglib.InternalError
|
|
@@ -638,6 +639,12 @@ class PostgresNode(object):
|
|
|
638
639
|
assert type(with_force) is bool
|
|
639
640
|
assert max_attempts > 0
|
|
640
641
|
|
|
642
|
+
try:
|
|
643
|
+
self._try_shutdown_internal(max_attempts, with_force)
|
|
644
|
+
finally:
|
|
645
|
+
self._maybe_stop_logger()
|
|
646
|
+
|
|
647
|
+
def _try_shutdown_internal(self, max_attempts, with_force):
|
|
641
648
|
attempts = 0
|
|
642
649
|
|
|
643
650
|
# try stopping server N times
|
|
@@ -668,7 +675,11 @@ class PostgresNode(object):
|
|
|
668
675
|
|
|
669
676
|
ps_command = ['ps', '-o', 'pid=', '-p', str(node_pid)]
|
|
670
677
|
|
|
671
|
-
ps_output = self._os_ops.
|
|
678
|
+
ps_output = self._os_ops.run(
|
|
679
|
+
cmd=ps_command,
|
|
680
|
+
shell=True,
|
|
681
|
+
check=False,
|
|
682
|
+
).stdout.decode('utf-8')
|
|
672
683
|
assert type(ps_output) is str
|
|
673
684
|
|
|
674
685
|
if ps_output == "":
|
|
@@ -687,7 +698,11 @@ class PostgresNode(object):
|
|
|
687
698
|
pass
|
|
688
699
|
|
|
689
700
|
# Check that node stopped - print only column pid without headers
|
|
690
|
-
ps_output = self._os_ops.
|
|
701
|
+
ps_output = self._os_ops.run(
|
|
702
|
+
cmd=ps_command,
|
|
703
|
+
shell=True,
|
|
704
|
+
check=False,
|
|
705
|
+
).stdout.decode('utf-8')
|
|
691
706
|
assert type(ps_output) is str
|
|
692
707
|
|
|
693
708
|
if ps_output == "":
|
|
@@ -1087,11 +1102,16 @@ class PostgresNode(object):
|
|
|
1087
1102
|
_params += ["-D"] if self._pg_version >= PgVer('9.5') else []
|
|
1088
1103
|
_params += [self.data_dir]
|
|
1089
1104
|
|
|
1090
|
-
|
|
1105
|
+
exec_r = utils.execute_utility3(
|
|
1106
|
+
self._os_ops,
|
|
1107
|
+
_params,
|
|
1108
|
+
self.utils_log_file,
|
|
1109
|
+
)
|
|
1110
|
+
assert type(exec_r.stdout) is str
|
|
1091
1111
|
|
|
1092
1112
|
out_dict = {}
|
|
1093
1113
|
|
|
1094
|
-
for line in
|
|
1114
|
+
for line in exec_r.stdout.splitlines():
|
|
1095
1115
|
key, _, value = line.partition(':')
|
|
1096
1116
|
out_dict[key.strip()] = value.strip()
|
|
1097
1117
|
|
|
@@ -1242,10 +1262,17 @@ class PostgresNode(object):
|
|
|
1242
1262
|
|
|
1243
1263
|
def LOCAL__start_node():
|
|
1244
1264
|
# 'error' will be None on Windows
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1265
|
+
exec_r = utils.execute_utility3(
|
|
1266
|
+
self._os_ops,
|
|
1267
|
+
_params,
|
|
1268
|
+
self.utils_log_file,
|
|
1269
|
+
exec_env=exec_env,
|
|
1270
|
+
)
|
|
1271
|
+
# TODO: WTF? Remove it!
|
|
1272
|
+
assert exec_r.returncode == 0
|
|
1273
|
+
assert exec_r.stderr is None or type(exec_r.stderr) is str
|
|
1274
|
+
if exec_r.stderr is not None and 'does not exist' in exec_r.stderr:
|
|
1275
|
+
raise ExecUtilException(exec_r.stderr)
|
|
1249
1276
|
|
|
1250
1277
|
def LOCAL__raise_cannot_start_node__std(from_exception):
|
|
1251
1278
|
assert isinstance(from_exception, Exception)
|
|
@@ -1331,11 +1358,17 @@ class PostgresNode(object):
|
|
|
1331
1358
|
"stop"
|
|
1332
1359
|
] + params # yapf: disable
|
|
1333
1360
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1361
|
+
try:
|
|
1362
|
+
utils.execute_utility3(
|
|
1363
|
+
self._os_ops,
|
|
1364
|
+
_params,
|
|
1365
|
+
logfile=self.utils_log_file,
|
|
1366
|
+
)
|
|
1367
|
+
self._manually_started_pm_pid = None
|
|
1368
|
+
finally:
|
|
1369
|
+
# always stop the reader thread, even if pg_ctl stop failed,
|
|
1370
|
+
# so it can't leak into interpreter shutdown.
|
|
1371
|
+
self._maybe_stop_logger()
|
|
1339
1372
|
return self
|
|
1340
1373
|
|
|
1341
1374
|
def kill(self, someone=None):
|
|
@@ -1391,9 +1424,16 @@ class PostgresNode(object):
|
|
|
1391
1424
|
] + params # yapf: disable
|
|
1392
1425
|
|
|
1393
1426
|
try:
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1427
|
+
exec_r = utils.execute_utility3(
|
|
1428
|
+
self._os_ops,
|
|
1429
|
+
_params,
|
|
1430
|
+
logfile=self.utils_log_file,
|
|
1431
|
+
)
|
|
1432
|
+
# TODO: WTF? Remove it!
|
|
1433
|
+
assert exec_r.returncode == 0
|
|
1434
|
+
assert exec_r.stderr is None or type(exec_r.stderr) is str
|
|
1435
|
+
if exec_r.stderr is not None and 'could not start server' in exec_r.stderr:
|
|
1436
|
+
raise ExecUtilException(exec_r.stderr)
|
|
1397
1437
|
except ExecUtilException as e:
|
|
1398
1438
|
msg = 'Cannot restart node'
|
|
1399
1439
|
files = self._collect_special_files()
|
|
@@ -1420,7 +1460,11 @@ class PostgresNode(object):
|
|
|
1420
1460
|
"reload"
|
|
1421
1461
|
] + params # yapf: disable
|
|
1422
1462
|
|
|
1423
|
-
|
|
1463
|
+
utils.execute_utility3(
|
|
1464
|
+
self._os_ops,
|
|
1465
|
+
_params,
|
|
1466
|
+
logfile=self.utils_log_file,
|
|
1467
|
+
)
|
|
1424
1468
|
|
|
1425
1469
|
return self
|
|
1426
1470
|
|
|
@@ -1442,7 +1486,11 @@ class PostgresNode(object):
|
|
|
1442
1486
|
"promote"
|
|
1443
1487
|
] # yapf: disable
|
|
1444
1488
|
|
|
1445
|
-
|
|
1489
|
+
utils.execute_utility3(
|
|
1490
|
+
self._os_ops,
|
|
1491
|
+
_params,
|
|
1492
|
+
self.utils_log_file,
|
|
1493
|
+
)
|
|
1446
1494
|
|
|
1447
1495
|
# for versions below 10 `promote` is asynchronous so we need to wait
|
|
1448
1496
|
# until it actually becomes writable
|
|
@@ -1477,7 +1525,11 @@ class PostgresNode(object):
|
|
|
1477
1525
|
"-w" # wait
|
|
1478
1526
|
] + params # yapf: disable
|
|
1479
1527
|
|
|
1480
|
-
return
|
|
1528
|
+
return utils.execute_utility3(
|
|
1529
|
+
self._os_ops,
|
|
1530
|
+
_params,
|
|
1531
|
+
self.utils_log_file,
|
|
1532
|
+
).stdout
|
|
1481
1533
|
|
|
1482
1534
|
def release_resources(self):
|
|
1483
1535
|
"""
|
|
@@ -1556,7 +1608,7 @@ class PostgresNode(object):
|
|
|
1556
1608
|
assert port is None or type(port) is int
|
|
1557
1609
|
assert type(variables) is dict
|
|
1558
1610
|
|
|
1559
|
-
|
|
1611
|
+
r = self._psql(
|
|
1560
1612
|
ignore_errors=True,
|
|
1561
1613
|
query=query,
|
|
1562
1614
|
filename=filename,
|
|
@@ -1567,6 +1619,8 @@ class PostgresNode(object):
|
|
|
1567
1619
|
port=port,
|
|
1568
1620
|
**variables
|
|
1569
1621
|
)
|
|
1622
|
+
assert type(r) is OsCommandResult
|
|
1623
|
+
return r.returncode, r.stdout, r.stderr
|
|
1570
1624
|
|
|
1571
1625
|
def _psql(
|
|
1572
1626
|
self,
|
|
@@ -1578,7 +1632,8 @@ class PostgresNode(object):
|
|
|
1578
1632
|
input=None,
|
|
1579
1633
|
host: typing.Optional[str] = None,
|
|
1580
1634
|
port: typing.Optional[int] = None,
|
|
1581
|
-
**variables
|
|
1635
|
+
**variables
|
|
1636
|
+
) -> OsCommandResult:
|
|
1582
1637
|
assert host is None or type(host) is str
|
|
1583
1638
|
assert port is None or type(port) is int
|
|
1584
1639
|
assert type(variables) is dict
|
|
@@ -1628,13 +1683,15 @@ class PostgresNode(object):
|
|
|
1628
1683
|
else:
|
|
1629
1684
|
raise QueryException('Query or filename must be provided')
|
|
1630
1685
|
|
|
1631
|
-
|
|
1686
|
+
r = self._os_ops.run(
|
|
1632
1687
|
psql_params,
|
|
1633
|
-
verbose=True,
|
|
1634
1688
|
input=input,
|
|
1635
1689
|
stderr=subprocess.PIPE,
|
|
1636
1690
|
stdout=subprocess.PIPE,
|
|
1637
|
-
|
|
1691
|
+
check=not ignore_errors,
|
|
1692
|
+
)
|
|
1693
|
+
assert type(r) is OsCommandResult
|
|
1694
|
+
return r
|
|
1638
1695
|
|
|
1639
1696
|
@method_decorator(positional_args_hack(['dbname', 'query']))
|
|
1640
1697
|
def safe_psql(self, query=None, expect_error=False, **kwargs):
|
|
@@ -1662,7 +1719,7 @@ class PostgresNode(object):
|
|
|
1662
1719
|
# force this setting
|
|
1663
1720
|
kwargs['ON_ERROR_STOP'] = 1
|
|
1664
1721
|
try:
|
|
1665
|
-
|
|
1722
|
+
exec_r = self._psql(ignore_errors=False, query=query, **kwargs)
|
|
1666
1723
|
except ExecUtilException as e:
|
|
1667
1724
|
if not expect_error:
|
|
1668
1725
|
raise QueryException(e.message, query)
|
|
@@ -1677,7 +1734,7 @@ class PostgresNode(object):
|
|
|
1677
1734
|
if expect_error:
|
|
1678
1735
|
raise InvalidOperationException("Exception was expected, but query finished successfully: `{}`.".format(query))
|
|
1679
1736
|
|
|
1680
|
-
return
|
|
1737
|
+
return exec_r.stdout
|
|
1681
1738
|
|
|
1682
1739
|
def dump(self,
|
|
1683
1740
|
filename=None,
|
|
@@ -1732,7 +1789,11 @@ class PostgresNode(object):
|
|
|
1732
1789
|
if options:
|
|
1733
1790
|
_params.extend(options)
|
|
1734
1791
|
|
|
1735
|
-
|
|
1792
|
+
utils.execute_utility3(
|
|
1793
|
+
self._os_ops,
|
|
1794
|
+
_params,
|
|
1795
|
+
self.utils_log_file,
|
|
1796
|
+
)
|
|
1736
1797
|
|
|
1737
1798
|
return filename
|
|
1738
1799
|
|
|
@@ -1761,7 +1822,11 @@ class PostgresNode(object):
|
|
|
1761
1822
|
|
|
1762
1823
|
# try pg_restore if dump is binary format, and psql if not
|
|
1763
1824
|
try:
|
|
1764
|
-
|
|
1825
|
+
utils.execute_utility3(
|
|
1826
|
+
self._os_ops,
|
|
1827
|
+
_params,
|
|
1828
|
+
self.utils_log_file,
|
|
1829
|
+
)
|
|
1765
1830
|
except ExecUtilException:
|
|
1766
1831
|
self.psql(filename=filename, dbname=dbname, username=username)
|
|
1767
1832
|
|
|
@@ -2002,12 +2067,14 @@ class PostgresNode(object):
|
|
|
2002
2067
|
dbname=dbname, username=username, **params)
|
|
2003
2068
|
# yapf: enable
|
|
2004
2069
|
|
|
2005
|
-
def pgbench(
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2070
|
+
def pgbench(
|
|
2071
|
+
self,
|
|
2072
|
+
dbname=None,
|
|
2073
|
+
username=None,
|
|
2074
|
+
stdout=None,
|
|
2075
|
+
stderr=None,
|
|
2076
|
+
options=None,
|
|
2077
|
+
) -> OsProcessController:
|
|
2011
2078
|
"""
|
|
2012
2079
|
Spawn a pgbench process.
|
|
2013
2080
|
|
|
@@ -2019,7 +2086,7 @@ class PostgresNode(object):
|
|
|
2019
2086
|
options: additional options for pgbench (list).
|
|
2020
2087
|
|
|
2021
2088
|
Returns:
|
|
2022
|
-
|
|
2089
|
+
OsProcessController.
|
|
2023
2090
|
"""
|
|
2024
2091
|
if options is None:
|
|
2025
2092
|
options = []
|
|
@@ -2036,10 +2103,14 @@ class PostgresNode(object):
|
|
|
2036
2103
|
# should be the last one
|
|
2037
2104
|
_params.append(dbname)
|
|
2038
2105
|
|
|
2039
|
-
proc = self._os_ops.
|
|
2106
|
+
proc = self._os_ops.popen(
|
|
2107
|
+
_params,
|
|
2108
|
+
stdout=stdout,
|
|
2109
|
+
stderr=stderr,
|
|
2110
|
+
)
|
|
2040
2111
|
|
|
2041
2112
|
# [2026-06-21] It is so
|
|
2042
|
-
assert isinstance(proc,
|
|
2113
|
+
assert isinstance(proc, OsProcessController)
|
|
2043
2114
|
return proc
|
|
2044
2115
|
|
|
2045
2116
|
def pgbench_with_wait(self,
|
|
@@ -2122,7 +2193,11 @@ class PostgresNode(object):
|
|
|
2122
2193
|
# should be the last one
|
|
2123
2194
|
_params.append(dbname)
|
|
2124
2195
|
|
|
2125
|
-
return
|
|
2196
|
+
return utils.execute_utility3(
|
|
2197
|
+
self._os_ops,
|
|
2198
|
+
_params,
|
|
2199
|
+
self.utils_log_file,
|
|
2200
|
+
).stdout
|
|
2126
2201
|
|
|
2127
2202
|
def connect(self,
|
|
2128
2203
|
dbname=None,
|
|
@@ -2295,7 +2370,22 @@ class PostgresNode(object):
|
|
|
2295
2370
|
]
|
|
2296
2371
|
upgrade_command += options
|
|
2297
2372
|
|
|
2298
|
-
|
|
2373
|
+
r: typing.Optional[typing.Any] = None
|
|
2374
|
+
try:
|
|
2375
|
+
r = self._os_ops.run(upgrade_command).stdout
|
|
2376
|
+
except BaseException as e:
|
|
2377
|
+
if not expect_error:
|
|
2378
|
+
raise
|
|
2379
|
+
|
|
2380
|
+
logging.info("Exception ({}): {}".format(
|
|
2381
|
+
type(e).__name__,
|
|
2382
|
+
e,
|
|
2383
|
+
))
|
|
2384
|
+
|
|
2385
|
+
if expect_error:
|
|
2386
|
+
raise RuntimeError("Operation executed without any errors.")
|
|
2387
|
+
|
|
2388
|
+
return r
|
|
2299
2389
|
|
|
2300
2390
|
def _release_resources(self):
|
|
2301
2391
|
self._free_port()
|