Files
Radicade/ServerTests/CommunityBoardRealtimeTests.cs
T
2026-10-16 23:33:13 -07:00

116 lines
4.4 KiB
C#

using System.Text.Json;
using RadicadeServer.Extensions;
using RadicadeServer.RecNet.Board;
using Xunit;
namespace RadicadeServer.Tests;
/// <summary>
/// A board the admin panel saves has to reach players without a restart. The only lever the client
/// offers for that is its notification table, which is keyed by name and drops any frame whose Id is
/// not the exact registered key - the same contract the progression frame lives under. The server
/// used to announce a save as the numeric enum 95 with an empty payload, which no handler matches.
/// </summary>
public class CommunityBoardRealtimeTests
{
private static CommunityBoard Board() => new()
{
FeaturedPlayer = new FeaturedPlayer
{
Id = 42,
TitleOverride = "Community Legend",
UrlOverride = "https://example/creator"
},
FeaturedRoomGroup = new FeaturedRoomGroup
{
FeaturedRoomGroupId = 1,
Name = "Top Picks",
Rooms = new List<FeaturedRoom>
{
new() { RoomId = 1001, RoomName = "Dodgeball Arena", ImageName = "room-1.png" }
}
},
CurrentAnnouncement = new BoardAnnouncement
{
Message = "See you in the Rec Center.",
MoreInfoUrl = "https://discord.gg/radicade"
},
InstagramImages = new List<InstagramImage>
{
new() { ImageName = "cb-1.png", ImageUrl = "https://cdn/cb-1.png" }
},
Videos = new List<BoardVideo>
{
new()
{
BlobName = "v.mp4",
Title = "Trailer",
Description = "Year in review",
ThumbnailBlobName = "t.png",
SourceUrl = "https://youtu.be/x"
}
}
};
[Fact]
public void TheBoardGoesOutUnderTheLiteralNameTheClientRegistersItsHandlerFor()
{
var frames = CommunityBoardBroadcast.BuildFrames(Board());
var boardFrame = frames[0];
Assert.Equal("CommunityBoardUpdate", (string)boardFrame.Id);
Assert.Contains("\"Id\":\"CommunityBoardUpdate\"", boardFrame.ToJson());
// Not the numeric enum (95): the client registers the board handler by name and drops any
// frame whose Id is not the exact key, which is why a saved board used to be invisible until
// the game was restarted.
Assert.DoesNotContain("\"Id\":\"95\"", boardFrame.ToJson());
}
[Fact]
public void TheBoardFrameCarriesTheWholeBoardSoTheClientNeedNotRefetch()
{
var frames = CommunityBoardBroadcast.BuildFrames(Board());
using var doc = JsonDocument.Parse(frames[0].ToJson());
var msg = doc.RootElement.GetProperty("Msg");
Assert.Equal("Community Legend", msg.GetProperty("FeaturedPlayer").GetProperty("TitleOverride").GetString());
Assert.Equal("Top Picks", msg.GetProperty("FeaturedRoomGroup").GetProperty("Name").GetString());
Assert.Equal("Dodgeball Arena",
msg.GetProperty("FeaturedRoomGroup").GetProperty("Rooms")[0].GetProperty("RoomName").GetString());
Assert.Equal(1, msg.GetProperty("InstagramImages").GetArrayLength());
Assert.Equal("Trailer", msg.GetProperty("Videos")[0].GetProperty("Title").GetString());
}
[Fact]
public void TheAnnouncementGoesOutUnderItsOwnNumericHandler()
{
var frames = CommunityBoardBroadcast.BuildFrames(Board());
var announcementFrame = frames.Single(f => Equals(f.Id, "96"));
Assert.Contains("\"Id\":\"96\"", announcementFrame.ToJson());
using var doc = JsonDocument.Parse(announcementFrame.ToJson());
var msg = doc.RootElement.GetProperty("Msg");
Assert.Equal("See you in the Rec Center.", msg.GetProperty("Message").GetString());
Assert.Equal("https://discord.gg/radicade", msg.GetProperty("MoreInfoUrl").GetString());
}
[Fact]
public void AnEmptyBoardStillSendsAWellFormedAnnouncementFrame()
{
var frames = CommunityBoardBroadcast.BuildFrames(new CommunityBoard());
Assert.Equal(2, frames.Count);
using var doc = JsonDocument.Parse(frames[1].ToJson());
Assert.Equal(string.Empty, doc.RootElement.GetProperty("Msg").GetProperty("Message").GetString());
}
[Fact]
public void ANullBoardPushesNothing()
{
Assert.Empty(CommunityBoardBroadcast.BuildFrames(null));
}
}