154 lines
6.7 KiB
C#
154 lines
6.7 KiB
C#
using System.Text.Json;
|
|
|
|
namespace FinalFactory.Rendezvous.Tests.Contracts;
|
|
|
|
public sealed class OpenApiCompatibilityTests
|
|
{
|
|
private static readonly string[] ExpectedPaths =
|
|
[
|
|
"/health/live",
|
|
"/health/ready",
|
|
"/v1/join-attempts",
|
|
"/v1/join-attempts/{attemptId}",
|
|
"/v1/join-attempts/{attemptId}/outcome",
|
|
"/v1/sessions",
|
|
"/v1/sessions/{listingId}",
|
|
"/v1/sessions/{listingId}/join-attempts",
|
|
"/v1/sessions/{listingId}/renew",
|
|
];
|
|
|
|
private static readonly string[] ExpectedListingProperties =
|
|
[
|
|
"buildVersion",
|
|
"capacity",
|
|
"contractVersion",
|
|
"dedicatedFallback",
|
|
"displayName",
|
|
"environmentId",
|
|
"gameId",
|
|
"listingId",
|
|
"metadata",
|
|
"protocolVersion",
|
|
"publisherTrustMode",
|
|
"regionId",
|
|
"visibility",
|
|
];
|
|
|
|
[Fact]
|
|
public void GeneratedOpenApiContainsTheFrozenV1Surface()
|
|
{
|
|
string path = Path.Combine(
|
|
ContractTestFiles.Directory,
|
|
"../../../../../docs/api/rendezvous-v1.json");
|
|
using JsonDocument document = JsonDocument.Parse(File.ReadAllText(Path.GetFullPath(path)));
|
|
JsonElement root = document.RootElement;
|
|
|
|
Assert.Equal("3.1.1", root.GetProperty("openapi").GetString());
|
|
string[] paths = root.GetProperty("paths")
|
|
.EnumerateObject()
|
|
.Select(static item => item.Name)
|
|
.Order(StringComparer.Ordinal)
|
|
.ToArray();
|
|
Assert.Equal(ExpectedPaths, paths);
|
|
|
|
JsonElement schemas = root.GetProperty("components").GetProperty("schemas");
|
|
Assert.Equal("string", schemas.GetProperty("GameId").GetProperty("type").GetString());
|
|
Assert.Equal("uuid", schemas.GetProperty("SessionListingId").GetProperty("format").GetString());
|
|
|
|
string[] listingProperties = schemas.GetProperty("SessionListing")
|
|
.GetProperty("properties")
|
|
.EnumerateObject()
|
|
.Select(static item => item.Name)
|
|
.Order(StringComparer.Ordinal)
|
|
.ToArray();
|
|
Assert.Equal(ExpectedListingProperties, listingProperties);
|
|
Assert.DoesNotContain(listingProperties, static property =>
|
|
property.Contains("token", StringComparison.OrdinalIgnoreCase)
|
|
|| property.Contains("playerId", StringComparison.OrdinalIgnoreCase));
|
|
JsonElement dedicatedFallback = schemas.GetProperty("SessionListing")
|
|
.GetProperty("properties")
|
|
.GetProperty("dedicatedFallback");
|
|
JsonElement fallbackReference = Assert.Single(
|
|
dedicatedFallback.GetProperty("oneOf").EnumerateArray(),
|
|
static schema => schema.TryGetProperty("$ref", out _));
|
|
Assert.Equal(
|
|
"#/components/schemas/NetworkEndpoint",
|
|
fallbackReference.GetProperty("$ref").GetString());
|
|
|
|
JsonElement outcomeReportProperties = schemas.GetProperty("ReportConnectionOutcomeRequest")
|
|
.GetProperty("properties");
|
|
Assert.True(outcomeReportProperties.TryGetProperty("elapsedBucket", out _));
|
|
Assert.True(outcomeReportProperties.TryGetProperty("elapsedMilliseconds", out _));
|
|
Assert.True(outcomeReportProperties.TryGetProperty("diagnosticCode", out _));
|
|
string[] outcomeNames = schemas.GetProperty("ConnectionOutcomeKind")
|
|
.GetProperty("enum")
|
|
.EnumerateArray()
|
|
.Select(static value => value.GetString()!)
|
|
.ToArray();
|
|
Assert.Contains("timedOut", outcomeNames);
|
|
Assert.Contains("staleHost", outcomeNames);
|
|
Assert.Contains("transportFailed", outcomeNames);
|
|
Assert.Contains("punchTimedOut", outcomeNames);
|
|
Assert.Contains("directConnectTimedOut", outcomeNames);
|
|
Assert.Contains("transportError", outcomeNames);
|
|
|
|
JsonElement publisherBearer = root.GetProperty("components")
|
|
.GetProperty("securitySchemes")
|
|
.GetProperty("PublisherBearer");
|
|
Assert.Equal("http", publisherBearer.GetProperty("type").GetString());
|
|
Assert.Equal("bearer", publisherBearer.GetProperty("scheme").GetString());
|
|
JsonElement attemptCapability = root.GetProperty("components")
|
|
.GetProperty("securitySchemes")
|
|
.GetProperty("JoinAttemptCapability");
|
|
Assert.Equal("apiKey", attemptCapability.GetProperty("type").GetString());
|
|
Assert.Equal(
|
|
"X-Rendezvous-Client-Punch-Capability",
|
|
attemptCapability.GetProperty("name").GetString());
|
|
(string Path, string Method)[] publisherOperations =
|
|
[
|
|
("/v1/sessions", "post"),
|
|
("/v1/sessions/{listingId}", "put"),
|
|
("/v1/sessions/{listingId}", "delete"),
|
|
("/v1/sessions/{listingId}/renew", "post"),
|
|
];
|
|
foreach ((string operationPath, string method) in publisherOperations)
|
|
{
|
|
JsonElement security = root.GetProperty("paths")
|
|
.GetProperty(operationPath)
|
|
.GetProperty(method)
|
|
.GetProperty("security");
|
|
Assert.True(security[0].TryGetProperty("PublisherBearer", out _));
|
|
}
|
|
|
|
JsonElement cancelParameters = root.GetProperty("paths")
|
|
.GetProperty("/v1/join-attempts/{attemptId}")
|
|
.GetProperty("delete")
|
|
.GetProperty("parameters");
|
|
JsonElement cancelCapability = Assert.Single(cancelParameters.EnumerateArray(), static parameter =>
|
|
parameter.GetProperty("in").GetString() == "header"
|
|
&& parameter.GetProperty("name").GetString()
|
|
== "X-Rendezvous-Client-Punch-Capability");
|
|
Assert.True(cancelCapability.GetProperty("required").GetBoolean());
|
|
foreach ((string operationPath, string method) in new[]
|
|
{
|
|
("/v1/join-attempts/{attemptId}", "delete"),
|
|
("/v1/join-attempts/{attemptId}/outcome", "post"),
|
|
})
|
|
{
|
|
JsonElement security = root.GetProperty("paths")
|
|
.GetProperty(operationPath)
|
|
.GetProperty(method)
|
|
.GetProperty("security");
|
|
Assert.True(security[0].TryGetProperty("JoinAttemptCapability", out _));
|
|
}
|
|
JsonElement hostPollParameters = root.GetProperty("paths")
|
|
.GetProperty("/v1/sessions/{listingId}/join-attempts")
|
|
.GetProperty("get")
|
|
.GetProperty("parameters");
|
|
JsonElement leaseToken = Assert.Single(hostPollParameters.EnumerateArray(), static parameter =>
|
|
parameter.GetProperty("in").GetString() == "header"
|
|
&& parameter.GetProperty("name").GetString() == "X-Rendezvous-Lease-Token");
|
|
Assert.True(leaseToken.GetProperty("required").GetBoolean());
|
|
}
|
|
}
|