using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Xunit;
using CncCollector.Core;
using CncCollector.Api;
using CncCollector.Config;
namespace CncCollector.Tests
{
///
/// CollectorApiServer 单元测试。
/// 使用无效DB配置创建引擎和API服务器,通过HTTP客户端验证认证和路由行为。
///
public class CollectorApiServerTests : IDisposable
{
private readonly CollectorEngine _engine;
private readonly CollectorApiServer _server;
private readonly HttpClient _client;
private readonly int _port;
private readonly string _apiKey = "test_api_key_123";
public CollectorApiServerTests()
{
// 使用随机端口避免冲突
_port = 15800 + new Random().Next(0, 1000);
var config = new CollectorConfig
{
BusinessConnection = "Server=invalid;Database=invalid;User Id=invalid;Password=invalid;",
LogConnection = "Server=invalid;Database=invalid;User Id=invalid;Password=invalid;",
ApiPort = _port
};
_engine = new CollectorEngine(config);
_server = new CollectorApiServer(_engine, _apiKey, _port);
_server.Start();
_client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
}
public void Dispose()
{
_server?.Stop();
_client?.Dispose();
}
// ===== 认证测试 =====
[Fact]
public async Task Status_无APIKey_返回401()
{
var resp = await _client.GetAsync($"http://localhost:{_port}/api/collector/status");
Assert.Equal(HttpStatusCode.Unauthorized, resp.StatusCode);
}
[Fact]
public async Task Status_错误APIKey_返回401()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
request.Headers.Add("X-Api-Key", "wrong_key");
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.Unauthorized, resp.StatusCode);
}
[Fact]
public async Task Status_正确APIKey_返回200()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
}
// ===== 响应格式测试 =====
[Fact]
public async Task Status_响应体为标准JSON格式()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
var body = await resp.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject>(body);
Assert.NotNull(json);
Assert.True(json.ContainsKey("code"));
Assert.True(json.ContainsKey("message"));
Assert.True(json.ContainsKey("data"));
}
[Fact]
public async Task Status_响应data包含预期字段()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
var body = await resp.Content.ReadAsStringAsync();
dynamic json = JsonConvert.DeserializeObject(body);
Assert.Equal(0, (int)json.code);
Assert.NotNull(json.data);
Assert.NotNull(json.data.isRunning);
Assert.NotNull(json.data.workerCount);
Assert.NotNull(json.data.workers);
}
// ===== 路由测试 =====
[Fact]
public async Task UnknownEndpoint_返回404()
{
var request = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/nonexistent");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.NotFound, resp.StatusCode);
}
[Fact]
public async Task Refresh_正确APIKey_返回200()
{
var request = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:{_port}/api/collector/refresh");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
}
[Fact]
public async Task Stop_正确APIKey_返回200()
{
var request = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:{_port}/api/collector/stop");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
}
[Fact]
public async Task Start_正确APIKey_返回200()
{
var request = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:{_port}/api/collector/start");
request.Headers.Add("X-Api-Key", _apiKey);
var resp = await _client.SendAsync(request);
Assert.Equal(HttpStatusCode.OK, resp.StatusCode);
}
// ===== 启停控制测试 =====
[Fact]
public async Task 启停顺序_状态正确切换()
{
// 停止
var stopReq = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:{_port}/api/collector/stop");
stopReq.Headers.Add("X-Api-Key", _apiKey);
await _client.SendAsync(stopReq);
// 检查状态为停止
var statusReq = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
statusReq.Headers.Add("X-Api-Key", _apiKey);
var statusResp = await _client.SendAsync(statusReq);
var body = await statusResp.Content.ReadAsStringAsync();
dynamic json = JsonConvert.DeserializeObject(body);
Assert.False((bool)json.data.isRunning);
// 启动
var startReq = new HttpRequestMessage(HttpMethod.Post, $"http://localhost:{_port}/api/collector/start");
startReq.Headers.Add("X-Api-Key", _apiKey);
await _client.SendAsync(startReq);
// 检查状态为运行
statusReq = new HttpRequestMessage(HttpMethod.Get, $"http://localhost:{_port}/api/collector/status");
statusReq.Headers.Add("X-Api-Key", _apiKey);
statusResp = await _client.SendAsync(statusReq);
body = await statusResp.Content.ReadAsStringAsync();
json = JsonConvert.DeserializeObject(body);
Assert.True((bool)json.data.isRunning);
}
}
}