testgres 1.15.2__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.
Files changed (48) hide show
  1. {testgres-1.15.2/testgres.egg-info → testgres-1.16.0}/PKG-INFO +2 -2
  2. {testgres-1.15.2 → testgres-1.16.0}/pyproject.toml +1 -1
  3. {testgres-1.15.2 → testgres-1.16.0}/src/__init__.py +8 -3
  4. {testgres-1.15.2 → testgres-1.16.0}/src/backup.py +9 -2
  5. {testgres-1.15.2 → testgres-1.16.0}/src/cache.py +14 -7
  6. {testgres-1.15.2 → testgres-1.16.0}/src/exceptions.py +2 -0
  7. {testgres-1.15.2 → testgres-1.16.0}/src/impl/platforms/linux/internal_platform_utils.py +15 -18
  8. {testgres-1.15.2 → testgres-1.16.0}/src/node.py +118 -36
  9. {testgres-1.15.2 → testgres-1.16.0}/src/utils.py +92 -40
  10. {testgres-1.15.2 → testgres-1.16.0/testgres.egg-info}/PKG-INFO +2 -2
  11. {testgres-1.15.2 → testgres-1.16.0}/testgres.egg-info/requires.txt +1 -1
  12. {testgres-1.15.2 → testgres-1.16.0}/tests/test_os_ops_common.py +2697 -30
  13. {testgres-1.15.2 → testgres-1.16.0}/tests/test_os_ops_local.py +3 -3
  14. {testgres-1.15.2 → testgres-1.16.0}/tests/test_os_ops_remote.py +28 -5
  15. {testgres-1.15.2 → testgres-1.16.0}/tests/test_testgres_common.py +2 -2
  16. {testgres-1.15.2 → testgres-1.16.0}/tests/test_utils.py +3 -3
  17. {testgres-1.15.2 → testgres-1.16.0}/LICENSE +0 -0
  18. {testgres-1.15.2 → testgres-1.16.0}/README.md +0 -0
  19. {testgres-1.15.2 → testgres-1.16.0}/setup.cfg +0 -0
  20. {testgres-1.15.2 → testgres-1.16.0}/src/api.py +0 -0
  21. {testgres-1.15.2 → testgres-1.16.0}/src/config.py +0 -0
  22. {testgres-1.15.2 → testgres-1.16.0}/src/connection.py +0 -0
  23. {testgres-1.15.2 → testgres-1.16.0}/src/consts.py +0 -0
  24. {testgres-1.15.2 → testgres-1.16.0}/src/decorators.py +0 -0
  25. {testgres-1.15.2 → testgres-1.16.0}/src/defaults.py +0 -0
  26. {testgres-1.15.2 → testgres-1.16.0}/src/enums.py +0 -0
  27. {testgres-1.15.2 → testgres-1.16.0}/src/impl/file_line_reader.py +0 -0
  28. {testgres-1.15.2 → testgres-1.16.0}/src/impl/internal_utils.py +0 -0
  29. {testgres-1.15.2 → testgres-1.16.0}/src/impl/platforms/internal_platform_utils.py +0 -0
  30. {testgres-1.15.2 → testgres-1.16.0}/src/impl/platforms/internal_platform_utils_factory.py +0 -0
  31. {testgres-1.15.2 → testgres-1.16.0}/src/impl/platforms/win32/internal_platform_utils.py +0 -0
  32. {testgres-1.15.2 → testgres-1.16.0}/src/impl/port_manager__generic.py +0 -0
  33. {testgres-1.15.2 → testgres-1.16.0}/src/impl/port_manager__generic2.py +0 -0
  34. {testgres-1.15.2 → testgres-1.16.0}/src/impl/port_manager__this_host.py +0 -0
  35. {testgres-1.15.2 → testgres-1.16.0}/src/logger.py +0 -0
  36. {testgres-1.15.2 → testgres-1.16.0}/src/node_app.py +0 -0
  37. {testgres-1.15.2 → testgres-1.16.0}/src/port_manager.py +0 -0
  38. {testgres-1.15.2 → testgres-1.16.0}/src/pubsub.py +0 -0
  39. {testgres-1.15.2 → testgres-1.16.0}/src/raise_error.py +0 -0
  40. {testgres-1.15.2 → testgres-1.16.0}/src/standby.py +0 -0
  41. {testgres-1.15.2 → testgres-1.16.0}/testgres.egg-info/SOURCES.txt +0 -0
  42. {testgres-1.15.2 → testgres-1.16.0}/testgres.egg-info/dependency_links.txt +0 -0
  43. {testgres-1.15.2 → testgres-1.16.0}/testgres.egg-info/top_level.txt +0 -0
  44. {testgres-1.15.2 → testgres-1.16.0}/tests/test_api.py +0 -0
  45. {testgres-1.15.2 → testgres-1.16.0}/tests/test_config.py +0 -0
  46. {testgres-1.15.2 → testgres-1.16.0}/tests/test_raise_error.py +0 -0
  47. {testgres-1.15.2 → testgres-1.16.0}/tests/test_testgres_local.py +0 -0
  48. {testgres-1.15.2 → 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.15.2
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.2.0
30
+ Requires-Dist: testgres.os_ops<4.0.0,>=3.3.0
31
31
  Dynamic: license-file
32
32
 
33
33
  [![CI Status](https://img.shields.io/github/actions/workflow/status/postgrespro/testgres/.github/workflows/ci.yml?label=CI)](https://github.com/postgrespro/testgres/actions/workflows/ci.yml)
@@ -65,7 +65,7 @@ dependencies = [
65
65
  "six>=1.9.0",
66
66
  "psutil",
67
67
  "packaging",
68
- "testgres.os_ops>=3.2.0,<4.0.0",
68
+ "testgres.os_ops>=3.3.0,<4.0.0",
69
69
  ]
70
70
 
71
71
  [project.urls]
@@ -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, ConnectionParams
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.15.2"
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
- execute_utility2(self.os_ops, _params, self.log_file)
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
- execute_utility2(os_ops, _params + (params or []), log)
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
- execute_utility2(os_ops, _params, logfile)
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.exec_command(
118
+ exec_r = os_ops.run(
117
119
  cmd=cmd,
118
- ignore_errors=True,
119
- verbose=True,
120
+ check=False,
120
121
  exec_env=__class__.sm_exec_env,
121
122
  )
122
123
 
123
- assert type(exec_r) is tuple
124
- assert len(exec_r) == 3
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
- exit_status, output_b, error_b = exec_r
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 = output_b.decode("utf-8")
136
- error = error_b.decode("utf-8")
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 exit_status != 0:
142
- errMsg = f"test command returned an unexpected exit code: {exit_status}"
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=exit_status,
143
+ exit_code=exec_r.returncode,
147
144
  out=output,
148
145
  error=error,
149
146
  )
@@ -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
@@ -674,7 +675,11 @@ class PostgresNode(object):
674
675
 
675
676
  ps_command = ['ps', '-o', 'pid=', '-p', str(node_pid)]
676
677
 
677
- ps_output = self._os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
678
+ ps_output = self._os_ops.run(
679
+ cmd=ps_command,
680
+ shell=True,
681
+ check=False,
682
+ ).stdout.decode('utf-8')
678
683
  assert type(ps_output) is str
679
684
 
680
685
  if ps_output == "":
@@ -693,7 +698,11 @@ class PostgresNode(object):
693
698
  pass
694
699
 
695
700
  # Check that node stopped - print only column pid without headers
696
- ps_output = self._os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
701
+ ps_output = self._os_ops.run(
702
+ cmd=ps_command,
703
+ shell=True,
704
+ check=False,
705
+ ).stdout.decode('utf-8')
697
706
  assert type(ps_output) is str
698
707
 
699
708
  if ps_output == "":
@@ -1093,11 +1102,16 @@ class PostgresNode(object):
1093
1102
  _params += ["-D"] if self._pg_version >= PgVer('9.5') else []
1094
1103
  _params += [self.data_dir]
1095
1104
 
1096
- data = execute_utility2(self._os_ops, _params, self.utils_log_file)
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
1097
1111
 
1098
1112
  out_dict = {}
1099
1113
 
1100
- for line in data.splitlines():
1114
+ for line in exec_r.stdout.splitlines():
1101
1115
  key, _, value = line.partition(':')
1102
1116
  out_dict[key.strip()] = value.strip()
1103
1117
 
@@ -1248,10 +1262,17 @@ class PostgresNode(object):
1248
1262
 
1249
1263
  def LOCAL__start_node():
1250
1264
  # 'error' will be None on Windows
1251
- _, _, error = execute_utility2(self._os_ops, _params, self.utils_log_file, verbose=True, exec_env=exec_env)
1252
- assert error is None or type(error) is str
1253
- if error and 'does not exist' in error:
1254
- raise Exception(error)
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)
1255
1276
 
1256
1277
  def LOCAL__raise_cannot_start_node__std(from_exception):
1257
1278
  assert isinstance(from_exception, Exception)
@@ -1338,7 +1359,11 @@ class PostgresNode(object):
1338
1359
  ] + params # yapf: disable
1339
1360
 
1340
1361
  try:
1341
- execute_utility2(self._os_ops, _params, self.utils_log_file)
1362
+ utils.execute_utility3(
1363
+ self._os_ops,
1364
+ _params,
1365
+ logfile=self.utils_log_file,
1366
+ )
1342
1367
  self._manually_started_pm_pid = None
1343
1368
  finally:
1344
1369
  # always stop the reader thread, even if pg_ctl stop failed,
@@ -1399,9 +1424,16 @@ class PostgresNode(object):
1399
1424
  ] + params # yapf: disable
1400
1425
 
1401
1426
  try:
1402
- error_code, out, error = execute_utility2(self._os_ops, _params, self.utils_log_file, verbose=True)
1403
- if error and 'could not start server' in error:
1404
- raise ExecUtilException
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)
1405
1437
  except ExecUtilException as e:
1406
1438
  msg = 'Cannot restart node'
1407
1439
  files = self._collect_special_files()
@@ -1428,7 +1460,11 @@ class PostgresNode(object):
1428
1460
  "reload"
1429
1461
  ] + params # yapf: disable
1430
1462
 
1431
- execute_utility2(self._os_ops, _params, self.utils_log_file)
1463
+ utils.execute_utility3(
1464
+ self._os_ops,
1465
+ _params,
1466
+ logfile=self.utils_log_file,
1467
+ )
1432
1468
 
1433
1469
  return self
1434
1470
 
@@ -1450,7 +1486,11 @@ class PostgresNode(object):
1450
1486
  "promote"
1451
1487
  ] # yapf: disable
1452
1488
 
1453
- execute_utility2(self._os_ops, _params, self.utils_log_file)
1489
+ utils.execute_utility3(
1490
+ self._os_ops,
1491
+ _params,
1492
+ self.utils_log_file,
1493
+ )
1454
1494
 
1455
1495
  # for versions below 10 `promote` is asynchronous so we need to wait
1456
1496
  # until it actually becomes writable
@@ -1485,7 +1525,11 @@ class PostgresNode(object):
1485
1525
  "-w" # wait
1486
1526
  ] + params # yapf: disable
1487
1527
 
1488
- return execute_utility2(self._os_ops, _params, self.utils_log_file)
1528
+ return utils.execute_utility3(
1529
+ self._os_ops,
1530
+ _params,
1531
+ self.utils_log_file,
1532
+ ).stdout
1489
1533
 
1490
1534
  def release_resources(self):
1491
1535
  """
@@ -1564,7 +1608,7 @@ class PostgresNode(object):
1564
1608
  assert port is None or type(port) is int
1565
1609
  assert type(variables) is dict
1566
1610
 
1567
- return self._psql(
1611
+ r = self._psql(
1568
1612
  ignore_errors=True,
1569
1613
  query=query,
1570
1614
  filename=filename,
@@ -1575,6 +1619,8 @@ class PostgresNode(object):
1575
1619
  port=port,
1576
1620
  **variables
1577
1621
  )
1622
+ assert type(r) is OsCommandResult
1623
+ return r.returncode, r.stdout, r.stderr
1578
1624
 
1579
1625
  def _psql(
1580
1626
  self,
@@ -1586,7 +1632,8 @@ class PostgresNode(object):
1586
1632
  input=None,
1587
1633
  host: typing.Optional[str] = None,
1588
1634
  port: typing.Optional[int] = None,
1589
- **variables):
1635
+ **variables
1636
+ ) -> OsCommandResult:
1590
1637
  assert host is None or type(host) is str
1591
1638
  assert port is None or type(port) is int
1592
1639
  assert type(variables) is dict
@@ -1636,13 +1683,15 @@ class PostgresNode(object):
1636
1683
  else:
1637
1684
  raise QueryException('Query or filename must be provided')
1638
1685
 
1639
- return self._os_ops.exec_command(
1686
+ r = self._os_ops.run(
1640
1687
  psql_params,
1641
- verbose=True,
1642
1688
  input=input,
1643
1689
  stderr=subprocess.PIPE,
1644
1690
  stdout=subprocess.PIPE,
1645
- ignore_errors=ignore_errors)
1691
+ check=not ignore_errors,
1692
+ )
1693
+ assert type(r) is OsCommandResult
1694
+ return r
1646
1695
 
1647
1696
  @method_decorator(positional_args_hack(['dbname', 'query']))
1648
1697
  def safe_psql(self, query=None, expect_error=False, **kwargs):
@@ -1670,7 +1719,7 @@ class PostgresNode(object):
1670
1719
  # force this setting
1671
1720
  kwargs['ON_ERROR_STOP'] = 1
1672
1721
  try:
1673
- ret, out, err = self._psql(ignore_errors=False, query=query, **kwargs)
1722
+ exec_r = self._psql(ignore_errors=False, query=query, **kwargs)
1674
1723
  except ExecUtilException as e:
1675
1724
  if not expect_error:
1676
1725
  raise QueryException(e.message, query)
@@ -1685,7 +1734,7 @@ class PostgresNode(object):
1685
1734
  if expect_error:
1686
1735
  raise InvalidOperationException("Exception was expected, but query finished successfully: `{}`.".format(query))
1687
1736
 
1688
- return out
1737
+ return exec_r.stdout
1689
1738
 
1690
1739
  def dump(self,
1691
1740
  filename=None,
@@ -1740,7 +1789,11 @@ class PostgresNode(object):
1740
1789
  if options:
1741
1790
  _params.extend(options)
1742
1791
 
1743
- execute_utility2(self._os_ops, _params, self.utils_log_file)
1792
+ utils.execute_utility3(
1793
+ self._os_ops,
1794
+ _params,
1795
+ self.utils_log_file,
1796
+ )
1744
1797
 
1745
1798
  return filename
1746
1799
 
@@ -1769,7 +1822,11 @@ class PostgresNode(object):
1769
1822
 
1770
1823
  # try pg_restore if dump is binary format, and psql if not
1771
1824
  try:
1772
- execute_utility2(self._os_ops, _params, self.utils_log_file)
1825
+ utils.execute_utility3(
1826
+ self._os_ops,
1827
+ _params,
1828
+ self.utils_log_file,
1829
+ )
1773
1830
  except ExecUtilException:
1774
1831
  self.psql(filename=filename, dbname=dbname, username=username)
1775
1832
 
@@ -2010,12 +2067,14 @@ class PostgresNode(object):
2010
2067
  dbname=dbname, username=username, **params)
2011
2068
  # yapf: enable
2012
2069
 
2013
- def pgbench(self,
2014
- dbname=None,
2015
- username=None,
2016
- stdout=None,
2017
- stderr=None,
2018
- options=None):
2070
+ def pgbench(
2071
+ self,
2072
+ dbname=None,
2073
+ username=None,
2074
+ stdout=None,
2075
+ stderr=None,
2076
+ options=None,
2077
+ ) -> OsProcessController:
2019
2078
  """
2020
2079
  Spawn a pgbench process.
2021
2080
 
@@ -2027,7 +2086,7 @@ class PostgresNode(object):
2027
2086
  options: additional options for pgbench (list).
2028
2087
 
2029
2088
  Returns:
2030
- Process created by subprocess.Popen.
2089
+ OsProcessController.
2031
2090
  """
2032
2091
  if options is None:
2033
2092
  options = []
@@ -2044,10 +2103,14 @@ class PostgresNode(object):
2044
2103
  # should be the last one
2045
2104
  _params.append(dbname)
2046
2105
 
2047
- proc = self._os_ops.exec_command(_params, stdout=stdout, stderr=stderr, get_process=True)
2106
+ proc = self._os_ops.popen(
2107
+ _params,
2108
+ stdout=stdout,
2109
+ stderr=stderr,
2110
+ )
2048
2111
 
2049
2112
  # [2026-06-21] It is so
2050
- assert isinstance(proc, subprocess.Popen)
2113
+ assert isinstance(proc, OsProcessController)
2051
2114
  return proc
2052
2115
 
2053
2116
  def pgbench_with_wait(self,
@@ -2130,7 +2193,11 @@ class PostgresNode(object):
2130
2193
  # should be the last one
2131
2194
  _params.append(dbname)
2132
2195
 
2133
- return execute_utility2(self._os_ops, _params, self.utils_log_file)
2196
+ return utils.execute_utility3(
2197
+ self._os_ops,
2198
+ _params,
2199
+ self.utils_log_file,
2200
+ ).stdout
2134
2201
 
2135
2202
  def connect(self,
2136
2203
  dbname=None,
@@ -2303,7 +2370,22 @@ class PostgresNode(object):
2303
2370
  ]
2304
2371
  upgrade_command += options
2305
2372
 
2306
- return self._os_ops.exec_command(upgrade_command, expect_error=expect_error)
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
2307
2389
 
2308
2390
  def _release_resources(self):
2309
2391
  self._free_port()