From ba9ee7300d0dd24b5a4a5ae4f179c6c27d15af2a Mon Sep 17 00:00:00 2001 From: wrexbe <81056464+wrexbe@users.noreply.github.com> Date: Mon, 15 Aug 2022 20:32:15 -0700 Subject: [PATCH] Added more docs to integration pool manager (#10632) --- Content.IntegrationTests/PoolManager.cs | 128 ++++++++++++++++++------ 1 file changed, 96 insertions(+), 32 deletions(-) diff --git a/Content.IntegrationTests/PoolManager.cs b/Content.IntegrationTests/PoolManager.cs index 85ba0df328..a43f480cec 100644 --- a/Content.IntegrationTests/PoolManager.cs +++ b/Content.IntegrationTests/PoolManager.cs @@ -12,12 +12,9 @@ using Content.IntegrationTests.Tests.Interaction.Click; using Content.IntegrationTests.Tests.Networking; using Content.Server.GameTicking; using Content.Shared.CCVar; -using Content.Shared.Maps; using NUnit.Framework; using Robust.Client; using Robust.Server; -using Robust.Server.GameStates; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; using Robust.Shared.Exceptions; @@ -30,11 +27,13 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.UnitTesting; - [assembly: LevelOfParallelism(3)] namespace Content.IntegrationTests; +/// +/// Making clients, and servers is slow, this manages a pool of them so tests can reuse them. +/// public static class PoolManager { private static readonly (string cvar, string value, bool tryAdd)[] ServerTestCvars = @@ -60,8 +59,8 @@ public static class PoolManager (CCVars.GameRoleTimers.Name, "false", false), }; - private static int PairId = 0; - private static object PairLock = new object(); + private static int PairId; + private static object PairLock = new(); private static List Pairs = new(); private static async Task ConfigurePrototypes(RobustIntegrationTest.IntegrationInstance instance, @@ -119,6 +118,10 @@ public static class PoolManager return server; } + /// + /// This shuts down the pool, and disposes all the server/client pairs. + /// This is a one time operation to be used when the testing program is exiting. + /// public static void Shutdown() { lock (PairLock) @@ -211,6 +214,11 @@ public static class PoolManager } } + /// + /// Gets a , which can be used to get access to a server, and client + /// + /// See + /// public static async Task GetServerClient(PoolSettings poolSettings = null, [System.Runtime.CompilerServices.CallerFilePath] string testMethodFilePath = "", [System.Runtime.CompilerServices.CallerMemberName] string testMethodName = "") => @@ -294,7 +302,7 @@ public static class PoolManager } /// - /// Used after checking pairs, Don't use this directly + /// Used by PairTracker after checking the server/client pair, Don't use this. /// /// public static void NoCheckReturn(Pair pair) @@ -424,6 +432,11 @@ public static class PoolManager return pair; } + /// + /// Creates a map, a grid, and a tile, and gives back references to them. + /// + /// A pairTracker + /// A TestMapData public static async Task CreateTestMap(PairTracker pairTracker) { var server = pairTracker.Pair.Server; @@ -451,6 +464,11 @@ public static class PoolManager return mapData; } + /// + /// Runs a server/client pair in sync + /// + /// A server/client pair + /// How many ticks to run them for public static async Task RunTicksSync(Pair pair, int ticks) { for (var i = 0; i < ticks; i++) @@ -460,13 +478,11 @@ public static class PoolManager } } - public static async Task WaitUntil(RobustIntegrationTest.IntegrationInstance instance, Func func, - int maxTicks = 600, - int tickStep = 1) - { - await WaitUntil(instance, async () => await Task.FromResult(func()), maxTicks, tickStep); - } - + /// + /// Runs the server/client in sync, but also ensures they are both idle each tick. + /// + /// The server/client pair + /// How many ticks to run public static async Task ReallyBeIdle(Pair pair, int runTicks = 25) { for (int i = 0; i < runTicks; i++) @@ -481,6 +497,27 @@ public static class PoolManager } } + /// + /// Runs a server, or a client until a condition is true + /// + /// The server or client + /// The condition to check + /// How many ticks to try before giving up + /// How many ticks to wait between checks + public static async Task WaitUntil(RobustIntegrationTest.IntegrationInstance instance, Func func, + int maxTicks = 600, + int tickStep = 1) + { + await WaitUntil(instance, async () => await Task.FromResult(func()), maxTicks, tickStep); + } + + /// + /// Runs a server, or a client until a condition is true + /// + /// The server or client + /// The async condition to check + /// How many ticks to try before giving up + /// How many ticks to wait between checks public static async Task WaitUntil(RobustIntegrationTest.IntegrationInstance instance, Func> func, int maxTicks = 600, int tickStep = 1) @@ -515,78 +552,96 @@ public static class PoolManager } } +/// +/// Settings for the pooled server, and client pair. +/// Some options are for changing the pair, and others are +/// so the pool can properly clean up what you borrowed. +/// public sealed class PoolSettings { - // Todo: We can make more of these pool-able, if we need enough of them for it to matter + // TODO: We can make more of these pool-able, if we need enough of them for it to matter + + /// + /// If the returned pair must not be reused + /// public bool MustNotBeReused => Destructive || NoLoadContent || DisableInterpolate || DummyTicker; + + /// + /// If the given pair must be brand new + /// public bool MustBeNew => Fresh || NoLoadContent || DisableInterpolate || DummyTicker; - public bool NotConnected => NoClient || NoServer || Disconnected; /// - /// We are going to ruin this pair + /// If the given pair must not be connected + /// + public bool NotConnected => NoClient || NoServer || Disconnected; + + /// + /// Set to true if the test will ruin the server/client pair. /// public bool Destructive { get; init; } /// - /// We need a brand new pair + /// Set to true if the given server/client pair should be created fresh. /// public bool Fresh { get; init; } /// - /// We need a pair that uses a dummy ticker + /// Set to true if the given server should be using a dummy ticker. /// public bool DummyTicker { get; init; } /// - /// We need the client, and server to be disconnected + /// Set to true if the given server/client pair should be disconnected from each other. /// public bool Disconnected { get; init; } /// - /// We need the server to be in the lobby + /// Set to true if the given server/client pair should be in the lobby. /// public bool InLobby { get; init; } /// - /// We don't want content loaded + /// Set this to true to skip loading the content files. + /// Note: This setting won't work with a client. /// public bool NoLoadContent { get; init; } /// - /// We want to add some prototypes + /// Set this to raw yaml text to load prototypes onto the given server/client pair. /// public string ExtraPrototypes { get; init; } /// - /// Disables NetInterp + /// Set this to true to disable the NetInterp CVar on the given server/client pair /// public bool DisableInterpolate { get; init; } /// - /// Tells the pool it has to clean up before the server/client can be used. + /// Set this to true to always clean up the server/client pair before giving it to another borrower /// public bool Dirty { get; init; } /// - /// Sets the map Cvar, and loads the map + /// Set this to the path of a map to have the given server/client pair load the map. /// public string Map { get; init; } // TODO for map painter /// - /// The test won't use the client (so we can skip cleaning it) + /// Set to true if the test won't use the client (so we can skip cleaning it up) /// public bool NoClient { get; init; } /// - /// The test won't use the client (so we can skip cleaning it) + /// Set to true if the test won't use the server (so we can skip cleaning it up) /// public bool NoServer { get; init; } /// - /// Guess if skipping recycling is ok + /// Tries to guess if we can skip recycling the server/client pair. /// /// The next set of settings the old pair will be set to - /// + /// If we can skip cleaning it up public bool CanFastRecycle(PoolSettings nextSettings) { if (Dirty) return false; @@ -603,6 +658,9 @@ public sealed class PoolSettings } } +/// +/// Holds a reference to things commonly needed when testing on a map +/// public sealed class TestMapData { public MapId MapId { get; set; } @@ -612,6 +670,9 @@ public sealed class TestMapData public TileRef Tile { get; set; } } +/// +/// A server/client pair +/// public sealed class Pair { public int PairId { get; init; } @@ -621,11 +682,14 @@ public sealed class Pair public RobustIntegrationTest.ClientIntegrationInstance Client { get; init; } } +/// +/// Used by the pool to keep track of a borrowed server/client pair. +/// public sealed class PairTracker : IAsyncDisposable { private int _disposed; - public async Task OnDirtyDispose() + private async Task OnDirtyDispose() { var usageTime = UsageWatch.Elapsed; await TestContext.Out.WriteLineAsync($"Dirty: Test returned in {usageTime.TotalMilliseconds} ms"); @@ -637,7 +701,7 @@ public sealed class PairTracker : IAsyncDisposable await TestContext.Out.WriteLineAsync($"Dirty: Disposed in {disposeTime.TotalMilliseconds} ms"); } - public async Task OnCleanDispose() + private async Task OnCleanDispose() { var usageTime = UsageWatch.Elapsed; await TestContext.Out.WriteLineAsync($"Clean: Test returned in {usageTime.TotalMilliseconds} ms");