节点在线、应用在线、配置在线使用令牌查询
大石头 authored at 2021-12-16 19:49:30
3.81 KiB
Stardust
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Routing;
using Stardust.Data.Platform;
using Stardust.WebApiTests.Fixtures;
using Xunit;

namespace Stardust.WebApiTests.Mcp;

/// <summary>
/// MCP 令牌 Reset 回归:GET /api/Platform/McpToken/Reset?id= 不得被 Detail/{id} 误匹配;
/// 重置后应返回新 token(一次性展示)。
/// </summary>
[Collection(WebApiCollection.Name)]
public class McpTokenResetTests
{
    private static Type ApiControllerType =>
        Type.GetType("Stardust.Web.Areas.Platform.Controllers.McpTokenController, StarWebApi")
        ?? throw new InvalidOperationException("StarWebApi McpTokenController not found");

    [Fact(DisplayName = "Reset 动作注册独立 HttpGet 路由(避免与 Detail/{id} 冲突)")]
    public void Reset_HasDedicatedHttpGetRoute()
    {
        var method = ApiControllerType.GetMethod(McpTokenController_Reset, BindingFlags.Public | BindingFlags.Instance);
        Assert.NotNull(method);

        var routeAttrs = method!.GetCustomAttributes<HttpMethodAttribute>(inherit: true)
            .Where(a => a.HttpMethods.Contains("GET", StringComparer.OrdinalIgnoreCase))
            .ToList();
        Assert.NotEmpty(routeAttrs);
        Assert.Contains(routeAttrs, a => a.Template != null && a.Template.Contains("Reset", StringComparison.OrdinalIgnoreCase));
    }

    // 避免测试工程引用 StarWebApi 控制器类型名冲突,用字符串匹配实际方法名 Reset
    private const string McpTokenController_Reset = "Reset";

    [Fact(DisplayName = "Reset 执行后 Token 变更且 JsonRefresh 含新 token")]
    public void Reset_Invoked_ReturnsNewTokenInJson()
    {
        var token = new McpToken
        {
            Name = "reset-route-test-" + Guid.NewGuid().ToString("N")[..8],
            Enable = true,
            Token = McpToken.GenerateToken(),
            ProjectId = 0,
        };

        try
        {
            Assert.True(token.Insert() > 0);
            var old = token.Token;

            var controller = Activator.CreateInstance(ApiControllerType)!;
            var httpContext = new DefaultHttpContext();
            typeof(ControllerBase).GetProperty(nameof(ControllerBase.ControllerContext))!
                .SetValue(controller, new ControllerContext { HttpContext = httpContext });

            var reset = ApiControllerType.GetMethod(McpTokenController_Reset, BindingFlags.Instance | BindingFlags.Public);
            Assert.NotNull(reset);

            var actionResult = reset!.Invoke(controller, new object[] { token.Id }) as ActionResult;
            Assert.NotNull(actionResult);

            var json = Assert.IsType<JsonResult>(actionResult);
            var body = json.Value;
            Assert.NotNull(body);

            var codeProp = body!.GetType().GetProperty("Code") ?? body.GetType().GetProperty("code");
            Assert.NotNull(codeProp);
            Assert.Equal(0, Convert.ToInt32(codeProp!.GetValue(body)));

            var dataProp = body.GetType().GetProperty("Data") ?? body.GetType().GetProperty("data");
            Assert.NotNull(dataProp);
            var data = dataProp!.GetValue(body);
            Assert.NotNull(data);

            var tokenProp = data!.GetType().GetProperty("token") ?? data.GetType().GetProperty("Token");
            Assert.NotNull(tokenProp);
            var newToken = tokenProp!.GetValue(data) as string;
            Assert.False(string.IsNullOrEmpty(newToken));
            Assert.StartsWith(McpToken.TokenPrefix, newToken);
            Assert.NotEqual(old, newToken);

            var reloaded = McpToken.FindById(token.Id);
            Assert.NotNull(reloaded);
            Assert.Equal(newToken, reloaded!.Token);
        }
        finally
        {
            token.Delete();
        }
    }
}