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");