diff --git a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs index cce4cda0..08335030 100644 --- a/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs +++ b/src/ZB.MOM.WW.ScadaBridge.CentralUI/ScriptAnalysis/SandboxScriptHost.cs @@ -464,6 +464,27 @@ public class SandboxAttributeAccessor string responseKey, object? responseValue, TimeSpan timeout) => throw NotInSandbox(nameof(WriteBatchAndWaitAsync)); + /// + /// Sandbox stand-in for the reset-aware AttributeAccessor.WriteBatchAndWaitAsync + /// overload (Gitea #36): present for editor/compile parity, throws + /// when run in Test Run (no device batch-write transport). + /// + /// The attribute values to write as a batch. + /// The flag attribute key to set to signal completion. + /// The value to set on the flag attribute. + /// The attribute key to observe for the device's response. + /// The response value to wait for. + /// The maximum time to wait for the response. + /// The attribute written first and waited on before the batch. + /// The reset value the device must echo before the batch is written. + /// The maximum time to wait for the reset echo; null means . + /// Never returns; always throws in the sandbox. + public Task WriteBatchAndWaitAsync( + IReadOnlyDictionary values, string flagKey, object? flagValue, + string responseKey, object? responseValue, TimeSpan timeout, + string resetKey, object? resetValue, TimeSpan? resetTimeout = null) + => throw NotInSandbox(nameof(WriteBatchAndWaitAsync)); + /// /// 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 diff --git a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs index f16ec046..74a34efc 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/ScriptAnalysis/ScriptAnalysisServiceTests.cs @@ -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 { { \"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"));