Forge
csharpdeeb25a2
1using System.Threading.Channels;
2using CascadeIDE.Services;
3using Xunit;
4using TestContext = Xunit.TestContext;
5
6namespace CascadeIDE.Tests;
7
8public sealed class BuildLogIngestionTests
9{
10 [Fact]
11 public async Task DrainToAppendAsync_Single_Small_Chunk_One_Append_At_End()
12 {
13 var ch = Channel.CreateUnbounded<string>();
14 var parts = new List<string>();
15 var drain = BuildLogIngestion.DrainToAppendAsync(
16 ch.Reader, s => parts.Add(s), maxBatchChars: 10_000, cancellationToken: TestContext.Current.CancellationToken);
17 await ch.Writer.WriteAsync("hello", TestContext.Current.CancellationToken);
18 ch.Writer.Complete();
19 await drain;
20 Assert.Equal(new[] { "hello" }, parts);
21 }
22
23 [Fact]
24 public async Task DrainToAppendAsync_Flushes_When_Threshold_Reached()
25 {
26 var ch = Channel.CreateUnbounded<string>();
27 var parts = new List<string>();
28 var drain = BuildLogIngestion.DrainToAppendAsync(
29 ch.Reader, s => parts.Add(s), maxBatchChars: 10, cancellationToken: TestContext.Current.CancellationToken);
30 await ch.Writer.WriteAsync("1234567890", TestContext.Current.CancellationToken);
31 ch.Writer.Complete();
32 await drain;
33 Assert.Equal(new[] { "1234567890" }, parts);
34 }
35
36 [Fact]
37 public async Task DrainToAppendAsync_Multiple_Chunks_Combine_Until_Threshold_Then_Spill()
38 {
39 var ch = Channel.CreateUnbounded<string>();
40 var parts = new List<string>();
41 var drain = BuildLogIngestion.DrainToAppendAsync(
42 ch.Reader, s => parts.Add(s), maxBatchChars: 5, cancellationToken: TestContext.Current.CancellationToken);
43 await ch.Writer.WriteAsync("12", TestContext.Current.CancellationToken);
44 await ch.Writer.WriteAsync("345", TestContext.Current.CancellationToken);
45 await ch.Writer.WriteAsync("6789", TestContext.Current.CancellationToken);
46 ch.Writer.Complete();
47 await drain;
48 Assert.Equal(new[] { "12345", "6789" }, parts);
49 }
50
51 [Fact]
52 public async Task DrainToAppendAsync_Empty_Skips_And_Still_Finishes()
53 {
54 var ch = Channel.CreateUnbounded<string>();
55 var parts = new List<string>();
56 var drain = BuildLogIngestion.DrainToAppendAsync(
57 ch.Reader, s => parts.Add(s), maxBatchChars: 100, cancellationToken: TestContext.Current.CancellationToken);
58 await ch.Writer.WriteAsync("", TestContext.Current.CancellationToken);
59 await ch.Writer.WriteAsync("x", TestContext.Current.CancellationToken);
60 ch.Writer.Complete();
61 await drain;
62 Assert.Equal(new[] { "x" }, parts);
63 }
64
65 [Fact]
66 public async Task OnEachDequeuedChunk_Receives_Every_Chunk_Independently_Of_Batch()
67 {
68 var ch = Channel.CreateUnbounded<string>();
69 var cat = new System.Text.StringBuilder();
70 var drain = BuildLogIngestion.DrainToAppendAsync(
71 ch.Reader,
72 static _ => { },
73 maxBatchChars: 10_000,
74 onEachDequeuedChunk: c => cat.Append(c),
75 cancellationToken: TestContext.Current.CancellationToken);
76 await ch.Writer.WriteAsync("a", TestContext.Current.CancellationToken);
77 await ch.Writer.WriteAsync("b", TestContext.Current.CancellationToken);
78 ch.Writer.Complete();
79 await drain;
80 Assert.Equal("ab", cat.ToString());
81 }
82
83 [Fact]
84 public async Task CreateBuildLogChannel_Can_Pass_Through_Single_Chunk()
85 {
86 var c = BuildLogIngestion.CreateBuildLogChannel(1);
87 await c.Writer.WriteAsync("x", TestContext.Current.CancellationToken);
88 c.Writer.Complete();
89 var r = await c.Reader.ReadAsync(TestContext.Current.CancellationToken);
90 Assert.Equal("x", r);
91 }
92}
93
View only · write via MCP/CIDE