using Akka.Actor;
using Akka.TestKit.Xunit2;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.WW.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.ScriptExecution;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Debugging;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Flattening;
using IAuditWriter = ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services.IAuditWriter;
using ZB.MOM.WW.ScadaBridge.SiteRuntime.Actors;
using ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts;
namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.Actors;
///
/// Flow Debugger design 2026-09-05 §5.1/§5.4: a traced makes
/// the launched run emit a ScriptRun row and return its ExecutionId plus the
/// inline trace events on the ; a traced, stamped
/// parents the value-change run to the writer. Untraced
/// paths are pinned unchanged.
///
public class ScriptActorTraceTests : TestKit, IDisposable
{
private sealed class CapturingAuditWriter : IAuditWriter
{
public List Events { get; } = new();
public Task WriteAsync(AuditEvent evt, CancellationToken ct = default)
{
lock (Events) Events.Add(evt);
return Task.CompletedTask;
}
public AuditEvent? WaitForKind(string action, TimeSpan timeout)
{
var deadline = DateTime.UtcNow + timeout;
while (DateTime.UtcNow < deadline)
{
lock (Events)
{
var hit = Events.FirstOrDefault(e => e.Action == action);
if (hit is not null) return hit;
}
Thread.Sleep(25);
}
return null;
}
}
private readonly SharedScriptLibrary _sharedLibrary;
private readonly SiteRuntimeOptions _options;
private readonly ScriptExecutionScheduler _scheduler;
private readonly CapturingAuditWriter _writer = new();
private readonly IServiceProvider _services;
public ScriptActorTraceTests()
{
_sharedLibrary = new SharedScriptLibrary(
new ScriptCompilationService(NullLogger.Instance),
NullLogger.Instance);
_options = new SiteRuntimeOptions { MaxScriptCallDepth = 10, ScriptExecutionTimeoutSeconds = 30 };
_scheduler = new ScriptExecutionScheduler(_options.ScriptExecutionThreadCount);
var sc = new ServiceCollection();
sc.AddSingleton(_writer);
_services = sc.BuildServiceProvider();
}
void IDisposable.Dispose()
{
Shutdown();
_scheduler.Dispose();
}
private static Script