Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
56 changes: 46 additions & 10 deletions python/tests/e2e/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,33 @@
import pytest

from xagent_sdk import AgentClient, UserClient
from xagent_sdk.cloud import WorkspaceClient
from xagent_sdk.cloud import Region, WorkspaceClient


def _cloud_base_url() -> str | None:
"""Resolve the cloud host for e2e: explicit ``XAGENT_BASE_URL`` wins,
else the host for ``XAGENT_REGION`` (``au``/``sg``). Returns ``None``
when neither is set -- there is no hosted default to guess, since the
service is per-region.
"""
explicit = os.environ.get("XAGENT_BASE_URL")
if explicit:
return explicit
region = os.environ.get("XAGENT_REGION")
if region:
return Region(region).base_url
Comment thread
AlexLiu190625 marked this conversation as resolved.
Outdated
return None


def _need_workspace() -> tuple[str, str]:
workspace_key = os.environ.get("XAGENT_WORKSPACE_KEY")
base_url = _cloud_base_url()
if not (workspace_key and base_url):
pytest.skip(
"e2e cloud surface requires XAGENT_WORKSPACE_KEY and "
"XAGENT_BASE_URL or XAGENT_REGION"
)
return workspace_key, base_url


def _need_personal() -> tuple[str, str]:
Expand Down Expand Up @@ -91,20 +117,30 @@ def patient_agent_client() -> Iterator[AgentClient]:
yield c


@pytest.fixture
def cloud_base_url() -> str:
"""Resolved cloud host for tests that build their own client (e.g. a
bad-key probe). Skips when no ``XAGENT_BASE_URL`` / ``XAGENT_REGION``
is set, since the service is per-region and has no default host.
"""
base_url = _cloud_base_url()
if base_url is None:
pytest.skip("e2e cloud surface requires XAGENT_BASE_URL or XAGENT_REGION")
return base_url


@pytest.fixture
def workspace_client() -> Iterator[WorkspaceClient]:
"""WorkspaceClient authenticated with a workspace key.

Requires ``XAGENT_WORKSPACE_KEY``; ``base_url`` falls back to
``XAGENT_BASE_URL`` and then the hosted default, so a developer
pointing at a staging deploy sets ``XAGENT_BASE_URL`` while one
hitting the hosted service sets only the key. 60s per-request timeout
so agent runs created here have room to complete.
Requires ``XAGENT_WORKSPACE_KEY`` plus an explicit host -- either
``XAGENT_BASE_URL`` (staging / self-host) or ``XAGENT_REGION``
(``au``/``sg``). The service is per-region, so a key only authenticates
against the region that minted it; there is no default host to fall
back to. 60s per-request timeout so agent runs created here have room
to complete.
"""
workspace_key = os.environ.get("XAGENT_WORKSPACE_KEY")
if not workspace_key:
pytest.skip("e2e workspace surface requires XAGENT_WORKSPACE_KEY")
base_url = os.environ.get("XAGENT_BASE_URL")
workspace_key, base_url = _need_workspace()
with WorkspaceClient(
workspace_key=workspace_key, base_url=base_url, timeout=60.0
) as c:
Expand Down
28 changes: 13 additions & 15 deletions python/tests/e2e/test_cloud_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
Marked ``@pytest.mark.e2e`` so the default ``pytest`` run skips them.
Run against a SaaS deploy with a workspace key::

XAGENT_WORKSPACE_KEY=xag_workspace_... uv run pytest -m e2e
# XAGENT_BASE_URL optional; defaults to the hosted endpoint
XAGENT_WORKSPACE_KEY=xag_workspace_... XAGENT_REGION=sg uv run pytest -m e2e
# Set XAGENT_REGION (au/sg) or XAGENT_BASE_URL (staging/self-host);
# the service is per-region and has no default host.

``E2E_TEMPLATE_ID`` picks the template to instantiate (defaults to the
first listed). The created agent is not deleted -- run on a scratch
Expand All @@ -27,13 +28,9 @@
pytestmark = pytest.mark.e2e


def _runtime_base_url() -> str:
# The minted runtime key drives the existing /v1/chat/tasks* surface
# on the same host the workspace client targets.
return os.environ.get("XAGENT_BASE_URL") or "https://cloud.xagent.run"


def test_workspace_full_flow(workspace_client: WorkspaceClient) -> None:
def test_workspace_full_flow(
workspace_client: WorkspaceClient, cloud_base_url: str
) -> None:
templates = workspace_client.templates.list()
if not templates:
pytest.skip("workspace exposes no templates; nothing to instantiate")
Expand All @@ -46,8 +43,10 @@ def test_workspace_full_flow(workspace_client: WorkspaceClient) -> None:
assert created.runtime_full_key is not None
assert created.runtime_full_key.startswith("xag_")

# The minted runtime key drives the /v1/chat/tasks* surface on the
# same host the workspace client targets.
with AgentClient(
api_key=created.runtime_full_key, base_url=_runtime_base_url(), timeout=120.0
api_key=created.runtime_full_key, base_url=cloud_base_url, timeout=120.0
) as runtime:
result = runtime.tasks.run(
agent_id=created.agent_id,
Expand All @@ -65,12 +64,11 @@ def test_unknown_template_raises(workspace_client: WorkspaceClient) -> None:
workspace_client.agents.create_from_template("does-not-exist-12345")


def test_bad_workspace_key_unauthorized() -> None:
base_url = os.environ.get("XAGENT_BASE_URL")
if not os.environ.get("XAGENT_WORKSPACE_KEY"):
pytest.skip("e2e workspace surface requires XAGENT_WORKSPACE_KEY")
def test_bad_workspace_key_unauthorized(cloud_base_url: str) -> None:
with (
WorkspaceClient(workspace_key="xag_workspace_bad_key", base_url=base_url) as c,
WorkspaceClient(
workspace_key="xag_workspace_bad_key", base_url=cloud_base_url
) as c,
pytest.raises(InvalidAPIKey),
):
c.agents.list()
Expand Down
Loading