Files
2026-07-10 10:24:29 +08:00

84 lines
3.5 KiB
C#

using System.Threading.Tasks;
using Xunit;
using XWorld.Framework.Protocol;
using XWorld.Server.Gateway;
namespace XWorld.Server.Gateway.Tests
{
public class GatewayEndToEndTests
{
private static Frame JoinRps()
=> new Frame(Channel.Framework, (ushort)FrameworkOpcode.MatchRequest,
new MatchRequestMsg { GameId = "rps", Version = 1 }.Encode());
[Fact]
public async Task Heartbeat_IsEchoedBack()
{
var host = new GameServerHost();
await host.StartAsync(TestGames.Root, tickIntervalMs: 20);
try
{
using var client = new WsTestClient();
await client.ConnectAsync(host.WsBaseUrl, pid: 7);
await client.SendFrameAsync(new Frame(Channel.Framework, (ushort)FrameworkOpcode.Heartbeat,
new HeartbeatMsg { ClientTimeMs = 999L }.Encode()));
Frame? echo = null;
for (int i = 0; i < 10; i++)
{
var f = await client.ReceiveFrameAsync(5000);
if (f.Channel == Channel.Framework && f.Opcode == (ushort)FrameworkOpcode.Heartbeat) { echo = f; break; }
}
Assert.True(echo.HasValue, "未收到心跳回显");
Assert.Equal(999L, HeartbeatMsg.Decode(echo.Value.Payload).ClientTimeMs);
await client.CloseAsync();
}
finally { await host.StopAsync(); }
}
[Fact]
public async Task Reconnect_ContinuesReceivingFromSameRoom()
{
var host = new GameServerHost();
// matchTimeoutTicks=3 → 单人后 AI 兜底成团;logicalDt=0.2 让 60s 对局慢跑;大重连窗口
await host.StartAsync(TestGames.Root, tickIntervalMs: 200,
reconnectWindowTicks: 100, matchTimeoutTicks: 3, logicalDt: 0.2f);
try
{
var client1 = new WsTestClient();
await client1.ConnectAsync(host.WsBaseUrl, pid: 42);
await client1.SendFrameAsync(JoinRps());
// 收到 MatchFound 后的第一个游戏快照
bool gotSnapshot = false;
for (int i = 0; i < 15 && !gotSnapshot; i++)
{
var f = await client1.ReceiveFrameAsync(5000);
if (f.Channel == Channel.Game) gotSnapshot = true;
}
Assert.True(gotSnapshot, "重连前应先收到一个快照");
// 断开
await client1.CloseAsync();
client1.Dispose();
// 用同 pid 重连
using var client2 = new WsTestClient();
await client2.ConnectAsync(host.WsBaseUrl, pid: 42);
// 房间仍在跑,下一个房间输出应发到 client2
bool gotAfterReconnect = false;
for (int i = 0; i < 15 && !gotAfterReconnect; i++)
{
var f = await client2.ReceiveFrameAsync(5000);
if (f.Channel == Channel.Game) gotAfterReconnect = true;
else if (f.Channel == Channel.Framework && f.Opcode == (ushort)FrameworkOpcode.RoomEnd) gotAfterReconnect = true;
}
Assert.True(gotAfterReconnect, "重连后应继续收到房间输出(快照或 RoomEnd)");
await client2.CloseAsync();
}
finally { await host.StopAsync(); }
}
}
}