diff --git a/docs/docs/SUMMARY.md b/docs/docs/SUMMARY.md index c2f9915daf..95f4245e0f 100644 --- a/docs/docs/SUMMARY.md +++ b/docs/docs/SUMMARY.md @@ -960,6 +960,7 @@ search: - [build_message](api/faststream/rabbit/testing/build_message.md) - utils - [build_url](api/faststream/rabbit/utils/build_url.md) + - [build_virtual_host](api/faststream/rabbit/utils/build_virtual_host.md) - [is_routing_exchange](api/faststream/rabbit/utils/is_routing_exchange.md) - redis - [ListSub](api/faststream/redis/ListSub.md) diff --git a/docs/docs/en/api/faststream/rabbit/utils/build_virtual_host.md b/docs/docs/en/api/faststream/rabbit/utils/build_virtual_host.md new file mode 100644 index 0000000000..bab956290b --- /dev/null +++ b/docs/docs/en/api/faststream/rabbit/utils/build_virtual_host.md @@ -0,0 +1,11 @@ +--- +# 0.5 - API +# 2 - Release +# 3 - Contributing +# 5 - Template Page +# 10 - Default +search: + boost: 0.5 +--- + +::: faststream.rabbit.utils.build_virtual_host diff --git a/faststream/rabbit/utils.py b/faststream/rabbit/utils.py index 02da20e589..6011fc05cb 100644 --- a/faststream/rabbit/utils.py +++ b/faststream/rabbit/utils.py @@ -12,6 +12,18 @@ from faststream.rabbit.schemas import RabbitExchange +def build_virtual_host( + url: Union[str, "URL", None], virtualhost: Optional[str], path: str +) -> str: + if (not url and not virtualhost) or virtualhost == "/": + return "" + elif virtualhost: + return virtualhost + else: + vh = path.replace("/", "", 1) + return vh + + def build_url( url: Union[str, "URL", None] = None, *, @@ -36,7 +48,7 @@ def build_url( port=port or original_url.port or default_port, login=login or original_url.user or "guest", password=password or original_url.password or "guest", - virtualhost=virtualhost or original_url.path.replace("/", "", 1), + virtualhost=build_virtual_host(url, virtualhost, original_url.path), ssl=use_ssl, ssl_options=ssl_options, client_properties=client_properties, diff --git a/tests/brokers/rabbit/test_connect.py b/tests/brokers/rabbit/test_connect.py index ed756ad87e..61934ec043 100644 --- a/tests/brokers/rabbit/test_connect.py +++ b/tests/brokers/rabbit/test_connect.py @@ -4,7 +4,6 @@ from faststream.rabbit import RabbitBroker from faststream.security import SASLPlaintext -from faststream.rabbit.utils import build_url from tests.brokers.base.connection import BrokerConnectionTestcase @@ -16,7 +15,7 @@ def get_broker_args(self, settings): return {"url": settings.url} @pytest.mark.asyncio - async def test_init_connect_by_raw_data(self, settings): + async def test_connect_handover_config_to_init(self, settings): broker = self.broker( host=settings.host, port=settings.port, @@ -29,7 +28,7 @@ async def test_init_connect_by_raw_data(self, settings): await broker.close() @pytest.mark.asyncio - async def test_connection_by_params(self, settings): + async def test_connect_handover_config_to_connect(self, settings): broker = self.broker() assert await broker.connect( host=settings.host, @@ -42,34 +41,7 @@ async def test_connection_by_params(self, settings): await broker.close() @pytest.mark.asyncio - async def test_connect_merge_kwargs_with_priority(self, settings): - broker = self.broker(host="fake-host", port=5677) # kwargs will be ignored - assert await broker.connect( - host=settings.host, - port=settings.port, - security=SASLPlaintext( - username=settings.login, - password=settings.password, - ), - ) - await broker.close() - - @pytest.mark.asyncio - async def test_connect_merge_args_and_kwargs_native(self, settings): + async def test_connect_handover_config_to_connect_override_init(self, settings): broker = self.broker("fake-url") # will be ignored assert await broker.connect(url=settings.url) await broker.close() - - @pytest.mark.asyncio - @pytest.mark.parametrize( - "test_input,expected", - [ - ("amqp://root:root@localhost:5672/vh", "amqp://root:root@localhost:5672/vh"), - ("amqp://root:root@localhost:5672/", "amqp://root:root@localhost:5672/"), - ("amqp://root:root@localhost:5672//vh", "amqp://root:root@localhost:5672//vh"), - ("amqp://root:root@localhost:5672/vh/vh2", "amqp://root:root@localhost:5672/vh/vh2"), - ("amqp://root:root@localhost:5672//vh/vh2", "amqp://root:root@localhost:5672//vh/vh2") - ] - ) - async def test_build_url(self, test_input, expected): - assert str(build_url(test_input)) == expected diff --git a/tests/brokers/rabbit/test_url_builder.py b/tests/brokers/rabbit/test_url_builder.py new file mode 100644 index 0000000000..7148f28794 --- /dev/null +++ b/tests/brokers/rabbit/test_url_builder.py @@ -0,0 +1,54 @@ +from typing import Any, Dict + +import pytest +from yarl import URL + +from faststream.rabbit.utils import build_url + + +class TestUrlBuilder: + def test_arg_priority_over_url(self, settings): + url = build_url( + url=settings.url, + host="host", + port=5673, + login="test", + password="test", # pragma: allowlist secret + virtualhost="test", + ) + assert url == URL("amqp://test:test@host:5673/test") + + def test_ssl_overwrites_protocol(self, settings): + url = build_url(url=settings.url, ssl=True) + assert url == URL("amqps://guest:guest@localhost:5672/") + + @pytest.mark.parametrize( + ("passed_url", "expected_url"), + [ + pytest.param( + "amqp://guest:guest@localhost:5672//", # pragma: allowlist secret + URL("amqp://guest:guest@localhost:5672//"), + ), + pytest.param( + "amqp://guest:guest@localhost:5672//test", # pragma: allowlist secret + URL("amqp://guest:guest@localhost:5672//test"), + ), + ], + ) + def test_exotic_virtualhost_variants(self, passed_url: str, expected_url: URL): + url = build_url(passed_url) + assert url == expected_url + + @pytest.mark.parametrize( + ("url_kwargs", "expected_url"), + [ + pytest.param({}, URL("amqp://guest:guest@localhost:5672/")), + pytest.param( + {"url": "fake", "virtualhost": "/", "host": "host"}, + URL("amqp://guest:guest@host:5672/"), + ), + ], + ) + def test_unpack_args(self, url_kwargs: Dict[str, Any], expected_url: URL) -> None: + url = build_url(**url_kwargs) + assert url == expected_url