| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- using System.Threading.Channels;
- using Xunit;
- using YZWater.Core.Services;
- namespace YZWater.Core.Tests.Services;
- /// <summary>
- /// 报警/审计写入队列"满了丢最旧"的可观测性回归。
- /// 背景:两个服务都用 BoundedChannelFullMode.DropOldest,并且忽略 TryWrite 的返回值 ——
- /// 队列塞满时记录被静默丢掉,界面和日志都不显示,事后看台账会以为"当时只发生过这些"。
- /// 现在丢弃条数被计数、周期性写日志,并在报警页/审计页底部提示。
- /// </summary>
- public class QueueDropAccountingTests
- {
- /// <summary>
- /// 这条测试盯的是整个改动的立足点:DropOldest 下 TryWrite 依然返回 true,
- /// 所以"写成功"不能当成"没丢数据",唯一的丢弃入口是 itemDropped 回调。
- /// </summary>
- [Fact]
- public void DropOldest_KeepsTryWriteTrue_And_ReportsDroppedItem()
- {
- var dropped = new List<int>();
- var channel = Channel.CreateBounded<int>(
- new BoundedChannelOptions(2) { FullMode = BoundedChannelFullMode.DropOldest },
- item => dropped.Add(item));
- Assert.True(channel.Writer.TryWrite(1));
- Assert.True(channel.Writer.TryWrite(2));
- // 队列已满:这一次写仍然"成功",但把最旧的 1 挤了出去
- Assert.True(channel.Writer.TryWrite(3));
- Assert.Equal(new[] { 1 }, dropped);
- Assert.Equal(new[] { 2, 3 }, ReadAll(channel));
- }
- /// <summary>
- /// 反向验证:只有 Wait 模式会在队满时让 TryWrite 返回 false,且不产生任何丢弃
- /// (实测 .NET 8:DropWrite/DropNewest/DropOldest 三种丢弃模式下 TryWrite 全部返回 true,
- /// 所以"写入成功"根本不能当成"没丢数据")
- /// </summary>
- [Fact]
- public void WaitMode_ReportsFailureOnTryWrite_And_DropsNothing()
- {
- var dropped = new List<int>();
- var channel = Channel.CreateBounded<int>(
- new BoundedChannelOptions(2) { FullMode = BoundedChannelFullMode.Wait },
- item => dropped.Add(item));
- Assert.True(channel.Writer.TryWrite(1));
- Assert.True(channel.Writer.TryWrite(2));
- Assert.False(channel.Writer.TryWrite(3));
- Assert.Empty(dropped);
- Assert.Equal(new[] { 1, 2 }, ReadAll(channel));
- }
- /// <summary>正常写入不该被算成丢弃:计数只应在队列真的满过时才涨</summary>
- [Fact]
- public void NewAlarmService_StartsWithNoDroppedRecords()
- {
- var service = new AlarmService(PlcPollingService.Instance);
- try
- {
- service.RecordJournalAlarm("测试用流水报警", 1);
- Assert.Equal(0, service.DroppedRecordCount);
- }
- finally
- {
- service.Dispose();
- }
- }
- private static int[] ReadAll(Channel<int> channel)
- {
- var items = new List<int>();
- while (channel.Reader.TryRead(out var item)) items.Add(item);
- return items.ToArray();
- }
- }
|