Skip to content

Commit 8bf0860

Browse files
committed
don't hardcode .ai into get_tunnel_url()
1 parent 68afe5a commit 8bf0860

4 files changed

Lines changed: 55 additions & 2 deletions

File tree

src/runloop_api_client/sdk/async_devbox.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,9 @@ async def get_tunnel_url(
161161
tunnel_view = await self.get_tunnel(**options)
162162
if tunnel_view is None:
163163
return None
164-
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.runloop.ai"
164+
api_host = self._client.base_url.host
165+
base_domain = api_host[4:] if api_host.startswith("api.") else api_host
166+
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.{base_domain}"
165167

166168
async def logs(
167169
self,

src/runloop_api_client/sdk/devbox.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ def get_tunnel_url(
160160
tunnel_view = self.get_tunnel(**options)
161161
if tunnel_view is None:
162162
return None
163-
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.runloop.ai"
163+
api_host = self._client.base_url.host
164+
base_domain = api_host[4:] if api_host.startswith("api.") else api_host
165+
return f"https://{port}-{tunnel_view.tunnel_key}.tunnel.{base_domain}"
164166

165167
def logs(
166168
self,

tests/sdk/async_devbox/test_core.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from types import SimpleNamespace
1010
from unittest.mock import AsyncMock
1111

12+
import httpx
13+
1214
import pytest
1315

1416
from tests.sdk.conftest import MockDevboxView
@@ -377,13 +379,36 @@ async def test_get_tunnel_url_constructs_url(self, mock_async_client: AsyncMock)
377379
tunnel=tunnel_view,
378380
)
379381
mock_async_client.devboxes.retrieve = AsyncMock(return_value=devbox_view_with_tunnel)
382+
mock_async_client.base_url = httpx.URL("https://api.runloop.ai")
380383

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

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

390+
@pytest.mark.asyncio
391+
async def test_get_tunnel_url_derives_domain_from_base_url(self, mock_async_client: AsyncMock) -> None:
392+
"""Test get_tunnel_url derives tunnel domain from client base_url."""
393+
tunnel_view = SimpleNamespace(
394+
tunnel_key="abc123xyz",
395+
auth_mode="open",
396+
create_time_ms=1234567890000,
397+
)
398+
devbox_view_with_tunnel = SimpleNamespace(
399+
id="dbx_123",
400+
status="running",
401+
tunnel=tunnel_view,
402+
)
403+
mock_async_client.devboxes.retrieve = AsyncMock(return_value=devbox_view_with_tunnel)
404+
devbox = AsyncDevbox(mock_async_client, "dbx_123")
405+
406+
mock_async_client.base_url = httpx.URL("https://api.runloop.pro")
407+
assert await devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.runloop.pro"
408+
409+
mock_async_client.base_url = httpx.URL("http://127.0.0.1:8080")
410+
assert await devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.127.0.0.1"
411+
387412
@pytest.mark.asyncio
388413
async def test_get_tunnel_url_returns_none_when_no_tunnel(self, mock_async_client: AsyncMock) -> None:
389414
"""Test get_tunnel_url returns None when no tunnel is enabled."""

tests/sdk/devbox/test_core.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from types import SimpleNamespace
1010
from unittest.mock import Mock
1111

12+
import httpx
13+
1214
import pytest
1315

1416
from tests.sdk.conftest import (
@@ -373,13 +375,35 @@ def test_get_tunnel_url_constructs_url(self, mock_client: Mock) -> None:
373375
tunnel=tunnel_view,
374376
)
375377
mock_client.devboxes.retrieve.return_value = devbox_view_with_tunnel
378+
mock_client.base_url = httpx.URL("https://api.runloop.ai")
376379

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

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

386+
def test_get_tunnel_url_derives_domain_from_base_url(self, mock_client: Mock) -> None:
387+
"""Test get_tunnel_url derives tunnel domain from client base_url."""
388+
tunnel_view = SimpleNamespace(
389+
tunnel_key="abc123xyz",
390+
auth_mode="open",
391+
create_time_ms=1234567890000,
392+
)
393+
devbox_view_with_tunnel = SimpleNamespace(
394+
id="dbx_123",
395+
status="running",
396+
tunnel=tunnel_view,
397+
)
398+
mock_client.devboxes.retrieve.return_value = devbox_view_with_tunnel
399+
devbox = Devbox(mock_client, "dbx_123")
400+
401+
mock_client.base_url = httpx.URL("https://api.runloop.pro")
402+
assert devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.runloop.pro"
403+
404+
mock_client.base_url = httpx.URL("http://127.0.0.1:8080")
405+
assert devbox.get_tunnel_url(8080) == "https://8080-abc123xyz.tunnel.127.0.0.1"
406+
383407
def test_get_tunnel_url_returns_none_when_no_tunnel(self, mock_client: Mock) -> None:
384408
"""Test get_tunnel_url returns None when no tunnel is enabled."""
385409
devbox_view_no_tunnel = SimpleNamespace(

0 commit comments

Comments
 (0)