using System.Reflection;
using Admin.NET.Plugin.AiDOP.Entity.S8;
using Admin.NET.Plugin.AiDOP.Service.S8.Rules;
using Xunit;
namespace Admin.NET.Plugin.AiDOP.Tests.S8;
///
/// S8-STANDARD-DATASET-HARD-CUTOVER-1:Legacy 符号**不存在**契约。
///
/// 与上一阶段的区别必须说清楚,否则这个文件会被误当成重复覆盖:
/// · 退役阶段断言的是「Legacy 被拒绝」——类型还在,只是调用会抛 410 / legacy_sql_retired;
/// · 本阶段断言的是「Legacy 根本不存在」——类型、Provider、参数、表全部消失。
/// 前者的测试已随实现一并删除;保留它们只会让人以为 Legacy 仍是一条需要防守的路径。
///
/// 用**运行期反射按名字查找**而非编译期引用:已删除的类型写不进 typeof(),
/// 编译期引用等于永远无法表达「它不存在」这个断言。
/// 名字用完全限定名,避免同名新类型意外让断言变绿。
///
public class S8LegacySymbolsRemovedTests
{
private static readonly Assembly PluginAssembly = typeof(AdoS8WatchRule).Assembly;
private static Type? Find(string fullName) => PluginAssembly.GetType(fullName, throwOnError: false);
///
/// 全量 Legacy 类型清单。任何一条复活都会让本用例红——
/// 这正是目的:Hard Cutover 之后不接受「先加回来再说」。
///
public static TheoryData RemovedTypes() => new()
{
// 报警规则(历史只读壳,Runtime Authority 一直是 AdoS8WatchRule)
"Admin.NET.Plugin.AiDOP.Entity.S8.AdoS8AlertRule",
"Admin.NET.Plugin.AiDOP.Service.S8.S8AlertRuleService",
"Admin.NET.Plugin.AiDOP.Controllers.S8.AdoS8ConfigAlertRulesController",
};
[Theory]
[MemberData(nameof(RemovedTypes))]
public void LegacyType_NoLongerExists(string fullName)
{
Assert.Null(Find(fullName));
}
///
/// T10:evaluator 契约不得再出现 alertRules 死参数。
///
/// 该形参存在期间,三个实现的方法体读取次数均为 0,调度器查库后转手丢弃——
/// 一个纯粹的假依赖,却让每个 tick 多打一次全表查询,也误导读者以为告警阈值来自那张表。
///
[Fact]
public void EvaluatorContract_HasNoAlertRulesParameter()
{
var evaluate = typeof(IS8RuleEvaluator).GetMethod(nameof(IS8RuleEvaluator.EvaluateAsync))!;
var names = evaluate.GetParameters().Select(p => p.Name).ToArray();
Assert.DoesNotContain("alertRules", names);
Assert.Equal(new[] { "tenantId", "factoryId", "rule", "cancellationToken" }, names);
}
///
/// 所有实现必须与接口同步收窄。只查接口不够——
/// 实现类若保留旧重载,调用方仍可能绑到它。
///
[Fact]
public void AllEvaluatorImplementations_HaveNoAlertRulesParameter()
{
var implementations = PluginAssembly.GetTypes()
.Where(t => t is { IsClass: true, IsAbstract: false } && typeof(IS8RuleEvaluator).IsAssignableFrom(t))
.ToArray();
// 防止「一个实现都没找到」时本用例空转通过。
Assert.NotEmpty(implementations);
foreach (var impl in implementations)
{
var overloads = impl.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.Name == nameof(IS8RuleEvaluator.EvaluateAsync))
.ToArray();
Assert.NotEmpty(overloads);
foreach (var m in overloads)
Assert.DoesNotContain(m.GetParameters(), p => p.Name == "alertRules");
}
}
}