]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add random seed options to tests (#30735)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Fri, 9 Aug 2024 05:25:43 +0000 (17:25 +1200)
committerGitHub <noreply@github.com>
Fri, 9 Aug 2024 05:25:43 +0000 (15:25 +1000)
* Add random seed options to tests

* Ensure profile randomization

Content.IntegrationTests/Pair/TestPair.cs
Content.IntegrationTests/PoolManager.cs
Content.IntegrationTests/PoolSettings.cs

index 0b681dcde10d477af8070007a5493f64daa99f6c..43b188fd32768372b00e8dfb75dfb556fe8fc385 100644 (file)
@@ -9,6 +9,7 @@ using Robust.Shared.GameObjects;
 using Robust.Shared.IoC;
 using Robust.Shared.Network;
 using Robust.Shared.Player;
+using Robust.Shared.Random;
 using Robust.Shared.Timing;
 using Robust.UnitTesting;
 
@@ -28,6 +29,12 @@ public sealed partial class TestPair
     public TestMapData? TestMap;
     private List<NetUserId> _modifiedProfiles = new();
 
+    private int _nextServerSeed;
+    private int _nextClientSeed;
+
+    public int ServerSeed;
+    public int ClientSeed;
+
     public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!;
     public RobustIntegrationTest.ClientIntegrationInstance Client { get;  private set; } = default!;
 
@@ -74,22 +81,27 @@ public sealed partial class TestPair
             await Server.WaitPost(() => gameTicker.RestartRound());
         }
 
-        if (settings.ShouldBeConnected)
+        // Always initially connect clients to generate an initial random set of preferences/profiles.
+        // This is to try and prevent issues where if the first test that connects the client is consistently some test
+        // that uses a fixed seed, it would effectively prevent it from beingrandomized.
+
+        Client.SetConnectTarget(Server);
+        await Client.WaitIdleAsync();
+        var netMgr = Client.ResolveDependency<IClientNetManager>();
+        await Client.WaitPost(() => netMgr.ClientConnect(null!, 0, null!));
+        await ReallyBeIdle(10);
+        await Client.WaitRunTicks(1);
+
+        if (!settings.ShouldBeConnected)
         {
-            Client.SetConnectTarget(Server);
-            await Client.WaitIdleAsync();
-            var netMgr = Client.ResolveDependency<IClientNetManager>();
-
-            await Client.WaitPost(() =>
-            {
-                if (!netMgr.IsConnected)
-                {
-                    netMgr.ClientConnect(null!, 0, null!);
-                }
-            });
+            await Client.WaitPost(() => netMgr.ClientDisconnect("Initial disconnect"));
             await ReallyBeIdle(10);
-            await Client.WaitRunTicks(1);
         }
+
+        var cRand = Client.ResolveDependency<IRobustRandom>();
+        var sRand = Server.ResolveDependency<IRobustRandom>();
+        _nextClientSeed = cRand.Next();
+        _nextServerSeed = sRand.Next();
     }
 
     public void Kill()
@@ -129,4 +141,33 @@ public sealed partial class TestPair
         CleanDisposed = 2,
         Dead = 3,
     }
+
+    public void SetupSeed()
+    {
+        var sRand = Server.ResolveDependency<IRobustRandom>();
+        if (Settings.ServerSeed is { } severSeed)
+        {
+            ServerSeed = severSeed;
+            sRand.SetSeed(ServerSeed);
+        }
+        else
+        {
+            ServerSeed = _nextServerSeed;
+            sRand.SetSeed(ServerSeed);
+            _nextServerSeed = sRand.Next();
+        }
+
+        var cRand = Client.ResolveDependency<IRobustRandom>();
+        if (Settings.ClientSeed is { } clientSeed)
+        {
+            ClientSeed = clientSeed;
+            cRand.SetSeed(ClientSeed);
+        }
+        else
+        {
+            ClientSeed = _nextClientSeed;
+            cRand.SetSeed(ClientSeed);
+            _nextClientSeed = cRand.Next();
+        }
+    }
 }
index 21c93ea8aeb5359991065aaf39f4aa6f64de0a33..34ac4060ddc88699dfb73a623404859d1aaa23ee 100644 (file)
@@ -252,7 +252,7 @@ public static partial class PoolManager
         }
         finally
         {
-            if (pair != null && pair.TestHistory.Count > 1)
+            if (pair != null && pair.TestHistory.Count > 0)
             {
                 await testOut.WriteLineAsync($"{nameof(GetServerClientPair)}: Pair {pair.Id} Test History Start");
                 for (var i = 0; i < pair.TestHistory.Count; i++)
@@ -268,12 +268,14 @@ public static partial class PoolManager
         var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed;
         await testOut.WriteLineAsync(
             $"{nameof(GetServerClientPair)}: Retrieving pair {pair.Id} from pool took {poolRetrieveTime.TotalMilliseconds} ms");
-        await testOut.WriteLineAsync(
-            $"{nameof(GetServerClientPair)}: Returning pair {pair.Id}");
 
         pair.ClearModifiedCvars();
         pair.Settings = poolSettings;
         pair.TestHistory.Add(currentTestName);
+        pair.SetupSeed();
+        await testOut.WriteLineAsync(
+            $"{nameof(GetServerClientPair)}: Returning pair {pair.Id} with client/server seeds: {pair.ClientSeed}/{pair.ServerSeed}");
+
         pair.Watch.Restart();
         return pair;
     }
index a78173808f85c69a8c558e2ce3f9305f34a03305..9da514e66b89b6e66a93e9949a9a38fa5103ec2f 100644 (file)
@@ -1,5 +1,7 @@
 #nullable enable
 
+using Robust.Shared.Random;
+
 namespace Content.IntegrationTests;
 
 /// <summary>
@@ -9,16 +11,6 @@ namespace Content.IntegrationTests;
 /// </summary>
 public sealed class PoolSettings
 {
-    /// <summary>
-    /// If the returned pair must not be reused
-    /// </summary>
-    public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes;
-
-    /// <summary>
-    /// If the given pair must be brand new
-    /// </summary>
-    public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes;
-
     /// <summary>
     /// Set to true if the test will ruin the server/client pair.
     /// </summary>
@@ -34,8 +26,6 @@ public sealed class PoolSettings
     /// </summary>
     public bool DummyTicker { get; init; } = true;
 
-    public bool UseDummyTicker => !InLobby && DummyTicker;
-
     /// <summary>
     /// If true, this enables the creation of admin logs during the test.
     /// </summary>
@@ -48,8 +38,6 @@ public sealed class PoolSettings
     /// </summary>
     public bool Connected { get; init; }
 
-    public bool ShouldBeConnected => InLobby || Connected;
-
     /// <summary>
     /// Set to true if the given server/client pair should be in the lobby.
     /// If the pair is not in the lobby at the end of the test, this test must be marked as dirty.
@@ -92,6 +80,34 @@ public sealed class PoolSettings
     /// </summary>
     public string? TestName { get; set; }
 
+    /// <summary>
+    /// If set, this will be used to call <see cref="IRobustRandom.SetSeed"/>
+    /// </summary>
+    public int? ServerSeed { get; set; }
+
+    /// <summary>
+    /// If set, this will be used to call <see cref="IRobustRandom.SetSeed"/>
+    /// </summary>
+    public int? ClientSeed { get; set; }
+
+    #region Inferred Properties
+
+    /// <summary>
+    /// If the returned pair must not be reused
+    /// </summary>
+    public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes;
+
+    /// <summary>
+    /// If the given pair must be brand new
+    /// </summary>
+    public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes;
+
+    public bool UseDummyTicker => !InLobby && DummyTicker;
+
+    public bool ShouldBeConnected => InLobby || Connected;
+
+    #endregion
+
     /// <summary>
     /// Tries to guess if we can skip recycling the server/client pair.
     /// </summary>
@@ -114,4 +130,4 @@ public sealed class PoolSettings
                && Map == nextSettings.Map
                && InLobby == nextSettings.InLobby;
     }
-}
\ No newline at end of file
+}