This commit is contained in:
jimmy committed 2025-11-14 16:56:57 +08:00
1 parent 237cbd8788
commit ab3721912d
102 files changed
+7929 -20

No files matched your search

@@ -0,0 +1,97 @@
using Sharp.NetServer.Middleware;
namespace NetServer.Test.UnitTests;
/// <summary>
/// 中间件管道测试(简化版)
/// </summary>
[TestClass]
public class MiddlewarePipelineTests
{
[TestMethod]
public async Task Pipeline_ShouldExecuteMiddlewaresInOrder()
{
// Arrange
var pipeline = new MiddlewarePipeline();
var executionOrder = new List<string>();
pipeline.Use(next => async context =>
{
executionOrder.Add("First-Before");
await next(context);
executionOrder.Add("First-After");
});
pipeline.Use(next => async context =>
{
executionOrder.Add("Second-Before");
await next(context);
executionOrder.Add("Second-After");
});
pipeline.Use(next => async context =>
{
executionOrder.Add("Third");
});
// Act
await pipeline.ExecuteAsync(null!); // 简化测试,不需要真实 context
// Assert
Assert.AreEqual(5, executionOrder.Count);
Assert.AreEqual("First-Before", executionOrder[0]);
Assert.AreEqual("Second-Before", executionOrder[1]);
Assert.AreEqual("Third", executionOrder[2]);
Assert.AreEqual("Second-After", executionOrder[3]);
Assert.AreEqual("First-After", executionOrder[4]);
}
[TestMethod]
public async Task Pipeline_ShouldSupportMultipleMiddlewares()
{
// Arrange
var pipeline = new MiddlewarePipeline();
var counter = 0;
for (int i = 0; i < 5; i++)
{
pipeline.Use(next => async context =>
{
counter++;
await next(context);
});
}
// Act
await pipeline.ExecuteAsync(null!);
// Assert
Assert.AreEqual(5, counter);
}
[TestMethod]
public async Task Pipeline_CanShortCircuit()
{
// Arrange
var pipeline = new MiddlewarePipeline();
var reachedEnd = false;
pipeline.Use(next => async context =>
{
// 短路,不调用 next
await Task.CompletedTask;
});
pipeline.Use(next => async context =>
{
reachedEnd = true;
await next(context);
});
// Act
await pipeline.ExecuteAsync(null!);
// Assert
Assert.IsFalse(reachedEnd, "Pipeline should be short-circuited");
}
}
@@ -0,0 +1,155 @@
using Sharp.NetServer.Routing;
using Sharp.NetServer.Attributes;
using Sharp.NetServer.Controllers;
using Sharp.NetServer.Models;
namespace NetServer.Test.UnitTests;
/// <summary>
/// 路由系统测试
/// </summary>
[TestClass]
public class RouteTableTests
{
[TestMethod]
public void RegisterController_ShouldDiscoverRoutes()
{
// Arrange
var routeTable = new RouteTable();
// Act
routeTable.RegisterController(typeof(TestController));
var routes = routeTable.GetAllRoutes();
// Assert
Assert.IsNotNull(routes);
Assert.IsTrue(routes.Count > 0);
Assert.IsTrue(routes.Any(r => r.Template == "/api/test/hello"));
}
[TestMethod]
public void FindRoute_ShouldMatchCorrectRoute()
{
// Arrange
var routeTable = new RouteTable();
routeTable.RegisterController(typeof(TestController));
// Act
var route = routeTable.FindRoute("GET", "/api/test/hello");
// Assert
Assert.IsNotNull(route);
Assert.AreEqual("GET", route.HttpMethod);
Assert.AreEqual("/api/test/hello", route.Template);
}
[TestMethod]
public void FindRoute_WithParameter_ShouldMatch()
{
// Arrange
var routeTable = new RouteTable();
routeTable.RegisterController(typeof(TestController));
// Act
var route = routeTable.FindRoute("GET", "/api/test/user/123");
// Assert
Assert.IsNotNull(route);
Assert.AreEqual("GET", route.HttpMethod);
}
[TestMethod]
public void FindRoute_InvalidPath_ShouldReturnNull()
{
// Arrange
var routeTable = new RouteTable();
routeTable.RegisterController(typeof(TestController));
// Act
var route = routeTable.FindRoute("GET", "/invalid/path");
// Assert
Assert.IsNull(route);
}
[TestMethod]
public void RegisterController_ShouldCaptureAuthorization()
{
// Arrange
var routeTable = new RouteTable();
// Act
routeTable.RegisterController(typeof(TestController));
var route = routeTable.FindRoute("GET", "/api/test/protected");
// Assert
Assert.IsNotNull(route);
Assert.IsTrue(route.RequireAuthorization);
}
[TestMethod]
public void RegisterController_ShouldCaptureAllowAnonymous()
{
// Arrange
var routeTable = new RouteTable();
// Act
routeTable.RegisterController(typeof(TestController));
var route = routeTable.FindRoute("GET", "/api/test/hello");
// Assert
Assert.IsNotNull(route);
Assert.IsTrue(route.AllowAnonymous);
}
[TestMethod]
public void RegisterController_ShouldCaptureRateLimit()
{
// Arrange
var routeTable = new RouteTable();
// Act
routeTable.RegisterController(typeof(TestController));
var route = routeTable.FindRoute("GET", "/api/test/limited");
// Assert
Assert.IsNotNull(route);
Assert.IsNotNull(route.RateLimitConfig);
Assert.AreEqual(100, route.RateLimitConfig.MaxRequests);
}
}
/// <summary>
/// 测试用控制器
/// </summary>
[ApiController]
[Route("api/test")]
internal class TestController : BaseController
{
[AllowAnonymous]
[HttpGet("hello")]
public async Task HelloAsync(HttpContext context)
{
await WriteSuccessResponseAsync(context, new { message = "Hello" });
}
[HttpGet("user/{id}")]
public async Task GetUserAsync(HttpContext context)
{
await WriteSuccessResponseAsync(context, new { id = "123" });
}
[Authorize]
[HttpGet("protected")]
public async Task ProtectedAsync(HttpContext context)
{
await WriteSuccessResponseAsync(context, new { message = "Protected" });
}
[RateLimit(100, RateLimitScope.Ip)]
[HttpGet("limited")]
public async Task LimitedAsync(HttpContext context)
{
await WriteSuccessResponseAsync(context, new { message = "Limited" });
}
}