Files
yunhai.netcore.tool/BasePlatformDotnet/tests/Yh.SchClass.OpenApi.Tests/SchClassLiveDebug.cs
T
wanghu 4226b042a8
ci / build-test (push) Failing after 2m18s
ci / publish (push) Skipped
添加教师树
2026-09-08 16:30:00 +08:00

189 lines
8.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.Extensions.Configuration;
namespace Yh.SchClass.OpenApi.Tests;
/// <summary>
/// 联调调试用的环境配置。地址来源优先级:
/// <para>
/// 1. 环境变量(<c>YH_SCHCLASS_DEBUG_HOST</c> / <c>YH_SCHCLASS_DEBUG_PATH</c>);
/// 2. <c>appsettings.json</c>:先独立节 <c>yh:schclass:open</c>,再共享节 <c>yh:open</c> 的
/// <c>BaseHost</c> + <c>SchClassPath</c>;
/// 3. 内置默认 <see cref="DefaultHost"/> + <see cref="DefaultPath"/>。
/// </para>
/// <para>
/// 关闭联调:置 <c>YH_SCHCLASS_DEBUG_OFF=1</c>,用例全部空跑通过(CI 用)。
/// </para>
/// </summary>
internal static class SchClassLiveDebug
{
public const string HostVar = "YH_SCHCLASS_DEBUG_HOST";
public const string PathVar = "YH_SCHCLASS_DEBUG_PATH";
public const string SchVar = "YH_SCHCLASS_DEBUG_SCH";
public const string ClassVar = "YH_SCHCLASS_DEBUG_CLASS";
public const string TeaVar = "YH_SCHCLASS_DEBUG_TEA";
public const string GroupVar = "YH_SCHCLASS_DEBUG_GROUP";
public const string OffVar = "YH_SCHCLASS_DEBUG_OFF";
/// <summary>配置与配置文件都未提供时的兜底联调主机。</summary>
public const string DefaultHost = "http://base.yunhaixingtong.com";
/// <summary>配置与配置文件都未提供时的兜底应用路径。</summary>
public const string DefaultPath = "/userclass";
private static readonly IConfiguration? Config;
static SchClassLiveDebug()
{
var file = System.IO.Path.Combine(AppContext.BaseDirectory, "appsettings.json");
if (File.Exists(file))
{
Config = new ConfigurationBuilder().AddJsonFile(file, optional: true).Build();
}
}
/// <summary>是否开启联调(默认开启;置 <c>YH_SCHCLASS_DEBUG_OFF=1</c> 可关闭,CI 用它空跑)。</summary>
public static bool Enabled
{
get
{
var off = Environment.GetEnvironmentVariable(OffVar);
return !(off == "1" || "true".Equals(off, StringComparison.OrdinalIgnoreCase));
}
}
private static string? Env(string name)
{
var value = Environment.GetEnvironmentVariable(name);
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}
private static string? Configured(string path)
{
var value = Config?[path];
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}
/// <summary>联调主机:环境变量 → yh:schclass:open:BaseHost → yh:open:BaseHost → 内置默认。</summary>
public static string Host =>
Env(HostVar)
?? Configured("yh:schclass:open:BaseHost")
?? Configured("yh:open:BaseHost")
?? DefaultHost;
/// <summary>联调基础路径:环境变量 → yh:schclass:open:BasePath → yh:open:SchClassPath → 内置默认。</summary>
public static string? Path =>
Env(PathVar)
?? Configured("yh:open:SchClassPath")
?? DefaultPath;
/// <summary>按当前配置构建门面。</summary>
public static SchClassOpenApi Create()
{
var options = new SchClassOpenApiOptions { BaseHost = Host, BasePath = Path };
return SchClassOpenApiFactory.Create(options);
}
/// <summary>联调目标地址(用于日志输出)。</summary>
public static string Target()
{
var options = new SchClassOpenApiOptions { BaseHost = Host, BasePath = Path };
return options.ResolveBaseUrl();
}
public static string? Sch => Env(SchVar);
public static string? ClassId => Env(ClassVar);
public static int? TeaSerId => int.TryParse(Env(TeaVar), out var id) ? id : null;
/// <summary>DbClass 分组号,缺省 3(对联调环境真实有效的分组)。</summary>
public static int? Group => int.TryParse(Env(GroupVar), out var g) ? g : null;
/// <summary>
/// 一键跑通全部端点(测试用例与 <c>DebugMain.Main</c> 调试入口共用)。
/// 缺省 ID 一律从真实数据推导:用捏造的 ID 会让端点恒成立 0 条,把真实问题伪装成"接口空"。
/// 返回失败端点名列表;<paramref name="log"/> 输出进度。
/// </summary>
public static async Task<List<string>> RunAllAsync(Action<string> log, string? only = null)
{
var api = Create();
var sch = Sch
?? (await api.SchInfo.AllListAsync()).FirstOrDefault()?.SchSerId ?? "S001";
var group = Group ?? 3;
var classId = ClassId;
if (classId == null)
{
var cls = (await api.VClass.GetVClassListAsync(sch)).FirstOrDefault();
classId = cls != null && cls.TryGetValue("ClassID", out var cid)
? cid.ToString()
: "1001";
}
var teaId = TeaSerId;
if (teaId == null)
{
var tea = (await api.DbClass.GetSchteaListAsync(group)).FirstOrDefault();
teaId = tea != null
&& tea.TryGetValue("UserTeaSerID", out var tid)
&& int.TryParse(tid.ToString(), out var parsed)
? parsed
: 77;
}
var cases = new List<(string Name, Func<Task<int>> Call)>
{
// Group=3 对应联调环境真实存在的分组;可用 YH_SCHCLASS_DEBUG_GROUP 覆盖
("DbClass.GetSchteaList", async () => (await api.DbClass.GetSchteaListAsync(group)).Count),
("VSchClass.GetVClassList", async () => (await api.VClass.GetVClassListAsync(sch)).Count),
("VSchClass.GetSchArrVClassListAll", async () => (await api.VClass.GetSchArrVClassListAllAsync()).Count),
("VSchClass.GetSchArrVClassListPost", async () => (await api.VClass.GetSchArrVClassListPostAsync(sch)).Count),
("Schoolen.GetSchLenLevellist", async () => (await api.Schooling.GetSchLenLevelListAsync(sch)).Count),
("Schoolen.GetSchLenlist", async () => (await api.Schooling.GetSchLenListAsync(sch)).Count),
("UserInfo.GetUserList", async () => (await api.UserInfo.GetUserListAsync(sch)).Count),
("SchInfo.AllList", async () => (await api.SchInfo.AllListAsync()).Count),
("SchInfo.GetSchlist", async () => (await api.SchInfo.GetSchListAsync(null)).Count),
("OATea.GetSchTeainfo", async () => (await api.TeaInfo.GetSchTeaInfoAsync(sch, null)).Count),
("OATea.GetArrTeainfo", async () => (await api.TeaInfo.GetArrTeaInfoAsync(teaId.Value.ToString())).Count),
("SchGroup.GetTeaTree", async () => (await api.SchTree.GetTeaTreeAsync(sch, null)).Count),
("OAStu.GetAllStulist", async () => (await api.StuInfo.GetAllStuListAsync()).Count),
("OAStu.GetSchStulist", async () => (await api.StuInfo.GetSchStuListAsync(sch, null)).Count),
("OAStu.GetClaStulist", async () => (await api.StuInfo.GetClaStuListAsync(classId, null)).Count),
("TeachInfo.GetSchTeachlist", async () => (await api.TeachInfo.GetSchTeachListAsync(sch, teaId)).Count),
("TeachInfo.GetSchClaTeachlist", async () => (await api.TeachInfo.GetSchClaTeachListAsync(classId)).Count),
("SubInfo.GetSchTeachSublist", async () => (await api.SubInfo.GetSchTeachSubListAsync(sch)).Count),
("SubInfo.GetSchSublist", async () => (await api.SubInfo.GetSchSubListAsync(sch, null, null)).Count),
("FamCom.GetStuUserFamIDList", async () => (await api.FamilyCompat.GetStuUserFamIdListAsync("1,2")).Count),
("FamCom.GetAllStuFamMem", async () => (await api.FamilyCompat.GetAllStuFamMemAsync("1,2")).Count),
};
if (only != null)
{
cases = cases.Where(c => c.Name.Contains(only, StringComparison.OrdinalIgnoreCase)).ToList();
if (cases.Count == 0)
{
log($"--only={only} 未匹配任何端点");
return new List<string> { "--only" };
}
}
var failures = new List<string>();
log($"联调目标:{Target()} sch={sch} classId={classId} teaId={teaId} group={group}");
foreach (var (name, call) in cases)
{
try
{
var count = await call();
log($" OK {name} -> {count} 条");
}
catch (Exception e)
{
failures.Add(name);
log($" FAIL {name} -> {e.GetType().Name}: {e.Message}");
}
}
log($"汇总:{cases.Count - failures.Count}/{cases.Count} 通过");
return failures;
}
}