feat(central-ui): Test Run sandbox mirrors the reset-aware WriteBatchAndWaitAsync (#36)
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
This commit is contained in:
@@ -464,6 +464,27 @@ public class SandboxAttributeAccessor
|
||||
string responseKey, object? responseValue, TimeSpan timeout)
|
||||
=> throw NotInSandbox(nameof(WriteBatchAndWaitAsync));
|
||||
|
||||
/// <summary>
|
||||
/// Sandbox stand-in for the reset-aware <c>AttributeAccessor.WriteBatchAndWaitAsync</c>
|
||||
/// overload (Gitea #36): present for editor/compile parity, throws
|
||||
/// <see cref="ScriptSandboxException"/> when run in Test Run (no device batch-write transport).
|
||||
/// </summary>
|
||||
/// <param name="values">The attribute values to write as a batch.</param>
|
||||
/// <param name="flagKey">The flag attribute key to set to signal completion.</param>
|
||||
/// <param name="flagValue">The value to set on the flag attribute.</param>
|
||||
/// <param name="responseKey">The attribute key to observe for the device's response.</param>
|
||||
/// <param name="responseValue">The response value to wait for.</param>
|
||||
/// <param name="timeout">The maximum time to wait for the response.</param>
|
||||
/// <param name="resetKey">The attribute written first and waited on before the batch.</param>
|
||||
/// <param name="resetValue">The reset value the device must echo before the batch is written.</param>
|
||||
/// <param name="resetTimeout">The maximum time to wait for the reset echo; <c>null</c> means <paramref name="timeout"/>.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/> in the sandbox.</returns>
|
||||
public Task<HandshakeResult> WriteBatchAndWaitAsync(
|
||||
IReadOnlyDictionary<string, object?> values, string flagKey, object? flagValue,
|
||||
string responseKey, object? responseValue, TimeSpan timeout,
|
||||
string resetKey, object? resetValue, TimeSpan? resetTimeout = null)
|
||||
=> throw NotInSandbox(nameof(WriteBatchAndWaitAsync));
|
||||
|
||||
/// <summary>
|
||||
/// Value-equality attribute wait — routed to the bound deployed instance cross-site
|
||||
/// (the same real event-driven waiter a site uses). Needs a bound instance; throws
|
||||
|
||||
+6
-1
@@ -756,13 +756,18 @@ public class ScriptAnalysisServiceTests
|
||||
// WaitAsync / WaitForAsync, so the editor false-flagged valid instance scripts
|
||||
// with CS1061 even though `template validate` and the deploy gate accept them.
|
||||
// The sandbox surface must mirror the runtime AttributeAccessor member-for-member.
|
||||
// Gitea #36: also covers the reset-aware WriteBatchAndWaitAsync overload
|
||||
// (writes+waits a reset key/value before the batch) with and without the
|
||||
// optional resetTimeout, returning a HandshakeResult.
|
||||
var code =
|
||||
"var data = new System.Collections.Generic.Dictionary<string, object?> { { \"Cmd\", 1 } };\n" +
|
||||
"var done = await Attributes.WriteBatchAndWaitAsync(data, \"Flag\", true, \"Done\", true, System.TimeSpan.FromSeconds(5));\n" +
|
||||
"var hit = await Attributes.WaitAsync(\"Done\", true, System.TimeSpan.FromSeconds(5));\n" +
|
||||
"var pred = await Attributes.WaitAsync(\"Done\", v => v != null, System.TimeSpan.FromSeconds(5));\n" +
|
||||
"var res = await Attributes.WaitForAsync(\"Done\", true, System.TimeSpan.FromSeconds(5));\n" +
|
||||
"return done && hit && pred && res.Matched;";
|
||||
"var hs = await Attributes.WriteBatchAndWaitAsync(data, \"Flag\", true, \"Done\", true, System.TimeSpan.FromSeconds(5), \"Done\", false, System.TimeSpan.FromSeconds(2));\n" +
|
||||
"var hs2 = await Attributes.WriteBatchAndWaitAsync(data, \"Flag\", true, \"Done\", true, System.TimeSpan.FromSeconds(5), \"Done\", false);\n" +
|
||||
"return done && hit && pred && res.Matched && hs.Matched && !hs2.ResetFailed;";
|
||||
var resp = _svc.Diagnose(new DiagnoseRequest(code));
|
||||
|
||||
Assert.DoesNotContain(resp.Markers, m => m.Code.StartsWith("CS"));
|
||||
|
||||
Reference in New Issue
Block a user