using Microsoft.Extensions.DependencyInjection; using ZB.MOM.WW.ScadaBridge.CentralUI.ScriptAnalysis; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.ScriptAnalysis; [Collection("Sandbox worker processes")] public class BoundedSandboxOutputTests { [Theory] [InlineData("block")] [InlineData("new { Data = block }")] public async Task Worker_OversizedConsoleAndReturn_AreExplicitlyBounded(string returnExpression) { using var services = new Microsoft.Extensions.DependencyInjection.ServiceCollection().BuildServiceProvider(); using var cache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions()); var runner = new ScriptAnalysisService(NSubstitute.Substitute.For(), cache, services); var result = await runner.RunInSandboxAsync(new SandboxRunRequest( "var block = new string('x', 100000); for (int i=0; i<1000; i++) System.Console.Write(block); return " + returnExpression + ";", null, 10), CancellationToken.None); Assert.True(result.Success, result.Error); Assert.True(result.ConsoleOutput.Length < 32100); Assert.Contains("truncated", result.ConsoleOutput); Assert.Contains("truncated", result.ReturnValueJson!); Assert.True(System.Text.Encoding.UTF8.GetByteCount(result.ReturnValueJson!) < 32000); } [Fact] public void ConcurrentRepeatedLargeWrites_RetainOnlyBudget() { var writer = new BoundedSandboxWriter(32000); var block = new string('x', 100000); Parallel.For(0, 1000, _ => writer.WriteLine(block)); Assert.Equal(32000, writer.RetainedCharacters); Assert.True(writer.DroppedCharacters >= 99968000); Assert.True(writer.ToString().Length < 32100); Assert.Contains("truncated", writer.ToString()); } }