Skip to content

Port numbers management is improved (#164) #165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
PostgresNode._C_MAX_START_ATEMPTS=5 is added (+ 1 new test)
Also
- TestgresTests.test_the_same_port is updated
- TestgresTests.test_port_rereserve_during_node_start is updated
- TestgresTests.test_port_conflict is added
  • Loading branch information
dmitry-lipetsk committed Dec 14, 2024
commit 663612cb870fbeade43db3a0c6f771127fb650a2
14 changes: 12 additions & 2 deletions testgres/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ def __repr__(self):


class PostgresNode(object):
# 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.
Expand Down Expand Up @@ -774,6 +777,9 @@ 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

Expand All @@ -789,13 +795,17 @@ def start(self, params=[], wait=True):
nAttempt = 0
timeout = 1
while True:
assert nAttempt >= 0
assert nAttempt < __class__._C_MAX_START_ATEMPTS
nAttempt += 1
try:
exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
if error and 'does not exist' in error:
raise Exception
except Exception as e:
if self._should_free_port and nAttempt < 5:
assert nAttempt > 0
assert nAttempt <= __class__._C_MAX_START_ATEMPTS
if self._should_free_port and nAttempt < __class__._C_MAX_START_ATEMPTS:
log_files1 = self._collect_log_files()
if self._detect_port_conflict(log_files0, log_files1):
log_files0 = log_files1
Expand All @@ -806,7 +816,7 @@ def start(self, params=[], wait=True):
time.sleep(timeout)
timeout = min(2 * timeout, 5)
cur_port = self.port
new_port = utils.reserve_port() # throw
new_port = utils.reserve_port() # can raise
try:
options = {'port': str(new_port)}
self.set_auto_conf(options)
Expand Down
58 changes: 56 additions & 2 deletions tests/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,8 @@ def test_the_same_port(self):
node.init().start()
self.assertTrue(node._should_free_port)
self.assertEqual(type(node.port), int)
node_port_copy = node.port
self.assertEqual(node.safe_psql("SELECT 1;"), b'1\n')

with get_new_node(port=node.port) as node2:
self.assertEqual(type(node2.port), int)
Expand All @@ -1064,6 +1066,11 @@ def test_the_same_port(self):

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(node.safe_psql("SELECT 3;"), b'3\n')

class tagPortManagerProxy:
sm_prev_testgres_reserve_port = None
sm_prev_testgres_release_port = None
Expand Down Expand Up @@ -1159,13 +1166,16 @@ def _proxy__release_port(dummyPortNumber):
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.safe_psql("SELECT 1;")
node1_port_copy = node1.port
self.assertEqual(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
Expand All @@ -1176,10 +1186,54 @@ def test_port_rereserve_during_node_start(self):
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(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(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(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", 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)

node2.safe_psql("SELECT 1;")
# node1 is still working
self.assertEqual(node1.port, node1_port_copy)
self.assertTrue(node1._should_free_port)
self.assertEqual(node1.safe_psql("SELECT 3;"), b'3\n')

def test_simple_with_bin_dir(self):
with get_new_node() as node:
Expand Down