diff --git a/python/lib/sift_client/_tests/util/test_test_results_utils.py b/python/lib/sift_client/_tests/util/test_test_results_utils.py index e23003d2f..fb4f70a9c 100644 --- a/python/lib/sift_client/_tests/util/test_test_results_utils.py +++ b/python/lib/sift_client/_tests/util/test_test_results_utils.py @@ -1,3 +1,4 @@ +import time from datetime import datetime, timezone import numpy as np @@ -16,11 +17,46 @@ assign_value_to_measurement, evaluate_measurement_bounds, ) -from sift_client.util.test_results.context_manager import NewStep +from sift_client.util.test_results.context_manager import NewStep, ReportContext pytestmark = pytest.mark.integration +class TestLogReplay: + """Test that the incremental replay subprocess creates real API objects.""" + + def test_replay_creates_report(self, sift_client): + unique_name = f"replay-test-{datetime.now(timezone.utc).isoformat()}" + + with ReportContext( + sift_client, + name=unique_name, + test_case="test_replay_creates_report", + log_file=True, + ) as rc: + with rc.new_step(name="Step A") as step_a: + with step_a.substep(name="Step A.1"): + pass + with rc.new_step(name="Step B"): + pass + + # Wait to ensure the report creation has completed. + time.sleep(2) + + reports = sift_client.test_results.list_(name=unique_name) + assert len(reports) >= 1, f"Expected report '{unique_name}' to be created by replay" + replay_report = reports[0] + assert replay_report.name == unique_name + + steps = sift_client.test_results.list_steps(test_reports=[replay_report]) + step_names = {s.name for s in steps} + assert "Step A" in step_names + assert "Step A.1" in step_names + assert "Step B" in step_names + + sift_client.test_results.delete(test_report=replay_report) + + class TestContextManager: def test_link_run_to_report(self, report_context, nostromo_run): report_context.report.update({"run_id": nostromo_run.id_}) diff --git a/python/lib/sift_client/transport/grpc_transport.py b/python/lib/sift_client/transport/grpc_transport.py index 07cda9855..232751485 100644 --- a/python/lib/sift_client/transport/grpc_transport.py +++ b/python/lib/sift_client/transport/grpc_transport.py @@ -9,6 +9,7 @@ import asyncio import atexit import logging +import os import threading from typing import Any from urllib.parse import urlparse @@ -98,6 +99,8 @@ def __init__(self, config: GrpcConfig): Args: config: The gRPC client configuration. """ + os.environ.setdefault("GRPC_ENABLE_FORK_SUPPORT", "0") + self._config = config # map each asyncio loop to its async channel and stub dict self._channels_async: dict[asyncio.AbstractEventLoop, Any] = {}