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
34 changes: 19 additions & 15 deletions koyeb/sandbox/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,19 +1073,23 @@ def _get_sandbox_url(self) -> Optional[Tuple[str, Optional[str]]]:
self._sandbox_url = (f"https://{domain}/koyeb-sandbox", None)
return self._sandbox_url

def _get_conn_info(self) -> Optional[ConnectionInfo]:
def _get_conn_info(self) -> ConnectionInfo:
"""
Internal method to get the parameters needed to connect to the sandbox.
Caches the info after first retrieval.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed, not accurate


Returns:
Optional[ConnectionInfo]: the information needed to connect to the sandbox
"""
sandbox_url, routing_key = self._get_sandbox_url()
if sandbox_url:
return ConnectionInfo(sandbox_url, routing_key, self.sandbox_secret)
ConnectionInfo: the information needed to connect to the sandbox

return None
Raises:
SandboxError: If the sandbox URL is not available.
"""
url = self._get_sandbox_url()
if url is None:
raise SandboxError(
"Sandbox URL is not available (the sandbox may no longer exist)"
)
sandbox_url, routing_key = url
return ConnectionInfo(sandbox_url, routing_key, self.sandbox_secret)

def _get_client(self) -> "SandboxClient": # type: ignore[name-defined]
"""
Expand All @@ -1098,9 +1102,7 @@ def _get_client(self) -> "SandboxClient": # type: ignore[name-defined]
SandboxError: If sandbox URL or secret is not available
"""
if self._client is None:
sandbox_url, routing_key = self._get_sandbox_url()
conn_info = ConnectionInfo(sandbox_url, routing_key, self.sandbox_secret)
self._client = create_sandbox_client(conn_info)
self._client = create_sandbox_client(self._get_conn_info())
return self._client

def _check_response_error(self, response: Dict, operation: str) -> None:
Expand Down Expand Up @@ -1517,13 +1519,15 @@ def __init__(self, *args, **kwargs):
self._async_client = None

def _get_async_client(self) -> "AsyncSandboxClient":
"""Get or create AsyncSandboxClient instance."""
"""Get or create AsyncSandboxClient instance.

Raises:
SandboxError: If the sandbox URL is not available.
"""
if self._async_client is None:
from .utils import create_async_sandbox_client

sandbox_url, routing_key = self._get_sandbox_url()
conn_info = ConnectionInfo(sandbox_url, routing_key, self.sandbox_secret)
self._async_client = create_async_sandbox_client(conn_info)
self._async_client = create_async_sandbox_client(self._get_conn_info())
return self._async_client

@classmethod
Expand Down
33 changes: 33 additions & 0 deletions koyeb/sandbox/test_sandbox_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import unittest
from unittest.mock import patch

from koyeb.sandbox.sandbox import AsyncSandbox, Sandbox
from koyeb.sandbox.utils import SandboxError


class TestGetClientWhenUrlUnavailable(unittest.TestCase):
"""A gone sandbox makes _get_sandbox_url() return None (the metadata/domain
lookups swallow NotFound and return None). _get_client/_get_async_client must
raise SandboxError in that case, as their docstring promises, rather than
letting a raw ``TypeError: cannot unpack non-iterable NoneType object`` escape.
"""

def test_get_client_raises_sandbox_error(self):
sb = Sandbox.__new__(Sandbox)
sb._client = None
sb.sandbox_secret = None
with patch.object(Sandbox, "_get_sandbox_url", return_value=None):
with self.assertRaises(SandboxError):
sb._get_client()

def test_get_async_client_raises_sandbox_error(self):
sb = AsyncSandbox.__new__(AsyncSandbox)
sb._async_client = None
sb.sandbox_secret = None
with patch.object(AsyncSandbox, "_get_sandbox_url", return_value=None):
with self.assertRaises(SandboxError):
sb._get_async_client()


if __name__ == "__main__":
unittest.main()
Loading