diff --git a/setup.py b/setup.py
index a41094d6..16586b88 100755
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@
     readme = f.read()
 
 setup(
-    version='1.10.3',
+    version='1.10.4',
     name='testgres',
     packages=['testgres', 'testgres.operations', 'testgres.helpers'],
     description='Testing utility for PostgreSQL and its extensions',
diff --git a/testgres/__init__.py b/testgres/__init__.py
index 8d0e38c6..665548d6 100644
--- a/testgres/__init__.py
+++ b/testgres/__init__.py
@@ -23,7 +23,8 @@
     CatchUpException, \
     StartNodeException, \
     InitNodeException, \
-    BackupException
+    BackupException, \
+    InvalidOperationException
 
 from .enums import \
     XLogMethod, \
@@ -60,7 +61,7 @@
     "NodeBackup", "testgres_config",
     "TestgresConfig", "configure_testgres", "scoped_config", "push_config", "pop_config",
     "NodeConnection", "DatabaseError", "InternalError", "ProgrammingError", "OperationalError",
-    "TestgresException", "ExecUtilException", "QueryException", "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException",
+    "TestgresException", "ExecUtilException", "QueryException", "TimeoutException", "CatchUpException", "StartNodeException", "InitNodeException", "BackupException", "InvalidOperationException",
     "XLogMethod", "IsolationLevel", "NodeStatus", "ProcessType", "DumpFormat",
     "PostgresNode", "NodeApp",
     "reserve_port", "release_port", "bound_ports", "get_bin_path", "get_pg_config", "get_pg_version",
diff --git a/testgres/exceptions.py b/testgres/exceptions.py
index ee329031..d61d4691 100644
--- a/testgres/exceptions.py
+++ b/testgres/exceptions.py
@@ -9,13 +9,14 @@ class TestgresException(Exception):
 
 @six.python_2_unicode_compatible
 class ExecUtilException(TestgresException):
-    def __init__(self, message=None, command=None, exit_code=0, out=None):
+    def __init__(self, message=None, command=None, exit_code=0, out=None, error=None):
         super(ExecUtilException, self).__init__(message)
 
         self.message = message
         self.command = command
         self.exit_code = exit_code
         self.out = out
+        self.error = error
 
     def __str__(self):
         msg = []
@@ -24,13 +25,17 @@ def __str__(self):
             msg.append(self.message)
 
         if self.command:
-            msg.append(u'Command: {}'.format(self.command))
+            command_s = ' '.join(self.command) if isinstance(self.command, list) else self.command,
+            msg.append(u'Command: {}'.format(command_s))
 
         if self.exit_code:
             msg.append(u'Exit code: {}'.format(self.exit_code))
 
+        if self.error:
+            msg.append(u'---- Error:\n{}'.format(self.error))
+
         if self.out:
-            msg.append(u'----\n{}'.format(self.out))
+            msg.append(u'---- Out:\n{}'.format(self.out))
 
         return self.convert_and_join(msg)
 
@@ -98,3 +103,7 @@ class InitNodeException(TestgresException):
 
 class BackupException(TestgresException):
     pass
+
+
+class InvalidOperationException(TestgresException):
+    pass
diff --git a/testgres/helpers/port_manager.py b/testgres/helpers/port_manager.py
index 6afdf8a9..cfc5c096 100644
--- a/testgres/helpers/port_manager.py
+++ b/testgres/helpers/port_manager.py
@@ -26,10 +26,11 @@ def find_free_port(self, ports: Optional[Set[int]] = None, exclude_ports: Option
         if ports is None:
             ports = set(range(1024, 65535))
 
-        if exclude_ports is None:
-            exclude_ports = set()
+        assert type(ports) == set  # noqa: E721
 
-        ports.difference_update(set(exclude_ports))
+        if exclude_ports is not None:
+            assert isinstance(exclude_ports, Iterable)
+            ports.difference_update(exclude_ports)
 
         sampled_ports = random.sample(tuple(ports), min(len(ports), 100))
 
diff --git a/testgres/node.py b/testgres/node.py
index 4ae30908..6f466ec9 100644
--- a/testgres/node.py
+++ b/testgres/node.py
@@ -5,6 +5,7 @@
 import signal
 import subprocess
 import threading
+import tempfile
 from queue import Queue
 
 import time
@@ -73,7 +74,8 @@
     TimeoutException,   \
     InitNodeException,  \
     TestgresException,  \
-    BackupException
+    BackupException,    \
+    InvalidOperationException
 
 from .logger import TestgresLogger
 
@@ -81,13 +83,13 @@
 
 from .standby import First
 
+from . import utils
+
 from .utils import \
     PgVer, \
     eprint, \
     get_bin_path, \
     get_pg_version, \
-    reserve_port, \
-    release_port, \
     execute_utility, \
     options_string, \
     clean_on_error
@@ -126,7 +128,11 @@ def __repr__(self):
 
 
 class PostgresNode(object):
-    def __init__(self, name=None, base_dir=None, port=None, conn_params: ConnectionParams = ConnectionParams(), bin_dir=None, prefix=None):
+    # a max number of node start attempts
+    _C_MAX_START_ATEMPTS = 5
+
+    def __init__(self, name=None, base_dir=None, port=None, conn_params: ConnectionParams = ConnectionParams(),
+                 bin_dir=None, prefix=None):
         """
         PostgresNode constructor.
 
@@ -156,7 +162,7 @@ def __init__(self, name=None, base_dir=None, port=None, conn_params: ConnectionP
             self.os_ops = LocalOperations(conn_params)
 
         self.host = self.os_ops.host
-        self.port = port or reserve_port()
+        self.port = port or utils.reserve_port()
 
         self.ssh_key = self.os_ops.ssh_key
 
@@ -469,6 +475,28 @@ def _collect_special_files(self):
 
         return result
 
+    def _collect_log_files(self):
+        # dictionary of log files + size in bytes
+
+        files = [
+            self.pg_log_file
+        ]  # yapf: disable
+
+        result = {}
+
+        for f in files:
+            # skip missing files
+            if not self.os_ops.path_exists(f):
+                continue
+
+            file_size = self.os_ops.get_file_size(f)
+            assert type(file_size) == int  # noqa: E721
+            assert file_size >= 0
+
+            result[f] = file_size
+
+        return result
+
     def init(self, initdb_params=None, cached=True, **kwargs):
         """
         Perform initdb for this node.
@@ -720,6 +748,22 @@ def slow_start(self, replica=False, dbname='template1', username=None, max_attem
                                         OperationalError},
                               max_attempts=max_attempts)
 
+    def _detect_port_conflict(self, log_files0, log_files1):
+        assert type(log_files0) == dict  # noqa: E721
+        assert type(log_files1) == dict  # noqa: E721
+
+        for file in log_files1.keys():
+            read_pos = 0
+
+            if file in log_files0.keys():
+                read_pos = log_files0[file]  # the previous size
+
+            file_content = self.os_ops.read_binary(file, read_pos)
+            file_content_s = file_content.decode()
+            if 'Is another postmaster already running on port' in file_content_s:
+                return True
+        return False
+
     def start(self, params=[], wait=True):
         """
         Starts the PostgreSQL node using pg_ctl if node has not been started.
@@ -734,40 +778,85 @@ def start(self, params=[], wait=True):
         Returns:
             This instance of :class:`.PostgresNode`.
         """
+
+        assert __class__._C_MAX_START_ATEMPTS > 1
+
         if self.is_started:
             return self
 
-        _params = [
-            self._get_bin_path("pg_ctl"),
-            "-D", self.data_dir,
-            "-l", self.pg_log_file,
-            "-w" if wait else '-W',  # --wait or --no-wait
-            "start"
-        ] + params  # yapf: disable
+        _params = [self._get_bin_path("pg_ctl"),
+                   "-D", self.data_dir,
+                   "-l", self.pg_log_file,
+                   "-w" if wait else '-W',  # --wait or --no-wait
+                   "start"] + params  # yapf: disable
 
-        startup_retries = 5
-        while True:
+        def LOCAL__start_node():
+            # 'error' will be None on Windows
+            _, _, error = execute_utility(_params, self.utils_log_file, verbose=True)
+            assert error is None or type(error) == str  # noqa: E721
+            if error and 'does not exist' in error:
+                raise Exception(error)
+
+        def LOCAL__raise_cannot_start_node(from_exception, msg):
+            assert isinstance(from_exception, Exception)
+            assert type(msg) == str  # noqa: E721
+            files = self._collect_special_files()
+            raise_from(StartNodeException(msg, files), from_exception)
+
+        def LOCAL__raise_cannot_start_node__std(from_exception):
+            assert isinstance(from_exception, Exception)
+            LOCAL__raise_cannot_start_node(from_exception, 'Cannot start node')
+
+        if not self._should_free_port:
             try:
-                exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
-                if error and 'does not exist' in error:
-                    raise Exception
+                LOCAL__start_node()
             except Exception as e:
-                files = self._collect_special_files()
-                if any(len(file) > 1 and 'Is another postmaster already '
-                                         'running on port' in file[1].decode() for
-                       file in files):
-                    logging.warning("Detected an issue with connecting to port {0}. "
-                                    "Trying another port after a 5-second sleep...".format(self.port))
-                    self.port = reserve_port()
-                    options = {'port': str(self.port)}
-                    self.set_auto_conf(options)
-                    startup_retries -= 1
-                    time.sleep(5)
+                LOCAL__raise_cannot_start_node__std(e)
+        else:
+            assert self._should_free_port
+            assert __class__._C_MAX_START_ATEMPTS > 1
+
+            log_files0 = self._collect_log_files()
+            assert type(log_files0) == dict  # noqa: E721
+
+            nAttempt = 0
+            timeout = 1
+            while True:
+                assert nAttempt >= 0
+                assert nAttempt < __class__._C_MAX_START_ATEMPTS
+                nAttempt += 1
+                try:
+                    LOCAL__start_node()
+                except Exception as e:
+                    assert nAttempt > 0
+                    assert nAttempt <= __class__._C_MAX_START_ATEMPTS
+                    if nAttempt == __class__._C_MAX_START_ATEMPTS:
+                        logging.error("Reached maximum retry attempts. Unable to start node.")
+                        LOCAL__raise_cannot_start_node(e, "Cannot start node after multiple attempts")
+
+                    log_files1 = self._collect_log_files()
+                    if not self._detect_port_conflict(log_files0, log_files1):
+                        LOCAL__raise_cannot_start_node__std(e)
+
+                    log_files0 = log_files1
+                    logging.warning(
+                        "Detected a conflict with using the port {0}. "
+                        "Trying another port after a {1}-second sleep...".format(self.port, timeout)
+                    )
+                    time.sleep(timeout)
+                    timeout = min(2 * timeout, 5)
+                    cur_port = self.port
+                    new_port = utils.reserve_port()  # can raise
+                    try:
+                        options = {'port': new_port}
+                        self.set_auto_conf(options)
+                    except:  # noqa: E722
+                        utils.release_port(new_port)
+                        raise
+                    self.port = new_port
+                    utils.release_port(cur_port)
                     continue
-
-                msg = 'Cannot start node'
-                raise_from(StartNodeException(msg, files), e)
-            break
+                break
         self._maybe_start_logger()
         self.is_started = True
         return self
@@ -930,8 +1019,10 @@ def free_port(self):
         """
 
         if self._should_free_port:
+            port = self.port
             self._should_free_port = False
-            release_port(self.port)
+            self.port = None
+            utils.release_port(port)
 
     def cleanup(self, max_attempts=3, full=False):
         """
@@ -986,13 +1077,43 @@ def psql(self,
             >>> psql(query='select 3', ON_ERROR_STOP=1)
         """
 
-        dbname = dbname or default_dbname()
+        return self._psql(
+            ignore_errors=True,
+            query=query,
+            filename=filename,
+            dbname=dbname,
+            username=username,
+            input=input,
+            **variables
+        )
+
+    def _psql(
+            self,
+            ignore_errors,
+            query=None,
+            filename=None,
+            dbname=None,
+            username=None,
+            input=None,
+            **variables):
+        assert type(variables) == dict  # noqa: E721
+
+        #
+        # We do not support encoding. It may be added later. Ok?
+        #
+        if input is None:
+            pass
+        elif type(input) == bytes:  # noqa: E721
+            pass
+        else:
+            raise Exception("Input data must be None or bytes.")
 
         psql_params = [
             self._get_bin_path("psql"),
             "-p", str(self.port),
             "-h", self.host,
             "-U", username or self.os_ops.username,
+            "-d", dbname or default_dbname(),
             "-X",  # no .psqlrc
             "-A",  # unaligned output
             "-t",  # print rows only
@@ -1005,31 +1126,19 @@ def psql(self,
 
         # select query source
         if query:
-            if self.os_ops.remote:
-                psql_params.extend(("-c", '"{}"'.format(query)))
-            else:
-                psql_params.extend(("-c", query))
+            psql_params.extend(("-c", query))
         elif filename:
             psql_params.extend(("-f", filename))
         else:
             raise QueryException('Query or filename must be provided')
 
-        # should be the last one
-        psql_params.append(dbname)
-        if not self.os_ops.remote:
-            # start psql process
-            process = subprocess.Popen(psql_params,
-                                       stdin=subprocess.PIPE,
-                                       stdout=subprocess.PIPE,
-                                       stderr=subprocess.PIPE)
-
-            # wait until it finishes and get stdout and stderr
-            out, err = process.communicate(input=input)
-            return process.returncode, out, err
-        else:
-            status_code, out, err = self.os_ops.exec_command(psql_params, verbose=True, input=input)
-
-            return status_code, out, err
+        return self.os_ops.exec_command(
+            psql_params,
+            verbose=True,
+            input=input,
+            stderr=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            ignore_errors=ignore_errors)
 
     @method_decorator(positional_args_hack(['dbname', 'query']))
     def safe_psql(self, query=None, expect_error=False, **kwargs):
@@ -1050,22 +1159,27 @@ def safe_psql(self, query=None, expect_error=False, **kwargs):
         Returns:
             psql's output as str.
         """
+        assert type(kwargs) == dict  # noqa: E721
+        assert not ("ignore_errors" in kwargs.keys())
+        assert not ("expect_error" in kwargs.keys())
 
         # force this setting
         kwargs['ON_ERROR_STOP'] = 1
         try:
-            ret, out, err = self.psql(query=query, **kwargs)
+            ret, out, err = self._psql(ignore_errors=False, query=query, **kwargs)
         except ExecUtilException as e:
-            ret = e.exit_code
-            out = e.out
-            err = e.message
-        if ret:
-            if expect_error:
-                out = (err or b'').decode('utf-8')
-            else:
-                raise QueryException((err or b'').decode('utf-8'), query)
-        elif expect_error:
-            assert False, "Exception was expected, but query finished successfully: `{}` ".format(query)
+            if not expect_error:
+                raise QueryException(e.message, query)
+
+            if type(e.error) == bytes:  # noqa: E721
+                return e.error.decode("utf-8")  # throw
+
+            # [2024-12-09] This situation is not expected
+            assert False
+            return e.error
+
+        if expect_error:
+            raise InvalidOperationException("Exception was expected, but query finished successfully: `{}`.".format(query))
 
         return out
 
@@ -1626,23 +1740,31 @@ def set_auto_conf(self, options, config='postgresql.auto.conf', rm_options={}):
 
             name, var = line.partition('=')[::2]
             name = name.strip()
-            var = var.strip()
-            var = var.strip('"')
-            var = var.strip("'")
 
-            # remove options specified in rm_options list
+            # Remove options specified in rm_options list
             if name in rm_options:
                 continue
 
             current_options[name] = var
 
         for option in options:
-            current_options[option] = options[option]
+            assert type(option) == str  # noqa: E721
+            assert option != ""
+            assert option.strip() == option
+
+            value = options[option]
+            valueType = type(value)
+
+            if valueType == str:
+                value = __class__._escape_config_value(value)
+            elif valueType == bool:
+                value = "on" if value else "off"
+
+            current_options[option] = value
 
         auto_conf = ''
         for option in current_options:
-            auto_conf += "{0} = '{1}'\n".format(
-                option, current_options[option])
+            auto_conf += option + " = " + str(current_options[option]) + "\n"
 
         for directive in current_directives:
             auto_conf += directive + "\n"
@@ -1690,6 +1812,30 @@ def _get_bin_path(self, filename):
             bin_path = get_bin_path(filename)
         return bin_path
 
+    def _escape_config_value(value):
+        assert type(value) == str  # noqa: E721
+
+        result = "'"
+
+        for ch in value:
+            if ch == "'":
+                result += "\\'"
+            elif ch == "\n":
+                result += "\\n"
+            elif ch == "\r":
+                result += "\\r"
+            elif ch == "\t":
+                result += "\\t"
+            elif ch == "\b":
+                result += "\\b"
+            elif ch == "\\":
+                result += "\\\\"
+            else:
+                result += ch
+
+        result += "'"
+        return result
+
 
 class NodeApp:
 
@@ -1729,6 +1875,8 @@ def make_simple(
             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)
@@ -1741,20 +1889,22 @@ def make_simple(
         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': '/tmp'}
+        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:
@@ -1769,11 +1919,16 @@ def make_simple(
         else:
             options['wal_keep_segments'] = '12'
 
-        # set default values
-        node.set_auto_conf(options)
-
         # Apply given parameters
-        node.set_auto_conf(pg_options)
+        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()
+
+        # Set config values
+        node.set_auto_conf(options)
 
         # kludge for testgres
         # https://github.com/postgrespro/testgres/issues/54
@@ -1782,3 +1937,26 @@ def make_simple(
             node.set_auto_conf({}, 'postgresql.conf', ['wal_keep_segments'])
 
         return node
+
+    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
+
+    def _raise_bugcheck(msg):
+        assert type(msg) == str  # noqa: E721
+        assert msg != ""
+        raise Exception("[BUG CHECK] " + msg)
diff --git a/testgres/operations/helpers.py b/testgres/operations/helpers.py
new file mode 100644
index 00000000..b50f0baa
--- /dev/null
+++ b/testgres/operations/helpers.py
@@ -0,0 +1,52 @@
+import locale
+
+
+class Helpers:
+    def _make_get_default_encoding_func():
+        # locale.getencoding is added in Python 3.11
+        if hasattr(locale, 'getencoding'):
+            return locale.getencoding
+
+        # It must exist
+        return locale.getpreferredencoding
+
+    # Prepared pointer on function to get a name of system codepage
+    _get_default_encoding_func = _make_get_default_encoding_func()
+
+    def GetDefaultEncoding():
+        #
+        #   Original idea/source was:
+        #
+        #   def os_ops.get_default_encoding():
+        #       if not hasattr(locale, 'getencoding'):
+        #       locale.getencoding = locale.getpreferredencoding
+        #       return locale.getencoding() or 'UTF-8'
+        #
+
+        assert __class__._get_default_encoding_func is not None
+
+        r = __class__._get_default_encoding_func()
+
+        if r:
+            assert r is not None
+            assert type(r) == str  # noqa: E721
+            assert r != ""
+            return r
+
+        # Is it an unexpected situation?
+        return 'UTF-8'
+
+    def PrepareProcessInput(input, encoding):
+        if not input:
+            return None
+
+        if type(input) == str:  # noqa: E721
+            if encoding is None:
+                return input.encode(__class__.GetDefaultEncoding())
+
+            assert type(encoding) == str  # noqa: E721
+            return input.encode(encoding)
+
+        # It is expected!
+        assert type(input) == bytes  # noqa: E721
+        return input
diff --git a/testgres/operations/local_ops.py b/testgres/operations/local_ops.py
index a0a9926d..8bdb22cd 100644
--- a/testgres/operations/local_ops.py
+++ b/testgres/operations/local_ops.py
@@ -10,7 +10,10 @@
 import psutil
 
 from ..exceptions import ExecUtilException
+from ..exceptions import InvalidOperationException
 from .os_ops import ConnectionParams, OsOperations, pglib, get_default_encoding
+from .raise_error import RaiseError
+from .helpers import Helpers
 
 try:
     from shutil import which as find_executable
@@ -47,14 +50,6 @@ def __init__(self, conn_params=None):
         self.remote = False
         self.username = conn_params.username or getpass.getuser()
 
-    @staticmethod
-    def _raise_exec_exception(message, command, exit_code, output):
-        """Raise an ExecUtilException."""
-        raise ExecUtilException(message=message.format(output),
-                                command=' '.join(command) if isinstance(command, list) else command,
-                                exit_code=exit_code,
-                                out=output)
-
     @staticmethod
     def _process_output(encoding, temp_file_path):
         """Process the output of a command from a temporary file."""
@@ -64,47 +59,68 @@ def _process_output(encoding, temp_file_path):
                 output = output.decode(encoding)
             return output, None  # In Windows stderr writing in stdout
 
-    def _run_command(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
-        """Execute a command and return the process and its output."""
-        if os.name == 'nt' and stdout is None:  # Windows
-            with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as temp_file:
-                stdout = temp_file
-                stderr = subprocess.STDOUT
-                process = subprocess.Popen(
-                    cmd,
-                    shell=shell,
-                    stdin=stdin or subprocess.PIPE if input is not None else None,
-                    stdout=stdout,
-                    stderr=stderr,
-                )
-                if get_process:
-                    return process, None, None
-                temp_file_path = temp_file.name
-
-            # Wait process finished
-            process.wait()
-
-            output, error = self._process_output(encoding, temp_file_path)
-            return process, output, error
-        else:  # Other OS
+    def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
+        # TODO: why don't we use the data from input?
+
+        with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as temp_file:
+            stdout = temp_file
+            stderr = subprocess.STDOUT
             process = subprocess.Popen(
                 cmd,
                 shell=shell,
                 stdin=stdin or subprocess.PIPE if input is not None else None,
-                stdout=stdout or subprocess.PIPE,
-                stderr=stderr or subprocess.PIPE,
+                stdout=stdout,
+                stderr=stderr,
             )
             if get_process:
                 return process, None, None
-            try:
-                output, error = process.communicate(input=input.encode(encoding) if input else None, timeout=timeout)
-                if encoding:
-                    output = output.decode(encoding)
-                    error = error.decode(encoding)
-                return process, output, error
-            except subprocess.TimeoutExpired:
-                process.kill()
-                raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
+            temp_file_path = temp_file.name
+
+        # Wait process finished
+        process.wait()
+
+        output, error = self._process_output(encoding, temp_file_path)
+        return process, output, error
+
+    def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
+        input_prepared = None
+        if not get_process:
+            input_prepared = Helpers.PrepareProcessInput(input, encoding)  # throw
+
+        assert input_prepared is None or (type(input_prepared) == bytes)  # noqa: E721
+
+        process = subprocess.Popen(
+            cmd,
+            shell=shell,
+            stdin=stdin or subprocess.PIPE if input is not None else None,
+            stdout=stdout or subprocess.PIPE,
+            stderr=stderr or subprocess.PIPE,
+        )
+        assert not (process is None)
+        if get_process:
+            return process, None, None
+        try:
+            output, error = process.communicate(input=input_prepared, timeout=timeout)
+        except subprocess.TimeoutExpired:
+            process.kill()
+            raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
+
+        assert type(output) == bytes  # noqa: E721
+        assert type(error) == bytes  # noqa: E721
+
+        if encoding:
+            output = output.decode(encoding)
+            error = error.decode(encoding)
+        return process, output, error
+
+    def _run_command(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
+        """Execute a command and return the process and its output."""
+        if os.name == 'nt' and stdout is None:  # Windows
+            method = __class__._run_command__nt
+        else:  # Other OS
+            method = __class__._run_command__generic
+
+        return method(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding)
 
     def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False, encoding=None, shell=False,
                      text=False, input=None, stdin=None, stdout=None, stderr=None, get_process=False, timeout=None,
@@ -112,11 +128,20 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
         """
         Execute a command in a subprocess and handle the output based on the provided parameters.
         """
+        assert type(expect_error) == bool  # noqa: E721
+        assert type(ignore_errors) == bool  # noqa: E721
+
         process, output, error = self._run_command(cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding)
         if get_process:
             return process
         if not ignore_errors and ((process.returncode != 0 or has_errors(output=output, error=error)) and not expect_error):
-            self._raise_exec_exception('Utility exited with non-zero code. Error `{}`', cmd, process.returncode, error or output)
+            RaiseError.UtilityExitedWithNonZeroCode(
+                cmd=cmd,
+                exit_code=process.returncode,
+                msg_arg=error or output,
+                error=error,
+                out=output
+            )
 
         if verbose:
             return process.returncode, output, error
@@ -242,13 +267,35 @@ def touch(self, filename):
             os.utime(filename, None)
 
     def read(self, filename, encoding=None, binary=False):
-        mode = "rb" if binary else "r"
-        with open(filename, mode) as file:
+        assert type(filename) == str  # noqa: E721
+        assert encoding is None or type(encoding) == str  # noqa: E721
+        assert type(binary) == bool  # noqa: E721
+
+        if binary:
+            if encoding is not None:
+                raise InvalidOperationException("Enconding is not allowed for read binary operation")
+
+            return self._read__binary(filename)
+
+        # python behavior
+        assert (None or "abc") == "abc"
+        assert ("" or "abc") == "abc"
+
+        return self._read__text_with_encoding(filename, encoding or get_default_encoding())
+
+    def _read__text_with_encoding(self, filename, encoding):
+        assert type(filename) == str  # noqa: E721
+        assert type(encoding) == str  # noqa: E721
+        with open(filename, mode='r', encoding=encoding) as file:  # open in a text mode
+            content = file.read()
+            assert type(content) == str  # noqa: E721
+            return content
+
+    def _read__binary(self, filename):
+        assert type(filename) == str  # noqa: E721
+        with open(filename, 'rb') as file:  # open in a binary mode
             content = file.read()
-            if binary:
-                return content
-            if isinstance(content, bytes):
-                return content.decode(encoding or get_default_encoding())
+            assert type(content) == bytes  # noqa: E721
             return content
 
     def readlines(self, filename, num_lines=0, binary=False, encoding=None):
@@ -284,12 +331,30 @@ def readlines(self, filename, num_lines=0, binary=False, encoding=None):
                         buffers * max(2, int(num_lines / max(cur_lines, 1)))
                     )  # Adjust buffer size
 
+    def read_binary(self, filename, offset):
+        assert type(filename) == str  # noqa: E721
+        assert type(offset) == int  # noqa: E721
+
+        if offset < 0:
+            raise ValueError("Negative 'offset' is not supported.")
+
+        with open(filename, 'rb') as file:  # open in a binary mode
+            file.seek(offset, os.SEEK_SET)
+            r = file.read()
+            assert type(r) == bytes  # noqa: E721
+            return r
+
     def isfile(self, remote_file):
         return os.path.isfile(remote_file)
 
     def isdir(self, dirname):
         return os.path.isdir(dirname)
 
+    def get_file_size(self, filename):
+        assert filename is not None
+        assert type(filename) == str  # noqa: E721
+        return os.path.getsize(filename)
+
     def remove_file(self, filename):
         return os.remove(filename)
 
diff --git a/testgres/operations/os_ops.py b/testgres/operations/os_ops.py
index 34242040..35525b3c 100644
--- a/testgres/operations/os_ops.py
+++ b/testgres/operations/os_ops.py
@@ -98,9 +98,21 @@ def read(self, filename, encoding, binary):
     def readlines(self, filename):
         raise NotImplementedError()
 
+    def read_binary(self, filename, offset):
+        assert type(filename) == str  # noqa: E721
+        assert type(offset) == int  # noqa: E721
+        assert offset >= 0
+        raise NotImplementedError()
+
     def isfile(self, remote_file):
         raise NotImplementedError()
 
+    def isdir(self, dirname):
+        raise NotImplementedError()
+
+    def get_file_size(self, filename):
+        raise NotImplementedError()
+
     # Processes control
     def kill(self, pid, signal):
         # Kill the process
diff --git a/testgres/operations/raise_error.py b/testgres/operations/raise_error.py
new file mode 100644
index 00000000..0e760e74
--- /dev/null
+++ b/testgres/operations/raise_error.py
@@ -0,0 +1,46 @@
+from ..exceptions import ExecUtilException
+from .helpers import Helpers
+
+
+class RaiseError:
+    def UtilityExitedWithNonZeroCode(cmd, exit_code, msg_arg, error, out):
+        assert type(exit_code) == int  # noqa: E721
+
+        msg_arg_s = __class__._TranslateDataIntoString(msg_arg).strip()
+        assert type(msg_arg_s) == str  # noqa: E721
+
+        if msg_arg_s == "":
+            msg_arg_s = "#no_error_message"
+
+        message = "Utility exited with non-zero code. Error: `" + msg_arg_s + "`"
+        raise ExecUtilException(
+            message=message,
+            command=cmd,
+            exit_code=exit_code,
+            out=out,
+            error=error)
+
+    def _TranslateDataIntoString(data):
+        if type(data) == bytes:  # noqa: E721
+            return __class__._TranslateDataIntoString__FromBinary(data)
+
+        return str(data)
+
+    def _TranslateDataIntoString__FromBinary(data):
+        assert type(data) == bytes  # noqa: E721
+
+        try:
+            return data.decode(Helpers.GetDefaultEncoding())
+        except UnicodeDecodeError:
+            pass
+
+        return "#cannot_decode_text"
+
+    def _BinaryIsASCII(data):
+        assert type(data) == bytes  # noqa: E721
+
+        for b in data:
+            if not (b >= 0 and b <= 127):
+                return False
+
+        return True
diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py
index 20095051..2f34ecec 100644
--- a/testgres/operations/remote_ops.py
+++ b/testgres/operations/remote_ops.py
@@ -3,6 +3,7 @@
 import platform
 import subprocess
 import tempfile
+import io
 
 # we support both pg8000 and psycopg2
 try:
@@ -14,7 +15,10 @@
         raise ImportError("You must have psycopg2 or pg8000 modules installed")
 
 from ..exceptions import ExecUtilException
+from ..exceptions import InvalidOperationException
 from .os_ops import OsOperations, ConnectionParams, get_default_encoding
+from .raise_error import RaiseError
+from .helpers import Helpers
 
 error_markers = [b'error', b'Permission denied', b'fatal', b'No such file or directory']
 
@@ -37,7 +41,6 @@ def cmdline(self):
 
 class RemoteOperations(OsOperations):
     def __init__(self, conn_params: ConnectionParams):
-
         if not platform.system().lower() == "linux":
             raise EnvironmentError("Remote operations are supported only on Linux!")
 
@@ -66,44 +69,59 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
         Args:
         - cmd (str): The command to be executed.
         """
+        assert type(expect_error) == bool  # noqa: E721
+        assert type(ignore_errors) == bool  # noqa: E721
+
+        input_prepared = None
+        if not get_process:
+            input_prepared = Helpers.PrepareProcessInput(input, encoding)  # throw
+
+        assert input_prepared is None or (type(input_prepared) == bytes)  # noqa: E721
+
         ssh_cmd = []
         if isinstance(cmd, str):
             ssh_cmd = ['ssh', self.ssh_dest] + self.ssh_args + [cmd]
         elif isinstance(cmd, list):
-            ssh_cmd = ['ssh', self.ssh_dest] + self.ssh_args + cmd
+            ssh_cmd = ['ssh', self.ssh_dest] + self.ssh_args + [subprocess.list2cmdline(cmd)]
+        else:
+            raise ValueError("Invalid 'cmd' argument type - {0}".format(type(cmd).__name__))
+
         process = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        assert not (process is None)
         if get_process:
             return process
 
         try:
-            result, error = process.communicate(input, timeout=timeout)
+            result, error = process.communicate(input=input_prepared, timeout=timeout)
         except subprocess.TimeoutExpired:
             process.kill()
             raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
 
         exit_status = process.returncode
 
-        if encoding:
-            result = result.decode(encoding)
-            error = error.decode(encoding)
-
-        if expect_error:
-            raise Exception(result, error)
+        assert type(result) == bytes  # noqa: E721
+        assert type(error) == bytes  # noqa: E721
 
         if not error:
-            error_found = 0
+            error_found = False
         else:
-            error = normalize_error(error)
             error_found = exit_status != 0 or any(
-                marker in error for marker in ['error', 'Permission denied', 'fatal', 'No such file or directory']
+                marker in error for marker in [b'error', b'Permission denied', b'fatal', b'No such file or directory']
             )
 
-        if not ignore_errors and error_found:
-            if isinstance(error, bytes):
-                message = b"Utility exited with non-zero code. Error: " + error
-            else:
-                message = f"Utility exited with non-zero code. Error: {error}"
-            raise ExecUtilException(message=message, command=cmd, exit_code=exit_status, out=result)
+        assert type(error_found) == bool  # noqa: E721
+
+        if encoding:
+            result = result.decode(encoding)
+            error = error.decode(encoding)
+
+        if not ignore_errors and error_found and not expect_error:
+            RaiseError.UtilityExitedWithNonZeroCode(
+                cmd=cmd,
+                exit_code=exit_status,
+                msg_arg=error,
+                error=error,
+                out=result)
 
         if verbose:
             return exit_status, result, error
@@ -303,13 +321,39 @@ def touch(self, filename):
         self.exec_command("touch {}".format(filename))
 
     def read(self, filename, binary=False, encoding=None):
-        cmd = "cat {}".format(filename)
-        result = self.exec_command(cmd, encoding=encoding)
-
-        if not binary and result:
-            result = result.decode(encoding or get_default_encoding())
-
-        return result
+        assert type(filename) == str  # noqa: E721
+        assert encoding is None or type(encoding) == str  # noqa: E721
+        assert type(binary) == bool  # noqa: E721
+
+        if binary:
+            if encoding is not None:
+                raise InvalidOperationException("Enconding is not allowed for read binary operation")
+
+            return self._read__binary(filename)
+
+        # python behavior
+        assert (None or "abc") == "abc"
+        assert ("" or "abc") == "abc"
+
+        return self._read__text_with_encoding(filename, encoding or get_default_encoding())
+
+    def _read__text_with_encoding(self, filename, encoding):
+        assert type(filename) == str  # noqa: E721
+        assert type(encoding) == str  # noqa: E721
+        content = self._read__binary(filename)
+        assert type(content) == bytes  # noqa: E721
+        buf0 = io.BytesIO(content)
+        buf1 = io.TextIOWrapper(buf0, encoding=encoding)
+        content_s = buf1.read()
+        assert type(content_s) == str  # noqa: E721
+        return content_s
+
+    def _read__binary(self, filename):
+        assert type(filename) == str  # noqa: E721
+        cmd = ["cat", filename]
+        content = self.exec_command(cmd)
+        assert type(content) == bytes  # noqa: E721
+        return content
 
     def readlines(self, filename, num_lines=0, binary=False, encoding=None):
         if num_lines > 0:
@@ -326,6 +370,18 @@ def readlines(self, filename, num_lines=0, binary=False, encoding=None):
 
         return lines
 
+    def read_binary(self, filename, offset):
+        assert type(filename) == str  # noqa: E721
+        assert type(offset) == int  # noqa: E721
+
+        if offset < 0:
+            raise ValueError("Negative 'offset' is not supported.")
+
+        cmd = ["tail", "-c", "+{}".format(offset + 1), filename]
+        r = self.exec_command(cmd)
+        assert type(r) == bytes  # noqa: E721
+        return r
+
     def isfile(self, remote_file):
         stdout = self.exec_command("test -f {}; echo $?".format(remote_file))
         result = int(stdout.strip())
@@ -336,6 +392,70 @@ def isdir(self, dirname):
         response = self.exec_command(cmd)
         return response.strip() == b"True"
 
+    def get_file_size(self, filename):
+        C_ERR_SRC = "RemoteOpertions::get_file_size"
+
+        assert filename is not None
+        assert type(filename) == str  # noqa: E721
+        cmd = ["du", "-b", filename]
+
+        s = self.exec_command(cmd, encoding=get_default_encoding())
+        assert type(s) == str  # noqa: E721
+
+        if len(s) == 0:
+            raise Exception(
+                "[BUG CHECK] Can't get size of file [{2}]. Remote operation returned an empty string. Check point [{0}][{1}].".format(
+                    C_ERR_SRC,
+                    "#001",
+                    filename
+                )
+            )
+
+        i = 0
+
+        while i < len(s) and s[i].isdigit():
+            assert s[i] >= '0'
+            assert s[i] <= '9'
+            i += 1
+
+        if i == 0:
+            raise Exception(
+                "[BUG CHECK] Can't get size of file [{2}]. Remote operation returned a bad formatted string. Check point [{0}][{1}].".format(
+                    C_ERR_SRC,
+                    "#002",
+                    filename
+                )
+            )
+
+        if i == len(s):
+            raise Exception(
+                "[BUG CHECK] Can't get size of file [{2}]. Remote operation returned a bad formatted string. Check point [{0}][{1}].".format(
+                    C_ERR_SRC,
+                    "#003",
+                    filename
+                )
+            )
+
+        if not s[i].isspace():
+            raise Exception(
+                "[BUG CHECK] Can't get size of file [{2}]. Remote operation returned a bad formatted string. Check point [{0}][{1}].".format(
+                    C_ERR_SRC,
+                    "#004",
+                    filename
+                )
+            )
+
+        r = 0
+
+        for i2 in range(0, i):
+            ch = s[i2]
+            assert ch >= '0'
+            assert ch <= '9'
+            # Here is needed to check overflow or that it is a human-valid result?
+            r = (r * 10) + ord(ch) - ord('0')
+
+        return r
+
     def remove_file(self, filename):
         cmd = "rm {}".format(filename)
         return self.exec_command(cmd)
diff --git a/testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py b/testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py
index b7174a7c..078fdbab 100644
--- a/testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py
+++ b/testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py
@@ -172,6 +172,10 @@ def __init__(self):
         self.ptrack = test_env.get('PG_PROBACKUP_PTRACK', None) == 'ON' and self.pg_config_version >= 110000
         self.wal_tree_enabled = test_env.get('PG_PROBACKUP_WAL_TREE_ENABLED', None) == 'ON'
 
+        self.bckp_source = test_env.get('PG_PROBACKUP_SOURCE', 'pro').lower()
+        if self.bckp_source not in ('base', 'direct', 'pro'):
+            raise Exception("Wrong PG_PROBACKUP_SOURCE value. Available options: base|direct|pro")
+
         self.paranoia = test_env.get('PG_PROBACKUP_PARANOIA', None) == 'ON'
         env_compress = test_env.get('ARCHIVE_COMPRESSION', None)
         if env_compress:
diff --git a/testgres/plugins/pg_probackup2/setup.py b/testgres/plugins/pg_probackup2/setup.py
index ade2d85d..619b8d39 100644
--- a/testgres/plugins/pg_probackup2/setup.py
+++ b/testgres/plugins/pg_probackup2/setup.py
@@ -4,7 +4,7 @@
     from distutils.core import setup
 
 setup(
-    version='0.0.4',
+    version='0.0.5',
     name='testgres_pg_probackup2',
     packages=['pg_probackup2', 'pg_probackup2.storage'],
     description='Plugin for testgres that manages pg_probackup2',
diff --git a/testgres/utils.py b/testgres/utils.py
index a4ee7877..4bd232b1 100644
--- a/testgres/utils.py
+++ b/testgres/utils.py
@@ -34,7 +34,7 @@ def __init__(self, version: str) -> None:
             super().__init__(version)
 
 
-def reserve_port():
+def internal__reserve_port():
     """
     Generate a new port and add it to 'bound_ports'.
     """
@@ -45,7 +45,7 @@ def reserve_port():
     return port
 
 
-def release_port(port):
+def internal__release_port(port):
     """
     Free port provided by reserve_port().
     """
@@ -53,6 +53,10 @@ def release_port(port):
     bound_ports.discard(port)
 
 
+reserve_port = internal__reserve_port
+release_port = internal__release_port
+
+
 def execute_utility(args, logfile=None, verbose=False):
     """
     Execute utility (pg_ctl, pg_dump etc).
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/helpers/run_conditions.py b/tests/helpers/run_conditions.py
new file mode 100644
index 00000000..8d57f753
--- /dev/null
+++ b/tests/helpers/run_conditions.py
@@ -0,0 +1,11 @@
+import pytest
+import platform
+
+
+class RunConditions:
+    # It is not a test kit!
+    __test__ = False
+
+    def skip_if_windows():
+        if platform.system().lower() == "windows":
+            pytest.skip("This test does not support Windows.")
diff --git a/tests/test_local.py b/tests/test_local.py
new file mode 100644
index 00000000..d7adce17
--- /dev/null
+++ b/tests/test_local.py
@@ -0,0 +1,258 @@
+import os
+
+import pytest
+import re
+
+from testgres import ExecUtilException
+from testgres import InvalidOperationException
+from testgres import LocalOperations
+
+from .helpers.run_conditions import RunConditions
+
+
+class TestLocalOperations:
+
+    @pytest.fixture(scope="function", autouse=True)
+    def setup(self):
+        self.operations = LocalOperations()
+
+    def test_exec_command_success(self):
+        """
+        Test exec_command for successful command execution.
+        """
+        RunConditions.skip_if_windows()
+
+        cmd = "python3 --version"
+        response = self.operations.exec_command(cmd, wait_exit=True, shell=True)
+
+        assert b'Python 3.' in response
+
+    def test_exec_command_failure(self):
+        """
+        Test exec_command for command execution failure.
+        """
+        RunConditions.skip_if_windows()
+
+        cmd = "nonexistent_command"
+        while True:
+            try:
+                self.operations.exec_command(cmd, wait_exit=True, shell=True)
+            except ExecUtilException as e:
+                error = e.message
+                break
+            raise Exception("We wait an exception!")
+        assert error == "Utility exited with non-zero code. Error: `/bin/sh: 1: nonexistent_command: not found`"
+
+    def test_exec_command_failure__expect_error(self):
+        """
+        Test exec_command for command execution failure.
+        """
+        RunConditions.skip_if_windows()
+
+        cmd = "nonexistent_command"
+
+        exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True, shell=True, expect_error=True)
+
+        assert error == b'/bin/sh: 1: nonexistent_command: not found\n'
+        assert exit_status == 127
+        assert result == b''
+
+    def test_read__text(self):
+        """
+        Test LocalOperations::read for text data.
+        """
+        filename = __file__  # current file
+
+        with open(filename, 'r') as file:  # open in a text mode
+            response0 = file.read()
+
+        assert type(response0) == str  # noqa: E721
+
+        response1 = self.operations.read(filename)
+        assert type(response1) == str  # noqa: E721
+        assert response1 == response0
+
+        response2 = self.operations.read(filename, encoding=None, binary=False)
+        assert type(response2) == str  # noqa: E721
+        assert response2 == response0
+
+        response3 = self.operations.read(filename, encoding="")
+        assert type(response3) == str  # noqa: E721
+        assert response3 == response0
+
+        response4 = self.operations.read(filename, encoding="UTF-8")
+        assert type(response4) == str  # noqa: E721
+        assert response4 == response0
+
+    def test_read__binary(self):
+        """
+        Test LocalOperations::read for binary data.
+        """
+        filename = __file__  # current file
+
+        with open(filename, 'rb') as file:  # open in a binary mode
+            response0 = file.read()
+
+        assert type(response0) == bytes  # noqa: E721
+
+        response1 = self.operations.read(filename, binary=True)
+        assert type(response1) == bytes  # noqa: E721
+        assert response1 == response0
+
+    def test_read__binary_and_encoding(self):
+        """
+        Test LocalOperations::read for binary data and encoding.
+        """
+        filename = __file__  # current file
+
+        with pytest.raises(
+                InvalidOperationException,
+                match=re.escape("Enconding is not allowed for read binary operation")):
+            self.operations.read(filename, encoding="", binary=True)
+
+    def test_read__unknown_file(self):
+        """
+        Test LocalOperations::read with unknown file.
+        """
+
+        with pytest.raises(FileNotFoundError, match=re.escape("[Errno 2] No such file or directory: '/dummy'")):
+            self.operations.read("/dummy")
+
+    def test_read_binary__spec(self):
+        """
+        Test LocalOperations::read_binary.
+        """
+        filename = __file__  # current file
+
+        with open(filename, 'rb') as file:  # open in a binary mode
+            response0 = file.read()
+
+        assert type(response0) == bytes  # noqa: E721
+
+        response1 = self.operations.read_binary(filename, 0)
+        assert type(response1) == bytes  # noqa: E721
+        assert response1 == response0
+
+        response2 = self.operations.read_binary(filename, 1)
+        assert type(response2) == bytes  # noqa: E721
+        assert len(response2) < len(response1)
+        assert len(response2) + 1 == len(response1)
+        assert response2 == response1[1:]
+
+        response3 = self.operations.read_binary(filename, len(response1))
+        assert type(response3) == bytes  # noqa: E721
+        assert len(response3) == 0
+
+        response4 = self.operations.read_binary(filename, len(response2))
+        assert type(response4) == bytes  # noqa: E721
+        assert len(response4) == 1
+        assert response4[0] == response1[len(response1) - 1]
+
+        response5 = self.operations.read_binary(filename, len(response1) + 1)
+        assert type(response5) == bytes  # noqa: E721
+        assert len(response5) == 0
+
+    def test_read_binary__spec__unk_file(self):
+        """
+        Test LocalOperations::read_binary with unknown file.
+        """
+
+        with pytest.raises(
+                FileNotFoundError,
+                match=re.escape("[Errno 2] No such file or directory: '/dummy'")):
+            self.operations.read_binary("/dummy", 0)
+
+    def test_read_binary__spec__negative_offset(self):
+        """
+        Test LocalOperations::read_binary with negative offset.
+        """
+
+        with pytest.raises(
+                ValueError,
+                match=re.escape("Negative 'offset' is not supported.")):
+            self.operations.read_binary(__file__, -1)
+
+    def test_get_file_size(self):
+        """
+        Test LocalOperations::get_file_size.
+        """
+        filename = __file__  # current file
+
+        sz0 = os.path.getsize(filename)
+        assert type(sz0) == int  # noqa: E721
+
+        sz1 = self.operations.get_file_size(filename)
+        assert type(sz1) == int  # noqa: E721
+        assert sz1 == sz0
+
+    def test_get_file_size__unk_file(self):
+        """
+        Test LocalOperations::get_file_size.
+        """
+
+        with pytest.raises(FileNotFoundError, match=re.escape("[Errno 2] No such file or directory: '/dummy'")):
+            self.operations.get_file_size("/dummy")
+
+    def test_isfile_true(self):
+        """
+        Test isfile for an existing file.
+        """
+        filename = __file__
+
+        response = self.operations.isfile(filename)
+
+        assert response is True
+
+    def test_isfile_false__not_exist(self):
+        """
+        Test isfile for a non-existing file.
+        """
+        filename = os.path.join(os.path.dirname(__file__), "nonexistent_file.txt")
+
+        response = self.operations.isfile(filename)
+
+        assert response is False
+
+    def test_isfile_false__directory(self):
+        """
+        Test isfile for a firectory.
+        """
+        name = os.path.dirname(__file__)
+
+        assert self.operations.isdir(name)
+
+        response = self.operations.isfile(name)
+
+        assert response is False
+
+    def test_isdir_true(self):
+        """
+        Test isdir for an existing directory.
+        """
+        name = os.path.dirname(__file__)
+
+        response = self.operations.isdir(name)
+
+        assert response is True
+
+    def test_isdir_false__not_exist(self):
+        """
+        Test isdir for a non-existing directory.
+        """
+        name = os.path.join(os.path.dirname(__file__), "it_is_nonexistent_directory")
+
+        response = self.operations.isdir(name)
+
+        assert response is False
+
+    def test_isdir_false__file(self):
+        """
+        Test isdir for a file.
+        """
+        name = __file__
+
+        assert self.operations.isfile(name)
+
+        response = self.operations.isdir(name)
+
+        assert response is False
diff --git a/tests/test_remote.py b/tests/test_remote.py
index e0e4a555..7071a9d9 100755
--- a/tests/test_remote.py
+++ b/tests/test_remote.py
@@ -1,8 +1,10 @@
 import os
 
 import pytest
+import re
 
 from testgres import ExecUtilException
+from testgres import InvalidOperationException
 from testgres import RemoteOperations
 from testgres import ConnectionParams
 
@@ -30,11 +32,26 @@ def test_exec_command_failure(self):
         Test exec_command for command execution failure.
         """
         cmd = "nonexistent_command"
-        try:
-            exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True)
-        except ExecUtilException as e:
-            error = e.message
-        assert error == b'Utility exited with non-zero code. Error: bash: line 1: nonexistent_command: command not found\n'
+        while True:
+            try:
+                self.operations.exec_command(cmd, verbose=True, wait_exit=True)
+            except ExecUtilException as e:
+                error = e.message
+                break
+            raise Exception("We wait an exception!")
+        assert error == 'Utility exited with non-zero code. Error: `bash: line 1: nonexistent_command: command not found`'
+
+    def test_exec_command_failure__expect_error(self):
+        """
+        Test exec_command for command execution failure.
+        """
+        cmd = "nonexistent_command"
+
+        exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True, shell=True, expect_error=True)
+
+        assert error == b'bash: line 1: nonexistent_command: command not found\n'
+        assert exit_status == 127
+        assert result == b''
 
     def test_is_executable_true(self):
         """
@@ -83,11 +100,14 @@ def test_makedirs_and_rmdirs_failure(self):
             self.operations.makedirs(path)
 
         # Test rmdirs
-        try:
-            exit_status, result, error = self.operations.rmdirs(path, verbose=True)
-        except ExecUtilException as e:
-            error = e.message
-        assert error == b"Utility exited with non-zero code. Error: rm: cannot remove '/root/test_dir': Permission denied\n"
+        while True:
+            try:
+                self.operations.rmdirs(path, verbose=True)
+            except ExecUtilException as e:
+                error = e.message
+                break
+            raise Exception("We wait an exception!")
+        assert error == "Utility exited with non-zero code. Error: `rm: cannot remove '/root/test_dir': Permission denied`"
 
     def test_listdir(self):
         """
@@ -163,6 +183,142 @@ def test_read_binary_file(self):
 
         assert isinstance(response, bytes)
 
+    def test_read__text(self):
+        """
+        Test RemoteOperations::read for text data.
+        """
+        filename = __file__  # current file
+
+        with open(filename, 'r') as file:  # open in a text mode
+            response0 = file.read()
+
+        assert type(response0) == str  # noqa: E721
+
+        response1 = self.operations.read(filename)
+        assert type(response1) == str  # noqa: E721
+        assert response1 == response0
+
+        response2 = self.operations.read(filename, encoding=None, binary=False)
+        assert type(response2) == str  # noqa: E721
+        assert response2 == response0
+
+        response3 = self.operations.read(filename, encoding="")
+        assert type(response3) == str  # noqa: E721
+        assert response3 == response0
+
+        response4 = self.operations.read(filename, encoding="UTF-8")
+        assert type(response4) == str  # noqa: E721
+        assert response4 == response0
+
+    def test_read__binary(self):
+        """
+        Test RemoteOperations::read for binary data.
+        """
+        filename = __file__  # current file
+
+        with open(filename, 'rb') as file:  # open in a binary mode
+            response0 = file.read()
+
+        assert type(response0) == bytes  # noqa: E721
+
+        response1 = self.operations.read(filename, binary=True)
+        assert type(response1) == bytes  # noqa: E721
+        assert response1 == response0
+
+    def test_read__binary_and_encoding(self):
+        """
+        Test RemoteOperations::read for binary data and encoding.
+        """
+        filename = __file__  # current file
+
+        with pytest.raises(
+                InvalidOperationException,
+                match=re.escape("Enconding is not allowed for read binary operation")):
+            self.operations.read(filename, encoding="", binary=True)
+
+    def test_read__unknown_file(self):
+        """
+        Test RemoteOperations::read with unknown file.
+        """
+
+        with pytest.raises(
+                ExecUtilException,
+                match=re.escape("cat: /dummy: No such file or directory")):
+            self.operations.read("/dummy")
+
+    def test_read_binary__spec(self):
+        """
+        Test RemoteOperations::read_binary.
+        """
+        filename = __file__  # currnt file
+
+        with open(filename, 'rb') as file:  # open in a binary mode
+            response0 = file.read()
+
+        assert type(response0) == bytes  # noqa: E721
+
+        response1 = self.operations.read_binary(filename, 0)
+        assert type(response1) == bytes  # noqa: E721
+        assert response1 == response0
+
+        response2 = self.operations.read_binary(filename, 1)
+        assert type(response2) == bytes  # noqa: E721
+        assert len(response2) < len(response1)
+        assert len(response2) + 1 == len(response1)
+        assert response2 == response1[1:]
+
+        response3 = self.operations.read_binary(filename, len(response1))
+        assert type(response3) == bytes  # noqa: E721
+        assert len(response3) == 0
+
+        response4 = self.operations.read_binary(filename, len(response2))
+        assert type(response4) == bytes  # noqa: E721
+        assert len(response4) == 1
+        assert response4[0] == response1[len(response1) - 1]
+
+        response5 = self.operations.read_binary(filename, len(response1) + 1)
+        assert type(response5) == bytes  # noqa: E721
+        assert len(response5) == 0
+
+    def test_read_binary__spec__unk_file(self):
+        """
+        Test RemoteOperations::read_binary with unknown file.
+        """
+
+        with pytest.raises(ExecUtilException, match=re.escape("tail: cannot open '/dummy' for reading: No such file or directory")):
+            self.operations.read_binary("/dummy", 0)
+
+    def test_read_binary__spec__negative_offset(self):
+        """
+        Test RemoteOperations::read_binary with negative offset.
+        """
+
+        with pytest.raises(
+                ValueError,
+                match=re.escape("Negative 'offset' is not supported.")):
+            self.operations.read_binary(__file__, -1)
+
+    def test_get_file_size(self):
+        """
+        Test RemoteOperations::get_file_size.
+        """
+        filename = __file__  # current file
+
+        sz0 = os.path.getsize(filename)
+        assert type(sz0) == int  # noqa: E721
+
+        sz1 = self.operations.get_file_size(filename)
+        assert type(sz1) == int  # noqa: E721
+        assert sz1 == sz0
+
+    def test_get_file_size__unk_file(self):
+        """
+        Test RemoteOperations::get_file_size.
+        """
+
+        with pytest.raises(ExecUtilException, match=re.escape("du: cannot access '/dummy': No such file or directory")):
+            self.operations.get_file_size("/dummy")
+
     def test_touch(self):
         """
         Test touch for creating a new file or updating access and modification times of an existing file.
@@ -177,18 +333,62 @@ def test_isfile_true(self):
         """
         Test isfile for an existing file.
         """
-        filename = "/etc/hosts"
+        filename = __file__
 
         response = self.operations.isfile(filename)
 
         assert response is True
 
-    def test_isfile_false(self):
+    def test_isfile_false__not_exist(self):
         """
         Test isfile for a non-existing file.
         """
-        filename = "/nonexistent_file.txt"
+        filename = os.path.join(os.path.dirname(__file__), "nonexistent_file.txt")
 
         response = self.operations.isfile(filename)
 
         assert response is False
+
+    def test_isfile_false__directory(self):
+        """
+        Test isfile for a firectory.
+        """
+        name = os.path.dirname(__file__)
+
+        assert self.operations.isdir(name)
+
+        response = self.operations.isfile(name)
+
+        assert response is False
+
+    def test_isdir_true(self):
+        """
+        Test isdir for an existing directory.
+        """
+        name = os.path.dirname(__file__)
+
+        response = self.operations.isdir(name)
+
+        assert response is True
+
+    def test_isdir_false__not_exist(self):
+        """
+        Test isdir for a non-existing directory.
+        """
+        name = os.path.join(os.path.dirname(__file__), "it_is_nonexistent_directory")
+
+        response = self.operations.isdir(name)
+
+        assert response is False
+
+    def test_isdir_false__file(self):
+        """
+        Test isdir for a file.
+        """
+        name = __file__
+
+        assert self.operations.isfile(name)
+
+        response = self.operations.isdir(name)
+
+        assert response is False
diff --git a/tests/test_simple.py b/tests/test_simple.py
index 41203a65..8148d05d 100644
--- a/tests/test_simple.py
+++ b/tests/test_simple.py
@@ -23,7 +23,9 @@
     BackupException, \
     QueryException, \
     TimeoutException, \
-    TestgresException, NodeApp
+    TestgresException, \
+    InvalidOperationException, \
+    NodeApp
 
 from testgres import \
     TestgresConfig, \
@@ -153,7 +155,6 @@ def test_init_unique_system_id(self):
 
         with scoped_config(cache_initdb=True,
                            cached_initdb_unique=True) as config:
-
             self.assertTrue(config.cache_initdb)
             self.assertTrue(config.cached_initdb_unique)
 
@@ -311,6 +312,23 @@ def test_psql(self):
             with self.assertRaises(QueryException):
                 node.safe_psql('select 1')
 
+    def test_safe_psql__expect_error(self):
+        with get_new_node().init().start() as node:
+            err = node.safe_psql('select_or_not_select 1', expect_error=True)
+            self.assertTrue(type(err) == str)  # noqa: E721
+            self.assertIn('select_or_not_select', err)
+            self.assertIn('ERROR:  syntax error at or near "select_or_not_select"', err)
+
+            # ---------
+            with self.assertRaises(InvalidOperationException) as ctx:
+                node.safe_psql("select 1;", expect_error=True)
+
+            self.assertEqual(str(ctx.exception), "Exception was expected, but query finished successfully: `select 1;`.")
+
+            # ---------
+            res = node.safe_psql("select 1;", expect_error=False)
+            self.assertEqual(rm_carriage_returns(res), b'1\n')
+
     def test_transactions(self):
         with get_new_node().init().start() as node:
 
@@ -376,13 +394,11 @@ def test_backup_multiple(self):
 
             with node.backup(xlog_method='fetch') as backup1, \
                     node.backup(xlog_method='fetch') as backup2:
-
                 self.assertNotEqual(backup1.base_dir, backup2.base_dir)
 
             with node.backup(xlog_method='fetch') as backup:
                 with backup.spawn_primary('node1', destroy=False) as node1, \
                         backup.spawn_primary('node2', destroy=False) as node2:
-
                     self.assertNotEqual(node1.base_dir, node2.base_dir)
 
     def test_backup_exhaust(self):
@@ -390,7 +406,6 @@ def test_backup_exhaust(self):
             node.init(allow_streaming=True).start()
 
             with node.backup(xlog_method='fetch') as backup:
-
                 # exhaust backup by creating new node
                 with backup.spawn_primary():
                     pass
@@ -778,7 +793,6 @@ def test_pg_config(self):
 
         # modify setting for this scope
         with scoped_config(cache_pg_config=False) as config:
-
             # sanity check for value
             self.assertFalse(config.cache_pg_config)
 
@@ -810,7 +824,6 @@ def test_config_stack(self):
             self.assertEqual(c1.cached_initdb_dir, d1)
 
             with scoped_config(cached_initdb_dir=d2) as c2:
-
                 stack_size = len(testgres.config.config_stack)
 
                 # try to break a stack
@@ -840,7 +853,6 @@ def test_unix_sockets(self):
     def test_auto_name(self):
         with get_new_node().init(allow_streaming=True).start() as m:
             with m.replicate().start() as r:
-
                 # check that nodes are running
                 self.assertTrue(m.status())
                 self.assertTrue(r.status())
@@ -1039,10 +1051,189 @@ def test_parse_pg_version(self):
     def test_the_same_port(self):
         with get_new_node() as node:
             node.init().start()
+            self.assertTrue(node._should_free_port)
+            self.assertEqual(type(node.port), int)
+            node_port_copy = node.port
+            self.assertEqual(rm_carriage_returns(node.safe_psql("SELECT 1;")), b'1\n')
+
+            with get_new_node(port=node.port) as node2:
+                self.assertEqual(type(node2.port), int)
+                self.assertEqual(node2.port, node.port)
+                self.assertFalse(node2._should_free_port)
+
+                with self.assertRaises(StartNodeException) as ctx:
+                    node2.init().start()
+
+                self.assertIn("Cannot start node", str(ctx.exception))
+
+            # node is still working
+            self.assertEqual(node.port, node_port_copy)
+            self.assertTrue(node._should_free_port)
+            self.assertEqual(rm_carriage_returns(node.safe_psql("SELECT 3;")), b'3\n')
+
+    class tagPortManagerProxy:
+        sm_prev_testgres_reserve_port = None
+        sm_prev_testgres_release_port = None
+
+        sm_DummyPortNumber = None
+        sm_DummyPortMaxUsage = None
+
+        sm_DummyPortCurrentUsage = None
+        sm_DummyPortTotalUsage = None
+
+        def __init__(self, dummyPortNumber, dummyPortMaxUsage):
+            assert type(dummyPortNumber) == int  # noqa: E721
+            assert type(dummyPortMaxUsage) == int  # noqa: E721
+            assert dummyPortNumber >= 0
+            assert dummyPortMaxUsage >= 0
+
+            assert __class__.sm_prev_testgres_reserve_port is None
+            assert __class__.sm_prev_testgres_release_port is None
+            assert testgres.utils.reserve_port == testgres.utils.internal__reserve_port
+            assert testgres.utils.release_port == testgres.utils.internal__release_port
+
+            __class__.sm_prev_testgres_reserve_port = testgres.utils.reserve_port
+            __class__.sm_prev_testgres_release_port = testgres.utils.release_port
+
+            testgres.utils.reserve_port = __class__._proxy__reserve_port
+            testgres.utils.release_port = __class__._proxy__release_port
+
+            assert testgres.utils.reserve_port == __class__._proxy__reserve_port
+            assert testgres.utils.release_port == __class__._proxy__release_port
+
+            __class__.sm_DummyPortNumber = dummyPortNumber
+            __class__.sm_DummyPortMaxUsage = dummyPortMaxUsage
+
+            __class__.sm_DummyPortCurrentUsage = 0
+            __class__.sm_DummyPortTotalUsage = 0
+
+        def __enter__(self):
+            return self
+
+        def __exit__(self, type, value, traceback):
+            assert __class__.sm_DummyPortCurrentUsage == 0
+
+            assert __class__.sm_prev_testgres_reserve_port is not None
+            assert __class__.sm_prev_testgres_release_port is not None
+
+            assert testgres.utils.reserve_port == __class__._proxy__reserve_port
+            assert testgres.utils.release_port == __class__._proxy__release_port
+
+            testgres.utils.reserve_port = __class__.sm_prev_testgres_reserve_port
+            testgres.utils.release_port = __class__.sm_prev_testgres_release_port
+
+            __class__.sm_prev_testgres_reserve_port = None
+            __class__.sm_prev_testgres_release_port = None
+
+        def _proxy__reserve_port():
+            assert type(__class__.sm_DummyPortMaxUsage) == int  # noqa: E721
+            assert type(__class__.sm_DummyPortTotalUsage) == int  # noqa: E721
+            assert type(__class__.sm_DummyPortCurrentUsage) == int  # noqa: E721
+            assert __class__.sm_DummyPortTotalUsage >= 0
+            assert __class__.sm_DummyPortCurrentUsage >= 0
+
+            assert __class__.sm_DummyPortTotalUsage <= __class__.sm_DummyPortMaxUsage
+            assert __class__.sm_DummyPortCurrentUsage <= __class__.sm_DummyPortTotalUsage
 
-            with get_new_node() as node2:
-                node2.port = node.port
-                node2.init().start()
+            assert __class__.sm_prev_testgres_reserve_port is not None
+
+            if __class__.sm_DummyPortTotalUsage == __class__.sm_DummyPortMaxUsage:
+                return __class__.sm_prev_testgres_reserve_port()
+
+            __class__.sm_DummyPortTotalUsage += 1
+            __class__.sm_DummyPortCurrentUsage += 1
+            return __class__.sm_DummyPortNumber
+
+        def _proxy__release_port(dummyPortNumber):
+            assert type(dummyPortNumber) == int  # noqa: E721
+
+            assert type(__class__.sm_DummyPortMaxUsage) == int  # noqa: E721
+            assert type(__class__.sm_DummyPortTotalUsage) == int  # noqa: E721
+            assert type(__class__.sm_DummyPortCurrentUsage) == int  # noqa: E721
+            assert __class__.sm_DummyPortTotalUsage >= 0
+            assert __class__.sm_DummyPortCurrentUsage >= 0
+
+            assert __class__.sm_DummyPortTotalUsage <= __class__.sm_DummyPortMaxUsage
+            assert __class__.sm_DummyPortCurrentUsage <= __class__.sm_DummyPortTotalUsage
+
+            assert __class__.sm_prev_testgres_release_port is not None
+
+            if __class__.sm_DummyPortCurrentUsage > 0 and dummyPortNumber == __class__.sm_DummyPortNumber:
+                assert __class__.sm_DummyPortTotalUsage > 0
+                __class__.sm_DummyPortCurrentUsage -= 1
+                return
+
+            return __class__.sm_prev_testgres_release_port(dummyPortNumber)
+
+    def test_port_rereserve_during_node_start(self):
+        assert testgres.PostgresNode._C_MAX_START_ATEMPTS == 5
+
+        C_COUNT_OF_BAD_PORT_USAGE = 3
+
+        with get_new_node() as node1:
+            node1.init().start()
+            self.assertTrue(node1._should_free_port)
+            self.assertEqual(type(node1.port), int)  # noqa: E721
+            node1_port_copy = node1.port
+            self.assertEqual(rm_carriage_returns(node1.safe_psql("SELECT 1;")), b'1\n')
+
+            with __class__.tagPortManagerProxy(node1.port, C_COUNT_OF_BAD_PORT_USAGE):
+                assert __class__.tagPortManagerProxy.sm_DummyPortNumber == node1.port
+                with get_new_node() as node2:
+                    self.assertTrue(node2._should_free_port)
+                    self.assertEqual(node2.port, node1.port)
+
+                    node2.init().start()
+
+                    self.assertNotEqual(node2.port, node1.port)
+                    self.assertTrue(node2._should_free_port)
+                    self.assertEqual(__class__.tagPortManagerProxy.sm_DummyPortCurrentUsage, 0)
+                    self.assertEqual(__class__.tagPortManagerProxy.sm_DummyPortTotalUsage, C_COUNT_OF_BAD_PORT_USAGE)
+                    self.assertTrue(node2.is_started)
+
+                    self.assertEqual(rm_carriage_returns(node2.safe_psql("SELECT 2;")), b'2\n')
+
+            # node1 is still working
+            self.assertEqual(node1.port, node1_port_copy)
+            self.assertTrue(node1._should_free_port)
+            self.assertEqual(rm_carriage_returns(node1.safe_psql("SELECT 3;")), b'3\n')
+
+    def test_port_conflict(self):
+        assert testgres.PostgresNode._C_MAX_START_ATEMPTS > 1
+
+        C_COUNT_OF_BAD_PORT_USAGE = testgres.PostgresNode._C_MAX_START_ATEMPTS
+
+        with get_new_node() as node1:
+            node1.init().start()
+            self.assertTrue(node1._should_free_port)
+            self.assertEqual(type(node1.port), int)  # noqa: E721
+            node1_port_copy = node1.port
+            self.assertEqual(rm_carriage_returns(node1.safe_psql("SELECT 1;")), b'1\n')
+
+            with __class__.tagPortManagerProxy(node1.port, C_COUNT_OF_BAD_PORT_USAGE):
+                assert __class__.tagPortManagerProxy.sm_DummyPortNumber == node1.port
+                with get_new_node() as node2:
+                    self.assertTrue(node2._should_free_port)
+                    self.assertEqual(node2.port, node1.port)
+
+                    with self.assertRaises(StartNodeException) as ctx:
+                        node2.init().start()
+
+                    self.assertIn("Cannot start node after multiple attempts", str(ctx.exception))
+
+                    self.assertEqual(node2.port, node1.port)
+                    self.assertTrue(node2._should_free_port)
+                    self.assertEqual(__class__.tagPortManagerProxy.sm_DummyPortCurrentUsage, 1)
+                    self.assertEqual(__class__.tagPortManagerProxy.sm_DummyPortTotalUsage, C_COUNT_OF_BAD_PORT_USAGE)
+                    self.assertFalse(node2.is_started)
+
+                # node2 must release our dummyPort (node1.port)
+                self.assertEqual(__class__.tagPortManagerProxy.sm_DummyPortCurrentUsage, 0)
+
+            # node1 is still working
+            self.assertEqual(node1.port, node1_port_copy)
+            self.assertTrue(node1._should_free_port)
+            self.assertEqual(rm_carriage_returns(node1.safe_psql("SELECT 3;")), b'3\n')
 
     def test_simple_with_bin_dir(self):
         with get_new_node() as node:
@@ -1061,6 +1252,52 @@ def test_simple_with_bin_dir(self):
         except FileNotFoundError:
             pass  # Expected error
 
+    def test_set_auto_conf(self):
+        # elements contain [property id, value, storage value]
+        testData = [
+            ["archive_command",
+             "cp '%p' \"/mnt/server/archivedir/%f\"",
+             "'cp \\'%p\\' \"/mnt/server/archivedir/%f\""],
+            ["restore_command",
+             'cp "/mnt/server/archivedir/%f" \'%p\'',
+             "'cp \"/mnt/server/archivedir/%f\" \\'%p\\''"],
+            ["log_line_prefix",
+             "'\n\r\t\b\\\"",
+             "'\\\'\\n\\r\\t\\b\\\\\""],
+            ["log_connections",
+             True,
+             "on"],
+            ["log_disconnections",
+             False,
+             "off"],
+            ["autovacuum_max_workers",
+             3,
+             "3"]
+        ]
+
+        with get_new_node() as node:
+            node.init().start()
+
+            options = {}
+
+            for x in testData:
+                options[x[0]] = x[1]
+
+            node.set_auto_conf(options)
+            node.stop()
+            node.slow_start()
+
+            auto_conf_path = f"{node.data_dir}/postgresql.auto.conf"
+            with open(auto_conf_path, "r") as f:
+                content = f.read()
+
+                for x in testData:
+                    self.assertIn(
+                        x[0] + " = " + x[2],
+                        content,
+                        x[0] + " stored wrong"
+                    )
+
 
 if __name__ == '__main__':
     if os.environ.get('ALT_CONFIG'):
diff --git a/tests/test_simple_remote.py b/tests/test_simple_remote.py
index 79bdb74c..c8dd2964 100755
--- a/tests/test_simple_remote.py
+++ b/tests/test_simple_remote.py
@@ -23,7 +23,8 @@
     BackupException, \
     QueryException, \
     TimeoutException, \
-    TestgresException
+    TestgresException, \
+    InvalidOperationException
 
 from testgres.config import \
     TestgresConfig, \
@@ -94,7 +95,6 @@ def removing(f):
 
 
 class TestgresRemoteTests(unittest.TestCase):
-
     def test_node_repr(self):
         with get_remote_node(conn_params=conn_params) as node:
             pattern = r"PostgresNode\(name='.+', port=.+, base_dir='.+'\)"
@@ -296,6 +296,23 @@ def test_psql(self):
             with self.assertRaises(QueryException):
                 node.safe_psql('select 1')
 
+    def test_safe_psql__expect_error(self):
+        with get_remote_node(conn_params=conn_params).init().start() as node:
+            err = node.safe_psql('select_or_not_select 1', expect_error=True)
+            self.assertTrue(type(err) == str)  # noqa: E721
+            self.assertIn('select_or_not_select', err)
+            self.assertIn('ERROR:  syntax error at or near "select_or_not_select"', err)
+
+            # ---------
+            with self.assertRaises(InvalidOperationException) as ctx:
+                node.safe_psql("select 1;", expect_error=True)
+
+            self.assertEqual(str(ctx.exception), "Exception was expected, but query finished successfully: `select 1;`.")
+
+            # ---------
+            res = node.safe_psql("select 1;", expect_error=False)
+            self.assertEqual(res, b'1\n')
+
     def test_transactions(self):
         with get_remote_node(conn_params=conn_params).init().start() as node:
             with node.connect() as con:
@@ -748,6 +765,7 @@ def test_pg_config(self):
 
         # save right before config change
         c1 = get_pg_config()
+
         # modify setting for this scope
         with scoped_config(cache_pg_config=False) as config:
             # sanity check for value
@@ -922,6 +940,9 @@ def test_child_pids(self):
         if pg_version_ge('10'):
             master_processes.append(ProcessType.LogicalReplicationLauncher)
 
+        if pg_version_ge('14'):
+            master_processes.remove(ProcessType.StatsCollector)
+
         repl_processes = [
             ProcessType.Startup,
             ProcessType.WalReceiver,