using System; using System.Collections.Generic; using ExperionCrawler.Core.Application.Feedforward; using ExperionCrawler.Infrastructure.Control; using Xunit; namespace ExperionCrawler.Tests; /// WO-1 (P-5 confidence 자동강등) 엔진 통합 검증. Downgrade는 private이라 Tick 경유로 관측. public class FeedforwardEngineTests { private static ColumnConfig Cfg(double feedFilterTau = 300, double moveThr = 0) => new() { Id = 1, Name = "C-TEST", Enabled = true, FeedTag = "f", ProductKey = "P", ScanSec = 2, FeedFilterTauSec = feedFilterTau, FeedMoveThresholdPerMin = moveThr, Streams = new[] { new StreamConfig { Key = "P", FlowTag = "ficq-6118", Role = StreamRole.Commanded, Grade = Confidence.A, TargetCoeff = 0.95 } } }; private static PvSnapshot Snap(double feed, double streamVal, bool streamGood) => new( new TagSample("f", feed, true, DateTime.UtcNow), null, Array.Empty(), new Dictionary { ["P"] = new TagSample("ficq-6118", streamVal, streamGood, DateTime.UtcNow) }); [Fact] // 정상·신선 → config 등급(A) 유지, 사유 없음 public void Fresh_normal_keeps_config_grade() { var res = new FeedforwardEngine().Tick(Cfg(), Snap(100, 95, true), new ColumnState(), DateTime.UtcNow); var p = res.Streams[0]; Assert.Equal(Confidence.A, p.Grade); Assert.Null(p.GradeReason); } [Fact] // PV 신선도 불량 → 한 단계 강등(A→B) + 사유 public void Stale_pv_downgrades_one_level() { var res = new FeedforwardEngine().Tick(Cfg(), Snap(100, 80, false), new ColumnState(), DateTime.UtcNow); var p = res.Streams[0]; Assert.Equal(Confidence.B, p.Grade); Assert.Contains("신선도", p.GradeReason); } [Fact] // stale + 과도 동시 → 두 단계 강등(A→C) Clamp 확인 public void Stale_plus_transient_clamps_to_C() { var cfg = Cfg(feedFilterTau: 0, moveThr: 1); // 필터 off + 작은 임계 → 큰 피드점프가 과도 유발 var engine = new FeedforwardEngine(); var st = new ColumnState(); engine.Tick(cfg, Snap(100, 80, false), st, DateTime.UtcNow); // tick1: 시드 var res = engine.Tick(cfg, Snap(1000, 80, false), st, DateTime.UtcNow); // tick2: 피드 급변 → 과도 var p = res.Streams[0]; Assert.True(res.Transient); Assert.Equal(Confidence.C, p.Grade); // A→(stale)B→(transient)C, C에서 클램프 } }