fix(inbound-api): surface compile warning on non-compiling method save
CompileAndRegister only swaps the cached handler on a successful compile, so a management (or DB) save of a non-compiling inbound script silently kept the previously-registered handler serving — stale results, still HTTP 200 — while UpdateApiMethod reported success. A broken save thus looked like a no-op, with the real Roslyn error only in the central log. Surface the diagnostics instead: a new CompileAndRegister(method, out errors) overload reports the compile/trust-model errors (the bool overload is kept for existing callers), and HandleCreate/UpdateApiMethod return them as a top-level compileWarning on the management result (null when the script compiled). The save still persists and the previously registered version keeps serving — the warning just stops a non-compiling save from looking like a success. - InboundScriptExecutor: Compile returns its diagnostics alongside the handler. - ManagementActor: TryCompileAndDescribe + flat ApiMethodResult projection so compileWarning rides at the top level without polluting the ApiMethod POCO. - Component-InboundAPI.md: document the non-fatal-but-surfaced contract. - Tests: executor diagnostics + non-compiling-update-keeps-previous-handler, plus an end-to-end ManagementActor test asserting compileWarning is returned.
This commit is contained in:
@@ -377,6 +377,37 @@ public class ManagementActorTests : TestKit, IDisposable
|
||||
Assert.Contains("Designer", response.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UpdateApiMethod_NonCompilingScript_SucceedsButReturnsCompileWarning()
|
||||
{
|
||||
// The save still persists, but a script that does not compile must surface a
|
||||
// top-level compileWarning in the result rather than silently looking like a
|
||||
// success — and the previously registered handler keeps serving (CompileAndRegister
|
||||
// never replaces a working delegate with a broken one).
|
||||
var existing = new Commons.Entities.InboundApi.ApiMethod("MyMethod", "return 1;")
|
||||
{
|
||||
Id = 7,
|
||||
TimeoutSeconds = 10
|
||||
};
|
||||
var apiRepo = Substitute.For<IInboundApiRepository>();
|
||||
apiRepo.GetApiMethodByIdAsync(7, Arg.Any<CancellationToken>()).Returns(existing);
|
||||
apiRepo.SaveChangesAsync(Arg.Any<CancellationToken>()).Returns(1);
|
||||
_services.AddScoped(_ => apiRepo);
|
||||
_services.AddSingleton(sp => new ZB.MOM.WW.ScadaBridge.InboundAPI.InboundScriptExecutor(
|
||||
NullLogger<ZB.MOM.WW.ScadaBridge.InboundAPI.InboundScriptExecutor>.Instance, sp));
|
||||
|
||||
var actor = CreateActor();
|
||||
// Undefined symbol -> genuine Roslyn compile error.
|
||||
var envelope = Envelope(
|
||||
new UpdateApiMethodCommand(7, "return doesNotCompile;", 10, null, null), "Designer");
|
||||
|
||||
actor.Tell(envelope);
|
||||
|
||||
var response = ExpectMsg<ManagementSuccess>(TimeSpan.FromSeconds(10));
|
||||
Assert.Contains("compileWarning", response.JsonData);
|
||||
Assert.Contains("failed to compile", response.JsonData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddTemplateAttribute_WithDeploymentRole_ReturnsUnauthorized()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user