Skip to content

Commit c4797b3

Browse files
committed
Add smoketests
1 parent 565d857 commit c4797b3

6 files changed

Lines changed: 156 additions & 3 deletions

File tree

src/runloop_api_client/sdk/_types.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
NetworkPolicyListParams,
2323
DevboxCreateTunnelParams,
2424
DevboxDownloadFileParams,
25+
DevboxEnableTunnelParams,
2526
DevboxRemoveTunnelParams,
2627
DevboxSnapshotDiskParams,
2728
NetworkPolicyCreateParams,
@@ -121,6 +122,10 @@ class SDKDevboxCreateTunnelParams(DevboxCreateTunnelParams, LongRequestOptions):
121122
pass
122123

123124

125+
class SDKDevboxEnableTunnelParams(DevboxEnableTunnelParams, LongRequestOptions):
126+
pass
127+
128+
124129
class SDKDevboxRemoveTunnelParams(DevboxRemoveTunnelParams, LongRequestOptions):
125130
pass
126131

src/runloop_api_client/sdk/async_devbox.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from ..types import (
1212
DevboxView,
13+
TunnelView,
1314
DevboxTunnelView,
1415
DevboxExecutionDetailView,
1516
DevboxCreateSSHKeyResponse,
@@ -24,6 +25,7 @@
2425
SDKDevboxUploadFileParams,
2526
SDKDevboxCreateTunnelParams,
2627
SDKDevboxDownloadFileParams,
28+
SDKDevboxEnableTunnelParams,
2729
SDKDevboxExecuteAsyncParams,
2830
SDKDevboxRemoveTunnelParams,
2931
SDKDevboxSnapshotDiskParams,
@@ -731,7 +733,9 @@ async def create_tunnel(
731733
self,
732734
**params: Unpack[SDKDevboxCreateTunnelParams],
733735
) -> DevboxTunnelView:
734-
"""Create a network tunnel to expose a devbox port publicly.
736+
"""[Deprecated] Create a legacy tunnel to expose a devbox port publicly.
737+
738+
Use :meth:`enable_tunnel` instead for the V2 tunnel API.
735739
736740
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxCreateTunnelParams` for available parameters
737741
:return: Details about the public endpoint
@@ -748,6 +752,30 @@ async def create_tunnel(
748752
**params,
749753
)
750754

755+
async def enable_tunnel(
756+
self,
757+
**params: Unpack[SDKDevboxEnableTunnelParams],
758+
) -> TunnelView:
759+
"""Enable a V2 tunnel for secure HTTP access to the devbox.
760+
761+
V2 tunnels provide encrypted URL-based access without exposing internal IDs.
762+
Each devbox can have one tunnel. The tunnel URL format is:
763+
``https://{port}-{tunnel_key}.tunnel.runloop.ai``
764+
765+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxEnableTunnelParams` for available parameters
766+
:return: Tunnel details including the tunnel key for constructing URLs
767+
:rtype: TunnelView
768+
769+
Example:
770+
>>> tunnel = await devbox.net.enable_tunnel(auth_mode="open")
771+
>>> print(f"Tunnel key: {tunnel.tunnel_key}")
772+
>>> # Access via: https://8080-{tunnel.tunnel_key}.tunnel.runloop.ai
773+
"""
774+
return await self._devbox._client.devboxes.enable_tunnel(
775+
self._devbox.id,
776+
**params,
777+
)
778+
751779
async def remove_tunnel(
752780
self,
753781
**params: Unpack[SDKDevboxRemoveTunnelParams],

src/runloop_api_client/sdk/devbox.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
from ..types import (
1212
DevboxView,
13+
TunnelView,
1314
DevboxTunnelView,
1415
DevboxExecutionDetailView,
1516
DevboxCreateSSHKeyResponse,
@@ -25,6 +26,7 @@
2526
SDKDevboxUploadFileParams,
2627
SDKDevboxCreateTunnelParams,
2728
SDKDevboxDownloadFileParams,
29+
SDKDevboxEnableTunnelParams,
2830
SDKDevboxExecuteAsyncParams,
2931
SDKDevboxRemoveTunnelParams,
3032
SDKDevboxSnapshotDiskParams,
@@ -734,7 +736,9 @@ def create_tunnel(
734736
self,
735737
**params: Unpack[SDKDevboxCreateTunnelParams],
736738
) -> DevboxTunnelView:
737-
"""Create a network tunnel to expose a devbox port publicly.
739+
"""[Deprecated] Create a legacy tunnel to expose a devbox port publicly.
740+
741+
Use :meth:`enable_tunnel` instead for the V2 tunnel API.
738742
739743
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxCreateTunnelParams` for available parameters
740744
:return: Details about the public endpoint
@@ -751,6 +755,30 @@ def create_tunnel(
751755
**params,
752756
)
753757

758+
def enable_tunnel(
759+
self,
760+
**params: Unpack[SDKDevboxEnableTunnelParams],
761+
) -> TunnelView:
762+
"""Enable a V2 tunnel for secure HTTP access to the devbox.
763+
764+
V2 tunnels provide encrypted URL-based access without exposing internal IDs.
765+
Each devbox can have one tunnel. The tunnel URL format is:
766+
``https://{port}-{tunnel_key}.tunnel.runloop.ai``
767+
768+
:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKDevboxEnableTunnelParams` for available parameters
769+
:return: Tunnel details including the tunnel key for constructing URLs
770+
:rtype: :class:`~runloop_api_client.types.tunnel_view.TunnelView`
771+
772+
Example:
773+
>>> tunnel = devbox.net.enable_tunnel(auth_mode="open")
774+
>>> print(f"Tunnel key: {tunnel.tunnel_key}")
775+
>>> # Access via: https://8080-{tunnel.tunnel_key}.tunnel.runloop.ai
776+
"""
777+
return self._devbox._client.devboxes.enable_tunnel(
778+
self._devbox.id,
779+
**params,
780+
)
781+
754782
def remove_tunnel(
755783
self,
756784
**params: Unpack[SDKDevboxRemoveTunnelParams],

tests/smoketests/sdk/test_async_devbox.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,53 @@ async def test_create_and_remove_tunnel(self, async_sdk_client: AsyncRunloopSDK)
458458
finally:
459459
await devbox.shutdown()
460460

461+
@pytest.mark.timeout(TWO_MINUTE_TIMEOUT)
462+
async def test_create_with_tunnel_param(self, async_sdk_client: AsyncRunloopSDK) -> None:
463+
"""Test creating a devbox with tunnel configuration in create params."""
464+
devbox = await async_sdk_client.devbox.create(
465+
name=unique_name("sdk-async-devbox-tunnel-param"),
466+
launch_parameters={"resource_size_request": "SMALL", "keep_alive_time_seconds": 60 * 5},
467+
tunnel={"auth_mode": "open"},
468+
)
469+
470+
try:
471+
# Verify devbox is running
472+
info = await devbox.get_info()
473+
assert info.status == "running"
474+
475+
# Verify tunnel was created at launch
476+
assert info.tunnel is not None
477+
assert info.tunnel.tunnel_key is not None
478+
assert info.tunnel.auth_mode is not None
479+
finally:
480+
await devbox.shutdown()
481+
482+
@pytest.mark.timeout(TWO_MINUTE_TIMEOUT)
483+
async def test_enable_tunnel(self, async_sdk_client: AsyncRunloopSDK) -> None:
484+
"""Test enabling a V2 tunnel on an existing devbox."""
485+
devbox = await async_sdk_client.devbox.create(
486+
name=unique_name("sdk-async-devbox-enable-tunnel"),
487+
launch_parameters={"resource_size_request": "SMALL", "keep_alive_time_seconds": 60 * 5},
488+
)
489+
490+
try:
491+
# Verify no tunnel exists initially
492+
info = await devbox.get_info()
493+
assert info.tunnel is None
494+
495+
# Enable tunnel using the V2 API via SDK
496+
tunnel = await devbox.net.enable_tunnel(auth_mode="open")
497+
assert tunnel is not None
498+
assert tunnel.tunnel_key is not None
499+
assert tunnel.auth_mode is not None
500+
501+
# Verify tunnel is now present in devbox info
502+
info = await devbox.get_info()
503+
assert info.tunnel is not None
504+
assert info.tunnel.tunnel_key == tunnel.tunnel_key
505+
finally:
506+
await devbox.shutdown()
507+
461508

462509
class TestAsyncDevboxCreationMethods:
463510
"""Test various async devbox creation methods."""

tests/smoketests/sdk/test_devbox.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,51 @@ def test_create_and_remove_tunnel(self, sdk_client: RunloopSDK) -> None:
455455
finally:
456456
devbox.shutdown()
457457

458+
@pytest.mark.timeout(TWO_MINUTE_TIMEOUT)
459+
def test_create_with_tunnel_param(self, sdk_client: RunloopSDK) -> None:
460+
"""Test creating a devbox with tunnel configuration in create params."""
461+
devbox = sdk_client.devbox.create(
462+
name=unique_name("sdk-devbox-tunnel-param"),
463+
launch_parameters={"resource_size_request": "SMALL", "keep_alive_time_seconds": 60 * 5},
464+
tunnel={"auth_mode": "open"},
465+
)
466+
467+
try:
468+
# Verify devbox is running
469+
info = devbox.get_info()
470+
assert info.status == "running"
471+
472+
# Verify tunnel was created at launch
473+
assert info.tunnel is not None
474+
assert info.tunnel.tunnel_key is not None
475+
assert info.tunnel.auth_mode is not None
476+
finally:
477+
devbox.shutdown()
478+
479+
@pytest.mark.timeout(TWO_MINUTE_TIMEOUT)
480+
def test_enable_tunnel(self, sdk_client: RunloopSDK) -> None:
481+
"""Test enabling a V2 tunnel on an existing devbox."""
482+
devbox = sdk_client.devbox.create(
483+
name=unique_name("sdk-devbox-enable-tunnel"),
484+
launch_parameters={"resource_size_request": "SMALL", "keep_alive_time_seconds": 60 * 5},
485+
)
486+
487+
try:
488+
info = devbox.get_info()
489+
assert info.tunnel is None
490+
491+
# Enable tunnel using the V2 API via SDK
492+
tunnel = devbox.net.enable_tunnel(auth_mode="open")
493+
assert tunnel is not None
494+
assert tunnel.tunnel_key is not None
495+
assert tunnel.auth_mode is not None
496+
497+
info = devbox.get_info()
498+
assert info.tunnel is not None
499+
assert info.tunnel.tunnel_key == tunnel.tunnel_key
500+
finally:
501+
devbox.shutdown()
502+
458503

459504
class TestDevboxCreationMethods:
460505
"""Test various devbox creation methods."""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)