1313 DynamoPortRange ,
1414 EtcdContext ,
1515 PortAllocationRequest ,
16- PortBinding ,
1716 PortMetadata ,
1817 allocate_and_reserve_port ,
1918 allocate_and_reserve_port_block ,
@@ -50,19 +49,6 @@ def test_invalid_port_range_min_greater_than_max(self):
5049 DynamoPortRange (min = 3000 , max = 3000 )
5150
5251
53- class TestEtcdContext :
54- """Test ETCD context functionality."""
55-
56- def test_make_port_key (self ):
57- """Test port key generation."""
58- mock_client = Mock ()
59- context = EtcdContext (client = mock_client , namespace = "test-ns" )
60-
61- with patch ("socket.gethostname" , return_value = "test-host" ):
62- key = context .make_port_key (8080 )
63- assert key == "dyn://test-ns/ports/test-host/8080"
64-
65-
6652class TestPortMetadata :
6753 """Test port metadata functionality."""
6854
@@ -80,77 +66,6 @@ def test_to_etcd_value_with_block_info(self):
8066 assert value ["block_start" ] == 8080
8167
8268
83- class TestPortBinding :
84- """Test PortBinding context manager."""
85-
86- def test_single_port_binding (self ):
87- """Test binding a single port."""
88- # Find an available port
89- with socket .socket () as s :
90- s .bind (("" , 0 ))
91- port = s .getsockname ()[1 ]
92-
93- binding = PortBinding (port )
94- assert binding .ports == [port ]
95-
96- # Test context manager
97- with binding :
98- # Port should be bound
99- assert len (binding .sockets ) == 1
100- # Trying to bind again should fail
101- with pytest .raises (OSError ):
102- with socket .socket () as s :
103- s .bind (("" , port ))
104-
105- # After context, sockets should be closed
106- # We should be able to bind again
107- with socket .socket () as s :
108- s .bind (("" , port ))
109-
110- def test_multiple_port_binding (self ):
111- """Test binding multiple ports."""
112- # Find available ports
113- ports = []
114- for _ in range (3 ):
115- with socket .socket () as s :
116- s .bind (("" , 0 ))
117- ports .append (s .getsockname ()[1 ])
118-
119- binding = PortBinding (ports )
120- assert binding .ports == ports
121-
122- with binding :
123- assert len (binding .sockets ) == 3
124- # All ports should be bound
125- for port in ports :
126- with pytest .raises (OSError ):
127- with socket .socket () as s :
128- s .bind (("" , port ))
129-
130- def test_partial_binding_failure (self ):
131- """Test cleanup when only some ports can be bound."""
132- # Bind a port that we'll keep occupied
133- blocker = socket .socket ()
134- blocker .bind (("" , 0 ))
135- blocked_port = blocker .getsockname ()[1 ]
136-
137- # Find another available port
138- with socket .socket () as s :
139- s .bind (("" , 0 ))
140- good_port = s .getsockname ()[1 ]
141-
142- # Try to bind both ports (one will fail)
143- binding = PortBinding ([good_port , blocked_port ])
144-
145- with pytest .raises (OSError ):
146- binding .__enter__ ()
147-
148- # All sockets should be cleaned up
149- assert all (sock ._closed for sock in binding .sockets if hasattr (sock , "_closed" ))
150-
151- blocker .close ()
152-
153-
15469class TestHoldPorts :
15570 """Test hold_ports context manager."""
15671
@@ -160,9 +75,11 @@ def test_hold_single_port(self):
16075 s .bind (("" , 0 ))
16176 port = s .getsockname ()[1 ]
16277
163- with hold_ports (port ) as binding :
164- assert isinstance (binding , PortBinding )
165- assert len (binding .sockets ) == 1
78+ with hold_ports (port ):
79+ assert not check_port_available (port )
80+
81+ # Port should be released after context exit
82+ assert check_port_available (port )
16683
16784 def test_hold_multiple_ports (self ):
16885 """Test holding multiple ports."""
@@ -172,31 +89,13 @@ def test_hold_multiple_ports(self):
17289 s .bind (("" , 0 ))
17390 ports .append (s .getsockname ()[1 ])
17491
175- with hold_ports (ports ) as binding :
176- assert isinstance (binding , PortBinding )
177- assert len (binding .sockets ) == 2
178-
179-
180- class TestCheckPortAvailable :
181- """Test check_port_available function."""
182-
183- def test_port_is_available (self ):
184- """Test checking an available port."""
185- # Find an available port
186- with socket .socket () as s :
187- s .bind (("" , 0 ))
188- port = s .getsockname ()[1 ]
189-
190- assert check_port_available (port ) is True
191-
192- def test_port_is_not_available (self ):
193- """Test checking an occupied port."""
194- # Occupy a port
195- with socket .socket () as blocker :
196- blocker .bind (("" , 0 ))
197- port = blocker .getsockname ()[1 ]
92+ with hold_ports (ports ):
93+ for port in ports :
94+ assert not check_port_available (port )
19895
199- assert check_port_available (port ) is False
96+ # All ports should be released after context exit
97+ for port in ports :
98+ assert check_port_available (port )
20099
201100
202101class TestReservePortInEtcd :
@@ -206,20 +105,18 @@ class TestReservePortInEtcd:
206105 async def test_reserve_port_success (self ):
207106 """Test successful port reservation in ETCD."""
208107 mock_client = AsyncMock ()
209- mock_client .primary_lease_id = Mock (
210- return_value = "test-lease-123"
211- ) # Regular Mock, not async
108+ mock_client .primary_lease_id = Mock (return_value = "test-lease-123" )
212109
213110 context = EtcdContext (client = mock_client , namespace = "test-ns" )
214111 metadata = PortMetadata (worker_id = "test-worker" , reason = "test" )
215112
216- with patch ( "socket.gethostname" , return_value = "test-host" ):
217- await reserve_port_in_etcd (context , 8080 , metadata )
113+ host_ip = get_host_ip ()
114+ await reserve_port_in_etcd (context , 8080 , metadata )
218115
219116 mock_client .kv_create .assert_called_once ()
220117 call_args = mock_client .kv_create .call_args
221118
222- assert call_args .kwargs ["key" ] == "dyn://test-ns/ports/test-host /8080"
119+ assert call_args .kwargs ["key" ] == f "dyn://test-ns/ports/{ host_ip } /8080"
223120 assert call_args .kwargs ["lease_id" ] == "test-lease-123"
224121
225122 # Check the value is valid JSON
@@ -236,7 +133,7 @@ class TestAllocateAndReservePort:
236133 async def test_allocate_single_port_success (self ):
237134 """Test successful single port allocation."""
238135 mock_client = AsyncMock ()
239- mock_client .primary_lease_id . return_value = "test-lease"
136+ mock_client .primary_lease_id = Mock ( return_value = "test-lease" )
240137
241138 context = EtcdContext (client = mock_client , namespace = "test-ns" )
242139 metadata = PortMetadata (worker_id = "test-worker" , reason = "test" )
@@ -264,7 +161,7 @@ class TestAllocateAndReservePortBlock:
264161 async def test_allocate_block_success (self ):
265162 """Test successful port block allocation."""
266163 mock_client = AsyncMock ()
267- mock_client .primary_lease_id . return_value = "test-lease"
164+ mock_client .primary_lease_id = Mock ( return_value = "test-lease" )
268165
269166 context = EtcdContext (client = mock_client , namespace = "test-ns" )
270167 metadata = PortMetadata (worker_id = "test-worker" , reason = "test" )
0 commit comments