Remove PoolSettings.ExtraPrototypes option (#18678)
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Content.Client.IoC;
|
||||
@@ -27,6 +29,7 @@ using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Robust.UnitTesting;
|
||||
|
||||
[assembly: LevelOfParallelism(3)]
|
||||
@@ -36,7 +39,7 @@ namespace Content.IntegrationTests;
|
||||
/// <summary>
|
||||
/// Making clients, and servers is slow, this manages a pool of them so tests can reuse them.
|
||||
/// </summary>
|
||||
public static class PoolManager
|
||||
public static partial class PoolManager
|
||||
{
|
||||
public const string TestMap = "Empty";
|
||||
|
||||
@@ -62,23 +65,12 @@ public static class PoolManager
|
||||
|
||||
private static int _pairId;
|
||||
private static readonly object PairLock = new();
|
||||
private static bool _initialized;
|
||||
|
||||
// Pair, IsBorrowed
|
||||
private static readonly Dictionary<Pair, bool> Pairs = new();
|
||||
private static bool _dead;
|
||||
private static Exception _poolFailureReason;
|
||||
|
||||
private static async Task ConfigurePrototypes(RobustIntegrationTest.IntegrationInstance instance,
|
||||
PoolSettings settings)
|
||||
{
|
||||
await instance.WaitPost(() =>
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
var changes = new Dictionary<Type, HashSet<string>>();
|
||||
prototypeManager.LoadString(settings.ExtraPrototypes.Trim(), true, changes);
|
||||
prototypeManager.ReloadPrototypes(changes);
|
||||
});
|
||||
}
|
||||
private static Exception? _poolFailureReason;
|
||||
|
||||
private static async Task<(RobustIntegrationTest.ServerIntegrationInstance, PoolTestLogHandler)> GenerateServer(
|
||||
PoolSettings poolSettings,
|
||||
@@ -86,7 +78,6 @@ public static class PoolManager
|
||||
{
|
||||
var options = new RobustIntegrationTest.ServerIntegrationOptions
|
||||
{
|
||||
ExtraPrototypes = poolSettings.ExtraPrototypes,
|
||||
ContentStart = true,
|
||||
Options = new ServerOptions()
|
||||
{
|
||||
@@ -144,6 +135,8 @@ public static class PoolManager
|
||||
{
|
||||
pair.Kill();
|
||||
}
|
||||
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
public static string DeathReport()
|
||||
@@ -174,7 +167,6 @@ public static class PoolManager
|
||||
{
|
||||
FailureLogLevel = LogLevel.Warning,
|
||||
ContentStart = true,
|
||||
ExtraPrototypes = poolSettings.ExtraPrototypes,
|
||||
ContentAssemblies = new[]
|
||||
{
|
||||
typeof(Shared.Entry.EntryPoint).Assembly,
|
||||
@@ -257,7 +249,7 @@ public static class PoolManager
|
||||
/// </summary>
|
||||
/// <param name="poolSettings">See <see cref="PoolSettings"/></param>
|
||||
/// <returns></returns>
|
||||
public static async Task<PairTracker> GetServerClient(PoolSettings poolSettings = null)
|
||||
public static async Task<PairTracker> GetServerClient(PoolSettings? poolSettings = null)
|
||||
{
|
||||
return await GetServerClientPair(poolSettings ?? new PoolSettings());
|
||||
}
|
||||
@@ -269,6 +261,9 @@ public static class PoolManager
|
||||
|
||||
private static async Task<PairTracker> GetServerClientPair(PoolSettings poolSettings)
|
||||
{
|
||||
if (!_initialized)
|
||||
throw new InvalidOperationException($"Pool manager has not been initialized");
|
||||
|
||||
// Trust issues with the AsyncLocal that backs this.
|
||||
var testContext = TestContext.CurrentContext;
|
||||
var testOut = TestContext.Out;
|
||||
@@ -277,7 +272,7 @@ public static class PoolManager
|
||||
var currentTestName = poolSettings.TestName ?? GetDefaultTestName(testContext);
|
||||
var poolRetrieveTimeWatch = new Stopwatch();
|
||||
await testOut.WriteLineAsync($"{nameof(GetServerClientPair)}: Called by test {currentTestName}");
|
||||
Pair pair = null;
|
||||
Pair? pair = null;
|
||||
try
|
||||
{
|
||||
poolRetrieveTimeWatch.Start();
|
||||
@@ -386,11 +381,11 @@ public static class PoolManager
|
||||
Assert.That(status, Is.EqualTo(expected));
|
||||
}
|
||||
|
||||
private static Pair GrabOptimalPair(PoolSettings poolSettings)
|
||||
private static Pair? GrabOptimalPair(PoolSettings poolSettings)
|
||||
{
|
||||
lock (PairLock)
|
||||
{
|
||||
Pair fallback = null;
|
||||
Pair? fallback = null;
|
||||
foreach (var pair in Pairs.Keys)
|
||||
{
|
||||
if (Pairs[pair])
|
||||
@@ -457,7 +452,7 @@ public static class PoolManager
|
||||
cNetMgr.ClientConnect(null!, 0, null!);
|
||||
});
|
||||
}
|
||||
await ReallyBeIdle(pair, 11);
|
||||
await ReallyBeIdle(pair, 5);
|
||||
|
||||
await testOut.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Disconnecting client, and restarting server");
|
||||
|
||||
@@ -466,43 +461,7 @@ public static class PoolManager
|
||||
cNetMgr.ClientDisconnect("Test pooling cleanup disconnect");
|
||||
});
|
||||
|
||||
await ReallyBeIdle(pair, 10);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(pair.Settings.ExtraPrototypes))
|
||||
{
|
||||
await testOut.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Removing prototypes");
|
||||
if (!pair.Settings.NoServer)
|
||||
{
|
||||
var serverProtoManager = pair.Server.ResolveDependency<IPrototypeManager>();
|
||||
await pair.Server.WaitPost(() =>
|
||||
{
|
||||
serverProtoManager.RemoveString(pair.Settings.ExtraPrototypes.Trim());
|
||||
});
|
||||
}
|
||||
if (!pair.Settings.NoClient)
|
||||
{
|
||||
var clientProtoManager = pair.Client.ResolveDependency<IPrototypeManager>();
|
||||
await pair.Client.WaitPost(() =>
|
||||
{
|
||||
clientProtoManager.RemoveString(pair.Settings.ExtraPrototypes.Trim());
|
||||
});
|
||||
}
|
||||
|
||||
await ReallyBeIdle(pair, 1);
|
||||
}
|
||||
|
||||
if (poolSettings.ExtraPrototypes != null)
|
||||
{
|
||||
await testOut.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Adding prototypes");
|
||||
if (!poolSettings.NoServer)
|
||||
{
|
||||
await ConfigurePrototypes(pair.Server, poolSettings);
|
||||
}
|
||||
if (!poolSettings.NoClient)
|
||||
{
|
||||
await ConfigurePrototypes(pair.Client, poolSettings);
|
||||
}
|
||||
}
|
||||
await ReallyBeIdle(pair, 5);
|
||||
|
||||
configManager.SetCVar(CCVars.GameMap, poolSettings.Map);
|
||||
await testOut.WriteLineAsync($"Recycling: {methodWatch.Elapsed.TotalMilliseconds} ms: Restarting server again");
|
||||
@@ -548,6 +507,7 @@ we are just going to end this here to save a lot of time. This is the exception
|
||||
Assert.Fail("The pool was shut down");
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<Pair> CreateServerClientPair(PoolSettings poolSettings, TextWriter testOut)
|
||||
{
|
||||
Pair pair;
|
||||
@@ -563,6 +523,9 @@ we are just going to end this here to save a lot of time. This is the exception
|
||||
ClientLogHandler = clientLog,
|
||||
PairId = Interlocked.Increment(ref _pairId)
|
||||
};
|
||||
|
||||
if (!poolSettings.NoLoadTestPrototypes)
|
||||
await pair.LoadPrototypes(_testPrototypes!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -757,6 +720,19 @@ we are just going to end this here to save a lot of time. This is the exception
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the pool manager.
|
||||
/// </summary>
|
||||
/// <param name="assembly">Assembly to search for to discover extra test prototypes.</param>
|
||||
public static void Startup(Assembly? assembly)
|
||||
{
|
||||
if (_initialized)
|
||||
throw new InvalidOperationException("Already initialized");
|
||||
|
||||
_initialized = true;
|
||||
DiscoverTestPrototypes(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -766,17 +742,15 @@ we are just going to end this here to save a lot of time. This is the exception
|
||||
/// </summary>
|
||||
public sealed class PoolSettings
|
||||
{
|
||||
// TODO: We can make more of these pool-able, if we need enough of them for it to matter
|
||||
|
||||
/// <summary>
|
||||
/// If the returned pair must not be reused
|
||||
/// </summary>
|
||||
public bool MustNotBeReused => Destructive || NoLoadContent || NoToolsExtraPrototypes;
|
||||
public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes;
|
||||
|
||||
/// <summary>
|
||||
/// If the given pair must be brand new
|
||||
/// </summary>
|
||||
public bool MustBeNew => Fresh || NoLoadContent || NoToolsExtraPrototypes;
|
||||
public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes;
|
||||
|
||||
/// <summary>
|
||||
/// If the given pair must not be connected
|
||||
@@ -816,9 +790,11 @@ public sealed class PoolSettings
|
||||
public bool NoLoadContent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this to raw yaml text to load prototypes onto the given server/client pair.
|
||||
/// This will return a server-client pair that has not loaded test prototypes.
|
||||
/// Try avoiding this whenever possible, as this will always create & destroy a new pair.
|
||||
/// Use <see cref="Pair.IsTestPrototype(EntityPrototype)"/> if you need to exclude test prototypees.
|
||||
/// </summary>
|
||||
public string ExtraPrototypes { get; init; }
|
||||
public bool NoLoadTestPrototypes { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Set this to true to disable the NetInterp CVar on the given server/client pair
|
||||
@@ -848,7 +824,7 @@ public sealed class PoolSettings
|
||||
/// <summary>
|
||||
/// Overrides the test name detection, and uses this in the test history instead
|
||||
/// </summary>
|
||||
public string TestName { get; set; }
|
||||
public string? TestName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tries to guess if we can skip recycling the server/client pair.
|
||||
@@ -870,19 +846,8 @@ public sealed class PoolSettings
|
||||
return NotConnected == nextSettings.NotConnected
|
||||
&& DummyTicker == nextSettings.DummyTicker
|
||||
&& Map == nextSettings.Map
|
||||
&& InLobby == nextSettings.InLobby
|
||||
&& ExtraPrototypes == nextSettings.ExtraPrototypes;
|
||||
&& InLobby == nextSettings.InLobby;
|
||||
}
|
||||
|
||||
// Prototype hot reload is not available outside TOOLS builds,
|
||||
// so we can't pool test instances that use ExtraPrototypes without TOOLS.
|
||||
#if TOOLS
|
||||
#pragma warning disable CA1822 // Can't be marked as static b/c the other branch exists but Omnisharp can't see both.
|
||||
private bool NoToolsExtraPrototypes => false;
|
||||
#pragma warning restore CA1822
|
||||
#else
|
||||
private bool NoToolsExtraPrototypes => !string.IsNullOrEmpty(ExtraPrototypes);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -893,7 +858,7 @@ public sealed class TestMapData
|
||||
public EntityUid MapUid { get; set; }
|
||||
public EntityUid GridUid { get; set; }
|
||||
public MapId MapId { get; set; }
|
||||
public MapGridComponent MapGrid { get; set; }
|
||||
public MapGridComponent MapGrid { get; set; } = default!;
|
||||
public EntityCoordinates GridCoords { get; set; }
|
||||
public MapCoordinates MapCoords { get; set; }
|
||||
public TileRef Tile { get; set; }
|
||||
@@ -907,12 +872,15 @@ public sealed class Pair
|
||||
public bool Dead { get; private set; }
|
||||
public int PairId { get; init; }
|
||||
public List<string> TestHistory { get; set; } = new();
|
||||
public PoolSettings Settings { get; set; }
|
||||
public RobustIntegrationTest.ServerIntegrationInstance Server { get; init; }
|
||||
public RobustIntegrationTest.ClientIntegrationInstance Client { get; init; }
|
||||
public PoolSettings Settings { get; set; } = default!;
|
||||
public RobustIntegrationTest.ServerIntegrationInstance Server { get; init; } = default!;
|
||||
public RobustIntegrationTest.ClientIntegrationInstance Client { get; init; } = default!;
|
||||
|
||||
public PoolTestLogHandler ServerLogHandler { get; init; }
|
||||
public PoolTestLogHandler ClientLogHandler { get; init; }
|
||||
public PoolTestLogHandler ServerLogHandler { get; init; } = default!;
|
||||
public PoolTestLogHandler ClientLogHandler { get; init; } = default!;
|
||||
|
||||
private Dictionary<Type, HashSet<string>> _loadedPrototypes = new();
|
||||
private HashSet<string> _loadedEntityPrototypes = new();
|
||||
|
||||
public void Kill()
|
||||
{
|
||||
@@ -932,6 +900,57 @@ public sealed class Pair
|
||||
ServerLogHandler.ActivateContext(testOut);
|
||||
ClientLogHandler.ActivateContext(testOut);
|
||||
}
|
||||
|
||||
public async Task LoadPrototypes(List<string> prototypes)
|
||||
{
|
||||
await LoadPrototypes(Server, prototypes);
|
||||
await LoadPrototypes(Client, prototypes);
|
||||
}
|
||||
|
||||
private async Task LoadPrototypes(RobustIntegrationTest.IntegrationInstance instance, List<string> prototypes)
|
||||
{
|
||||
var changed = new Dictionary<Type, HashSet<string>>();
|
||||
var protoMan = instance.ResolveDependency<IPrototypeManager>();
|
||||
foreach (var file in prototypes)
|
||||
{
|
||||
protoMan.LoadString(file, changed: changed);
|
||||
}
|
||||
|
||||
await instance.WaitPost(() => protoMan.ReloadPrototypes(changed));
|
||||
|
||||
foreach (var (kind, ids) in changed)
|
||||
{
|
||||
_loadedPrototypes.GetOrNew(kind).UnionWith(ids);
|
||||
}
|
||||
|
||||
if (_loadedPrototypes.TryGetValue(typeof(EntityPrototype), out var entIds))
|
||||
_loadedEntityPrototypes.UnionWith(entIds);
|
||||
}
|
||||
|
||||
public bool IsTestPrototype(EntityPrototype proto)
|
||||
{
|
||||
return _loadedEntityPrototypes.Contains(proto.ID);
|
||||
}
|
||||
|
||||
public bool IsTestEntityPrototype(string id)
|
||||
{
|
||||
return _loadedEntityPrototypes.Contains(id);
|
||||
}
|
||||
|
||||
public bool IsTestPrototype<TPrototype>(string id) where TPrototype : IPrototype
|
||||
{
|
||||
return IsTestPrototype(typeof(TPrototype), id);
|
||||
}
|
||||
|
||||
public bool IsTestPrototype<TPrototype>(TPrototype proto) where TPrototype : IPrototype
|
||||
{
|
||||
return IsTestPrototype(typeof(TPrototype), proto.ID);
|
||||
}
|
||||
|
||||
public bool IsTestPrototype(Type kind, string id)
|
||||
{
|
||||
return _loadedPrototypes.TryGetValue(kind, out var ids) && ids.Contains(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -941,8 +960,8 @@ public sealed class PairTracker : IAsyncDisposable
|
||||
{
|
||||
private readonly TextWriter _testOut;
|
||||
private int _disposed;
|
||||
public Stopwatch UsageWatch { get; set; }
|
||||
public Pair Pair { get; init; }
|
||||
public Stopwatch UsageWatch { get; set; } = default!;
|
||||
public Pair Pair { get; init; } = default!;
|
||||
|
||||
public PairTracker(TextWriter testOut)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user