Files
OpenShell/e2e/python/conftest.py
Drew Newberry 33bbda3d33 refactor(persistence): adopt continuation-token pagination (#3249)
* refactor(persistence): adopt continuation-token pagination

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(pagination): address continuation review findings

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(tui): recover completed list refreshes

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(pagination): address review scalability findings

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* fix(pagination): repair branch validation

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

* docs(go): use page size in template example

Signed-off-by: Drew Newberry <anewberry@nvidia.com>

---------

Signed-off-by: Drew Newberry <anewberry@nvidia.com>
2026-09-11 00:02:07 +00:00

128 lines
4.2 KiB
Python

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
import fcntl
import os
import time
from typing import TYPE_CHECKING
import grpc
import pytest
from openshell import Sandbox, SandboxClient, WorkspaceClient
if TYPE_CHECKING:
from collections.abc import Callable, Iterator
def pytest_configure(config: pytest.Config) -> None:
config.addinivalue_line(
"markers",
"exclusive_gateway_config: hold an exclusive lock on gateway-global "
"config so no other xdist worker observes a transient global setting",
)
@pytest.fixture(autouse=True)
def _gateway_config_guard(
request: pytest.FixtureRequest,
tmp_path_factory: pytest.TempPathFactory,
) -> Iterator[None]:
"""Readers-writer guard over gateway-global config mutations.
The e2e gateway is shared across xdist workers, so a test that flips a
gateway-global setting can leak that transient value into another worker's
sandbox creation. Every test holds a shared lock by default; a test marked
``exclusive_gateway_config`` holds an exclusive lock, so while it mutates and
restores the setting no other worker is mid-test and none can observe the
transient value. The lock file lives in the run's shared base temp dir
(``getbasetemp().parent``), which is common to all xdist workers.
"""
lock_path = tmp_path_factory.getbasetemp().parent / "gateway-config.lock"
exclusive = (
request.node.get_closest_marker("exclusive_gateway_config") is not None
)
with lock_path.open("w") as lock_file:
fcntl.flock(lock_file, fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH)
yield
@pytest.fixture(scope="session")
def cluster_name() -> str | None:
return os.environ.get("OPENSHELL_GATEWAY")
@pytest.fixture(scope="session")
def sandbox_client(cluster_name: str | None) -> Iterator[SandboxClient]:
with SandboxClient.from_active_cluster(cluster=cluster_name) as client:
yield client
@pytest.fixture(scope="session", autouse=True)
def ensure_sandbox_persistence_ready(sandbox_client: SandboxClient) -> None:
for _ in range(60):
try:
sandbox_client.list_ids(workspace="default", page_size=1)
return
except grpc.RpcError as exc:
details = exc.details() or ""
if exc.code() == grpc.StatusCode.UNAVAILABLE:
time.sleep(2)
continue
if (
exc.code() == grpc.StatusCode.INTERNAL
and "no such table: objects" in details
):
time.sleep(1)
continue
raise
pytest.fail(
"openshell-server persistence is not initialized (missing sqlite objects table); "
"redeploy the active cluster and rerun e2e sandbox tests"
)
@pytest.fixture
def sandbox(cluster_name: str | None) -> Callable[..., Sandbox]:
def _create(*, spec: object | None = None, delete_on_exit: bool = True) -> Sandbox:
return Sandbox(
workspace="default",
cluster=cluster_name,
spec=spec,
delete_on_exit=delete_on_exit,
# The sandbox image is large (Python, Node.js, coding agents) so the
# first pod in the cluster may need extra time for the image pull.
ready_timeout_seconds=300.0,
)
return _create
@pytest.fixture(scope="session")
def workspace_client(sandbox_client: SandboxClient) -> WorkspaceClient:
return WorkspaceClient.from_sandbox_client(sandbox_client)
@pytest.fixture(scope="session")
def _worker_suffix(worker_id: str) -> str:
"""Return a suffix for worker-unique resource names.
Uses the built-in ``worker_id`` fixture from pytest-xdist which returns
``"gw0"``, ``"gw1"``, etc. for workers, or ``"master"`` for non-xdist runs.
"""
if worker_id == "master":
return ""
return f"-{worker_id}"
@pytest.fixture
def run_python() -> Callable[[Sandbox, str], tuple[int, str, str]]:
def _run(sandbox: Sandbox, code: str) -> tuple[int, str, str]:
result = sandbox.exec(["python", "-c", code], timeout_seconds=20)
return result.exit_code, result.stdout, result.stderr
return _run