Skip to content

Commit 22ca197

Browse files
committed
Allow passing ChannelOptions to BaseApiClient
Signed-off-by: Leandro Lucarella <[email protected]>
1 parent b5392c5 commit 22ca197

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

src/frequenz/client/base/client.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
from grpc.aio import AioRpcError, Channel
1212

13-
from .channel import parse_grpc_uri
13+
from .channel import ChannelOptions, parse_grpc_uri
1414
from .exception import ApiClientError, ClientNotConnected
1515

1616
StubT = TypeVar("StubT")
@@ -117,6 +117,7 @@ def __init__(
117117
create_stub: Callable[[Channel], StubT],
118118
*,
119119
connect: bool = True,
120+
channel_defaults: ChannelOptions = ChannelOptions(),
120121
) -> None:
121122
"""Create an instance and connect to the server.
122123
@@ -127,9 +128,12 @@ def __init__(
127128
created. If `False`, the client will not connect to the server until
128129
[connect()][frequenz.client.base.client.BaseApiClient.connect] is
129130
called.
131+
channel_defaults: The default options for the gRPC channel to create using
132+
the server URL.
130133
"""
131134
self._server_url: str = server_url
132135
self._create_stub: Callable[[Channel], StubT] = create_stub
136+
self._channel_defaults: ChannelOptions = channel_defaults
133137
self._channel: Channel | None = None
134138
self._stub: StubT | None = None
135139
if connect:
@@ -156,6 +160,11 @@ def channel(self) -> Channel:
156160
raise ClientNotConnected(server_url=self.server_url, operation="channel")
157161
return self._channel
158162

163+
@property
164+
def channel_defaults(self) -> ChannelOptions:
165+
"""The default options for the gRPC channel."""
166+
return self._channel_defaults
167+
159168
@property
160169
def stub(self) -> StubT:
161170
"""The underlying gRPC stub.
@@ -192,7 +201,7 @@ def connect(self, server_url: str | None = None) -> None:
192201
self._server_url = server_url
193202
elif self.is_connected:
194203
return
195-
self._channel = parse_grpc_uri(self._server_url)
204+
self._channel = parse_grpc_uri(self._server_url, self._channel_defaults)
196205
self._stub = self._create_stub(self._channel)
197206

198207
async def disconnect(self) -> None:

tests/test_client.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import pytest
1212
import pytest_mock
1313

14+
from frequenz.client.base.channel import ChannelOptions, SslOptions
1415
from frequenz.client.base.client import BaseApiClient, StubT, call_stub_method
1516
from frequenz.client.base.exception import ClientNotConnected, UnknownError
1617

@@ -52,6 +53,7 @@ def create_client_with_mocks(
5253
*,
5354
auto_connect: bool = True,
5455
server_url: str = _DEFAULT_SERVER_URL,
56+
channel_defaults: ChannelOptions | None = None,
5557
) -> tuple[BaseApiClient[mock.MagicMock], _ClientMocks]:
5658
"""Create a BaseApiClient instance with mocks."""
5759
mock_stub = mock.MagicMock(name="stub")
@@ -60,10 +62,14 @@ def create_client_with_mocks(
6062
mock_parse_grpc_uri = mocker.patch(
6163
"frequenz.client.base.client.parse_grpc_uri", return_value=mock_channel
6264
)
65+
kwargs = {}
66+
if channel_defaults is not None:
67+
kwargs["channel_defaults"] = channel_defaults
6368
client = BaseApiClient(
6469
server_url=server_url,
6570
create_stub=mock_create_stub,
6671
connect=auto_connect,
72+
**kwargs,
6773
)
6874
return client, _ClientMocks(
6975
stub=mock_stub,
@@ -82,7 +88,9 @@ def test_base_api_client_init(
8288
client, mocks = create_client_with_mocks(mocker, auto_connect=auto_connect)
8389
assert client.server_url == _DEFAULT_SERVER_URL
8490
if auto_connect:
85-
mocks.parse_grpc_uri.assert_called_once_with(client.server_url)
91+
mocks.parse_grpc_uri.assert_called_once_with(
92+
client.server_url, ChannelOptions()
93+
)
8694
assert client.channel is mocks.channel
8795
assert client.stub is mocks.stub
8896
assert client.is_connected
@@ -93,6 +101,20 @@ def test_base_api_client_init(
93101
mocks.create_stub.assert_not_called()
94102

95103

104+
def test_base_api_client_init_with_channel_defaults(
105+
mocker: pytest_mock.MockFixture,
106+
) -> None:
107+
"""Test initializing the BaseApiClient with channel defaults."""
108+
channel_defaults = ChannelOptions(port=1234, ssl=SslOptions(enabled=False))
109+
client, mocks = create_client_with_mocks(mocker, channel_defaults=channel_defaults)
110+
assert client.server_url == _DEFAULT_SERVER_URL
111+
mocks.parse_grpc_uri.assert_called_once_with(client.server_url, channel_defaults)
112+
assert client.channel is mocks.channel
113+
assert client.stub is mocks.stub
114+
assert client.is_connected
115+
mocks.create_stub.assert_called_once_with(mocks.channel)
116+
117+
96118
@pytest.mark.parametrize(
97119
"new_server_url", [None, _DEFAULT_SERVER_URL, "grpc://localhost:50051"]
98120
)
@@ -128,7 +150,9 @@ def test_base_api_client_connect(
128150
mocks.parse_grpc_uri.assert_not_called()
129151
mocks.create_stub.assert_not_called()
130152
else:
131-
mocks.parse_grpc_uri.assert_called_once_with(client.server_url)
153+
mocks.parse_grpc_uri.assert_called_once_with(
154+
client.server_url, ChannelOptions()
155+
)
132156
mocks.create_stub.assert_called_once_with(mocks.channel)
133157

134158

@@ -166,7 +190,9 @@ async def test_base_api_client_async_context_manager(
166190
mocks.parse_grpc_uri.assert_not_called()
167191
mocks.create_stub.assert_not_called()
168192
else:
169-
mocks.parse_grpc_uri.assert_called_once_with(client.server_url)
193+
mocks.parse_grpc_uri.assert_called_once_with(
194+
client.server_url, ChannelOptions()
195+
)
170196
mocks.create_stub.assert_called_once_with(mocks.channel)
171197

172198
mocks.channel.__aexit__.assert_called_once_with(None, None, None)

0 commit comments

Comments
 (0)