VanguardReMaster/server/tests/Vanguard.Server.Tests/OrleansServerE2ETests.cs

102 lines
3.8 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Vanguard.Server.Api;
using Xunit.Sdk;
namespace Vanguard.Server.Tests;
/// <summary>
/// Полный матч через HTTP + WebSocket с включённым Orleans: проверяет не
/// только грану, но и связку registry → adapter → endpoint → silo.
/// </summary>
[Collection("Orleans")]
public class OrleansServerE2ETests
{
[Fact]
public async Task Two_Clients_Play_A_Full_Match_With_Orleans_Enabled()
{
using var factory = NewFactory();
using var http = factory.CreateClient();
var deck = ServerTestData.BuildDeck();
var firstQueue = await EnqueueAsync(http, "p1", deck);
var secondQueue = await EnqueueAsync(http, "p2", deck);
var firstStatus = await WaitForMatchAsync(http, firstQueue.QueueId, "p1");
var secondStatus = await WaitForMatchAsync(http, secondQueue.QueueId, "p2");
Assert.Equal(firstStatus.MatchId, secondStatus.MatchId);
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(120));
await using var first = await TestGameClient.ConnectAsync(
factory, firstStatus.MatchId!, firstStatus.Ticket!, "p1", 0, cts.Token);
await using var second = await TestGameClient.ConnectAsync(
factory, secondStatus.MatchId!, secondStatus.Ticket!, "p2", 0, cts.Token);
await Task.WhenAll(
first.PlayRandomlyAsync(seed: 11, cts.Token),
second.PlayRandomlyAsync(seed: 22, cts.Token));
Assert.True(first.View.IsFinished, "Первый клиент не увидел завершение партии.");
Assert.True(second.View.IsFinished, "Второй клиент не увидел завершение партии.");
Assert.Equal(first.View.Winner, second.View.Winner);
var health = await http.GetFromJsonAsync<JsonElement>("/health");
Assert.True(health.GetProperty("matches").GetInt32() >= 1);
}
private static WebApplicationFactory<Program> NewFactory()
{
return new WebApplicationFactory<Program>().WithWebHostBuilder(builder =>
{
builder.UseSetting("Orleans:Enabled", "true");
// Не пересекаться с TestCluster из OrleansMatchTests.
builder.UseSetting("Orleans:SiloPort", "21111");
builder.UseSetting("Orleans:GatewayPort", "21000");
});
}
private static async Task<QueueAccepted> EnqueueAsync(
HttpClient http,
string playerId,
List<string> deck)
{
var response = await http.PostAsJsonAsync(
"/api/game/queue",
new QueueRequest(playerId, "classic-ranked", deck));
if (!response.IsSuccessStatusCode)
throw new XunitException(await response.Content.ReadAsStringAsync());
return (await response.Content.ReadFromJsonAsync<QueueAccepted>())!;
}
private static async Task<QueueStatusResponse> WaitForMatchAsync(
HttpClient http,
Guid queueId,
string playerId)
{
for (var attempt = 0; attempt < 200; attempt++)
{
var status = await http.GetFromJsonAsync<QueueStatusResponse>(
$"/api/game/queue/{queueId}?playerId={playerId}");
if (status is null)
throw new XunitException("Очередь исчезла.");
if (status.Status == "matched")
return status;
if (status.Status is "failed" or "expired" or "cancelled")
throw new XunitException($"Очередь в состоянии {status.Status}: {status.Reason}");
await Task.Delay(50);
}
throw new XunitException("Матч не был найден за 10 секунд.");
}
}