Content-Length: 35255 | pFad | http://github.com/postgrespro/testgres/pull/278.diff
thub.com
diff --git a/testgres/__init__.py b/testgres/__init__.py
index 339ae62..555784b 100644
--- a/testgres/__init__.py
+++ b/testgres/__init__.py
@@ -33,8 +33,9 @@
ProcessType, \
DumpFormat
-from .node import PostgresNode, NodeApp
+from .node import PostgresNode
from .node import PortManager
+from .node_app import NodeApp
from .utils import \
reserve_port, \
@@ -62,8 +63,9 @@
"NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
"TestgresException", "ExecUtilException", "QueryException", "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
"XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
- "PostgresNode", "NodeApp",
- "PortManager",
+ NodeApp.__name__,
+ PostgresNode.__name__,
+ PortManager.__name__,
"reserve_port", "release_port", "bound_ports", "get_bin_path", "get_pg_config", "get_pg_version",
"First", "Any",
"OsOperations", "LocalOperations", "RemoteOperations", "ConnectionParams"
diff --git a/testgres/node.py b/testgres/node.py
index 208846a..60d9e30 100644
--- a/testgres/node.py
+++ b/testgres/node.py
@@ -7,8 +7,6 @@
import signal
import subprocess
import threading
-import tempfile
-import platform
from queue import Queue
import time
@@ -692,9 +690,6 @@ def _try_shutdown(self, max_attempts, with_force=False):
ps_output,
ps_command)
- def _release_resources(self):
- self.free_port()
-
@staticmethod
def _throw_bugcheck__unexpected_result_of_ps(result, cmd):
assert type(result) == str # noqa: E721
@@ -1326,25 +1321,18 @@ def pg_ctl(self, params):
return execute_utility2(self.os_ops, _params, self.utils_log_file)
+ def release_resources(self):
+ """
+ Release resorces owned by this node.
+ """
+ return self._release_resources()
+
def free_port(self):
"""
Reclaim port owned by this node.
NOTE: this method does not release manually defined port but reset it.
"""
- assert type(self._should_free_port) == bool # noqa: E721
-
- if not self._should_free_port:
- self._port = None
- else:
- assert type(self._port) == int # noqa: E721
-
- assert self._port_manager is not None
- assert isinstance(self._port_manager, PortManager)
-
- port = self._port
- self._should_free_port = False
- self._port = None
- self._port_manager.release_port(port)
+ return self._free_port()
def cleanup(self, max_attempts=3, full=False, release_resources=False):
"""
@@ -2158,6 +2146,25 @@ def upgrade_from(self, old_node, options=None, expect_error=False):
return self.os_ops.exec_command(upgrade_command, expect_error=expect_error)
+ def _release_resources(self):
+ self._free_port()
+
+ def _free_port(self):
+ assert type(self._should_free_port) == bool # noqa: E721
+
+ if not self._should_free_port:
+ self._port = None
+ else:
+ assert type(self._port) == int # noqa: E721
+
+ assert self._port_manager is not None
+ assert isinstance(self._port_manager, PortManager)
+
+ port = self._port
+ self._should_free_port = False
+ self._port = None
+ self._port_manager.release_port(port)
+
def _get_bin_path(self, filename):
assert self._os_ops is not None
assert isinstance(self._os_ops, OsOperations)
@@ -2352,164 +2359,3 @@ def delect_port_conflict(log_reader: PostgresNodeLogReader) -> bool:
return True
return False
-
-
-class NodeApp:
-
- def __init__(self, test_path=None, nodes_to_cleanup=None, os_ops=None):
- assert os_ops is None or isinstance(os_ops, OsOperations)
-
- if os_ops is None:
- os_ops = LocalOperations.get_single_instance()
-
- assert isinstance(os_ops, OsOperations)
-
- if test_path:
- if os.path.isabs(test_path):
- self.test_path = test_path
- else:
- self.test_path = os_ops.build_path(os_ops.cwd(), test_path)
- else:
- self.test_path = os_ops.cwd()
- self.nodes_to_cleanup = nodes_to_cleanup if nodes_to_cleanup else []
- self.os_ops = os_ops
-
- def make_empty(
- self,
- base_dir=None,
- port=None,
- bin_dir=None):
- real_base_dir = self.os_ops.build_path(self.test_path, base_dir)
- self.os_ops.rmdirs(real_base_dir, ignore_errors=True)
- self.os_ops.makedirs(real_base_dir)
-
- node = PostgresNode(base_dir=real_base_dir, port=port, bin_dir=bin_dir)
- self.nodes_to_cleanup.append(node)
-
- return node
-
- def make_simple(
- self,
- base_dir=None,
- port=None,
- set_replication=False,
- ptrack_enable=False,
- initdb_params=[],
- pg_options={},
- checksum=True,
- bin_dir=None):
- assert type(pg_options) == dict # noqa: E721
-
- if checksum and '--data-checksums' not in initdb_params:
- initdb_params.append('--data-checksums')
- node = self.make_empty(base_dir, port, bin_dir=bin_dir)
- node.init(
- initdb_params=initdb_params, allow_streaming=set_replication)
-
- # set major version
- pg_version_file = self.os_ops.read(self.os_ops.build_path(node.data_dir, 'PG_VERSION'))
- node.major_version_str = str(pg_version_file.rstrip())
- node.major_version = float(node.major_version_str)
-
- # Set default parameters
- options = {
- 'max_connections': 100,
- 'shared_buffers': '10MB',
- 'fsync': 'off',
- 'wal_level': 'logical',
- 'hot_standby': 'off',
- 'log_line_prefix': '%t [%p]: [%l-1] ',
- 'log_statement': 'none',
- 'log_duration': 'on',
- 'log_min_duration_statement': 0,
- 'log_connections': 'on',
- 'log_disconnections': 'on',
- 'restart_after_crash': 'off',
- 'autovacuum': 'off',
- # unix_socket_directories will be defined later
- }
-
- # Allow replication in pg_hba.conf
- if set_replication:
- options['max_wal_senders'] = 10
-
- if ptrack_enable:
- options['ptrack.map_size'] = '1'
- options['shared_preload_libraries'] = 'ptrack'
-
- if node.major_version >= 13:
- options['wal_keep_size'] = '200MB'
- else:
- options['wal_keep_segments'] = '12'
-
- # Apply given parameters
- for option_name, option_value in iteritems(pg_options):
- options[option_name] = option_value
-
- # Define delayed propertyes
- if not ("unix_socket_directories" in options.keys()):
- options["unix_socket_directories"] = __class__._gettempdir_for_socket()
-
- # Set config values
- node.set_auto_conf(options)
-
- # kludge for testgres
- # https://github.com/postgrespro/testgres/issues/54
- # for PG >= 13 remove 'wal_keep_segments' parameter
- if node.major_version >= 13:
- node.set_auto_conf({}, 'postgresql.conf', ['wal_keep_segments'])
-
- return node
-
- @staticmethod
- def _gettempdir_for_socket():
- platform_system_name = platform.system().lower()
-
- if platform_system_name == "windows":
- return __class__._gettempdir()
-
- #
- # [2025-02-17] Hot fix.
- #
- # Let's use hard coded path as Postgres likes.
- #
- # pg_config_manual.h:
- #
- # #ifndef WIN32
- # #define DEFAULT_PGSOCKET_DIR "/tmp"
- # #else
- # #define DEFAULT_PGSOCKET_DIR ""
- # #endif
- #
- # On the altlinux-10 tempfile.gettempdir() may return
- # the path to "private" temp directiry - "/temp/.private//"
- #
- # But Postgres want to find a socket file in "/tmp" (see above).
- #
-
- return "/tmp"
-
- @staticmethod
- def _gettempdir():
- v = tempfile.gettempdir()
-
- #
- # Paranoid checks
- #
- if type(v) != str: # noqa: E721
- __class__._raise_bugcheck("tempfile.gettempdir returned a value with type {0}.".format(type(v).__name__))
-
- if v == "":
- __class__._raise_bugcheck("tempfile.gettempdir returned an empty string.")
-
- if not os.path.exists(v):
- __class__._raise_bugcheck("tempfile.gettempdir returned a not exist path [{0}].".format(v))
-
- # OK
- return v
-
- @staticmethod
- def _raise_bugcheck(msg):
- assert type(msg) == str # noqa: E721
- assert msg != ""
- raise Exception("[BUG CHECK] " + msg)
diff --git a/testgres/node_app.py b/testgres/node_app.py
new file mode 100644
index 0000000..6e7b7c4
--- /dev/null
+++ b/testgres/node_app.py
@@ -0,0 +1,317 @@
+from .node import OsOperations
+from .node import LocalOperations
+from .node import PostgresNode
+from .node import PortManager
+
+import os
+import platform
+import tempfile
+import typing
+
+
+T_DICT_STR_STR = typing.Dict[str, str]
+T_LIST_STR = typing.List[str]
+
+
+class NodeApp:
+ _test_path: str
+ _os_ops: OsOperations
+ _port_manager: PortManager
+ _nodes_to_cleanup: typing.List[PostgresNode]
+
+ def __init__(
+ self,
+ test_path: typing.Optional[str] = None,
+ nodes_to_cleanup: typing.Optional[list] = None,
+ os_ops: typing.Optional[OsOperations] = None,
+ port_manager: typing.Optional[PortManager] = None,
+ ):
+ assert test_path is None or type(test_path) == str # noqa: E721
+ assert os_ops is None or isinstance(os_ops, OsOperations)
+ assert port_manager is None or isinstance(port_manager, PortManager)
+
+ if os_ops is None:
+ os_ops = LocalOperations.get_single_instance()
+
+ assert isinstance(os_ops, OsOperations)
+ self._os_ops = os_ops
+ self._port_manager = port_manager
+
+ if test_path is None:
+ self._test_path = os_ops.cwd()
+ elif os.path.isabs(test_path):
+ self._test_path = test_path
+ else:
+ self._test_path = os_ops.build_path(os_ops.cwd(), test_path)
+
+ if nodes_to_cleanup is None:
+ self._nodes_to_cleanup = []
+ else:
+ self._nodes_to_cleanup = nodes_to_cleanup
+
+ @property
+ def test_path(self) -> str:
+ assert type(self._test_path) == str # noqa: E721
+ return self._test_path
+
+ @property
+ def os_ops(self) -> OsOperations:
+ assert isinstance(self._os_ops, OsOperations)
+ return self._os_ops
+
+ @property
+ def port_manager(self) -> PortManager:
+ assert self._port_manager is None or isinstance(self._port_manager, PortManager)
+ return self._port_manager
+
+ @property
+ def nodes_to_cleanup(self) -> typing.List[PostgresNode]:
+ assert type(self._nodes_to_cleanup) == list # noqa: E721
+ return self._nodes_to_cleanup
+
+ def make_empty(
+ self,
+ base_dir: str,
+ port: typing.Optional[int] = None,
+ bin_dir: typing.Optional[str] = None
+ ) -> PostgresNode:
+ assert type(base_dir) == str # noqa: E721
+ assert port is None or type(port) == int # noqa: E721
+ assert bin_dir is None or type(bin_dir) == str # noqa: E721
+
+ assert isinstance(self._os_ops, OsOperations)
+ assert type(self._test_path) == str # noqa: E721
+
+ if base_dir is None:
+ raise ValueError("Argument 'base_dir' is not defined.")
+
+ if base_dir == "":
+ raise ValueError("Argument 'base_dir' is empty.")
+
+ real_base_dir = self._os_ops.build_path(self._test_path, base_dir)
+ self._os_ops.rmdirs(real_base_dir, ignore_errors=True)
+ self._os_ops.makedirs(real_base_dir)
+
+ port_manager: PortManager = None
+
+ if port is None:
+ port_manager = self._port_manager
+
+ node = PostgresNode(
+ base_dir=real_base_dir,
+ port=port,
+ bin_dir=bin_dir,
+ os_ops=self._os_ops,
+ port_manager=port_manager
+ )
+
+ try:
+ assert type(self._nodes_to_cleanup) == list # noqa: E721
+ self._nodes_to_cleanup.append(node)
+ except: # noqa: E722
+ node.cleanup(release_resources=True)
+ raise
+
+ return node
+
+ def make_simple(
+ self,
+ base_dir: str,
+ port: typing.Optional[int] = None,
+ set_replication: bool = False,
+ ptrack_enable: bool = False,
+ initdb_params: typing.Optional[T_LIST_STR] = None,
+ pg_options: typing.Optional[T_DICT_STR_STR] = None,
+ checksum: bool = True,
+ bin_dir: typing.Optional[str] = None
+ ) -> PostgresNode:
+ assert type(base_dir) == str # noqa: E721
+ assert port is None or type(port) == int # noqa: E721
+ assert type(set_replication) == bool # noqa: E721
+ assert type(ptrack_enable) == bool # noqa: E721
+ assert initdb_params is None or type(initdb_params) == list # noqa: E721
+ assert pg_options is None or type(pg_options) == dict # noqa: E721
+ assert type(checksum) == bool # noqa: E721
+ assert bin_dir is None or type(bin_dir) == str # noqa: E721
+
+ node = self.make_empty(
+ base_dir,
+ port,
+ bin_dir=bin_dir
+ )
+
+ final_initdb_params = initdb_params
+
+ if checksum:
+ final_initdb_params = __class__._paramlist_append_is_not_exist(
+ initdb_params,
+ final_initdb_params,
+ '--data-checksums'
+ )
+ assert final_initdb_params is not None
+ assert '--data-checksums' in final_initdb_params
+
+ node.init(
+ initdb_params=final_initdb_params,
+ allow_streaming=set_replication
+ )
+
+ # set major version
+ pg_version_file = self._os_ops.read(self._os_ops.build_path(node.data_dir, 'PG_VERSION'))
+ node.major_version_str = str(pg_version_file.rstrip())
+ node.major_version = float(node.major_version_str)
+
+ # Set default parameters
+ options = {
+ 'max_connections': 100,
+ 'shared_buffers': '10MB',
+ 'fsync': 'off',
+ 'wal_level': 'logical',
+ 'hot_standby': 'off',
+ 'log_line_prefix': '%t [%p]: [%l-1] ',
+ 'log_statement': 'none',
+ 'log_duration': 'on',
+ 'log_min_duration_statement': 0,
+ 'log_connections': 'on',
+ 'log_disconnections': 'on',
+ 'restart_after_crash': 'off',
+ 'autovacuum': 'off',
+ # unix_socket_directories will be defined later
+ }
+
+ # Allow replication in pg_hba.conf
+ if set_replication:
+ options['max_wal_senders'] = 10
+
+ if ptrack_enable:
+ options['ptrack.map_size'] = '1'
+ options['shared_preload_libraries'] = 'ptrack'
+
+ if node.major_version >= 13:
+ options['wal_keep_size'] = '200MB'
+ else:
+ options['wal_keep_segments'] = '12'
+
+ # Apply given parameters
+ if pg_options is not None:
+ assert type(pg_options) == dict # noqa: E721
+ for option_name, option_value in pg_options.items():
+ options[option_name] = option_value
+
+ # Define delayed propertyes
+ if not ("unix_socket_directories" in options.keys()):
+ options["unix_socket_directories"] = __class__._gettempdir_for_socket()
+
+ # Set config values
+ node.set_auto_conf(options)
+
+ # kludge for testgres
+ # https://github.com/postgrespro/testgres/issues/54
+ # for PG >= 13 remove 'wal_keep_segments' parameter
+ if node.major_version >= 13:
+ node.set_auto_conf({}, 'postgresql.conf', ['wal_keep_segments'])
+
+ return node
+
+ @staticmethod
+ def _paramlist_has_param(
+ params: typing.Optional[T_LIST_STR],
+ param: str
+ ) -> bool:
+ assert type(param) == str # noqa: E721
+
+ if params is None:
+ return False
+
+ assert type(params) == list # noqa: E721
+
+ if param in params:
+ return True
+
+ return False
+
+ @staticmethod
+ def _paramlist_append(
+ user_params: typing.Optional[T_LIST_STR],
+ updated_params: typing.Optional[T_LIST_STR],
+ param: str,
+ ) -> T_LIST_STR:
+ assert user_params is None or type(user_params) == list # noqa: E721
+ assert updated_params is None or type(updated_params) == list # noqa: E721
+ assert type(param) == str # noqa: E721
+
+ if updated_params is None:
+ if user_params is None:
+ return [param]
+
+ return [*user_params, param]
+
+ assert updated_params is not None
+ if updated_params is user_params:
+ return [*user_params, param]
+
+ updated_params.append(param)
+ return updated_params
+
+ @staticmethod
+ def _paramlist_append_is_not_exist(
+ user_params: typing.Optional[T_LIST_STR],
+ updated_params: typing.Optional[T_LIST_STR],
+ param: str,
+ ) -> typing.Optional[T_LIST_STR]:
+ if __class__._paramlist_has_param(updated_params, param):
+ return updated_params
+ return __class__._paramlist_append(user_params, updated_params, param)
+
+ @staticmethod
+ def _gettempdir_for_socket() -> str:
+ platform_system_name = platform.system().lower()
+
+ if platform_system_name == "windows":
+ return __class__._gettempdir()
+
+ #
+ # [2025-02-17] Hot fix.
+ #
+ # Let's use hard coded path as Postgres likes.
+ #
+ # pg_config_manual.h:
+ #
+ # #ifndef WIN32
+ # #define DEFAULT_PGSOCKET_DIR "/tmp"
+ # #else
+ # #define DEFAULT_PGSOCKET_DIR ""
+ # #endif
+ #
+ # On the altlinux-10 tempfile.gettempdir() may return
+ # the path to "private" temp directiry - "/temp/.private//"
+ #
+ # But Postgres want to find a socket file in "/tmp" (see above).
+ #
+
+ return "/tmp"
+
+ @staticmethod
+ def _gettempdir() -> str:
+ v = tempfile.gettempdir()
+
+ #
+ # Paranoid checks
+ #
+ if type(v) != str: # noqa: E721
+ __class__._raise_bugcheck("tempfile.gettempdir returned a value with type {0}.".format(type(v).__name__))
+
+ if v == "":
+ __class__._raise_bugcheck("tempfile.gettempdir returned an empty string.")
+
+ if not os.path.exists(v):
+ __class__._raise_bugcheck("tempfile.gettempdir returned a not exist path [{0}].".format(v))
+
+ # OK
+ return v
+
+ @staticmethod
+ def _raise_bugcheck(msg):
+ assert type(msg) == str # noqa: E721
+ assert msg != ""
+ raise Exception("[BUG CHECK] " + msg)
diff --git a/testgres/operations/local_ops.py b/testgres/operations/local_ops.py
index 103ee4d..99d8e32 100644
--- a/testgres/operations/local_ops.py
+++ b/testgres/operations/local_ops.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import getpass
import logging
import os
@@ -11,6 +13,7 @@
import psutil
import typing
import threading
+import copy
from ..exceptions import ExecUtilException
from ..exceptions import InvalidOperationException
@@ -29,13 +32,26 @@
class LocalOperations(OsOperations):
+ sm_dummy_conn_params = ConnectionParams()
sm_single_instance: OsOperations = None
sm_single_instance_guard = threading.Lock()
+ # TODO: make it read-only
+ conn_params: ConnectionParams
+ host: str
+ ssh_key: typing.Optional[str]
+ remote: bool
+ username: str
+
def __init__(self, conn_params=None):
+ super().__init__()
+
+ if conn_params is __class__.sm_dummy_conn_params:
+ return
+
if conn_params is None:
conn_params = ConnectionParams()
- super(LocalOperations, self).__init__(conn_params.username)
+
self.conn_params = conn_params
self.host = conn_params.host
self.ssh_key = None
@@ -58,6 +74,15 @@ def get_single_instance() -> OsOperations:
assert type(__class__.sm_single_instance) == __class__ # noqa: E721
return __class__.sm_single_instance
+ def create_clone(self) -> LocalOperations:
+ clone = __class__(__class__.sm_dummy_conn_params)
+ clone.conn_params = copy.copy(self.conn_params)
+ clone.host = self.host
+ clone.ssh_key = self.ssh_key
+ clone.remote = self.remote
+ clone.username = self.username
+ return clone
+
@staticmethod
def _process_output(encoding, temp_file_path):
"""Process the output of a command from a temporary file."""
diff --git a/testgres/operations/os_ops.py b/testgres/operations/os_ops.py
index 7cebc8b..4642226 100644
--- a/testgres/operations/os_ops.py
+++ b/testgres/operations/os_ops.py
@@ -1,4 +1,5 @@
-import getpass
+from __future__ import annotations
+
import locale
@@ -17,9 +18,11 @@ def get_default_encoding():
class OsOperations:
- def __init__(self, username=None):
- self.ssh_key = None
- self.username = username or getpass.getuser()
+ def __init__(self):
+ pass
+
+ def create_clone(self) -> OsOperations:
+ raise NotImplementedError()
# Command execution
def exec_command(self, cmd, **kwargs):
diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py
index 8b973a1..15d78b1 100644
--- a/testgres/operations/remote_ops.py
+++ b/testgres/operations/remote_ops.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
import getpass
import os
import posixpath
@@ -7,6 +9,7 @@
import io
import logging
import typing
+import copy
from ..exceptions import ExecUtilException
from ..exceptions import InvalidOperationException
@@ -42,11 +45,29 @@ def cmdline(self):
class RemoteOperations(OsOperations):
+ sm_dummy_conn_params = ConnectionParams()
+
+ conn_params: ConnectionParams
+ host: str
+ port: int
+ ssh_key: str
+ ssh_args: list
+ remote: bool
+ username: str
+ ssh_dest: str
+
def __init__(self, conn_params: ConnectionParams):
if not platform.system().lower() == "linux":
raise EnvironmentError("Remote operations are supported only on Linux!")
- super().__init__(conn_params.username)
+ if conn_params is None:
+ raise ValueError("Argument 'conn_params' is None.")
+
+ super().__init__()
+
+ if conn_params is __class__.sm_dummy_conn_params:
+ return
+
self.conn_params = conn_params
self.host = conn_params.host
self.port = conn_params.port
@@ -63,6 +84,18 @@ def __init__(self, conn_params: ConnectionParams):
def __enter__(self):
return self
+ def create_clone(self) -> RemoteOperations:
+ clone = __class__(__class__.sm_dummy_conn_params)
+ clone.conn_params = copy.copy(self.conn_params)
+ clone.host = self.host
+ clone.port = self.port
+ clone.ssh_key = self.ssh_key
+ clone.ssh_args = copy.copy(self.ssh_args)
+ clone.remote = self.remote
+ clone.username = self.username
+ clone.ssh_dest = self.ssh_dest
+ return clone
+
def exec_command(
self, cmd, wait_exit=False, verbose=False, expect_error=False,
encoding=None, shell=True, text=False, input=None, stdin=None, stdout=None,
diff --git a/tests/test_os_ops_common.py b/tests/test_os_ops_common.py
index 5b135a4..d3c8575 100644
--- a/tests/test_os_ops_common.py
+++ b/tests/test_os_ops_common.py
@@ -37,6 +37,13 @@ def os_ops(self, request: pytest.FixtureRequest) -> OsOperations:
assert isinstance(request.param, OsOperations)
return request.param
+ def test_create_clone(self, os_ops: OsOperations):
+ assert isinstance(os_ops, OsOperations)
+ clone = os_ops.create_clone()
+ assert clone is not None
+ assert clone is not os_ops
+ assert type(clone) == type(os_ops) # noqa: E721
+
def test_exec_command_success(self, os_ops: OsOperations):
"""
Test exec_command for successful command execution.
diff --git a/tests/test_testgres_common.py b/tests/test_testgres_common.py
index 3f4a471..a7ddbb2 100644
--- a/tests/test_testgres_common.py
+++ b/tests/test_testgres_common.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from .helpers.global_data import PostgresNodeService
from .helpers.global_data import PostgresNodeServices
from .helpers.global_data import OsOperations
@@ -13,6 +15,7 @@
from testgres import ProcessType
from testgres import NodeStatus
from testgres import IsolationLevel
+from testgres import NodeApp
# New name prevents to collect test-functions in TestgresException and fixes
# the problem with pytest warning.
@@ -1584,6 +1587,251 @@ def test_node__no_port_manager(self, node_svc: PostgresNodeService):
finally:
node_svc.port_manager.release_port(port)
+ class tag_rmdirs_protector:
+ _os_ops: OsOperations
+ _cwd: str
+ _old_rmdirs: any
+ _cwd: str
+
+ def __init__(self, os_ops: OsOperations):
+ self._os_ops = os_ops
+ self._cwd = os.path.abspath(os_ops.cwd())
+ self._old_rmdirs = os_ops.rmdirs
+
+ def __enter__(self):
+ assert self._os_ops.rmdirs == self._old_rmdirs
+ self._os_ops.rmdirs = self.proxy__rmdirs
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ assert self._os_ops.rmdirs == self.proxy__rmdirs
+ self._os_ops.rmdirs = self._old_rmdirs
+ return False
+
+ def proxy__rmdirs(self, path, ignore_errors=True):
+ raise Exception("Call of rmdirs is not expected!")
+
+ def test_node_app__make_empty__base_dir_is_None(self, node_svc: PostgresNodeService):
+ assert type(node_svc) == PostgresNodeService # noqa: E721
+
+ assert isinstance(node_svc.os_ops, OsOperations)
+ assert node_svc.port_manager is not None
+ assert isinstance(node_svc.port_manager, PortManager)
+
+ tmp_dir = node_svc.os_ops.mkdtemp()
+ assert tmp_dir is not None
+ assert type(tmp_dir) == str # noqa: E721
+ logging.info("temp directory is [{}]".format(tmp_dir))
+
+ # -----------
+ os_ops = node_svc.os_ops.create_clone()
+ assert os_ops is not node_svc.os_ops
+
+ # -----------
+ with __class__.tag_rmdirs_protector(os_ops):
+ node_app = NodeApp(test_path=tmp_dir, os_ops=os_ops)
+ assert node_app.os_ops is os_ops
+
+ with pytest.raises(expected_exception=BaseException) as x:
+ node_app.make_empty(base_dir=None)
+
+ if type(x.value) == AssertionError: # noqa: E721
+ pass
+ else:
+ assert type(x.value) == ValueError # noqa: E721
+ assert str(x.value) == "Argument 'base_dir' is not defined."
+
+ # -----------
+ logging.info("temp directory [{}] is deleting".format(tmp_dir))
+ node_svc.os_ops.rmdir(tmp_dir)
+
+ def test_node_app__make_empty__base_dir_is_Empty(self, node_svc: PostgresNodeService):
+ assert type(node_svc) == PostgresNodeService # noqa: E721
+
+ assert isinstance(node_svc.os_ops, OsOperations)
+ assert node_svc.port_manager is not None
+ assert isinstance(node_svc.port_manager, PortManager)
+
+ tmp_dir = node_svc.os_ops.mkdtemp()
+ assert tmp_dir is not None
+ assert type(tmp_dir) == str # noqa: E721
+ logging.info("temp directory is [{}]".format(tmp_dir))
+
+ # -----------
+ os_ops = node_svc.os_ops.create_clone()
+ assert os_ops is not node_svc.os_ops
+
+ # -----------
+ with __class__.tag_rmdirs_protector(os_ops):
+ node_app = NodeApp(test_path=tmp_dir, os_ops=os_ops)
+ assert node_app.os_ops is os_ops
+
+ with pytest.raises(expected_exception=ValueError) as x:
+ node_app.make_empty(base_dir="")
+
+ assert str(x.value) == "Argument 'base_dir' is empty."
+
+ # -----------
+ logging.info("temp directory [{}] is deleting".format(tmp_dir))
+ node_svc.os_ops.rmdir(tmp_dir)
+
+ def test_node_app__make_empty(self, node_svc: PostgresNodeService):
+ assert type(node_svc) == PostgresNodeService # noqa: E721
+
+ assert isinstance(node_svc.os_ops, OsOperations)
+ assert node_svc.port_manager is not None
+ assert isinstance(node_svc.port_manager, PortManager)
+
+ tmp_dir = node_svc.os_ops.mkdtemp()
+ assert tmp_dir is not None
+ assert type(tmp_dir) == str # noqa: E721
+ logging.info("temp directory is [{}]".format(tmp_dir))
+
+ # -----------
+ node_app = NodeApp(
+ test_path=tmp_dir,
+ os_ops=node_svc.os_ops,
+ port_manager=node_svc.port_manager
+ )
+
+ assert node_app.os_ops is node_svc.os_ops
+ assert node_app.port_manager is node_svc.port_manager
+ assert type(node_app.nodes_to_cleanup) == list # noqa: E721
+ assert len(node_app.nodes_to_cleanup) == 0
+
+ node: PostgresNode = None
+ try:
+ node = node_app.make_simple("node")
+ assert node is not None
+ assert isinstance(node, PostgresNode)
+ assert node.os_ops is node_svc.os_ops
+ assert node.port_manager is node_svc.port_manager
+
+ assert type(node_app.nodes_to_cleanup) == list # noqa: E721
+ assert len(node_app.nodes_to_cleanup) == 1
+ assert node_app.nodes_to_cleanup[0] is node
+
+ node.slow_start()
+ finally:
+ if node is not None:
+ node.stop()
+ node.release_resources()
+
+ node.cleanup(release_resources=True)
+
+ # -----------
+ logging.info("temp directory [{}] is deleting".format(tmp_dir))
+ node_svc.os_ops.rmdir(tmp_dir)
+
+ def test_node_app__make_simple__checksum(self, node_svc: PostgresNodeService):
+ assert type(node_svc) == PostgresNodeService # noqa: E721
+
+ assert isinstance(node_svc.os_ops, OsOperations)
+ assert node_svc.port_manager is not None
+ assert isinstance(node_svc.port_manager, PortManager)
+
+ tmp_dir = node_svc.os_ops.mkdtemp()
+ assert tmp_dir is not None
+ assert type(tmp_dir) == str # noqa: E721
+
+ logging.info("temp directory is [{}]".format(tmp_dir))
+ node_app = NodeApp(test_path=tmp_dir, os_ops=node_svc.os_ops)
+
+ C_NODE = "node"
+
+ # -----------
+ def LOCAL__test(checksum: bool, initdb_params: typing.Optional[list]):
+ initdb_params0 = initdb_params
+ initdb_params0_copy = initdb_params0.copy() if initdb_params0 is not None else None
+
+ with node_app.make_simple(C_NODE, checksum=checksum, initdb_params=initdb_params):
+ assert initdb_params is initdb_params0
+ if initdb_params0 is not None:
+ assert initdb_params0 == initdb_params0_copy
+
+ assert initdb_params is initdb_params0
+ if initdb_params0 is not None:
+ assert initdb_params0 == initdb_params0_copy
+
+ # -----------
+ LOCAL__test(checksum=False, initdb_params=None)
+ LOCAL__test(checksum=True, initdb_params=None)
+
+ # -----------
+ params = []
+ LOCAL__test(checksum=False, initdb_params=params)
+ LOCAL__test(checksum=True, initdb_params=params)
+
+ # -----------
+ params = ["--no-sync"]
+ LOCAL__test(checksum=False, initdb_params=params)
+ LOCAL__test(checksum=True, initdb_params=params)
+
+ # -----------
+ params = ["--data-checksums"]
+ LOCAL__test(checksum=False, initdb_params=params)
+ LOCAL__test(checksum=True, initdb_params=params)
+
+ # -----------
+ logging.info("temp directory [{}] is deleting".format(tmp_dir))
+ node_svc.os_ops.rmdir(tmp_dir)
+
+ def test_node_app__make_empty_with_explicit_port(self, node_svc: PostgresNodeService):
+ assert type(node_svc) == PostgresNodeService # noqa: E721
+
+ assert isinstance(node_svc.os_ops, OsOperations)
+ assert node_svc.port_manager is not None
+ assert isinstance(node_svc.port_manager, PortManager)
+
+ tmp_dir = node_svc.os_ops.mkdtemp()
+ assert tmp_dir is not None
+ assert type(tmp_dir) == str # noqa: E721
+ logging.info("temp directory is [{}]".format(tmp_dir))
+
+ # -----------
+ node_app = NodeApp(
+ test_path=tmp_dir,
+ os_ops=node_svc.os_ops,
+ port_manager=node_svc.port_manager
+ )
+
+ assert node_app.os_ops is node_svc.os_ops
+ assert node_app.port_manager is node_svc.port_manager
+ assert type(node_app.nodes_to_cleanup) == list # noqa: E721
+ assert len(node_app.nodes_to_cleanup) == 0
+
+ port = node_app.port_manager.reserve_port()
+ assert type(port) == int # noqa: E721
+
+ node: PostgresNode = None
+ try:
+ node = node_app.make_simple("node", port=port)
+ assert node is not None
+ assert isinstance(node, PostgresNode)
+ assert node.os_ops is node_svc.os_ops
+ assert node.port_manager is None # <---------
+ assert node.port == port
+ assert node._should_free_port == False # noqa: E712
+
+ assert type(node_app.nodes_to_cleanup) == list # noqa: E721
+ assert len(node_app.nodes_to_cleanup) == 1
+ assert node_app.nodes_to_cleanup[0] is node
+
+ node.slow_start()
+ finally:
+ if node is not None:
+ node.stop()
+ node.free_port()
+
+ assert node._port is None
+ assert not node._should_free_port
+
+ node.cleanup(release_resources=True)
+
+ # -----------
+ logging.info("temp directory [{}] is deleting".format(tmp_dir))
+ node_svc.os_ops.rmdir(tmp_dir)
+
@staticmethod
def helper__get_node(
node_svc: PostgresNodeService,
--- a PPN by Garber Painting Akron. With Image Size Reduction included!Fetched URL: http://github.com/postgrespro/testgres/pull/278.diff
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy