| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- using Serilog.Events;
- using Xunit;
- using YZWater.Core.Services;
- namespace YZWater.Core.Tests.Services;
- /// <summary>
- /// 测点数据质量事件的记录方式回归。
- /// 背景:现场报警历史被"测点 X 读取失败 / 已恢复"刷满 —— 一次抖动就是"点位数 × 2"行,
- /// 真报警被埋掉,而且这些行是系统自动确认的流水,操作员既确认不了也复位不了,
- /// 误点复位还会让程序往 PLC 的复位地址写一次脉冲。
- /// 现在一轮最多两条汇总(明细仍在日志文件里),且带独立类型 Quality。
- /// </summary>
- [Collection("Serilog minimum level")]
- public class QualityJournalTests : IDisposable
- {
- private readonly LogEventLevel _originalLevel = LogService.MinimumLevel;
- private readonly AlarmService _service;
- public QualityJournalTests()
- {
- LogService.ApplyMinimumLevel("Error");
- _service = new AlarmService(PlcPollingService.Instance);
- }
- public void Dispose()
- {
- _service.Dispose();
- LogService.ApplyMinimumLevel(_originalLevel.ToString());
- }
- [Fact]
- public void TwentyBadTags_SummarizeIntoOneMessage_NotTwenty()
- {
- var lost = Enumerable.Range(1, 20).Select(i => $"{i}#泵.Run").ToList();
- var (lostMessage, restoredMessage) =
- PlcPollingService.BuildQualityJournalMessages(lost, new List<string>());
- Assert.Null(restoredMessage);
- Assert.NotNull(lostMessage);
- var message = lostMessage!;
- // 一条消息讲清规模,而不是一个点一条流水
- Assert.Contains("20", message);
- Assert.Contains("共 20 个", message);
- // 清单截断到前 8 个,避免整张点位表被塞进一条记录
- Assert.DoesNotContain("20#泵.Run", message);
- Assert.Contains("8#泵.Run", message);
- // 键名拼错时 LanguageService 会原样返回键,这条断言保证模板真的解析了
- Assert.DoesNotContain("TagQualityLostSummary", message);
- }
- [Fact]
- public void LostAndRestored_ProduceTwoSeparateMessages()
- {
- var (lost, restored) = PlcPollingService.BuildQualityJournalMessages(
- new List<string> { "DI.高压报警" }, new List<string> { "1#泵.Fault", "2#泵.Fault" });
- Assert.NotNull(lost);
- Assert.Contains("DI.高压报警", lost);
- Assert.NotNull(restored);
- Assert.Contains("1#泵.Fault", restored);
- Assert.DoesNotContain("DI.高压报警", restored);
- }
- [Fact]
- public void NoTransitions_ProduceNoRows()
- {
- var (lost, restored) = PlcPollingService.BuildQualityJournalMessages(
- new List<string>(), new List<string>());
- Assert.Null(lost);
- Assert.Null(restored);
- }
- /// <summary>
- /// 诊断流水不得进入活跃报警集合 —— 否则它会占用报警位、被升级/泛溢逻辑统计,
- /// 还会让"复位"误以为有东西可复位而去写 PLC。
- /// </summary>
- [Fact]
- public void JournalAlarm_NeverBecomesAnActiveAlarm()
- {
- _service.RecordJournalAlarm("1 个测点读取失败:1#泵.Run", level: 1, alarmType: "Quality");
- Assert.Equal(0, _service.ActiveAlarmCount);
- Assert.False(_service.HasActiveAlarm);
- }
- }
|