InboundGrantAndTenantBaselineGuardTests.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. using Xunit;
  2. namespace Admin.NET.Plugin.AiDOP.Tests.DataPlatform;
  3. /// <summary>
  4. /// 推送凭据与租户基线的源码守卫。测试项目不连库,行为判断见
  5. /// <see cref="InboundGrantIssuanceTests"/>;这里钉住调用侧不会把两张表拆开、
  6. /// 也不会在解析失败时静默跳过。
  7. /// </summary>
  8. public class InboundGrantAndTenantBaselineGuardTests
  9. {
  10. private static string RepoFile(params string[] parts)
  11. {
  12. var dir = new DirectoryInfo(AppContext.BaseDirectory);
  13. while (dir != null && !File.Exists(Path.Combine(dir.FullName, "AGENTS.md")))
  14. dir = dir.Parent;
  15. Assert.NotNull(dir);
  16. return File.ReadAllText(Path.Combine(new[] { dir!.FullName }.Concat(parts).ToArray()));
  17. }
  18. [Fact]
  19. public void CreateGrant_WritesIdentityAndGrantInOneTransaction_AndClearsCache()
  20. {
  21. var source = RepoFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "DataPlatform", "MdpSourceMappingService.cs");
  22. var method = SliceMethod(source, "CreateGrant");
  23. var begin = method.IndexOf("BeginTran()", StringComparison.Ordinal);
  24. var commit = method.IndexOf("CommitTran()", StringComparison.Ordinal);
  25. Assert.True(begin >= 0 && commit > begin, "新建身份与授权行必须在同一事务里");
  26. var body = method[begin..commit];
  27. Assert.Contains("new SysOpenAccess", body);
  28. Assert.Contains("BindTenantId = tenant", body);
  29. Assert.Contains("new MdpInboundGrant", body);
  30. Assert.Contains("CacheConst.KeyOpenAccess", method);
  31. Assert.Contains("RejectCrossTenant", method);
  32. }
  33. [Fact]
  34. public void TenantCreate_LogsEveryFailedBaselineResolution()
  35. {
  36. var source = RepoFile("server", "Admin.NET.Core", "Service", "Tenant", "SysTenantService.cs");
  37. Assert.Contains("类型未解析", source);
  38. Assert.Contains("未注册到容器", source);
  39. Assert.Contains("方法未找到", source);
  40. }
  41. [Fact]
  42. public void ReinitEndpoint_RequiresSuperAdmin_AndExplicitTenant()
  43. {
  44. var source = RepoFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "Infrastructure", "AidopTenantBaselineController.cs");
  45. var method = SliceMethod(source, "Reinit");
  46. Assert.Contains("RequireSuperAdmin".Replace("RequireSuperAdmin", "SuperAdmin"), method);
  47. Assert.Contains("ErrorCodeEnum.SA001", method);
  48. Assert.Contains("input.TenantId", method);
  49. Assert.DoesNotContain("_user.TenantId", method);
  50. }
  51. [Fact]
  52. public void BaselineSeed_SkipsRowsThatAlreadyExist()
  53. {
  54. var source = RepoFile("server", "Plugins", "Admin.NET.Plugin.AiDOP", "Infrastructure", "AidopTenantInitService.cs");
  55. var guards = source.Split("if (exists) continue").Length - 1;
  56. Assert.True(guards >= 3, $"存在性检查不足,重跑可能重复插入:{guards}");
  57. }
  58. private static string SliceMethod(string source, string name)
  59. {
  60. var at = source.IndexOf(name + "(", StringComparison.Ordinal);
  61. Assert.True(at >= 0, $"找不到方法 {name}");
  62. var open = source.IndexOf('{', at);
  63. var depth = 0;
  64. for (var end = open; end < source.Length; end++)
  65. {
  66. if (source[end] == '{') depth++;
  67. else if (source[end] == '}' && --depth == 0)
  68. return source[open..(end + 1)];
  69. }
  70. throw new InvalidOperationException($"方法 {name} 没有闭合");
  71. }
  72. }