diff --git a/Content.IntegrationTests/ContentIntegrationTest.cs b/Content.IntegrationTests/ContentIntegrationTest.cs index a5596482a9..2b50e5197f 100644 --- a/Content.IntegrationTests/ContentIntegrationTest.cs +++ b/Content.IntegrationTests/ContentIntegrationTest.cs @@ -1,10 +1,11 @@ +using System; +using System.Threading.Tasks; using Content.Client; using Content.Client.Interfaces.Parallax; using Content.Server; -using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Robust.Shared.ContentPack; -using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.UnitTesting; using EntryPoint = Content.Client.EntryPoint; @@ -13,25 +14,33 @@ namespace Content.IntegrationTests { public abstract class ContentIntegrationTest : RobustIntegrationTest { - protected override ClientIntegrationInstance StartClient(ClientIntegrationOptions options = null) + protected sealed override ClientIntegrationInstance StartClient(ClientIntegrationOptions options = null) { options ??= new ClientIntegrationOptions(); + // ReSharper disable once RedundantNameQualifier options.ClientContentAssembly = typeof(EntryPoint).Assembly; options.SharedContentAssembly = typeof(Shared.EntryPoint).Assembly; options.BeforeStart += () => { - // Connecting to Discord is a massive waste of time. - // Basically just makes the CI logs a mess. - IoCManager.Resolve().SetCVar("discord.enabled", false); IoCManager.Resolve().SetModuleBaseCallbacks(new ClientModuleTestingCallbacks { ClientBeforeIoC = () => { + if (options is ClientContentIntegrationOption contentOptions) + { + contentOptions.ContentBeforeIoC?.Invoke(); + } + IoCManager.Register(true); } }); }; + + // Connecting to Discord is a massive waste of time. + // Basically just makes the CI logs a mess. + options.CVarOverrides["discord.enabled"] = "true"; + return base.StartClient(options); } @@ -52,6 +61,11 @@ namespace Content.IntegrationTests { ServerBeforeIoC = () => { + if (options is ServerContentIntegrationOption contentOptions) + { + contentOptions.ContentBeforeIoC?.Invoke(); + } + IoCManager.Register(true); } }); @@ -59,5 +73,43 @@ namespace Content.IntegrationTests return StartServer(options); } + + protected async Task<(ClientIntegrationInstance client, ServerIntegrationInstance server)> StartConnectedServerClientPair(ClientIntegrationOptions clientOptions = null, ServerIntegrationOptions serverOptions = null) + { + var client = StartClient(clientOptions); + var server = StartServerDummyTicker(serverOptions); + + await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); + + client.SetConnectTarget(server); + + client.Post(() => IoCManager.Resolve().ClientConnect(null, 0, null)); + + await RunTicksSync(client, server, 10); + + return (client, server); + } + + /// + /// Runs ticks on both server and client while keeping their main loop in sync. + /// + protected static async Task RunTicksSync(ClientIntegrationInstance client, ServerIntegrationInstance server, int ticks) + { + for (var i = 0; i < ticks; i++) + { + await server.WaitRunTicks(1); + await client.WaitRunTicks(1); + } + } + + protected sealed class ClientContentIntegrationOption : ClientIntegrationOptions + { + public Action ContentBeforeIoC { get; set; } + } + + protected sealed class ServerContentIntegrationOption : ServerIntegrationOptions + { + public Action ContentBeforeIoC { get; set; } + } } }