节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
4.55 KiB
Stardust
using System.IO;
using Xunit;

namespace ServerTest.Mcp;

/// <summary>
/// 节点只读 MCP 复用 MVC/API 已有查询,不再在工具内 FindAll 后内存过滤或分页。
/// 纯源码断言,不连数据库。
/// </summary>
public class NodeToolsReuseTests
{
    private static String Read(String relativePath) => File.ReadAllText(SourceRoot.FindPath(relativePath));

    /// <summary>截取某个类的源码,避免后面的写工具干扰断言。</summary>
    private static String ClassBody(String source, String className)
    {
        var marker = $"public class {className}";
        var start = source.IndexOf(marker, StringComparison.Ordinal);
        Assert.True(start >= 0, $"未找到 {className}");
        var next = source.IndexOf("public class ", start + marker.Length, StringComparison.Ordinal);
        return next < 0 ? source[start..] : source[start..next];
    }

    [Fact(DisplayName = "节点列表复用 Node.Search / NodeOnline.Search,不再全表过滤分页")]
    public void NodeList_ReusesEntitySearch()
    {
        var body = ClassBody(Read("Stardust.Mcp/Tools/Nodes/NodeTools.cs"), "NodeListTool");

        Assert.Contains("McpGuard.NeedProject(ctx)", body);
        Assert.Contains("Node.Search(", body);
        Assert.Contains("NodeOnline.Search(", body);
        Assert.Contains("NodeOnline.FindByNodeId(", body);
        Assert.DoesNotContain("Node.FindAll", body);
        Assert.DoesNotContain("NodeOnline.FindAll(", body);
        Assert.DoesNotContain(".Skip(", body);
        Assert.DoesNotContain(".Take(", body);
    }

    [Fact(DisplayName = "节点详情复用 FindAllByNodeId 与 NodeCommand.Search")]
    public void NodeDetail_ReusesOnlineAndCommandSearch()
    {
        var body = ClassBody(Read("Stardust.Mcp/Tools/Nodes/NodeTools.cs"), "NodeDetailTool");

        Assert.Contains("McpGuard.Node(", body);
        Assert.Contains("NodeOnline.FindAllByNodeId(", body);
        Assert.Contains("NodeCommand.Search(", body);
        Assert.DoesNotContain("NodeCommand.FindAll", body);
        Assert.DoesNotContain("NodeOnline.FindAll(", body);
        Assert.Contains(".OrderByDescending(e => e.UpdateTime)", body);
        Assert.DoesNotContain(".Take(", body);
    }

    [Fact(DisplayName = "节点应用复用 AppOnline.Search")]
    public void NodeApps_ReusesAppOnlineSearch()
    {
        var body = ClassBody(Read("Stardust.Mcp/Tools/Nodes/NodeTools.cs"), "NodeAppsTool");

        Assert.Contains("McpGuard.Node(", body);
        Assert.Contains("AppOnline.Search(", body);
        Assert.DoesNotContain("AppOnline.FindAll", body);
    }

    [Fact(DisplayName = "节点/应用命令与进程工具仍委托 IMcpOperations")]
    public void WriteTools_StillDelegateOperations()
    {
        var source = Read("Stardust.Mcp/Tools/Nodes/NodeTools.cs");

        Assert.Contains("ops.SendNodeCommandAsync(", ClassBody(source, "NodeCommandTool"));
        Assert.Contains("ops.SendAppCommandAsync(", ClassBody(source, "AppCommandTool"));
        Assert.Contains("new AppCommandTool().InvokeAsync(", ClassBody(source, "AppProcessTool"));
    }

    [Fact(DisplayName = "节点、在线、命令、应用在线的 API 与 MVC 调用同一实体查询")]
    public void ApiAndMvc_ShareEntitySearch()
    {
        const String node = "return Node.Search(projectId, provinceId, cityId, category, product, kind, version, runtime, framework, arch, enable, start, end, p[\"Q\"], p);";
        const String online = "return NodeOnline.Search(projectId, nodeId, provinceId, cityId, category, start, end, p[\"Q\"], p);";
        const String command = "return NodeCommand.Search(nodeId, command, start, end, p[\"Q\"], p);";
        const String appOnline = "return AppOnline.Search(projectId, appId, nodeId, category, start, end, p[\"Q\"], p);";

        Assert.Contains(node, Read("Stardust.Web/Areas/Nodes/Controllers/NodeController.cs"));
        Assert.Contains(node, Read("Stardust.WebApi/Areas/Nodes/Controllers/NodeController.cs"));
        Assert.Contains(online, Read("Stardust.Web/Areas/Nodes/Controllers/NodeOnlineController.cs"));
        Assert.Contains(online, Read("Stardust.WebApi/Areas/Nodes/Controllers/NodeOnlineController.cs"));
        Assert.Contains(command, Read("Stardust.Web/Areas/Nodes/Controllers/NodeCommandController.cs"));
        Assert.Contains(command, Read("Stardust.WebApi/Areas/Nodes/Controllers/NodeCommandController.cs"));
        Assert.Contains(appOnline, Read("Stardust.Web/Areas/Registry/Controllers/AppOnlineController.cs"));
        Assert.Contains(appOnline, Read("Stardust.WebApi/Areas/Registry/Controllers/AppOnlineController.cs"));
    }
}