testgres 1.13.7__tar.gz → 1.14.1__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 (46) hide show
  1. {testgres-1.13.7/testgres.egg-info → testgres-1.14.1}/PKG-INFO +3 -4
  2. {testgres-1.13.7 → testgres-1.14.1}/README.md +1 -2
  3. {testgres-1.13.7 → testgres-1.14.1}/pyproject.toml +1 -1
  4. {testgres-1.13.7 → testgres-1.14.1}/src/__init__.py +5 -5
  5. {testgres-1.13.7 → testgres-1.14.1}/src/api.py +11 -2
  6. {testgres-1.13.7 → testgres-1.14.1}/src/backup.py +1 -6
  7. {testgres-1.13.7 → testgres-1.14.1}/src/node.py +137 -95
  8. {testgres-1.13.7 → testgres-1.14.1}/src/node_app.py +40 -40
  9. {testgres-1.13.7 → testgres-1.14.1}/src/utils.py +28 -1
  10. {testgres-1.13.7 → testgres-1.14.1/testgres.egg-info}/PKG-INFO +3 -4
  11. {testgres-1.13.7 → testgres-1.14.1}/testgres.egg-info/SOURCES.txt +1 -0
  12. {testgres-1.13.7 → testgres-1.14.1}/testgres.egg-info/requires.txt +1 -1
  13. testgres-1.14.1/tests/test_api.py +30 -0
  14. {testgres-1.13.7 → testgres-1.14.1}/tests/test_testgres_common.py +52 -4
  15. {testgres-1.13.7 → testgres-1.14.1}/LICENSE +0 -0
  16. {testgres-1.13.7 → testgres-1.14.1}/setup.cfg +0 -0
  17. {testgres-1.13.7 → testgres-1.14.1}/src/cache.py +0 -0
  18. {testgres-1.13.7 → testgres-1.14.1}/src/config.py +0 -0
  19. {testgres-1.13.7 → testgres-1.14.1}/src/connection.py +0 -0
  20. {testgres-1.13.7 → testgres-1.14.1}/src/consts.py +0 -0
  21. {testgres-1.13.7 → testgres-1.14.1}/src/decorators.py +0 -0
  22. {testgres-1.13.7 → testgres-1.14.1}/src/defaults.py +0 -0
  23. {testgres-1.13.7 → testgres-1.14.1}/src/enums.py +0 -0
  24. {testgres-1.13.7 → testgres-1.14.1}/src/exceptions.py +0 -0
  25. {testgres-1.13.7 → testgres-1.14.1}/src/impl/internal_utils.py +0 -0
  26. {testgres-1.13.7 → testgres-1.14.1}/src/impl/platforms/internal_platform_utils.py +0 -0
  27. {testgres-1.13.7 → testgres-1.14.1}/src/impl/platforms/internal_platform_utils_factory.py +0 -0
  28. {testgres-1.13.7 → testgres-1.14.1}/src/impl/platforms/linux/internal_platform_utils.py +0 -0
  29. {testgres-1.13.7 → testgres-1.14.1}/src/impl/platforms/win32/internal_platform_utils.py +0 -0
  30. {testgres-1.13.7 → testgres-1.14.1}/src/impl/port_manager__generic.py +0 -0
  31. {testgres-1.13.7 → testgres-1.14.1}/src/impl/port_manager__this_host.py +0 -0
  32. {testgres-1.13.7 → testgres-1.14.1}/src/logger.py +0 -0
  33. {testgres-1.13.7 → testgres-1.14.1}/src/port_manager.py +0 -0
  34. {testgres-1.13.7 → testgres-1.14.1}/src/pubsub.py +0 -0
  35. {testgres-1.13.7 → testgres-1.14.1}/src/raise_error.py +0 -0
  36. {testgres-1.13.7 → testgres-1.14.1}/src/standby.py +0 -0
  37. {testgres-1.13.7 → testgres-1.14.1}/testgres.egg-info/dependency_links.txt +0 -0
  38. {testgres-1.13.7 → testgres-1.14.1}/testgres.egg-info/top_level.txt +0 -0
  39. {testgres-1.13.7 → testgres-1.14.1}/tests/test_config.py +0 -0
  40. {testgres-1.13.7 → testgres-1.14.1}/tests/test_os_ops_common.py +0 -0
  41. {testgres-1.13.7 → testgres-1.14.1}/tests/test_os_ops_local.py +0 -0
  42. {testgres-1.13.7 → testgres-1.14.1}/tests/test_os_ops_remote.py +0 -0
  43. {testgres-1.13.7 → testgres-1.14.1}/tests/test_raise_error.py +0 -0
  44. {testgres-1.13.7 → testgres-1.14.1}/tests/test_testgres_local.py +0 -0
  45. {testgres-1.13.7 → testgres-1.14.1}/tests/test_testgres_remote.py +0 -0
  46. {testgres-1.13.7 → testgres-1.14.1}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testgres
3
- Version: 1.13.7
3
+ Version: 1.14.1
4
4
  Summary: Testing utility for PostgreSQL and its extensions
5
5
  Author-email: Postgres Professional <testgres@postgrespro.ru>
6
6
  License: PostgreSQL
@@ -27,11 +27,10 @@ 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<3.0.0,>=2.1.0
30
+ Requires-Dist: testgres.os_ops<3.0.0,>=2.3.0
31
31
  Dynamic: license-file
32
32
 
33
- [![CI Status](https://img.shields.io/github/actions/workflow/status/postgrespro/testgres/.github/workflows/package-verification.yml?label=CI)](https://github.com/postgrespro/testgres/actions/workflows/package-verification.yml)
34
- [![codecov](https://codecov.io/gh/postgrespro/testgres/branch/master/graph/badge.svg)](https://codecov.io/gh/postgrespro/testgres)
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)
35
34
  [![PyPI package version](https://badge.fury.io/py/testgres.svg)](https://badge.fury.io/py/testgres)
36
35
  [![PyPI python versions](https://img.shields.io/pypi/pyversions/testgres)](https://pypi.org/project/testgres)
37
36
  [![PyPI downloads](https://img.shields.io/pypi/dm/testgres)](https://pypi.org/project/testgres)
@@ -1,5 +1,4 @@
1
- [![CI Status](https://img.shields.io/github/actions/workflow/status/postgrespro/testgres/.github/workflows/package-verification.yml?label=CI)](https://github.com/postgrespro/testgres/actions/workflows/package-verification.yml)
2
- [![codecov](https://codecov.io/gh/postgrespro/testgres/branch/master/graph/badge.svg)](https://codecov.io/gh/postgrespro/testgres)
1
+ [![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)
3
2
  [![PyPI package version](https://badge.fury.io/py/testgres.svg)](https://badge.fury.io/py/testgres)
4
3
  [![PyPI python versions](https://img.shields.io/pypi/pyversions/testgres)](https://pypi.org/project/testgres)
5
4
  [![PyPI downloads](https://img.shields.io/pypi/dm/testgres)](https://pypi.org/project/testgres)
@@ -65,7 +65,7 @@ dependencies = [
65
65
  "six>=1.9.0",
66
66
  "psutil",
67
67
  "packaging",
68
- "testgres.os_ops>=2.1.0,<3.0.0",
68
+ "testgres.os_ops>=2.3.0,<3.0.0",
69
69
  ]
70
70
 
71
71
  [project.urls]
@@ -56,7 +56,7 @@ from testgres.operations.os_ops import OsOperations, ConnectionParams
56
56
  from testgres.operations.local_ops import LocalOperations
57
57
  from testgres.operations.remote_ops import RemoteOperations
58
58
 
59
- __version__ = "1.13.7"
59
+ __version__ = "1.14.1"
60
60
 
61
61
  __all__ = [
62
62
  "get_new_node",
@@ -65,12 +65,12 @@ __all__ = [
65
65
  "TestgresConfig", "configure_testgres", "scoped_config", "push_config", "pop_config",
66
66
  "NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
67
67
  "TestgresException", "ExecUtilException", "QueryException",
68
- QueryTimeoutException.__name__,
68
+ "QueryTimeoutException",
69
69
  "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
70
70
  "XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
71
- NodeApp.__name__,
72
- PostgresNode.__name__,
73
- PortManager.__name__,
71
+ "NodeApp",
72
+ "PostgresNode",
73
+ "PortManager",
74
74
  "reserve_port", "release_port", "bound_ports", "get_bin_path", "get_pg_config", "get_pg_version",
75
75
  "First", "Any",
76
76
  "OsOperations", "LocalOperations", "RemoteOperations", "ConnectionParams"
@@ -31,6 +31,10 @@ PostgresNode(name='...', port=..., base_dir='...')
31
31
  [(3,)]
32
32
  """
33
33
  from .node import PostgresNode
34
+ from testgres.operations.remote_ops import ConnectionParams
35
+ from testgres.operations.remote_ops import RemoteOperations
36
+
37
+ import typing
34
38
 
35
39
 
36
40
  def get_new_node(name=None, base_dir=None, **kwargs):
@@ -42,11 +46,16 @@ def get_new_node(name=None, base_dir=None, **kwargs):
42
46
  return PostgresNode(name=name, base_dir=base_dir, **kwargs)
43
47
 
44
48
 
45
- def get_remote_node(name=None, conn_params=None):
49
+ def get_remote_node(name=None, conn_params: typing.Optional[ConnectionParams] = None):
46
50
  """
47
51
  Simply a wrapper around :class:`.PostgresNode` constructor for remote node.
48
52
  See :meth:`.PostgresNode.__init__` for details.
49
53
  For remote connection you can add the next parameter:
50
54
  conn_params = ConnectionParams(host='127.0.0.1', ssh_key=None, username=default_username())
51
55
  """
52
- return get_new_node(name=name, conn_params=conn_params)
56
+
57
+ if conn_params is None:
58
+ raise ValueError("Argument 'conn_params' is None.")
59
+
60
+ os_ops = RemoteOperations(conn_params)
61
+ return PostgresNode(name=name, os_ops=os_ops)
@@ -152,12 +152,7 @@ class NodeBackup(object):
152
152
  # Build a new PostgresNode
153
153
  assert self.original_node is not None
154
154
 
155
- if (hasattr(self.original_node, "clone_with_new_name_and_base_dir")):
156
- node = self.original_node.clone_with_new_name_and_base_dir(name=name, base_dir=base_dir)
157
- else:
158
- # For backward compatibility
159
- NodeClass = self.original_node.__class__
160
- node = NodeClass(name=name, base_dir=base_dir, conn_params=self.original_node.os_ops.conn_params)
155
+ node = self.original_node.clone_with_new_name_and_base_dir(name=name, base_dir=base_dir)
161
156
 
162
157
  assert node is not None
163
158
  assert type(node) is self.original_node.__class__
@@ -2,7 +2,6 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import logging
5
- import os
6
5
  import signal
7
6
  import subprocess
8
7
 
@@ -91,7 +90,6 @@ from . import utils
91
90
  from .utils import \
92
91
  PgVer, \
93
92
  eprint, \
94
- get_bin_path2, \
95
93
  get_pg_version2, \
96
94
  execute_utility2, \
97
95
  options_string, \
@@ -101,7 +99,6 @@ from .raise_error import RaiseError
101
99
 
102
100
  from .backup import NodeBackup
103
101
 
104
- from testgres.operations.os_ops import ConnectionParams
105
102
  from testgres.operations.os_ops import OsOperations
106
103
  from testgres.operations.local_ops import LocalOperations
107
104
 
@@ -164,21 +161,25 @@ class PostgresNode(object):
164
161
  _C_PM_PID__IS_NOT_DETECTED = -1
165
162
 
166
163
  _name: typing.Optional[str]
164
+ _host: str
167
165
  _port: typing.Optional[int]
166
+ _bin_dir: str
168
167
  _should_free_port: bool
169
168
  _os_ops: OsOperations
170
169
  _port_manager: typing.Optional[PortManager]
171
170
  _manually_started_pm_pid: typing.Optional[int]
172
171
 
173
- def __init__(self,
174
- name=None,
175
- base_dir=None,
176
- port: typing.Optional[int] = None,
177
- conn_params: typing.Optional[ConnectionParams] = None,
178
- bin_dir=None,
179
- prefix=None,
180
- os_ops: typing.Optional[OsOperations] = None,
181
- port_manager: typing.Optional[PortManager] = None):
172
+ def __init__(
173
+ self,
174
+ name=None,
175
+ base_dir=None,
176
+ port: typing.Optional[int] = None,
177
+ bin_dir: typing.Optional[str] = None,
178
+ prefix=None,
179
+ os_ops: typing.Optional[OsOperations] = None,
180
+ port_manager: typing.Optional[PortManager] = None,
181
+ host: typing.Optional[str] = None,
182
+ ):
182
183
  """
183
184
  PostgresNode constructor.
184
185
 
@@ -189,15 +190,13 @@ class PostgresNode(object):
189
190
  bin_dir: path to node's binary directory.
190
191
  os_ops: None or correct OS operation object.
191
192
  port_manager: None or correct port manager object.
193
+ host: None or valid address of node host.
192
194
  """
193
195
  assert port is None or type(port) is int
196
+ assert bin_dir is None or type(bin_dir) is str
194
197
  assert os_ops is None or isinstance(os_ops, OsOperations)
195
198
  assert port_manager is None or isinstance(port_manager, PortManager)
196
-
197
- if conn_params is not None:
198
- assert type(conn_params) is ConnectionParams
199
-
200
- raise InvalidOperationException("conn_params is deprecated, please use os_ops parameter instead.")
199
+ assert host is None or type(host) is str
201
200
 
202
201
  # private
203
202
  if os_ops is None:
@@ -210,9 +209,15 @@ class PostgresNode(object):
210
209
  assert self._os_ops is not None
211
210
  assert isinstance(self._os_ops, OsOperations)
212
211
 
213
- self._pg_version = PgVer(get_pg_version2(self._os_ops, bin_dir))
212
+ if bin_dir is not None:
213
+ self._bin_dir = bin_dir
214
+ else:
215
+ self._bin_dir = utils.get_bin_dir(self._os_ops)
216
+
217
+ assert type(self._bin_dir) is str
218
+
219
+ self._pg_version = PgVer(get_pg_version2(self._os_ops, self._bin_dir))
214
220
  self._base_dir = base_dir
215
- self._bin_dir = bin_dir
216
221
  self._prefix = prefix
217
222
  self._logger = None
218
223
  self._master = None
@@ -220,6 +225,16 @@ class PostgresNode(object):
220
225
  # basic
221
226
  self._name = name or generate_app_name()
222
227
 
228
+ if host is not None:
229
+ assert type(host) is str
230
+ self._host = host
231
+ else:
232
+ self._host = self._os_ops.host
233
+ assert type(self._host) is str
234
+
235
+ if self._host == "":
236
+ raise RuntimeError("PostgresNode host is empty.")
237
+
223
238
  if port is not None:
224
239
  assert type(port) is int
225
240
  assert port_manager is None
@@ -250,10 +265,6 @@ class PostgresNode(object):
250
265
  self.cleanup_on_bad_exit = testgres_config.node_cleanup_on_bad_exit
251
266
  self.shutdown_max_attempts = 3
252
267
 
253
- # NOTE: for compatibility
254
- self.utils_log_name = self.utils_log_file
255
- self.pg_log_name = self.pg_log_file
256
-
257
268
  # Node state
258
269
  self._manually_started_pm_pid = None
259
270
 
@@ -318,6 +329,7 @@ class PostgresNode(object):
318
329
  assert isinstance(self._port_manager, PortManager)
319
330
  assert self._os_ops is not None
320
331
  assert isinstance(self._os_ops, OsOperations)
332
+ assert type(self._host) is str
321
333
 
322
334
  node = PostgresNode(
323
335
  name=name,
@@ -325,7 +337,9 @@ class PostgresNode(object):
325
337
  bin_dir=self._bin_dir,
326
338
  prefix=self._prefix,
327
339
  os_ops=self._os_ops,
328
- port_manager=self._port_manager)
340
+ port_manager=self._port_manager,
341
+ host=self._host,
342
+ )
329
343
 
330
344
  return node
331
345
 
@@ -349,9 +363,9 @@ class PostgresNode(object):
349
363
 
350
364
  @property
351
365
  def host(self) -> str:
352
- assert self._os_ops is not None
353
- assert isinstance(self._os_ops, OsOperations)
354
- return self._os_ops.host
366
+ assert self._host is not None
367
+ assert type(self._host) is str
368
+ return self._host
355
369
 
356
370
  @property
357
371
  def port(self) -> int:
@@ -468,7 +482,7 @@ class PostgresNode(object):
468
482
  assert type(self.master) is PostgresNode
469
483
 
470
484
  # master should be on the same host
471
- assert self.master.host == self.host
485
+ assert self.master.host == self._host
472
486
 
473
487
  with self.master.connect() as con:
474
488
  for row in con.execute(sql, self.name):
@@ -486,18 +500,17 @@ class PostgresNode(object):
486
500
  @property
487
501
  def base_dir(self):
488
502
  if not self._base_dir:
489
- self._base_dir = self.os_ops.mkdtemp(prefix=self._prefix or TMP_NODE)
503
+ self._base_dir = self._os_ops.mkdtemp(prefix=self._prefix or TMP_NODE)
490
504
 
491
505
  # NOTE: it's safe to create a new dir
492
- if not self.os_ops.path_exists(self._base_dir):
493
- self.os_ops.makedirs(self._base_dir)
506
+ if not self._os_ops.path_exists(self._base_dir):
507
+ self._os_ops.makedirs(self._base_dir)
494
508
 
495
509
  return self._base_dir
496
510
 
497
511
  @property
498
- def bin_dir(self):
499
- if not self._bin_dir:
500
- self._bin_dir = os.path.dirname(get_bin_path2(self.os_ops, "pg_config"))
512
+ def bin_dir(self) -> str:
513
+ assert type(self._bin_dir) is str
501
514
  return self._bin_dir
502
515
 
503
516
  @property
@@ -509,8 +522,8 @@ class PostgresNode(object):
509
522
  assert type(path) is str
510
523
 
511
524
  # NOTE: it's safe to create a new dir
512
- if not self.os_ops.path_exists(path):
513
- self.os_ops.makedirs(path)
525
+ if not self._os_ops.path_exists(path):
526
+ self._os_ops.makedirs(path)
514
527
 
515
528
  return path
516
529
 
@@ -542,6 +555,16 @@ class PostgresNode(object):
542
555
  assert type(path) is str
543
556
  return path
544
557
 
558
+ # NOTE: for compatibility
559
+ @property
560
+ def utils_log_name(self) -> str:
561
+ return self.utils_log_file
562
+
563
+ # NOTE: for compatibility
564
+ @property
565
+ def pg_log_name(self) -> str:
566
+ return self.pg_log_file
567
+
545
568
  @property
546
569
  def version(self):
547
570
  """
@@ -587,7 +610,7 @@ class PostgresNode(object):
587
610
 
588
611
  ps_command = ['ps', '-o', 'pid=', '-p', str(node_pid)]
589
612
 
590
- ps_output = self.os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
613
+ ps_output = self._os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
591
614
  assert type(ps_output) is str
592
615
 
593
616
  if ps_output == "":
@@ -600,13 +623,13 @@ class PostgresNode(object):
600
623
 
601
624
  try:
602
625
  eprint('Force stopping node {0} with PID {1}'.format(self.name, node_pid))
603
- self.os_ops.kill(node_pid, signal.SIGKILL)
626
+ self._os_ops.kill(node_pid, signal.SIGKILL)
604
627
  except Exception:
605
628
  # The node has already stopped
606
629
  pass
607
630
 
608
631
  # Check that node stopped - print only column pid without headers
609
- ps_output = self.os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
632
+ ps_output = self._os_ops.exec_command(cmd=ps_command, shell=True, ignore_errors=True).decode('utf-8')
610
633
  assert type(ps_output) is str
611
634
 
612
635
  if ps_output == "":
@@ -669,7 +692,7 @@ class PostgresNode(object):
669
692
 
670
693
  signal_name = self._os_ops.build_path(self.data_dir, "standby.signal")
671
694
  assert type(signal_name) is str
672
- self.os_ops.touch(signal_name)
695
+ self._os_ops.touch(signal_name)
673
696
  else:
674
697
  line += "standby_mode=on\n"
675
698
 
@@ -730,10 +753,10 @@ class PostgresNode(object):
730
753
 
731
754
  for f, num_lines in files:
732
755
  # skip missing files
733
- if not self.os_ops.path_exists(f):
756
+ if not self._os_ops.path_exists(f):
734
757
  continue
735
758
 
736
- file_lines = self.os_ops.readlines(f, num_lines, binary=True, encoding=None)
759
+ file_lines = self._os_ops.readlines(f, num_lines, binary=True, encoding=None)
737
760
  lines = b''.join(file_lines)
738
761
 
739
762
  # fill list
@@ -800,14 +823,14 @@ class PostgresNode(object):
800
823
 
801
824
  # filter lines in hba file
802
825
  # get rid of comments and blank lines
803
- hba_conf_file = self.os_ops.readlines(hba_conf)
826
+ hba_conf_file = self._os_ops.readlines(hba_conf)
804
827
  lines = [
805
828
  s for s in hba_conf_file
806
829
  if len(s.strip()) > 0 and not s.startswith('#')
807
830
  ]
808
831
 
809
832
  # write filtered lines
810
- self.os_ops.write(hba_conf, lines, truncate=True)
833
+ self._os_ops.write(hba_conf, lines, truncate=True)
811
834
 
812
835
  # replication-related settings
813
836
  if allow_streaming:
@@ -819,7 +842,7 @@ class PostgresNode(object):
819
842
  # get auth methods
820
843
  auth_local = get_auth_method('local')
821
844
  auth_host = get_auth_method('host')
822
- subnet_base = ".".join(self.os_ops.host.split('.')[:-1] + ['0'])
845
+ subnet_base = ".".join(self._os_ops.host.split('.')[:-1] + ['0'])
823
846
 
824
847
  new_lines = [
825
848
  u"local\treplication\tall\t\t\t{}\n".format(auth_local),
@@ -832,15 +855,15 @@ class PostgresNode(object):
832
855
  ] # yapf: disable
833
856
 
834
857
  # write missing lines
835
- self.os_ops.write(hba_conf, new_lines)
858
+ self._os_ops.write(hba_conf, new_lines)
836
859
 
837
860
  # overwrite config file
838
- self.os_ops.write(postgres_conf, '', truncate=True)
861
+ self._os_ops.write(postgres_conf, '', truncate=True)
839
862
 
840
863
  self.append_conf(fsync=fsync,
841
864
  max_worker_processes=MAX_WORKER_PROCESSES,
842
865
  log_statement=log_statement,
843
- listen_addresses=self.host,
866
+ listen_addresses=self._host,
844
867
  port=self.port) # yapf:disable
845
868
 
846
869
  # common replication settings
@@ -915,7 +938,7 @@ class PostgresNode(object):
915
938
  conf_text = ''
916
939
  for line in lines:
917
940
  conf_text += text_type(line) + '\n'
918
- self.os_ops.write(config_name, conf_text)
941
+ self._os_ops.write(config_name, conf_text)
919
942
 
920
943
  return self
921
944
 
@@ -931,6 +954,12 @@ class PostgresNode(object):
931
954
  return x.node_status
932
955
 
933
956
  def _get_node_state(self) -> utils.PostgresNodeState:
957
+ if self._base_dir is None:
958
+ return utils.PostgresNodeState(
959
+ node_status=NodeStatus.Uninitialized,
960
+ pid=None,
961
+ )
962
+
934
963
  return utils.get_pg_node_state(
935
964
  self._os_ops,
936
965
  self.bin_dir,
@@ -948,7 +977,7 @@ class PostgresNode(object):
948
977
  _params += ["-D"] if self._pg_version >= PgVer('9.5') else []
949
978
  _params += [self.data_dir]
950
979
 
951
- data = execute_utility2(self.os_ops, _params, self.utils_log_file)
980
+ data = execute_utility2(self._os_ops, _params, self.utils_log_file)
952
981
 
953
982
  out_dict = {}
954
983
 
@@ -958,7 +987,14 @@ class PostgresNode(object):
958
987
 
959
988
  return out_dict
960
989
 
961
- def slow_start(self, replica=False, dbname='template1', username=None, max_attempts=0, exec_env=None):
990
+ def slow_start(
991
+ self,
992
+ replica: bool = False,
993
+ dbname: typing.Optional[str] = 'template1',
994
+ username: typing.Optional[str] = None,
995
+ max_attempts: int = 0,
996
+ exec_env: typing.Optional[typing.Dict[str, str]] = None,
997
+ ):
962
998
  """
963
999
  Starts the PostgreSQL instance and then polls the instance
964
1000
  until it reaches the expected state (primary or replica). The state is checked
@@ -971,6 +1007,8 @@ class PostgresNode(object):
971
1007
  If False, waits for the instance to be in primary mode. Default is False.
972
1008
  max_attempts:
973
1009
  """
1010
+ assert dbname is None or type(dbname) is str
1011
+ assert username is None or type(username) is str
974
1012
  assert exec_env is None or type(exec_env) is dict
975
1013
 
976
1014
  self.start(exec_env=exec_env)
@@ -992,7 +1030,7 @@ class PostgresNode(object):
992
1030
  self.poll_query_until(
993
1031
  query=query,
994
1032
  dbname=dbname,
995
- username=username or self.os_ops.username,
1033
+ username=username or self._os_ops.username,
996
1034
  suppress=suppressed_exceptions,
997
1035
  max_attempts=max_attempts,
998
1036
  )
@@ -1094,7 +1132,7 @@ class PostgresNode(object):
1094
1132
 
1095
1133
  def LOCAL__start_node():
1096
1134
  # 'error' will be None on Windows
1097
- _, _, error = execute_utility2(self.os_ops, _params, self.utils_log_file, verbose=True, exec_env=exec_env)
1135
+ _, _, error = execute_utility2(self._os_ops, _params, self.utils_log_file, verbose=True, exec_env=exec_env)
1098
1136
  assert error is None or type(error) is str
1099
1137
  if error and 'does not exist' in error:
1100
1138
  raise Exception(error)
@@ -1183,7 +1221,7 @@ class PostgresNode(object):
1183
1221
  "stop"
1184
1222
  ] + params # yapf: disable
1185
1223
 
1186
- execute_utility2(self.os_ops, _params, self.utils_log_file)
1224
+ execute_utility2(self._os_ops, _params, self.utils_log_file)
1187
1225
 
1188
1226
  self._manually_started_pm_pid = None
1189
1227
 
@@ -1207,7 +1245,10 @@ class PostgresNode(object):
1207
1245
 
1208
1246
  assert x.node_status == NodeStatus.Running
1209
1247
  assert type(x.pid) is int
1210
- sig = signal.SIGKILL if os.name != 'nt' else signal.SIGBREAK
1248
+ if self._os_ops.get_platform() == "win32":
1249
+ sig = 21 # signal.SIGBREAK
1250
+ else:
1251
+ sig = signal.SIGKILL
1211
1252
  if someone is None:
1212
1253
  self._os_ops.kill(x.pid, sig)
1213
1254
  self._manually_started_pm_pid = None
@@ -1240,7 +1281,7 @@ class PostgresNode(object):
1240
1281
  ] + params # yapf: disable
1241
1282
 
1242
1283
  try:
1243
- error_code, out, error = execute_utility2(self.os_ops, _params, self.utils_log_file, verbose=True)
1284
+ error_code, out, error = execute_utility2(self._os_ops, _params, self.utils_log_file, verbose=True)
1244
1285
  if error and 'could not start server' in error:
1245
1286
  raise ExecUtilException
1246
1287
  except ExecUtilException as e:
@@ -1269,7 +1310,7 @@ class PostgresNode(object):
1269
1310
  "reload"
1270
1311
  ] + params # yapf: disable
1271
1312
 
1272
- execute_utility2(self.os_ops, _params, self.utils_log_file)
1313
+ execute_utility2(self._os_ops, _params, self.utils_log_file)
1273
1314
 
1274
1315
  return self
1275
1316
 
@@ -1291,7 +1332,7 @@ class PostgresNode(object):
1291
1332
  "promote"
1292
1333
  ] # yapf: disable
1293
1334
 
1294
- execute_utility2(self.os_ops, _params, self.utils_log_file)
1335
+ execute_utility2(self._os_ops, _params, self.utils_log_file)
1295
1336
 
1296
1337
  # for versions below 10 `promote` is asynchronous so we need to wait
1297
1338
  # until it actually becomes writable
@@ -1326,7 +1367,7 @@ class PostgresNode(object):
1326
1367
  "-w" # wait
1327
1368
  ] + params # yapf: disable
1328
1369
 
1329
- return execute_utility2(self.os_ops, _params, self.utils_log_file)
1370
+ return execute_utility2(self._os_ops, _params, self.utils_log_file)
1330
1371
 
1331
1372
  def release_resources(self):
1332
1373
  """
@@ -1362,7 +1403,7 @@ class PostgresNode(object):
1362
1403
  else:
1363
1404
  rm_dir = self.data_dir # just data, save logs
1364
1405
 
1365
- self.os_ops.rmdirs(rm_dir, ignore_errors=False)
1406
+ self._os_ops.rmdirs(rm_dir, ignore_errors=False)
1366
1407
 
1367
1408
  if release_resources:
1368
1409
  self._release_resources()
@@ -1443,7 +1484,7 @@ class PostgresNode(object):
1443
1484
  raise Exception("Input data must be None or bytes.")
1444
1485
 
1445
1486
  if host is None:
1446
- host = self.host
1487
+ host = self._host
1447
1488
 
1448
1489
  if port is None:
1449
1490
  port = self.port
@@ -1457,7 +1498,7 @@ class PostgresNode(object):
1457
1498
  self._get_bin_path("psql"),
1458
1499
  "-p", str(port),
1459
1500
  "-h", host,
1460
- "-U", username or self.os_ops.username,
1501
+ "-U", username or self._os_ops.username,
1461
1502
  "-d", dbname or default_dbname(),
1462
1503
  "-X", # no .psqlrc
1463
1504
  "-A", # unaligned output
@@ -1477,7 +1518,7 @@ class PostgresNode(object):
1477
1518
  else:
1478
1519
  raise QueryException('Query or filename must be provided')
1479
1520
 
1480
- return self.os_ops.exec_command(
1521
+ return self._os_ops.exec_command(
1481
1522
  psql_params,
1482
1523
  verbose=True,
1483
1524
  input=input,
@@ -1560,9 +1601,9 @@ class PostgresNode(object):
1560
1601
  # Generate tmpfile or tmpdir
1561
1602
  def tmpfile():
1562
1603
  if format == DumpFormat.Directory:
1563
- fname = self.os_ops.mkdtemp(prefix=TMP_DUMP)
1604
+ fname = self._os_ops.mkdtemp(prefix=TMP_DUMP)
1564
1605
  else:
1565
- fname = self.os_ops.mkstemp(prefix=TMP_DUMP)
1606
+ fname = self._os_ops.mkstemp(prefix=TMP_DUMP)
1566
1607
  return fname
1567
1608
 
1568
1609
  filename = filename or tmpfile()
@@ -1570,9 +1611,9 @@ class PostgresNode(object):
1570
1611
  _params = [
1571
1612
  self._get_bin_path("pg_dump"),
1572
1613
  "-p", str(self.port),
1573
- "-h", self.host,
1614
+ "-h", self._host,
1574
1615
  "-f", filename,
1575
- "-U", username or self.os_ops.username,
1616
+ "-U", username or self._os_ops.username,
1576
1617
  "-d", dbname or default_dbname(),
1577
1618
  "-F", format.value
1578
1619
  ] # yapf: disable
@@ -1581,7 +1622,7 @@ class PostgresNode(object):
1581
1622
  if options:
1582
1623
  _params.extend(options)
1583
1624
 
1584
- execute_utility2(self.os_ops, _params, self.utils_log_file)
1625
+ execute_utility2(self._os_ops, _params, self.utils_log_file)
1585
1626
 
1586
1627
  return filename
1587
1628
 
@@ -1597,12 +1638,12 @@ class PostgresNode(object):
1597
1638
 
1598
1639
  # Set default arguments
1599
1640
  dbname = dbname or default_dbname()
1600
- username = username or self.os_ops.username
1641
+ username = username or self._os_ops.username
1601
1642
 
1602
1643
  _params = [
1603
1644
  self._get_bin_path("pg_restore"),
1604
1645
  "-p", str(self.port),
1605
- "-h", self.host,
1646
+ "-h", self._host,
1606
1647
  "-U", username,
1607
1648
  "-d", dbname,
1608
1649
  filename
@@ -1610,20 +1651,22 @@ class PostgresNode(object):
1610
1651
 
1611
1652
  # try pg_restore if dump is binary format, and psql if not
1612
1653
  try:
1613
- execute_utility2(self.os_ops, _params, self.utils_log_name)
1654
+ execute_utility2(self._os_ops, _params, self.utils_log_file)
1614
1655
  except ExecUtilException:
1615
1656
  self.psql(filename=filename, dbname=dbname, username=username)
1616
1657
 
1617
1658
  @method_decorator(positional_args_hack(['dbname', 'query']))
1618
- def poll_query_until(self,
1619
- query,
1620
- dbname=None,
1621
- username=None,
1622
- max_attempts=0,
1623
- sleep_time: typing.Union[int, float] = 1,
1624
- expected=True,
1625
- commit=True,
1626
- suppress=None):
1659
+ def poll_query_until(
1660
+ self,
1661
+ query,
1662
+ dbname: typing.Optional[str] = None,
1663
+ username: typing.Optional[str] = None,
1664
+ max_attempts: int = 0,
1665
+ sleep_time: typing.Union[int, float] = 1,
1666
+ expected: bool = True,
1667
+ commit: bool = True,
1668
+ suppress: typing.Optional[typing.Iterable[BaseException]] = None,
1669
+ ) -> None:
1627
1670
  """
1628
1671
  Run a query once per second until it returns 'expected'.
1629
1672
  Query should return a single value (1 row, 1 column).
@@ -1650,6 +1693,8 @@ class PostgresNode(object):
1650
1693
  assert max_attempts >= 0
1651
1694
  assert type(sleep_time) in [int, float]
1652
1695
  assert sleep_time > 0
1696
+ assert suppress is None or isinstance(suppress, typing.Iterable)
1697
+
1653
1698
  attempts = 0
1654
1699
  while max_attempts == 0 or attempts < max_attempts:
1655
1700
  try:
@@ -1874,14 +1919,14 @@ class PostgresNode(object):
1874
1919
  _params = [
1875
1920
  self._get_bin_path("pgbench"),
1876
1921
  "-p", str(self.port),
1877
- "-h", self.host,
1878
- "-U", username or self.os_ops.username
1922
+ "-h", self._host,
1923
+ "-U", username or self._os_ops.username
1879
1924
  ] + options # yapf: disable
1880
1925
 
1881
1926
  # should be the last one
1882
1927
  _params.append(dbname)
1883
1928
 
1884
- proc = self.os_ops.exec_command(_params, stdout=stdout, stderr=stderr, wait_exit=True, get_process=True)
1929
+ proc = self._os_ops.exec_command(_params, stdout=stdout, stderr=stderr, wait_exit=True, get_process=True)
1885
1930
 
1886
1931
  return proc
1887
1932
 
@@ -1947,8 +1992,8 @@ class PostgresNode(object):
1947
1992
  _params = [
1948
1993
  self._get_bin_path("pgbench"),
1949
1994
  "-p", str(self.port),
1950
- "-h", self.host,
1951
- "-U", username or self.os_ops.username
1995
+ "-h", self._host,
1996
+ "-U", username or self._os_ops.username
1952
1997
  ] + options # yapf: disable
1953
1998
 
1954
1999
  for key, value in iteritems(kwargs):
@@ -1965,7 +2010,7 @@ class PostgresNode(object):
1965
2010
  # should be the last one
1966
2011
  _params.append(dbname)
1967
2012
 
1968
- return execute_utility2(self.os_ops, _params, self.utils_log_file)
2013
+ return execute_utility2(self._os_ops, _params, self.utils_log_file)
1969
2014
 
1970
2015
  def connect(self,
1971
2016
  dbname=None,
@@ -2054,9 +2099,9 @@ class PostgresNode(object):
2054
2099
  assert isinstance(self._os_ops, OsOperations)
2055
2100
 
2056
2101
  # parse postgresql.auto.conf
2057
- path = self.os_ops.build_path(self.data_dir, config)
2102
+ path = self._os_ops.build_path(self.data_dir, config)
2058
2103
 
2059
- lines = self.os_ops.readlines(path)
2104
+ lines = self._os_ops.readlines(path)
2060
2105
  current_options = {}
2061
2106
  current_directives = []
2062
2107
  for line in lines:
@@ -2103,7 +2148,7 @@ class PostgresNode(object):
2103
2148
  for directive in current_directives:
2104
2149
  auto_conf += directive + "\n"
2105
2150
 
2106
- self.os_ops.write(path, auto_conf, truncate=True)
2151
+ self._os_ops.write(path, auto_conf, truncate=True)
2107
2152
 
2108
2153
  def upgrade_from(self, old_node, options=None, expect_error=False):
2109
2154
  """
@@ -2138,7 +2183,7 @@ class PostgresNode(object):
2138
2183
  ]
2139
2184
  upgrade_command += options
2140
2185
 
2141
- return self.os_ops.exec_command(upgrade_command, expect_error=expect_error)
2186
+ return self._os_ops.exec_command(upgrade_command, expect_error=expect_error)
2142
2187
 
2143
2188
  def _release_resources(self):
2144
2189
  self._free_port()
@@ -2162,12 +2207,9 @@ class PostgresNode(object):
2162
2207
  def _get_bin_path(self, filename):
2163
2208
  assert self._os_ops is not None
2164
2209
  assert isinstance(self._os_ops, OsOperations)
2210
+ assert type(self._bin_dir) is str
2165
2211
 
2166
- if self.bin_dir:
2167
- bin_path = self._os_ops.build_path(self.bin_dir, filename)
2168
- else:
2169
- bin_path = get_bin_path2(self.os_ops, filename)
2170
- return bin_path
2212
+ return self._os_ops.build_path(self._bin_dir, filename)
2171
2213
 
2172
2214
  @staticmethod
2173
2215
  def _escape_config_value(value):
@@ -3,9 +3,6 @@ from .node import LocalOperations
3
3
  from .node import PostgresNode
4
4
  from .node import PortManager
5
5
 
6
- import os
7
- import platform
8
- import tempfile
9
6
  import typing
10
7
 
11
8
 
@@ -16,7 +13,7 @@ T_LIST_STR = typing.List[str]
16
13
  class NodeApp:
17
14
  _test_path: str
18
15
  _os_ops: OsOperations
19
- _port_manager: PortManager
16
+ _port_manager: typing.Optional[PortManager]
20
17
  _nodes_to_cleanup: typing.List[PostgresNode]
21
18
 
22
19
  def __init__(
@@ -39,7 +36,7 @@ class NodeApp:
39
36
 
40
37
  if test_path is None:
41
38
  self._test_path = os_ops.cwd()
42
- elif os.path.isabs(test_path):
39
+ elif self._os_ops.is_abs_path(test_path):
43
40
  self._test_path = test_path
44
41
  else:
45
42
  self._test_path = os_ops.build_path(os_ops.cwd(), test_path)
@@ -60,7 +57,7 @@ class NodeApp:
60
57
  return self._os_ops
61
58
 
62
59
  @property
63
- def port_manager(self) -> PortManager:
60
+ def port_manager(self) -> typing.Optional[PortManager]:
64
61
  assert self._port_manager is None or isinstance(self._port_manager, PortManager)
65
62
  return self._port_manager
66
63
 
@@ -158,6 +155,8 @@ class NodeApp:
158
155
 
159
156
  # set major version
160
157
  pg_version_file = self._os_ops.read(self._os_ops.build_path(node.data_dir, 'PG_VERSION'))
158
+
159
+ # What is it ???
161
160
  node.major_version_str = str(pg_version_file.rstrip())
162
161
  node.major_version = float(node.major_version_str)
163
162
 
@@ -200,7 +199,7 @@ class NodeApp:
200
199
 
201
200
  # Define delayed propertyes
202
201
  if "unix_socket_directories" not in options.keys():
203
- options["unix_socket_directories"] = __class__._gettempdir_for_socket()
202
+ options["unix_socket_directories"] = self._gettempdir_for_socket()
204
203
 
205
204
  # Set config values
206
205
  node.set_auto_conf(options)
@@ -260,49 +259,50 @@ class NodeApp:
260
259
  return updated_params
261
260
  return __class__._paramlist_append(user_params, updated_params, param)
262
261
 
263
- @staticmethod
264
- def _gettempdir_for_socket() -> str:
265
- platform_system_name = platform.system().lower()
266
-
267
- if platform_system_name == "windows":
268
- return __class__._gettempdir()
269
-
270
- #
271
- # [2025-02-17] Hot fix.
272
- #
273
- # Let's use hard coded path as Postgres likes.
274
- #
275
- # pg_config_manual.h:
276
- #
277
- # #ifndef WIN32
278
- # #define DEFAULT_PGSOCKET_DIR "/tmp"
279
- # #else
280
- # #define DEFAULT_PGSOCKET_DIR ""
281
- # #endif
282
- #
283
- # On the altlinux-10 tempfile.gettempdir() may return
284
- # the path to "private" temp directiry - "/temp/.private/<username>/"
285
- #
286
- # But Postgres want to find a socket file in "/tmp" (see above).
287
- #
262
+ def _gettempdir_for_socket(self) -> str:
263
+ assert isinstance(self._os_ops, OsOperations)
288
264
 
289
- return "/tmp"
265
+ platform_name = self._os_ops.get_platform()
266
+
267
+ if platform_name == "linux":
268
+ #
269
+ # [2025-02-17] Hot fix.
270
+ #
271
+ # Let's use hard coded path as Postgres likes.
272
+ #
273
+ # pg_config_manual.h:
274
+ #
275
+ # #ifndef WIN32
276
+ # #define DEFAULT_PGSOCKET_DIR "/tmp"
277
+ # #else
278
+ # #define DEFAULT_PGSOCKET_DIR ""
279
+ # #endif
280
+ #
281
+ # On the altlinux-10 tempfile.gettempdir() may return
282
+ # the path to "private" temp directiry - "/temp/.private/<username>/"
283
+ #
284
+ # But Postgres want to find a socket file in "/tmp" (see above).
285
+ #
286
+ return "/tmp"
287
+
288
+ return self._gettempdir()
289
+
290
+ def _gettempdir(self) -> str:
291
+ assert isinstance(self._os_ops, OsOperations)
290
292
 
291
- @staticmethod
292
- def _gettempdir() -> str:
293
- v = tempfile.gettempdir()
293
+ v = self._os_ops.get_tempdir()
294
294
 
295
295
  #
296
296
  # Paranoid checks
297
297
  #
298
298
  if type(v) is str:
299
- __class__._raise_bugcheck("tempfile.gettempdir returned a value with type {0}.".format(type(v).__name__))
299
+ __class__._raise_bugcheck("os_ops.get_tempdir returned a value with type {0}.".format(type(v).__name__))
300
300
 
301
301
  if v == "":
302
- __class__._raise_bugcheck("tempfile.gettempdir returned an empty string.")
302
+ __class__._raise_bugcheck("os_ops.get_tempdir returned an empty string.")
303
303
 
304
- if not os.path.exists(v):
305
- __class__._raise_bugcheck("tempfile.gettempdir returned a not exist path [{0}].".format(v))
304
+ if not self._os_ops.path_exists(v):
305
+ __class__._raise_bugcheck("os_ops.get_tempdir returned a not exist path [{0}].".format(v))
306
306
 
307
307
  # OK
308
308
  return v
@@ -140,7 +140,7 @@ def get_bin_path2(os_ops: OsOperations, filename):
140
140
  assert isinstance(os_ops, OsOperations)
141
141
 
142
142
  # check if it's already absolute
143
- if os.path.isabs(filename):
143
+ if os_ops.is_abs_path(filename):
144
144
  return filename
145
145
  if isinstance(os_ops, RemoteOperations):
146
146
  pg_config = os.environ.get("PG_CONFIG_REMOTE") or os.environ.get("PG_CONFIG")
@@ -165,6 +165,33 @@ def get_bin_path2(os_ops: OsOperations, filename):
165
165
  return filename
166
166
 
167
167
 
168
+ def get_bin_dir(os_ops: OsOperations) -> str:
169
+ assert os_ops is not None
170
+ assert isinstance(os_ops, OsOperations)
171
+
172
+ if isinstance(os_ops, RemoteOperations):
173
+ pg_config = os.environ.get("PG_CONFIG_REMOTE") or os.environ.get("PG_CONFIG")
174
+ else:
175
+ # try PG_CONFIG - get from local machine
176
+ pg_config = os.environ.get("PG_CONFIG")
177
+
178
+ if pg_config:
179
+ bindir = get_pg_config(pg_config, os_ops)["BINDIR"]
180
+ return bindir
181
+
182
+ # try PG_BIN
183
+ pg_bin = os_ops.environ("PG_BIN")
184
+ if pg_bin:
185
+ return pg_bin
186
+
187
+ pg_config_path = os_ops.find_executable('pg_config')
188
+ if pg_config_path:
189
+ bindir = get_pg_config(pg_config_path)["BINDIR"]
190
+ return bindir
191
+
192
+ raise RuntimeError("BinDir is not detected.")
193
+
194
+
168
195
  def get_pg_config(pg_config_path=None, os_ops=None):
169
196
  """
170
197
  Return output of pg_config (provided that it is installed).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testgres
3
- Version: 1.13.7
3
+ Version: 1.14.1
4
4
  Summary: Testing utility for PostgreSQL and its extensions
5
5
  Author-email: Postgres Professional <testgres@postgrespro.ru>
6
6
  License: PostgreSQL
@@ -27,11 +27,10 @@ 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<3.0.0,>=2.1.0
30
+ Requires-Dist: testgres.os_ops<3.0.0,>=2.3.0
31
31
  Dynamic: license-file
32
32
 
33
- [![CI Status](https://img.shields.io/github/actions/workflow/status/postgrespro/testgres/.github/workflows/package-verification.yml?label=CI)](https://github.com/postgrespro/testgres/actions/workflows/package-verification.yml)
34
- [![codecov](https://codecov.io/gh/postgrespro/testgres/branch/master/graph/badge.svg)](https://codecov.io/gh/postgrespro/testgres)
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)
35
34
  [![PyPI package version](https://badge.fury.io/py/testgres.svg)](https://badge.fury.io/py/testgres)
36
35
  [![PyPI python versions](https://img.shields.io/pypi/pyversions/testgres)](https://pypi.org/project/testgres)
37
36
  [![PyPI downloads](https://img.shields.io/pypi/dm/testgres)](https://pypi.org/project/testgres)
@@ -32,6 +32,7 @@ testgres.egg-info/SOURCES.txt
32
32
  testgres.egg-info/dependency_links.txt
33
33
  testgres.egg-info/requires.txt
34
34
  testgres.egg-info/top_level.txt
35
+ tests/test_api.py
35
36
  tests/test_config.py
36
37
  tests/test_os_ops_common.py
37
38
  tests/test_os_ops_local.py
@@ -3,4 +3,4 @@ port-for>=0.4
3
3
  six>=1.9.0
4
4
  psutil
5
5
  packaging
6
- testgres.os_ops<3.0.0,>=2.1.0
6
+ testgres.os_ops<3.0.0,>=2.3.0
@@ -0,0 +1,30 @@
1
+ from src import api as testgres_api
2
+ from src.node import PostgresNode
3
+
4
+ from tests.helpers.global_data import OsOpsDescrs
5
+
6
+
7
+ class TestAPI:
8
+ def test_001__get_new_node(self):
9
+ C_NODE_NAME = "abc"
10
+
11
+ with testgres_api.get_new_node(name=C_NODE_NAME) as node:
12
+ assert type(node) is PostgresNode
13
+ assert node.name == C_NODE_NAME
14
+ node.init()
15
+ node.slow_start()
16
+ node.stop()
17
+ return
18
+
19
+ def test_001__get_remote_node(self):
20
+ C_NODE_NAME = "abc"
21
+
22
+ conn_params = OsOpsDescrs.sm_remote_conn_params
23
+
24
+ with testgres_api.get_remote_node(name=C_NODE_NAME, conn_params=conn_params) as node:
25
+ assert type(node) is PostgresNode
26
+ assert node.name == C_NODE_NAME
27
+ node.init()
28
+ node.slow_start()
29
+ node.stop()
30
+ return
@@ -94,8 +94,8 @@ class TestTestgresCommon:
94
94
 
95
95
  # Author: Mark G.
96
96
  assert v.major == 1
97
- assert v.minor == 13
98
- assert v.micro == 7
97
+ assert v.minor == 14
98
+ assert v.micro == 1
99
99
 
100
100
  assert str(v) == testgres_version
101
101
  return
@@ -132,7 +132,53 @@ class TestTestgresCommon:
132
132
  assert (isinstance(node.version, PgVer))
133
133
  assert (node.version == PgVer(version))
134
134
 
135
+ def test_node_constructor__default(self):
136
+ node = PostgresNode()
137
+ assert node._os_ops is not None
138
+ assert isinstance(node._os_ops, OsOperations)
139
+ assert node._port_manager is not None
140
+ assert isinstance(node._port_manager, PortManager)
141
+ assert node._name is not None
142
+ assert type(node._name) is str
143
+ assert node._name != ""
144
+ assert node._base_dir is None
145
+ return
146
+
147
+ def test_node_constructor__host(self):
148
+ C_HOST = "AbCdE"
149
+
150
+ unique_id = uuid.uuid4().hex
151
+
152
+ with PostgresNode(host=C_HOST) as node:
153
+ assert node._host == C_HOST
154
+ assert node.host == C_HOST
155
+ assert isinstance(node.os_ops, OsOperations)
156
+
157
+ tmpdir = node.os_ops.get_tempdir()
158
+ nodedir2 = node.os_ops.build_path(tmpdir, "node2--" + unique_id)
159
+
160
+ C_NODE2_NAME = "node2"
161
+
162
+ with node.clone_with_new_name_and_base_dir(
163
+ name=C_NODE2_NAME,
164
+ base_dir=nodedir2,
165
+ ) as node2:
166
+ assert node2 is not None
167
+ assert node2 is not node
168
+
169
+ assert node2._host == C_HOST
170
+ assert node2.host == C_HOST
171
+
172
+ assert node2._name == C_NODE2_NAME
173
+ assert node2._base_dir == nodedir2
174
+ assert node2._port != node._port
175
+ assert node2._os_ops is node._os_ops
176
+ assert node2._port_manager is node._port_manager
177
+ return
178
+
135
179
  def test_node_repr(self, node_svc: PostgresNodeService):
180
+ assert isinstance(node_svc, PostgresNodeService)
181
+
136
182
  with __class__.helper__get_node(node_svc).init() as node:
137
183
  pattern = r"PostgresNode\(name='.+', port=.+, base_dir='.+'\)"
138
184
  assert re.match(pattern, str(node)) is not None
@@ -2422,13 +2468,14 @@ where c.relname=%s;"""
2422
2468
  class tag_rmdirs_protector:
2423
2469
  _os_ops: OsOperations
2424
2470
  _cwd: str
2425
- _old_rmdirs: any
2471
+ _old_rmdirs: typing.Optional[typing.Callable]
2426
2472
  _cwd: str
2427
2473
 
2428
2474
  def __init__(self, os_ops: OsOperations):
2429
2475
  self._os_ops = os_ops
2430
2476
  self._cwd = os.path.abspath(os_ops.cwd())
2431
2477
  self._old_rmdirs = os_ops.rmdirs
2478
+ return
2432
2479
 
2433
2480
  def __enter__(self):
2434
2481
  assert self._os_ops.rmdirs == self._old_rmdirs
@@ -2437,6 +2484,7 @@ where c.relname=%s;"""
2437
2484
 
2438
2485
  def __exit__(self, exc_type, exc_val, exc_tb):
2439
2486
  assert self._os_ops.rmdirs == self.proxy__rmdirs
2487
+ assert isinstance(self._old_rmdirs, typing.Callable)
2440
2488
  self._os_ops.rmdirs = self._old_rmdirs
2441
2489
  return False
2442
2490
 
@@ -2465,7 +2513,7 @@ where c.relname=%s;"""
2465
2513
  assert node_app.os_ops is os_ops
2466
2514
 
2467
2515
  with pytest.raises(expected_exception=BaseException) as x:
2468
- node_app.make_empty(base_dir=None)
2516
+ node_app.make_empty(base_dir=None) # type: ignore
2469
2517
 
2470
2518
  if type(x.value) is AssertionError:
2471
2519
  pass
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes