unity-mcp/Server/tests/integration/test_editor_state_v2_contra...

59 lines
2.3 KiB
Python
Raw Normal View History

Async Test Infrastructure & Editor Readiness Status + new refresh_unity tool (#507) * Add editor readiness v2, refresh tool, and preflight guards * Detect external package changes and harden refresh retry * feat: add TestRunnerNoThrottle and async test running with background stall prevention - Add TestRunnerNoThrottle.cs: Sets editor to 'No Throttling' mode during test runs with SessionState persistence across domain reload - Add run_tests_async and get_test_job tools for non-blocking test execution - Add TestJobManager for async test job tracking with progress monitoring - Add ForceSynchronousImport to all AssetDatabase.Refresh() calls to prevent stalls - Mark DomainReloadResilienceTests as [Explicit] with documentation explaining the test infrastructure limitation (internal coroutine waits vs MCP socket polling) - MCP workflow is unaffected - socket messages provide external stimulus that keeps Unity responsive even when backgrounded * refactor: simplify and clean up code - Remove unused Newtonsoft.Json.Linq import from TestJobManager - Add throttling to SessionState persistence (once per second) to reduce overhead - Critical job state changes (start/finish) still persist immediately - Fix duplicate XML summary tag in DomainReloadResilienceTests * docs: add async test tools to README, document domain reload limitation - Add run_tests_async and get_test_job to main README tools list - Document background stall limitation for domain reload tests in DEV readme * ci: add separate job for domain reload tests Run [Explicit] domain_reload tests in their own job using -testCategory * ci: run domain reload tests in same job as regular tests Combines into single job with two test steps to reuse cached Library * fix: address coderabbit review issues - Fix TOCTOU race in TestJobManager.StartJob (single lock scope for check-and-set) - Store TestRunnerApi reference with HideAndDontSave to prevent GC/serialization issues * docs: update tool descriptions to prefer run_tests_async - run_tests_async is now marked as preferred for long-running suites - run_tests description notes it blocks and suggests async alternative * docs: update README screenshot to v8.6 UI * docs: add v8.6 UI screenshot * Update README for MCP version and instructions for v8.7 * fix: handle preflight busy signals and derive job status from test results - manage_asset, manage_gameobject, manage_scene now check preflight return value and propagate busy/retry signals to clients (fixes Sourcery #1) - TestJobManager.FinalizeCurrentJobFromRunFinished now sets job status to Failed when resultPayload.Failed > 0, not always Succeeded (fixes Sourcery #2) * fix: increase HTTP server startup timeout for dev mode When 'Force fresh server install' is enabled, uvx uses --no-cache --refresh which rebuilds the package and takes significantly longer to start. - Increase timeout from 10s to 45s when dev mode is enabled - Add informative log message explaining the longer startup time - Show actual timeout value in warning message * fix: derive job status from test results in FinalizeFromTask fallback Apply same logic as FinalizeCurrentJobFromRunFinished: check result.Failed > 0 to correctly mark jobs as Failed when tests fail, even in the fallback path when RunFinished callback is not delivered.
2026-01-04 04:42:32 +08:00
import pytest
from services.registry import get_registered_resources
from .test_helpers import DummyContext
@pytest.mark.asyncio
async def test_editor_state_v2_is_registered_and_has_contract_fields(monkeypatch):
"""
Red test: we expect a canonical v2 resource `unity://editor_state` with required top-level fields.
Today, only `unity://editor/state` exists and is minimal.
"""
# Import the v2 module to ensure it registers its decorator without disturbing global registry state.
import services.resources.editor_state_v2 # noqa: F401
resources = get_registered_resources()
v2 = next((r for r in resources if r.get("uri") == "unity://editor_state"), None)
assert v2 is not None, (
"Expected canonical readiness resource `unity://editor_state` to be registered. "
"This is required so clients can poll readiness/staleness and avoid tool loops."
)
async def fake_send_with_unity_instance(send_fn, unity_instance, command_type, params, **kwargs):
# Minimal stub payload for v2 resource tests. The server layer should enrich with staleness/advice.
assert command_type in {"get_editor_state_v2", "get_editor_state"}
return {
"success": True,
"data": {
"schema_version": "unity-mcp/editor_state@2",
"observed_at_unix_ms": 1730000000000,
"sequence": 1,
"compilation": {"is_compiling": False, "is_domain_reload_pending": False},
"tests": {"is_running": False},
},
}
# Patch transport so the resource can be invoked without Unity running.
import transport.unity_transport as unity_transport
monkeypatch.setattr(unity_transport, "send_with_unity_instance", fake_send_with_unity_instance)
result = await v2["func"](DummyContext())
payload = result.model_dump() if hasattr(result, "model_dump") else result
assert isinstance(payload, dict)
# Contract assertions (top-level)
assert payload.get("success") is True
data = payload.get("data")
assert isinstance(data, dict)
assert data.get("schema_version") == "unity-mcp/editor_state@2"
assert "observed_at_unix_ms" in data
assert "sequence" in data
assert "advice" in data
assert "staleness" in data