Files

96 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tests architecture
How the package's tests exercise commands. There are two complementary styles — **ViaClient** (over real HTTP, end-to-end) and **CommandDirect** (calling the static command method straight) — backed by a small set of shared test helpers.
## Two test styles
### ViaClient — exercise the full HTTP path
Spin up an isolated `PipelineTestServer` and call `server.Execute(command, params)`. This goes over HTTP through the same routing, parameter coercion, and threading the real server uses — it tests the command *as a client sees it*.
```csharp
[Test]
public void SetTransform_ViaClient_ArrayParams_Apply()
{
var go = Track(new GameObject("Xform219_Arrays"));
using (var server = new PipelineTestServer())
{
var response = server.Execute("set_transform", new
{
target = new { instanceId = PipelineUtils.GetObjectId(go) },
position = new[] { 1f, 2f, 3f },
rotation = new[] { 0f, 90f, 0f },
scale = new[] { 2f, 2f, 2f }
});
Assert.IsTrue(response.IsSuccess, $"set_transform should succeed: {response.Error}");
Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition);
}
}
```
The test server is isolated: it uses the **test editor port range `7850``7899`** and **writes no descriptor**, so it never disturbs the live editor server (which uses `7800``7849`). `Execute` pumps the server's own dispatcher while the HTTP call is in flight, so `MainThreadRequired` commands complete even from a plain `[Test]` that blocks the main thread — no deadlock.
### CommandDirect — call the static method directly
Call the command's static method with typed arguments. This is synchronous, with **no server, HTTP, or dispatcher** involved — fast and ideal for unit-testing command logic and parameter handling.
```csharp
[Test]
public void SetTransform_Direct_TypedArrays_Apply()
{
var go = Track(new GameObject("Xform219_Direct"));
GameObjectCommands.SetTransform(RefTo(go),
position: new[] { 1f, 2f, 3f },
rotation: new[] { 0f, 90f, 0f },
scale: new[] { 2f, 2f, 2f });
Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition);
Assert.AreEqual(new Vector3(2, 2, 2), go.transform.localScale);
}
```
Use **CommandDirect** to verify a command's behavior with strongly-typed inputs; use **ViaClient** to additionally verify wire-level concerns (JSON coercion, required-parameter validation, threading).
## Shared helpers
| Helper | Role |
|--------|------|
| `PipelineTestServer` | Disposable wrapper that starts an isolated `TestEditorPipelineServer`, wires up a `PipelineClient`, and exposes `Execute(command, parameters, timeoutMs = 30000)`. Pumps the server dispatcher during each call to avoid main-thread deadlock. |
| `TestEditorPipelineServer` | `EditorPipelineServer` subclass for tests. Overrides `WritesDescriptor => false`, `GetPortRange() => (7850, 7899)`, and `GetToken()` (from `SecurityTokenManager`) so it is fully isolated from the live server. |
| `PipelineClient` | Test-side HTTP client. Constructed from a URL+token or a server/manager instance. Key methods: `ExecuteCommandAsync` (`/api/exec`), `GetStatusAsync` (`/api/status`), `PostJsonAsync`. Returns a `PipelineResponse` (`IsSuccess`, `StatusCode`, `Error`, `JsonResponse`, `IsCommandSuccess`). |
| `EditorTestUtilities` | Async helpers for editor state, e.g. `WaitFor(Func<bool> condition, timeoutMs)` to poll a condition without busy-waiting. |
| `LiveServerGuard` | Assembly-level `ITestAction` that asserts the **live editor server survives the test run**. |
### `PipelineTestServer` setup
```csharp
public PipelineTestServer()
{
m_Server = new TestEditorPipelineServer();
m_Server.Start(); // auto-assigns a port in 7850-7899; writes no descriptor
m_Client = new PipelineClient($"http://localhost:{m_Server.Port}", SecurityTokenManager.GetOrCreateToken());
}
```
Wrap it in a `using` (it is disposable) so the isolated server is stopped at the end of the test.
### `LiveServerGuard`
Applied once at assembly scope (`[assembly: LiveServerGuard]`), it runs before and after **every** test in the editor suite. If a live editor server was advertising its descriptor before a test, the guard asserts afterwards that the test did not disturb it — the descriptor still exists, the port is unchanged, and the server is still listening:
```csharp
Assert.IsNotNull(after, $"'{test.Name}' deleted the live pipeline server descriptor");
Assert.AreEqual(m_Before.Port, after.Port, $"'{test.Name}' changed the port");
Assert.IsTrue(IsListening(after.Port, after.EvalToken), $"'{test.Name}' left the server not responding");
```
This is what makes it safe to "dogfood" — run the test suite against the very editor you are driving — without a test clobbering the live server. Tests that intentionally start/stop the live server are marked `[Explicit]` and must hand it back intact.
## See also
- [Creating commands](creating-commands.md) — the command API these tests exercise.
- [Connectivity](connectivity.md) — ports, descriptor, and auth (the test server deliberately skips the descriptor).