Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 3 additions & 1 deletion src/runloop_api_client/sdk/async_devbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,9 @@ async def get_tunnel_url(
tunnel_view = await self.get_tunnel(**options)
if tunnel_view is None:
return None
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.runloop.ai"
api_host = self._client.base_url.host
base_domain = api_host[4:] if api_host.startswith("api.") else api_host
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.{base_domain}"

async def logs(
self,
Expand Down
4 changes: 3 additions & 1 deletion src/runloop_api_client/sdk/devbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,9 @@ def get_tunnel_url(
tunnel_view = self.get_tunnel(**options)
if tunnel_view is None:
return None
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.runloop.ai"
api_host = self._client.base_url.host
base_domain = api_host[4:] if api_host.startswith("api.") else api_host
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.{base_domain}"

def logs(
self,
Expand Down
24 changes: 24 additions & 0 deletions tests/sdk/async_devbox/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from types import SimpleNamespace
from unittest.mock import AsyncMock

import httpx
import pytest

from tests.sdk.conftest import MockDevboxView
Expand Down Expand Up @@ -377,13 +378,36 @@ async def test_get_tunnel_url_constructs_url(self, mock_async_client: AsyncMock)
tunnel=tunnel_view,
)
mock_async_client.devboxes.retrieve = AsyncMock(return_value=devbox_view_with_tunnel)
mock_async_client.base_url = httpx.URL("https://api.runloop.ai")

devbox = AsyncDevbox(mock_async_client, "dbx_123")
result = await devbox.get_tunnel_url(8080)

assert result == "https://8080-abc123xyz.tunnel.runloop.ai"
mock_async_client.devboxes.retrieve.assert_called_once_with("dbx_123")

@pytest.mark.asyncio
async def test_get_tunnel_url_derives_domain_from_base_url(self, mock_async_client: AsyncMock) -> None:
"""Test get_tunnel_url derives tunnel domain from client base_url."""
tunnel_view = SimpleNamespace(
tunnel_key="abc123xyz",
auth_mode="open",
create_time_ms=1234567890000,
)
devbox_view_with_tunnel = SimpleNamespace(
id="dbx_123",
status="running",
tunnel=tunnel_view,
)
mock_async_client.devboxes.retrieve = AsyncMock(return_value=devbox_view_with_tunnel)
devbox = AsyncDevbox(mock_async_client, "dbx_123")

mock_async_client.base_url = httpx.URL("https://api.runloop.pro")
assert await devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.runloop.pro"

mock_async_client.base_url = httpx.URL("http://127.0.0.1:8080")
assert await devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.127.0.0.1"

@pytest.mark.asyncio
async def test_get_tunnel_url_returns_none_when_no_tunnel(self, mock_async_client: AsyncMock) -> None:
"""Test get_tunnel_url returns None when no tunnel is enabled."""
Expand Down
23 changes: 23 additions & 0 deletions tests/sdk/devbox/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from types import SimpleNamespace
from unittest.mock import Mock

import httpx
import pytest

from tests.sdk.conftest import (
Expand Down Expand Up @@ -373,13 +374,35 @@ def test_get_tunnel_url_constructs_url(self, mock_client: Mock) -> None:
tunnel=tunnel_view,
)
mock_client.devboxes.retrieve.return_value = devbox_view_with_tunnel
mock_client.base_url = httpx.URL("https://api.runloop.ai")

devbox = Devbox(mock_client, "dbx_123")
result = devbox.get_tunnel_url(8080)

assert result == "https://8080-abc123xyz.tunnel.runloop.ai"
mock_client.devboxes.retrieve.assert_called_once_with("dbx_123")

def test_get_tunnel_url_derives_domain_from_base_url(self, mock_client: Mock) -> None:
"""Test get_tunnel_url derives tunnel domain from client base_url."""
tunnel_view = SimpleNamespace(
tunnel_key="abc123xyz",
auth_mode="open",
create_time_ms=1234567890000,
)
devbox_view_with_tunnel = SimpleNamespace(
id="dbx_123",
status="running",
tunnel=tunnel_view,
)
mock_client.devboxes.retrieve.return_value = devbox_view_with_tunnel
devbox = Devbox(mock_client, "dbx_123")

mock_client.base_url = httpx.URL("https://api.runloop.pro")
assert devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.runloop.pro"

mock_client.base_url = httpx.URL("http://127.0.0.1:8080")
assert devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.127.0.0.1"

def test_get_tunnel_url_returns_none_when_no_tunnel(self, mock_client: Mock) -> None:
"""Test get_tunnel_url returns None when no tunnel is enabled."""
devbox_view_no_tunnel = SimpleNamespace(
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.