55
66import dataclasses
77import pathlib
8+ from datetime import timedelta
89from unittest import mock
910
1011import pytest
1314
1415from frequenz .client .base .channel import (
1516 ChannelOptions ,
17+ KeepAliveOptions ,
1618 SslOptions ,
1719 _to_bool ,
1820 parse_grpc_uri ,
@@ -136,6 +138,67 @@ class _ValidUrlTestCase:
136138 ),
137139 ),
138140 ),
141+ _ValidUrlTestCase (
142+ title = "Keep-alive no defaults" ,
143+ uri = "grpc://localhost:1234?keep_alive=1&keep_alive_interval_s=300"
144+ + "&keep_alive_timeout_s=60" ,
145+ expected_host = "localhost" ,
146+ expected_port = 1234 ,
147+ expected_options = ChannelOptions (
148+ keep_alive = KeepAliveOptions (
149+ enabled = True ,
150+ interval = timedelta (minutes = 5 ),
151+ timeout = timedelta (minutes = 1 ),
152+ ),
153+ ),
154+ ),
155+ _ValidUrlTestCase (
156+ title = "Keep-alive default timeout" ,
157+ uri = "grpc://localhost:1234?keep_alive=1&keep_alive_interval_s=300" ,
158+ defaults = ChannelOptions (
159+ keep_alive = KeepAliveOptions (
160+ enabled = True ,
161+ interval = timedelta (seconds = 10 ),
162+ timeout = timedelta (seconds = 2 ),
163+ ),
164+ ),
165+ expected_host = "localhost" ,
166+ expected_port = 1234 ,
167+ expected_options = ChannelOptions (
168+ keep_alive = KeepAliveOptions (
169+ enabled = True ,
170+ interval = timedelta (seconds = 300 ),
171+ timeout = timedelta (seconds = 2 ),
172+ ),
173+ ),
174+ ),
175+ _ValidUrlTestCase (
176+ title = "Keep-alive default interval" ,
177+ uri = "grpc://localhost:1234?keep_alive=1&keep_alive_timeout_s=60" ,
178+ defaults = ChannelOptions (
179+ keep_alive = KeepAliveOptions (
180+ enabled = True , interval = timedelta (minutes = 30 )
181+ ),
182+ ),
183+ expected_host = "localhost" ,
184+ expected_port = 1234 ,
185+ expected_options = ChannelOptions (
186+ keep_alive = KeepAliveOptions (
187+ enabled = True ,
188+ timeout = timedelta (minutes = 1 ),
189+ interval = timedelta (minutes = 30 ),
190+ ),
191+ ),
192+ ),
193+ _ValidUrlTestCase (
194+ title = "keep-alive disabled" ,
195+ uri = "grpc://localhost:1234?keep_alive=0" ,
196+ expected_host = "localhost" ,
197+ expected_port = 1234 ,
198+ expected_options = ChannelOptions (
199+ keep_alive = KeepAliveOptions (enabled = False ),
200+ ),
201+ ),
139202 ],
140203 ids = lambda case : case .title ,
141204)
@@ -154,7 +217,9 @@ def test_parse_uri_ok( # pylint: disable=too-many-locals
154217 )
155218 expected_port = case .expected_port
156219 expected_ssl = (
157- expected_options .ssl .enabled if "ssl=" in uri else defaults .ssl .enabled
220+ expected_options .ssl .enabled
221+ if "ssl=" in uri or defaults .ssl .enabled is None
222+ else defaults .ssl .enabled
158223 )
159224 expected_root_certificates = (
160225 expected_options .ssl .root_certificates
@@ -196,6 +261,35 @@ def test_parse_uri_ok( # pylint: disable=too-many-locals
196261
197262 assert channel == expected_channel
198263 expected_target = f"{ expected_host } :{ expected_port } "
264+ expected_keep_alive = (
265+ expected_options .keep_alive if "keep_alive=" in uri else defaults .keep_alive
266+ )
267+ expected_keep_alive_interval = (
268+ expected_keep_alive .interval
269+ if "keep_alive_interval_s=" in uri
270+ else defaults .keep_alive .interval
271+ )
272+ expected_keep_alive_timeout = (
273+ expected_keep_alive .timeout
274+ if "keep_alive_timeout_s=" in uri
275+ else defaults .keep_alive .timeout
276+ )
277+ expected_channel_options = (
278+ [
279+ ("grpc.http2.max_pings_without_data" , 0 ),
280+ ("grpc.keepalive_permit_without_calls" , 1 ),
281+ (
282+ "grpc.keepalive_time_ms" ,
283+ (expected_keep_alive_interval .total_seconds () * 1000 ),
284+ ),
285+ (
286+ "grpc.keepalive_timeout_ms" ,
287+ expected_keep_alive_timeout .total_seconds () * 1000 ,
288+ ),
289+ ]
290+ if expected_keep_alive .enabled
291+ else None
292+ )
199293 if expected_ssl :
200294 if isinstance (expected_root_certificates , pathlib .Path ):
201295 get_contents_mock .assert_any_call (
@@ -221,10 +315,12 @@ def test_parse_uri_ok( # pylint: disable=too-many-locals
221315 certificate_chain = expected_certificate_chain ,
222316 )
223317 secure_channel_mock .assert_called_once_with (
224- expected_target , expected_credentials
318+ expected_target , expected_credentials , expected_channel_options
225319 )
226320 else :
227- insecure_channel_mock .assert_called_once_with (expected_target )
321+ insecure_channel_mock .assert_called_once_with (
322+ expected_target , expected_channel_options
323+ )
228324
229325
230326@pytest .mark .parametrize ("value" , ["true" , "on" , "1" , "TrUe" , "On" , "ON" , "TRUE" ])
0 commit comments