Initial commit: Client Doc docs Server Tools
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user