Add random seed options to tests (#30735)
* Add random seed options to tests * Ensure profile randomization
This commit is contained in:
@@ -9,6 +9,7 @@ using Robust.Shared.GameObjects;
|
|||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
using Robust.UnitTesting;
|
using Robust.UnitTesting;
|
||||||
|
|
||||||
@@ -28,6 +29,12 @@ public sealed partial class TestPair
|
|||||||
public TestMapData? TestMap;
|
public TestMapData? TestMap;
|
||||||
private List<NetUserId> _modifiedProfiles = new();
|
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.ServerIntegrationInstance Server { get; private set; } = default!;
|
||||||
public RobustIntegrationTest.ClientIntegrationInstance Client { 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());
|
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
|
||||||
Client.SetConnectTarget(Server);
|
// that uses a fixed seed, it would effectively prevent it from beingrandomized.
|
||||||
await Client.WaitIdleAsync();
|
|
||||||
var netMgr = Client.ResolveDependency<IClientNetManager>();
|
|
||||||
|
|
||||||
await Client.WaitPost(() =>
|
Client.SetConnectTarget(Server);
|
||||||
{
|
await Client.WaitIdleAsync();
|
||||||
if (!netMgr.IsConnected)
|
var netMgr = Client.ResolveDependency<IClientNetManager>();
|
||||||
{
|
await Client.WaitPost(() => netMgr.ClientConnect(null!, 0, null!));
|
||||||
netMgr.ClientConnect(null!, 0, null!);
|
await ReallyBeIdle(10);
|
||||||
}
|
await Client.WaitRunTicks(1);
|
||||||
});
|
|
||||||
|
if (!settings.ShouldBeConnected)
|
||||||
|
{
|
||||||
|
await Client.WaitPost(() => netMgr.ClientDisconnect("Initial disconnect"));
|
||||||
await ReallyBeIdle(10);
|
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()
|
public void Kill()
|
||||||
@@ -129,4 +141,33 @@ public sealed partial class TestPair
|
|||||||
CleanDisposed = 2,
|
CleanDisposed = 2,
|
||||||
Dead = 3,
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ public static partial class PoolManager
|
|||||||
}
|
}
|
||||||
finally
|
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");
|
await testOut.WriteLineAsync($"{nameof(GetServerClientPair)}: Pair {pair.Id} Test History Start");
|
||||||
for (var i = 0; i < pair.TestHistory.Count; i++)
|
for (var i = 0; i < pair.TestHistory.Count; i++)
|
||||||
@@ -268,12 +268,14 @@ public static partial class PoolManager
|
|||||||
var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed;
|
var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed;
|
||||||
await testOut.WriteLineAsync(
|
await testOut.WriteLineAsync(
|
||||||
$"{nameof(GetServerClientPair)}: Retrieving pair {pair.Id} from pool took {poolRetrieveTime.TotalMilliseconds} ms");
|
$"{nameof(GetServerClientPair)}: Retrieving pair {pair.Id} from pool took {poolRetrieveTime.TotalMilliseconds} ms");
|
||||||
await testOut.WriteLineAsync(
|
|
||||||
$"{nameof(GetServerClientPair)}: Returning pair {pair.Id}");
|
|
||||||
|
|
||||||
pair.ClearModifiedCvars();
|
pair.ClearModifiedCvars();
|
||||||
pair.Settings = poolSettings;
|
pair.Settings = poolSettings;
|
||||||
pair.TestHistory.Add(currentTestName);
|
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();
|
pair.Watch.Restart();
|
||||||
return pair;
|
return pair;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
|
||||||
namespace Content.IntegrationTests;
|
namespace Content.IntegrationTests;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -9,16 +11,6 @@ namespace Content.IntegrationTests;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class PoolSettings
|
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>
|
/// <summary>
|
||||||
/// Set to true if the test will ruin the server/client pair.
|
/// Set to true if the test will ruin the server/client pair.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -34,8 +26,6 @@ public sealed class PoolSettings
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool DummyTicker { get; init; } = true;
|
public bool DummyTicker { get; init; } = true;
|
||||||
|
|
||||||
public bool UseDummyTicker => !InLobby && DummyTicker;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, this enables the creation of admin logs during the test.
|
/// If true, this enables the creation of admin logs during the test.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -48,8 +38,6 @@ public sealed class PoolSettings
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Connected { get; init; }
|
public bool Connected { get; init; }
|
||||||
|
|
||||||
public bool ShouldBeConnected => InLobby || Connected;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set to true if the given server/client pair should be in the lobby.
|
/// 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.
|
/// 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>
|
/// </summary>
|
||||||
public string? TestName { get; set; }
|
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>
|
/// <summary>
|
||||||
/// Tries to guess if we can skip recycling the server/client pair.
|
/// Tries to guess if we can skip recycling the server/client pair.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -114,4 +130,4 @@ public sealed class PoolSettings
|
|||||||
&& Map == nextSettings.Map
|
&& Map == nextSettings.Map
|
||||||
&& InLobby == nextSettings.InLobby;
|
&& InLobby == nextSettings.InLobby;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user