Skip to content

Commit 22795f5

Browse files
PostgresNode::start2 is added (#314)
New method starts a node but does not touch 'is_started' flag. It is a special support for tests where node starts but implicitly stops within some time. For example server detects a corrupted data during recovery and stops. Test is added.
1 parent ee4a461 commit 22795f5

2 files changed

Lines changed: 69 additions & 24 deletions

File tree

src/node.py

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,9 +1005,36 @@ def slow_start(self, replica=False, dbname='template1', username=None, max_attem
10051005
raise
10061006
return
10071007

1008-
def start(self, params=[], wait=True, exec_env=None):
1008+
def start(self, params=[], wait=True, exec_env=None) -> PostgresNode:
10091009
"""
1010-
Starts the PostgreSQL node using pg_ctl if node has not been started.
1010+
Starts the PostgreSQL node using pg_ctl and set flag 'is_started'.
1011+
By default, it waits for the operation to complete before returning.
1012+
Optionally, it can return immediately without waiting for the start operation
1013+
to complete by setting the `wait` parameter to False.
1014+
1015+
Args:
1016+
params: additional arguments for pg_ctl.
1017+
wait: wait until operation completes.
1018+
1019+
Returns:
1020+
This instance of :class:`.PostgresNode`.
1021+
"""
1022+
self.start2()
1023+
1024+
if not wait:
1025+
# Postmaster process is starting in background
1026+
self._manually_started_pm_pid = __class__._C_PM_PID__IS_NOT_DETECTED
1027+
else:
1028+
self._manually_started_pm_pid = self._get_node_state().pid
1029+
if self._manually_started_pm_pid is None:
1030+
self._raise_cannot_start_node(None, "Cannot detect postmaster pid.")
1031+
1032+
assert type(self._manually_started_pm_pid) == int # noqa: E721
1033+
return self
1034+
1035+
def start2(self, params=[], wait=True, exec_env=None) -> None:
1036+
"""
1037+
Starts the PostgreSQL node using pg_ctl.
10111038
By default, it waits for the operation to complete before returning.
10121039
Optionally, it can return immediately without waiting for the start operation
10131040
to complete by setting the `wait` parameter to False.
@@ -1040,18 +1067,9 @@ def LOCAL__start_node():
10401067
if error and 'does not exist' in error:
10411068
raise Exception(error)
10421069

1043-
def LOCAL__raise_cannot_start_node(
1044-
from_exception: typing.Optional[Exception],
1045-
msg: str
1046-
):
1047-
assert from_exception is None or isinstance(from_exception, Exception)
1048-
assert type(msg) == str # noqa: E721
1049-
files = self._collect_special_files()
1050-
raise_from(StartNodeException(msg, files), from_exception)
1051-
10521070
def LOCAL__raise_cannot_start_node__std(from_exception):
10531071
assert isinstance(from_exception, Exception)
1054-
LOCAL__raise_cannot_start_node(from_exception, 'Cannot start node')
1072+
self._raise_cannot_start_node(from_exception, 'Cannot start node')
10551073

10561074
if not self._should_free_port:
10571075
try:
@@ -1078,7 +1096,7 @@ def LOCAL__raise_cannot_start_node__std(from_exception):
10781096
assert nAttempt > 0
10791097
assert nAttempt <= __class__._C_MAX_START_ATEMPTS
10801098
if nAttempt == __class__._C_MAX_START_ATEMPTS:
1081-
LOCAL__raise_cannot_start_node(e, "Cannot start node after multiple attempts.")
1099+
self._raise_cannot_start_node(e, "Cannot start node after multiple attempts.")
10821100

10831101
is_it_port_conflict = PostgresNodeUtils.delect_port_conflict(log_reader)
10841102

@@ -1103,18 +1121,17 @@ def LOCAL__raise_cannot_start_node__std(from_exception):
11031121
continue
11041122
break
11051123
self._maybe_start_logger()
1124+
return
11061125

1107-
if not wait:
1108-
# Postmaster process is starting in background
1109-
self._manually_started_pm_pid = __class__._C_PM_PID__IS_NOT_DETECTED
1110-
else:
1111-
self._manually_started_pm_pid = self._get_node_state().pid
1112-
if self._manually_started_pm_pid is None:
1113-
LOCAL__raise_cannot_start_node(None, "Cannot detect postmaster pid.")
1114-
1115-
assert type(self._manually_started_pm_pid) == int # noqa: E721
1116-
1117-
return self
1126+
def _raise_cannot_start_node(
1127+
self,
1128+
from_exception: typing.Optional[Exception],
1129+
msg: str
1130+
):
1131+
assert from_exception is None or isinstance(from_exception, Exception)
1132+
assert type(msg) == str # noqa: E721
1133+
files = self._collect_special_files()
1134+
raise_from(StartNodeException(msg, files), from_exception)
11181135

11191136
def stop(self, params=[], wait=True):
11201137
"""

tests/test_testgres_common.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,34 @@ def test_uninitialized_start(self, node_svc: PostgresNodeService):
283283
assert node.status() == NodeStatus.Uninitialized
284284
return
285285

286+
def test_start2(self, node_svc: PostgresNodeService):
287+
assert isinstance(node_svc, PostgresNodeService)
288+
289+
with __class__.helper__get_node(node_svc) as node:
290+
node.init()
291+
assert not node.is_started
292+
assert node.status() == NodeStatus.Stopped
293+
node.start2()
294+
assert not node.is_started
295+
assert node.status() == NodeStatus.Running
296+
297+
with pytest.raises(expected_exception=StartNodeException) as x:
298+
# can't start node more than once
299+
node.start2()
300+
301+
assert x is not None
302+
assert type(x.value) == StartNodeException # noqa: E721
303+
assert type(x.value.description) == str # noqa: E721
304+
assert type(x.value.message) == str # noqa: E721
305+
306+
assert x.value.description == "Cannot start node"
307+
assert x.value.message.startswith(x.value.description)
308+
309+
assert not node.is_started
310+
assert node.status() == NodeStatus.Running
311+
312+
return
313+
286314
def test_restart(self, node_svc: PostgresNodeService):
287315
assert isinstance(node_svc, PostgresNodeService)
288316

0 commit comments

Comments
 (0)