mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-23 04:57:17 +01:00
Test oldest compatible BYOND version in Live test
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
|
||||
startup_complete = TRUE
|
||||
if(run_bridge_test)
|
||||
CheckBridgeLimits()
|
||||
CheckBridgeLimits(run_bridge_test)
|
||||
|
||||
/world/Topic(T, Addr, Master, Keys)
|
||||
if(findtext(T, "tgs_integration_test_tactics3") == 0)
|
||||
@@ -76,9 +76,9 @@ var/run_bridge_test
|
||||
var/tactics2 = data["tgs_integration_test_tactics2"]
|
||||
if(tactics2)
|
||||
if(startup_complete)
|
||||
CheckBridgeLimits()
|
||||
CheckBridgeLimits(tactics2)
|
||||
else
|
||||
run_bridge_test = TRUE
|
||||
run_bridge_test = tactics2
|
||||
return "ack2"
|
||||
|
||||
// Topic limit tests
|
||||
@@ -259,17 +259,17 @@ var/suppress_bridge_spam = FALSE
|
||||
var/payload = jointext(builder, "")
|
||||
return payload
|
||||
|
||||
/proc/CheckBridgeLimits()
|
||||
/proc/CheckBridgeLimits(id)
|
||||
set waitfor = FALSE
|
||||
CheckBridgeLimitsImpl()
|
||||
CheckBridgeLimitsImpl(id)
|
||||
|
||||
/proc/CheckBridgeLimitsImpl()
|
||||
/proc/CheckBridgeLimitsImpl(id)
|
||||
sleep(30)
|
||||
|
||||
// Evil custom bridge command hacking here
|
||||
var/datum/tgs_api/v5/api = TGS_READ_GLOBAL(tgs)
|
||||
var/old_ai = api.access_identifier
|
||||
api.access_identifier = "tgs_integration_test"
|
||||
api.access_identifier = id
|
||||
|
||||
lastTgsError = null
|
||||
|
||||
|
||||
@@ -41,7 +41,10 @@ namespace Tgstation.Server.Tests
|
||||
});
|
||||
var logger = loggerFactory.CreateLogger("CachingFileDownloader");
|
||||
|
||||
await InitializeByondVersion(logger, ByondTest.TestVersion, new PlatformIdentifier().IsWindows, cancellationToken);
|
||||
var cfd = new CachingFileDownloader(loggerFactory.CreateLogger<CachingFileDownloader>());
|
||||
var edgeVersion = await ByondTest.GetEdgeVersion(cfd, cancellationToken);
|
||||
|
||||
await InitializeByondVersion(logger, edgeVersion, new PlatformIdentifier().IsWindows, cancellationToken);
|
||||
|
||||
// predownload the target github release update asset
|
||||
var gitHubToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -23,13 +25,15 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
sealed class ByondTest : JobsRequiredTest
|
||||
{
|
||||
public static readonly Version TestVersion = new(515, 1605);
|
||||
|
||||
readonly IByondClient byondClient;
|
||||
readonly IFileDownloader fileDownloader;
|
||||
|
||||
readonly Api.Models.Instance metadata;
|
||||
|
||||
static Version edgeVersion;
|
||||
|
||||
Version testVersion;
|
||||
|
||||
public ByondTest(IByondClient byondClient, IJobsClient jobsClient, IFileDownloader fileDownloader, Api.Models.Instance metadata)
|
||||
: base(jobsClient)
|
||||
{
|
||||
@@ -44,8 +48,22 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
return RunContinued(firstInstall, cancellationToken);
|
||||
}
|
||||
|
||||
public static async Task<Version> GetEdgeVersion(IFileDownloader fileDownloader, CancellationToken cancellationToken)
|
||||
{
|
||||
if (edgeVersion != null)
|
||||
return edgeVersion;
|
||||
|
||||
await using var provider = fileDownloader.DownloadFile(new Uri("https://www.byond.com/download/version.txt"), null);
|
||||
var stream = await provider.GetResult(cancellationToken);
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, false, -1, true);
|
||||
var text = await reader.ReadToEndAsync();
|
||||
var splits = text.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries);
|
||||
return edgeVersion = Version.Parse(splits.Last());
|
||||
}
|
||||
|
||||
async Task RunPartOne(CancellationToken cancellationToken)
|
||||
{
|
||||
testVersion = await GetEdgeVersion(fileDownloader, cancellationToken);
|
||||
await TestNoVersion(cancellationToken);
|
||||
await TestInstallStable(cancellationToken);
|
||||
}
|
||||
@@ -62,7 +80,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
var deleteThisOneBecauseItWasntPartOfTheOriginalTest = await byondClient.DeleteVersion(new ByondVersionDeleteRequest
|
||||
{
|
||||
Version = new(TestVersion.Major, TestVersion.Minor, 2)
|
||||
Version = new(testVersion.Major, testVersion.Minor, 2)
|
||||
}, cancellationToken);
|
||||
await WaitForJob(deleteThisOneBecauseItWasntPartOfTheOriginalTest, 30, false, null, cancellationToken);
|
||||
|
||||
@@ -76,14 +94,14 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
var uninstallResponseTask = byondClient.DeleteVersion(
|
||||
new ByondVersionDeleteRequest
|
||||
{
|
||||
Version = TestVersion
|
||||
Version = testVersion
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
var badBecauseActiveResponseTask = ApiAssert.ThrowsException<ConflictException>(() => byondClient.DeleteVersion(
|
||||
new ByondVersionDeleteRequest
|
||||
{
|
||||
Version = new(TestVersion.Major, TestVersion.Minor, 1)
|
||||
Version = new(testVersion.Major, testVersion.Minor, 1)
|
||||
},
|
||||
cancellationToken), ErrorCode.ByondCannotDeleteActiveVersion);
|
||||
|
||||
@@ -98,13 +116,13 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await nonExistentUninstallResponseTask;
|
||||
|
||||
await uninstallTask;
|
||||
var byondDir = Path.Combine(metadata.Path, "Byond", TestVersion.ToString());
|
||||
var byondDir = Path.Combine(metadata.Path, "Byond", testVersion.ToString());
|
||||
Assert.IsFalse(Directory.Exists(byondDir));
|
||||
|
||||
var newVersions = await byondClient.InstalledVersions(null, cancellationToken);
|
||||
Assert.IsNotNull(newVersions);
|
||||
Assert.AreEqual(1, newVersions.Count);
|
||||
Assert.AreEqual(new Version(TestVersion.Major, TestVersion.Minor, 1), newVersions[0].Version);
|
||||
Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 1), newVersions[0].Version);
|
||||
}
|
||||
|
||||
async Task TestInstallFakeVersion(CancellationToken cancellationToken)
|
||||
@@ -122,7 +140,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
var newModel = new ByondVersionRequest
|
||||
{
|
||||
Version = TestVersion
|
||||
Version = testVersion
|
||||
};
|
||||
var test = await byondClient.SetActiveVersion(newModel, null, cancellationToken);
|
||||
Assert.IsNotNull(test.InstallJob);
|
||||
@@ -179,12 +197,12 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
using var windowsByondInstaller = byondInstaller as WindowsByondInstaller;
|
||||
|
||||
// get the bytes for stable
|
||||
using var stableBytesMs = await byondInstaller.DownloadVersion(TestVersion, cancellationToken);
|
||||
using var stableBytesMs = await byondInstaller.DownloadVersion(testVersion, cancellationToken);
|
||||
|
||||
var test = await byondClient.SetActiveVersion(
|
||||
new ByondVersionRequest
|
||||
{
|
||||
Version = TestVersion,
|
||||
Version = testVersion,
|
||||
UploadCustomZip = true
|
||||
},
|
||||
stableBytesMs,
|
||||
@@ -198,7 +216,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
var test2 = await byondClient.SetActiveVersion(
|
||||
new ByondVersionRequest
|
||||
{
|
||||
Version = TestVersion,
|
||||
Version = testVersion,
|
||||
UploadCustomZip = true
|
||||
},
|
||||
stableBytesMs,
|
||||
@@ -208,22 +226,22 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await WaitForJob(test2.InstallJob, 30, false, null, cancellationToken);
|
||||
|
||||
var newSettings = await byondClient.ActiveVersion(cancellationToken);
|
||||
Assert.AreEqual(new Version(TestVersion.Major, TestVersion.Minor, 2), newSettings.Version);
|
||||
Assert.AreEqual(new Version(testVersion.Major, testVersion.Minor, 2), newSettings.Version);
|
||||
|
||||
// test a few switches
|
||||
var installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest
|
||||
{
|
||||
Version = TestVersion
|
||||
Version = testVersion
|
||||
}, null, cancellationToken);
|
||||
Assert.IsNull(installResponse.InstallJob);
|
||||
await ApiAssert.ThrowsException<ApiConflictException>(() => byondClient.SetActiveVersion(new ByondVersionRequest
|
||||
{
|
||||
Version = new Version(TestVersion.Major, TestVersion.Minor, 3)
|
||||
Version = new Version(testVersion.Major, testVersion.Minor, 3)
|
||||
}, null, cancellationToken), ErrorCode.ByondNonExistentCustomVersion);
|
||||
|
||||
installResponse = await byondClient.SetActiveVersion(new ByondVersionRequest
|
||||
{
|
||||
Version = new Version(TestVersion.Major, TestVersion.Minor, 1)
|
||||
Version = new Version(testVersion.Major, testVersion.Minor, 1)
|
||||
}, null, cancellationToken);
|
||||
Assert.IsNull(installResponse.InstallJob);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await configurationClient.CreateDirectory(staticDir, cancellationToken);
|
||||
}
|
||||
|
||||
Task SetupDMApiTests(CancellationToken cancellationToken)
|
||||
public Task SetupDMApiTests(CancellationToken cancellationToken)
|
||||
{
|
||||
// just use an I/O manager here
|
||||
var ioManager = new DefaultIOManager();
|
||||
|
||||
@@ -20,15 +20,24 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
readonly IDreamDaemonClient dreamDaemonClient;
|
||||
readonly IInstanceClient instanceClient;
|
||||
|
||||
readonly ushort dmPort;
|
||||
readonly ushort ddPort;
|
||||
readonly bool lowPriorityDeployments;
|
||||
|
||||
Task vpTest;
|
||||
|
||||
public DeploymentTest(IInstanceClient instanceClient, IJobsClient jobsClient, bool lowPriorityDeployments) : base(jobsClient)
|
||||
public DeploymentTest(
|
||||
IInstanceClient instanceClient,
|
||||
IJobsClient jobsClient,
|
||||
ushort dmPort,
|
||||
ushort ddPort,
|
||||
bool lowPriorityDeployments) : base(jobsClient)
|
||||
{
|
||||
this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient));
|
||||
dreamMakerClient = instanceClient.DreamMaker;
|
||||
dreamDaemonClient = instanceClient.DreamDaemon;
|
||||
this.dmPort = dmPort;
|
||||
this.ddPort = ddPort;
|
||||
this.lowPriorityDeployments = lowPriorityDeployments;
|
||||
}
|
||||
|
||||
@@ -50,14 +59,9 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
async Task CheckDreamDaemonPriority(Task deploymentJobWaitTask, CancellationToken cancellationToken)
|
||||
{
|
||||
// this doesn't check dm's priority, but it really should
|
||||
|
||||
while (!deploymentJobWaitTask.IsCompleted)
|
||||
{
|
||||
var ddProcessName = new PlatformIdentifier().IsWindows && ByondTest.TestVersion >= new Version(515, 1598)
|
||||
? "dd"
|
||||
: "DreamDaemon";
|
||||
|
||||
var allProcesses = TestLiveServer.GetAllDDProcesses();
|
||||
var allProcesses = TestLiveServer.GetDDProcessesOnPort(dmPort);
|
||||
if (allProcesses.Count == 0)
|
||||
continue;
|
||||
|
||||
@@ -115,27 +119,27 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
var updatedDM = await dreamMakerClient.Update(new DreamMakerRequest
|
||||
{
|
||||
ProjectName = "tests/DMAPI/ApiFree/api_free",
|
||||
ApiValidationPort = TestLiveServer.DMPort
|
||||
ApiValidationPort = dmPort
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(TestLiveServer.DMPort, updatedDM.ApiValidationPort);
|
||||
Assert.AreEqual(dmPort, updatedDM.ApiValidationPort);
|
||||
Assert.AreEqual("tests/DMAPI/ApiFree/api_free", updatedDM.ProjectName);
|
||||
}
|
||||
else
|
||||
{
|
||||
var updatedDM = await dreamMakerClient.Update(new DreamMakerRequest
|
||||
{
|
||||
ApiValidationPort = TestLiveServer.DMPort
|
||||
ApiValidationPort = dmPort
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(TestLiveServer.DMPort, updatedDM.ApiValidationPort);
|
||||
Assert.AreEqual(dmPort, updatedDM.ApiValidationPort);
|
||||
}
|
||||
|
||||
var updatedDD = await dreamDaemonClient.Update(new DreamDaemonRequest
|
||||
{
|
||||
StartupTimeout = 15,
|
||||
Port = TestLiveServer.DDPort
|
||||
Port = ddPort
|
||||
}, cancellationToken);
|
||||
Assert.AreEqual(15U, updatedDD.StartupTimeout);
|
||||
Assert.AreEqual(TestLiveServer.DDPort, updatedDD.Port);
|
||||
Assert.AreEqual(ddPort, updatedDD.Port);
|
||||
|
||||
async Task<JobResponse> CompileAfterByondInstall()
|
||||
{
|
||||
@@ -152,11 +156,11 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await Task.WhenAll(
|
||||
ApiAssert.ThrowsException<ConflictException>(() => dreamDaemonClient.Update(new DreamDaemonRequest
|
||||
{
|
||||
Port = TestLiveServer.DMPort
|
||||
Port = dmPort,
|
||||
}, cancellationToken), ErrorCode.PortNotAvailable),
|
||||
ApiAssert.ThrowsException<ConflictException>(() => dreamMakerClient.Update(new DreamMakerRequest
|
||||
{
|
||||
ApiValidationPort = TestLiveServer.DDPort
|
||||
ApiValidationPort = ddPort
|
||||
}, cancellationToken), ErrorCode.PortNotAvailable),
|
||||
deploymentJobWaitTask);
|
||||
|
||||
|
||||
@@ -1,38 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Moq;
|
||||
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
using Tgstation.Server.Client;
|
||||
using Tgstation.Server.Client.Components;
|
||||
using Tgstation.Server.Host.Components;
|
||||
using Tgstation.Server.Host.Components.Byond;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.System;
|
||||
|
||||
namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
sealed class InstanceTest
|
||||
{
|
||||
readonly IInstanceClient instanceClient;
|
||||
readonly IInstanceManagerClient instanceManagerClient;
|
||||
readonly IFileDownloader fileDownloader;
|
||||
readonly InstanceManager instanceManager;
|
||||
readonly ushort serverPort;
|
||||
|
||||
public InstanceTest(IInstanceClient instanceClient, IInstanceManagerClient instanceManagerClient, IFileDownloader fileDownloader, InstanceManager instanceManager, ushort serverPort)
|
||||
public InstanceTest(IInstanceManagerClient instanceManagerClient, IFileDownloader fileDownloader, InstanceManager instanceManager, ushort serverPort)
|
||||
{
|
||||
this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient));
|
||||
this.instanceManagerClient = instanceManagerClient ?? throw new ArgumentNullException(nameof(instanceManagerClient));
|
||||
this.fileDownloader = fileDownloader ?? throw new ArgumentNullException(nameof(fileDownloader));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
this.serverPort = serverPort;
|
||||
}
|
||||
|
||||
public async Task RunTests(bool highPrioDD, bool lowPrioDeployment, CancellationToken cancellationToken)
|
||||
public async Task RunTests(
|
||||
IInstanceClient instanceClient,
|
||||
ushort dmPort,
|
||||
ushort ddPort,
|
||||
bool highPrioDD,
|
||||
bool lowPrioDeployment,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var byondTest = new ByondTest(instanceClient.Byond, instanceClient.Jobs, fileDownloader, instanceClient.Metadata);
|
||||
var chatTest = new ChatTest(instanceClient.ChatBots, instanceManagerClient, instanceClient.Jobs, instanceClient.Metadata);
|
||||
var configTest = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata);
|
||||
var repoTest = new RepositoryTest(instanceClient.Repository, instanceClient.Jobs);
|
||||
var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, lowPrioDeployment);
|
||||
var dmTest = new DeploymentTest(instanceClient, instanceClient.Jobs, dmPort, ddPort, lowPrioDeployment);
|
||||
|
||||
var byondTask = byondTest.Run(cancellationToken, out var firstInstall);
|
||||
var chatTask = chatTest.RunPreWatchdog(cancellationToken);
|
||||
@@ -48,7 +65,135 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await dmTask;
|
||||
await byondTask;
|
||||
|
||||
await new WatchdogTest(instanceClient, instanceManager, serverPort, highPrioDD).Run(cancellationToken);
|
||||
await new WatchdogTest(
|
||||
await ByondTest.GetEdgeVersion(fileDownloader, cancellationToken), instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken);
|
||||
}
|
||||
|
||||
public async Task RunCompatTests(
|
||||
IInstanceClient instanceClient,
|
||||
ushort dmPort,
|
||||
ushort ddPort,
|
||||
bool highPrioDD,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var compatVersion = new Version(510, 1346);
|
||||
const string Origin = "https://github.com/Cyberboss/common_core";
|
||||
var cloneRequest = instanceClient.Repository.Clone(new RepositoryCreateRequest
|
||||
{
|
||||
Origin = new Uri(Origin),
|
||||
}, cancellationToken);
|
||||
|
||||
|
||||
var dmUpdateRequest = instanceClient.DreamMaker.Update(new DreamMakerRequest
|
||||
{
|
||||
ApiValidationPort = dmPort,
|
||||
}, cancellationToken);
|
||||
|
||||
// need at least one chat bot to satisfy DMAPI test,
|
||||
// use discord as it allows multi-botting on on token unlike IRC
|
||||
var connectionString = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_TOKEN");
|
||||
if (String.IsNullOrWhiteSpace(connectionString))
|
||||
// needs to just be valid
|
||||
connectionString = new DiscordConnectionStringBuilder
|
||||
{
|
||||
BasedMeme = true,
|
||||
BotToken = "some_token",
|
||||
DeploymentBranding = true,
|
||||
DMOutputDisplay = DiscordDMOutputDisplayType.Always,
|
||||
}.ToString();
|
||||
else
|
||||
// standardize
|
||||
connectionString = new DiscordConnectionStringBuilder(connectionString).ToString();
|
||||
|
||||
var channelIdStr = Environment.GetEnvironmentVariable("TGS_TEST_DISCORD_CHANNEL");
|
||||
if (String.IsNullOrWhiteSpace(channelIdStr))
|
||||
channelIdStr = "487268744419344384";
|
||||
|
||||
var chatRequest = instanceClient.ChatBots.Create(new ChatBotCreateRequest
|
||||
{
|
||||
ChannelLimit = 10,
|
||||
Channels = new List<ChatChannel>
|
||||
{
|
||||
new ChatChannel
|
||||
{
|
||||
ChannelData = channelIdStr,
|
||||
Tag = "some_tag",
|
||||
IsAdminChannel = true,
|
||||
IsSystemChannel = true,
|
||||
IsUpdatesChannel = true,
|
||||
IsWatchdogChannel = true,
|
||||
},
|
||||
},
|
||||
ConnectionString = connectionString,
|
||||
Enabled = true,
|
||||
Name = "compat_test_bot",
|
||||
Provider = ChatProvider.Discord,
|
||||
ReconnectionInterval = 1,
|
||||
}, cancellationToken);
|
||||
|
||||
var jrt = new JobsRequiredTest(instanceClient.Jobs);
|
||||
|
||||
IByondInstaller byondInstaller = new PlatformIdentifier().IsWindows
|
||||
? new WindowsByondInstaller(
|
||||
Mock.Of<IProcessExecutor>(),
|
||||
Mock.Of<IIOManager>(),
|
||||
fileDownloader,
|
||||
Options.Create(new GeneralConfiguration()),
|
||||
Mock.Of<ILogger<WindowsByondInstaller>>())
|
||||
: new PosixByondInstaller(
|
||||
Mock.Of<IPostWriteHandler>(),
|
||||
Mock.Of<IIOManager>(),
|
||||
fileDownloader,
|
||||
Mock.Of<ILogger<PosixByondInstaller>>());
|
||||
|
||||
using var windowsByondInstaller = byondInstaller as WindowsByondInstaller;
|
||||
|
||||
// get the bytes for stable
|
||||
ByondInstallResponse installJob2;
|
||||
using (var stableBytesMs = await byondInstaller.DownloadVersion(compatVersion, cancellationToken))
|
||||
{
|
||||
installJob2 = await instanceClient.Byond.SetActiveVersion(new ByondVersionRequest
|
||||
{
|
||||
UploadCustomZip = true,
|
||||
Version = compatVersion,
|
||||
}, stableBytesMs, cancellationToken);
|
||||
}
|
||||
|
||||
await chatRequest;
|
||||
|
||||
var jobs = await instanceClient.Jobs.List(null, cancellationToken);
|
||||
var theJobWeWant = jobs.First(x => x.Description.Contains("Reconnect chat bot"));
|
||||
|
||||
await Task.WhenAll(
|
||||
jrt.WaitForJob(installJob2.InstallJob, 30, false, null, cancellationToken),
|
||||
jrt.WaitForJob(cloneRequest.Result.ActiveJob, 60, false, null, cancellationToken),
|
||||
jrt.WaitForJob(theJobWeWant, 30, false, null, cancellationToken),
|
||||
dmUpdateRequest,
|
||||
cloneRequest);
|
||||
|
||||
var configSetupTask = new ConfigurationTest(instanceClient.Configuration, instanceClient.Metadata).SetupDMApiTests(cancellationToken);
|
||||
|
||||
if (TestingUtils.RunningInGitHubActions
|
||||
|| String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"))
|
||||
|| Environment.MachineName.Equals("CYBERSTATIONXVI", StringComparison.OrdinalIgnoreCase))
|
||||
await instanceClient.Repository.Update(new RepositoryUpdateRequest
|
||||
{
|
||||
CreateGitHubDeployments = true,
|
||||
PostTestMergeComment = true,
|
||||
PushTestMergeCommits = true,
|
||||
AccessUser = "Cyberboss",
|
||||
AccessToken = Environment.GetEnvironmentVariable("TGS_TEST_GITHUB_TOKEN"),
|
||||
}, cancellationToken);
|
||||
|
||||
await configSetupTask;
|
||||
|
||||
await new WatchdogTest(compatVersion, instanceClient, instanceManager, serverPort, highPrioDD, ddPort).Run(cancellationToken);
|
||||
|
||||
await instanceManagerClient.Update(new InstanceUpdateRequest
|
||||
{
|
||||
Id = instanceClient.Metadata.Id,
|
||||
Online = false,
|
||||
}, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,21 +24,23 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
public DMApiParameters DMApiParameters => new DMApiParametersImpl
|
||||
{
|
||||
AccessIdentifier = "tgs_integration_test"
|
||||
AccessIdentifier = accessIdentifier
|
||||
};
|
||||
|
||||
long lastBridgeRequestSize = 0;
|
||||
|
||||
readonly TaskCompletionSource bridgeTestsTcs;
|
||||
readonly ushort serverPort;
|
||||
readonly string accessIdentifier;
|
||||
|
||||
bool chunksProcessed = false;
|
||||
|
||||
public TestBridgeHandler(TaskCompletionSource tcs, ILogger<TestBridgeHandler> logger, ushort serverPort)
|
||||
public TestBridgeHandler(TaskCompletionSource tcs, ILogger<TestBridgeHandler> logger, string accessIdentifier, ushort serverPort)
|
||||
: base(logger)
|
||||
{
|
||||
bridgeTestsTcs = tcs;
|
||||
this.serverPort = serverPort;
|
||||
this.accessIdentifier = accessIdentifier;
|
||||
}
|
||||
|
||||
public async Task<BridgeResponse> ProcessBridgeRequest(BridgeParameters parameters, CancellationToken cancellationToken)
|
||||
|
||||
@@ -17,7 +17,6 @@ using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Tgstation.Server.Api;
|
||||
using Tgstation.Server.Api.Models;
|
||||
using Tgstation.Server.Api.Models.Request;
|
||||
using Tgstation.Server.Api.Models.Response;
|
||||
@@ -38,25 +37,66 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
sealed class WatchdogTest : JobsRequiredTest
|
||||
{
|
||||
static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
builder.AddConsole();
|
||||
builder.SetMinimumLevel(LogLevel.Trace);
|
||||
});
|
||||
|
||||
public static readonly TopicClient StaticTopicClient = new(new SocketParameters
|
||||
{
|
||||
SendTimeout = TimeSpan.FromSeconds(30),
|
||||
ReceiveTimeout = TimeSpan.FromSeconds(30),
|
||||
ConnectTimeout = TimeSpan.FromSeconds(30),
|
||||
DisconnectTimeout = TimeSpan.FromSeconds(30)
|
||||
}, loggerFactory.CreateLogger($"WatchdogTest.TopicClient.Static"));
|
||||
|
||||
readonly IInstanceClient instanceClient;
|
||||
readonly InstanceManager instanceManager;
|
||||
readonly ushort serverPort;
|
||||
readonly ushort ddPort;
|
||||
readonly bool highPrioDD;
|
||||
readonly TopicClient topicClient;
|
||||
readonly Version testVersion;
|
||||
|
||||
bool ranTimeoutTest = false;
|
||||
|
||||
public WatchdogTest(IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD)
|
||||
public WatchdogTest(Version testVersion, IInstanceClient instanceClient, InstanceManager instanceManager, ushort serverPort, bool highPrioDD, ushort ddPort)
|
||||
: base(instanceClient.Jobs)
|
||||
{
|
||||
this.instanceClient = instanceClient ?? throw new ArgumentNullException(nameof(instanceClient));
|
||||
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
|
||||
this.serverPort = serverPort;
|
||||
this.highPrioDD = highPrioDD;
|
||||
this.ddPort = ddPort;
|
||||
this.testVersion = testVersion ?? throw new ArgumentNullException(nameof(testVersion));
|
||||
|
||||
this.topicClient = new(new SocketParameters
|
||||
{
|
||||
SendTimeout = TimeSpan.FromSeconds(30),
|
||||
ReceiveTimeout = TimeSpan.FromSeconds(30),
|
||||
ConnectTimeout = TimeSpan.FromSeconds(30),
|
||||
DisconnectTimeout = TimeSpan.FromSeconds(30)
|
||||
}, loggerFactory.CreateLogger($"WatchdogTest.TopicClient.{instanceClient.Metadata.Name}"));
|
||||
}
|
||||
|
||||
public async Task Run(CancellationToken cancellationToken)
|
||||
{
|
||||
System.Console.WriteLine("TEST: START WATCHDOG TESTS");
|
||||
System.Console.WriteLine($"TEST: START WATCHDOG TESTS {instanceClient.Metadata.Name}");
|
||||
|
||||
async Task CheckByondVersions()
|
||||
{
|
||||
var listTask = instanceClient.Byond.InstalledVersions(null, cancellationToken);
|
||||
|
||||
var list = await listTask;
|
||||
|
||||
Assert.AreEqual(1, list.Count);
|
||||
var byondVersion = list[0];
|
||||
|
||||
Assert.AreEqual(1, byondVersion.Version.Build);
|
||||
Assert.AreEqual(testVersion.Major, byondVersion.Version.Major);
|
||||
Assert.AreEqual(testVersion.Minor, byondVersion.Version.Minor);
|
||||
}
|
||||
|
||||
await Task.WhenAll(
|
||||
// Increase startup timeout, disable heartbeats, enable map threads because we've tested without for years
|
||||
@@ -64,10 +104,11 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
StartupTimeout = 15,
|
||||
HealthCheckSeconds = 0,
|
||||
Port = TestLiveServer.DDPort,
|
||||
Port = ddPort,
|
||||
MapThreads = 2,
|
||||
LogOutput = false,
|
||||
}, cancellationToken),
|
||||
CheckByondVersions(),
|
||||
ApiAssert.ThrowsException<ApiConflictException>(() => instanceClient.DreamDaemon.Update(new DreamDaemonRequest
|
||||
{
|
||||
SoftShutdown = true,
|
||||
@@ -100,7 +141,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
// for the restart staging tests
|
||||
await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, true, cancellationToken);
|
||||
|
||||
System.Console.WriteLine("TEST: END WATCHDOG TESTS");
|
||||
System.Console.WriteLine($"TEST: END WATCHDOG TESTS {instanceClient.Metadata.Name}");
|
||||
}
|
||||
|
||||
async Task InteropTestsForLongRunningDme(CancellationToken cancellationToken)
|
||||
@@ -152,10 +193,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
|
||||
|
||||
var topicRequestResult = await TopicClient.SendTopic(
|
||||
var topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"shadow_wizard_money_gang=1",
|
||||
TestLiveServer.DDPort,
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
@@ -184,10 +225,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
async Task<JobResponse> TestDeleteByondInstallErrorCasesAndQueing(CancellationToken cancellationToken)
|
||||
{
|
||||
var testCustomVersion = new Version(ByondTest.TestVersion.Major, ByondTest.TestVersion.Minor, 1);
|
||||
var testCustomVersion = new Version(testVersion.Major, testVersion.Minor, 1);
|
||||
var currentByond = await instanceClient.Byond.ActiveVersion(cancellationToken);
|
||||
Assert.IsNotNull(currentByond);
|
||||
Assert.AreEqual(ByondTest.TestVersion.Semver(), currentByond.Version);
|
||||
Assert.AreEqual(testVersion.Semver(), currentByond.Version);
|
||||
|
||||
// Change the active version and check we get delayed while deleting the old one because the watchdog is using it
|
||||
var setActiveResponse = await instanceClient.Byond.SetActiveVersion(
|
||||
@@ -204,7 +245,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
var deleteJob = await instanceClient.Byond.DeleteVersion(
|
||||
new ByondVersionDeleteRequest
|
||||
{
|
||||
Version = ByondTest.TestVersion,
|
||||
Version = testVersion,
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
@@ -219,7 +260,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
setActiveResponse = await instanceClient.Byond.SetActiveVersion(
|
||||
new ByondVersionRequest
|
||||
{
|
||||
Version = ByondTest.TestVersion,
|
||||
Version = testVersion,
|
||||
},
|
||||
null,
|
||||
cancellationToken);
|
||||
@@ -245,7 +286,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
deleteJob = await instanceClient.Byond.DeleteVersion(
|
||||
new ByondVersionDeleteRequest
|
||||
{
|
||||
Version = ByondTest.TestVersion,
|
||||
Version = testVersion,
|
||||
},
|
||||
cancellationToken);
|
||||
|
||||
@@ -255,13 +296,13 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
return deleteJob;
|
||||
}
|
||||
|
||||
static async Task SendChatOverloadCommand(CancellationToken cancellationToken)
|
||||
async Task SendChatOverloadCommand(CancellationToken cancellationToken)
|
||||
{
|
||||
// for the code coverage really...
|
||||
var topicRequestResult = await TopicClient.SendTopic(
|
||||
var topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics5=1",
|
||||
TestLiveServer.DDPort,
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
@@ -389,7 +430,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, true);
|
||||
blockSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
|
||||
blockSocket.Bind(new IPEndPoint(IPAddress.Any, TestLiveServer.DDPort));
|
||||
blockSocket.Bind(new IPEndPoint(IPAddress.Any, ddPort));
|
||||
|
||||
// Don't use StartDD here
|
||||
startJob = await instanceClient.DreamDaemon.Start(cancellationToken);
|
||||
@@ -453,7 +494,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
CheckDDPriority();
|
||||
|
||||
// lock on to DD and pause it so it can't health check
|
||||
var ddProcs = TestLiveServer.GetAllDDProcesses().Where(x => !x.HasExited).ToList();
|
||||
var ddProcs = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList();
|
||||
if (ddProcs.Count != 1)
|
||||
Assert.Fail($"Incorrect number of DD processes: {ddProcs.Count}");
|
||||
|
||||
@@ -474,10 +515,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
Assert.IsFalse(ddProc.HasExited);
|
||||
|
||||
// check DD agrees
|
||||
var topicRequestResult = await TopicClient.SendTopic(
|
||||
var topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics8=1",
|
||||
TestLiveServer.DDPort,
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
@@ -542,7 +583,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
try
|
||||
{
|
||||
SocketExtensions.BindTest(TestLiveServer.DDPort, false);
|
||||
SocketExtensions.BindTest(ddPort, false);
|
||||
break;
|
||||
}
|
||||
catch
|
||||
@@ -583,12 +624,13 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
builder.SetMinimumLevel(LogLevel.Trace);
|
||||
}))
|
||||
{
|
||||
var bridgeProcessor = new TestBridgeHandler(bridgeTestsTcs, loggerFactory.CreateLogger<TestBridgeHandler>(), serverPort);
|
||||
var accessIdentifier = $"tgs_integration_test_for_instance_{instanceClient.Metadata.Name}";
|
||||
var bridgeProcessor = new TestBridgeHandler(bridgeTestsTcs, loggerFactory.CreateLogger<TestBridgeHandler>(), accessIdentifier, serverPort);
|
||||
using var bridgeRegistration = instanceManager.RegisterHandler(bridgeProcessor);
|
||||
|
||||
System.Console.WriteLine("TEST: Sending Bridge tests topic...");
|
||||
|
||||
var bridgeTestTopicResult = await TopicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_tactics2=1", TestLiveServer.DDPort, cancellationToken);
|
||||
var bridgeTestTopicResult = await topicClient.SendTopic(IPAddress.Loopback, $"tgs_integration_test_tactics2={accessIdentifier}", ddPort, cancellationToken);
|
||||
Assert.AreEqual("ack2", bridgeTestTopicResult.StringData);
|
||||
|
||||
await bridgeTestsTcs.Task.WaitAsync(cancellationToken);
|
||||
@@ -600,7 +642,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
|
||||
}
|
||||
|
||||
static async Task ValidateTopicLimits(CancellationToken cancellationToken)
|
||||
async Task ValidateTopicLimits(CancellationToken cancellationToken)
|
||||
{
|
||||
// Time for topic tests
|
||||
// Request
|
||||
@@ -620,7 +662,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
var baseSize = (int)(DMApiConstants.MaximumTopicRequestLength - 1);
|
||||
|
||||
var topicString = $"tgs_integration_test_tactics3={TopicClient.SanitizeString(json)}";
|
||||
var topicString = $"tgs_integration_test_tactics3={topicClient.SanitizeString(json)}";
|
||||
var wrappingSize = topicString.Length;
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
@@ -638,10 +680,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
try
|
||||
{
|
||||
System.Console.WriteLine($"Topic send limit test S:{currentSize}...");
|
||||
topicRequestResult = await TopicClient.SendTopic(
|
||||
topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics3={TopicClient.SanitizeString(JsonConvert.SerializeObject(topic, DMApiConstants.SerializerSettings))}",
|
||||
TestLiveServer.DDPort,
|
||||
$"tgs_integration_test_tactics3={topicClient.SanitizeString(JsonConvert.SerializeObject(topic, DMApiConstants.SerializerSettings))}",
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
}
|
||||
catch (ArgumentOutOfRangeException)
|
||||
@@ -679,10 +721,10 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
{
|
||||
var currentSize = baseSize + (int)Math.Pow(2, nextPow);
|
||||
System.Console.WriteLine($"Topic recieve limit test S:{currentSize}...");
|
||||
var topicRequestResult = await TopicClient.SendTopic(
|
||||
var topicRequestResult = await topicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics4={TopicClient.SanitizeString(currentSize.ToString())}",
|
||||
TestLiveServer.DDPort,
|
||||
$"tgs_integration_test_tactics4={topicClient.SanitizeString(currentSize.ToString())}",
|
||||
ddPort,
|
||||
cancellationToken);
|
||||
|
||||
if (topicRequestResult.ResponseType != TopicResponseType.StringResponse
|
||||
@@ -799,11 +841,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
void CheckDDPriority()
|
||||
{
|
||||
var ddProcessName = new PlatformIdentifier().IsWindows && ByondTest.TestVersion >= new Version(515, 1598)
|
||||
? "dd"
|
||||
: "DreamDaemon";
|
||||
|
||||
var allProcesses = TestLiveServer.GetAllDDProcesses().Where(x => !x.HasExited).ToList();
|
||||
var allProcesses = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList();
|
||||
if (allProcesses.Count == 0)
|
||||
Assert.Fail("Expected DreamDaemon to be running here");
|
||||
|
||||
@@ -827,6 +865,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
var daemonStatus = await DeployTestDme(DmeName, DreamDaemonSecurity.Trusted, true, cancellationToken);
|
||||
|
||||
var initialCompileJob = daemonStatus.ActiveCompileJob;
|
||||
Assert.IsNotNull(initialCompileJob);
|
||||
Assert.AreEqual(WatchdogStatus.Offline, daemonStatus.Status.Value);
|
||||
Assert.IsNotNull(daemonStatus.ActiveCompileJob);
|
||||
Assert.IsNull(daemonStatus.StagedCompileJob);
|
||||
@@ -908,7 +947,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken cancellationToken)
|
||||
{
|
||||
System.Console.WriteLine("TEST: WATCHDOG BYOND VERSION UPDATE TEST");
|
||||
var versionToInstall = ByondTest.TestVersion;
|
||||
var versionToInstall = testVersion;
|
||||
|
||||
versionToInstall = versionToInstall.Semver();
|
||||
var currentByondVersion = await instanceClient.Byond.ActiveVersion(cancellationToken);
|
||||
@@ -979,7 +1018,7 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
|
||||
Assert.AreEqual(WatchdogStatus.Online, daemonStatus.Status.Value);
|
||||
CheckDDPriority();
|
||||
Assert.AreEqual(TestLiveServer.DDPort, daemonStatus.CurrentPort);
|
||||
Assert.AreEqual(ddPort, daemonStatus.CurrentPort);
|
||||
|
||||
// Try killing the DD process to ensure it gets set to the restoring state
|
||||
do
|
||||
@@ -1007,9 +1046,9 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
await CheckDMApiFail(daemonStatus.ActiveCompileJob, cancellationToken);
|
||||
}
|
||||
|
||||
static bool KillDD(bool require)
|
||||
bool KillDD(bool require)
|
||||
{
|
||||
var ddProcs = TestLiveServer.GetAllDDProcesses().Where(x => !x.HasExited).ToList();
|
||||
var ddProcs = TestLiveServer.GetDDProcessesOnPort(ddPort).Where(x => !x.HasExited).ToList();
|
||||
if (require && ddProcs.Count == 0 || ddProcs.Count > 1)
|
||||
Assert.Fail($"Incorrect number of DD processes: {ddProcs.Count}");
|
||||
|
||||
@@ -1020,29 +1059,15 @@ namespace Tgstation.Server.Tests.Live.Instance
|
||||
return ddProc != null;
|
||||
}
|
||||
|
||||
static readonly ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
builder.AddConsole();
|
||||
builder.SetMinimumLevel(LogLevel.Trace);
|
||||
});
|
||||
|
||||
public static readonly TopicClient TopicClient = new(new SocketParameters
|
||||
{
|
||||
SendTimeout = TimeSpan.FromSeconds(30),
|
||||
ReceiveTimeout = TimeSpan.FromSeconds(30),
|
||||
ConnectTimeout = TimeSpan.FromSeconds(30),
|
||||
DisconnectTimeout = TimeSpan.FromSeconds(30)
|
||||
}, loggerFactory.CreateLogger("WatchdogTest.TopicClient"));
|
||||
|
||||
public Task<DreamDaemonResponse> TellWorldToReboot(CancellationToken cancellationToken) => TellWorldToReboot2(instanceClient, cancellationToken);
|
||||
public static async Task<DreamDaemonResponse> TellWorldToReboot2(IInstanceClient instanceClient, CancellationToken cancellationToken)
|
||||
public Task<DreamDaemonResponse> TellWorldToReboot(CancellationToken cancellationToken) => TellWorldToReboot2(instanceClient, ddPort, cancellationToken);
|
||||
public static async Task<DreamDaemonResponse> TellWorldToReboot2(IInstanceClient instanceClient, ushort ddPort, CancellationToken cancellationToken)
|
||||
{
|
||||
var daemonStatus = await instanceClient.DreamDaemon.Read(cancellationToken);
|
||||
Assert.IsNotNull(daemonStatus.StagedCompileJob);
|
||||
var initialCompileJob = daemonStatus.ActiveCompileJob;
|
||||
|
||||
System.Console.WriteLine("TEST: Sending world reboot topic...");
|
||||
var result = await TopicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", TestLiveServer.DDPort, cancellationToken);
|
||||
var result = await StaticTopicClient.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", ddPort, cancellationToken);
|
||||
Assert.AreEqual("ack", result.StringData);
|
||||
|
||||
using var tempCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace Tgstation.Server.Tests.Live
|
||||
this.testRootPath = testRootPath ?? throw new ArgumentNullException(nameof(testRootPath));
|
||||
}
|
||||
|
||||
public async Task<InstanceResponse> CreateTestInstance(CancellationToken cancellationToken)
|
||||
public async Task<InstanceResponse> CreateTestInstance(string name, CancellationToken cancellationToken)
|
||||
{
|
||||
var instance = await CreateTestInstanceStub("LiveTestsInstance", cancellationToken);
|
||||
var instance = await CreateTestInstanceStub(name, cancellationToken);
|
||||
return await instanceManagerClient.Update(new InstanceUpdateRequest
|
||||
{
|
||||
Id = instance.Id,
|
||||
@@ -52,7 +52,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
Task<InstanceResponse> CreateTestInstanceStub(string name, CancellationToken cancellationToken) => instanceManagerClient.CreateOrAttach(new InstanceCreateRequest
|
||||
{
|
||||
Name = name,
|
||||
Path = Path.Combine(testRootPath, Guid.NewGuid().ToString()),
|
||||
Path = Path.Combine(testRootPath, $"Instance-{name}"),
|
||||
Online = true,
|
||||
ChatBotLimit = 2
|
||||
}, cancellationToken);
|
||||
|
||||
@@ -15,6 +15,7 @@ using Tgstation.Server.Host;
|
||||
using Tgstation.Server.Host.Configuration;
|
||||
using Tgstation.Server.Host.Core;
|
||||
using Tgstation.Server.Host.Extensions;
|
||||
using Tgstation.Server.Host.IO;
|
||||
using Tgstation.Server.Host.Setup;
|
||||
using Tgstation.Server.Host.Utils;
|
||||
|
||||
@@ -22,6 +23,33 @@ namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
sealed class LiveTestingServer : IServer, IDisposable
|
||||
{
|
||||
public static string BaseDirectory { get; }
|
||||
|
||||
static LiveTestingServer()
|
||||
{
|
||||
SerilogContextHelper.AddSwarmNodeIdentifierToTemplate();
|
||||
BaseDirectory = Environment.GetEnvironmentVariable("TGS_TEST_TEMP_DIRECTORY");
|
||||
if (string.IsNullOrWhiteSpace(BaseDirectory))
|
||||
{
|
||||
BaseDirectory = Path.Combine(Path.GetTempPath(), "TGS_INTEGRATION_TEST");
|
||||
Cleanup(BaseDirectory).GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
static async Task Cleanup(string directory)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i)
|
||||
try
|
||||
{
|
||||
new DefaultIOManager().DeleteDirectory(directory, default).GetAwaiter().GetResult();
|
||||
}
|
||||
catch
|
||||
{
|
||||
GC.Collect(int.MaxValue, GCCollectionMode.Forced, false);
|
||||
await Task.Delay(3000);
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Url { get; }
|
||||
|
||||
public string Directory { get; }
|
||||
@@ -44,25 +72,10 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
public IServer RealServer { get; private set; }
|
||||
|
||||
static LiveTestingServer()
|
||||
{
|
||||
SerilogContextHelper.AddSwarmNodeIdentifierToTemplate();
|
||||
}
|
||||
|
||||
public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth, ushort port = 15010)
|
||||
{
|
||||
Assert.IsTrue(port >= 10000); // for testing bridge request limit
|
||||
Directory = Environment.GetEnvironmentVariable("TGS_TEST_TEMP_DIRECTORY");
|
||||
if (string.IsNullOrWhiteSpace(Directory))
|
||||
{
|
||||
Directory = Path.Combine(Path.GetTempPath(), "TGS_INTEGRATION_TEST");
|
||||
if (System.IO.Directory.Exists(Directory) && swarmConfiguration == null)
|
||||
try
|
||||
{
|
||||
System.IO.Directory.Delete(Directory, true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
Directory = BaseDirectory;
|
||||
|
||||
Directory = Path.Combine(Directory, Guid.NewGuid().ToString());
|
||||
System.IO.Directory.CreateDirectory(Directory);
|
||||
@@ -83,7 +96,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
Assert.Inconclusive("No connection string configured in env var TGS_TEST_CONNECTION_STRING!");
|
||||
|
||||
if (String.IsNullOrEmpty(gitHubAccessToken))
|
||||
Console.WriteLine("WARNING: No GitHub access token configured, test may fail due to rate limits!");
|
||||
System.Console.WriteLine("WARNING: No GitHub access token configured, test may fail due to rate limits!");
|
||||
|
||||
DumpOpenApiSpecpath = !String.IsNullOrEmpty(dumpOpenAPISpecPathEnvVar);
|
||||
|
||||
@@ -148,19 +161,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
UpdatePath = Path.Combine(Directory, Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
for (int i = 0; i < 5; ++i)
|
||||
try
|
||||
{
|
||||
//System.IO.Directory.Delete(Directory, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
GC.Collect(int.MaxValue, GCCollectionMode.Forced, false);
|
||||
Thread.Sleep(3000);
|
||||
}
|
||||
}
|
||||
public void Dispose() => Cleanup(Directory).GetAwaiter().GetResult();
|
||||
|
||||
public void UpdateSwarmArguments(SwarmConfiguration swarmConfiguration)
|
||||
{
|
||||
@@ -194,7 +195,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
public async Task Run(CancellationToken cancellationToken)
|
||||
{
|
||||
var messageAddition = swarmNodeId != null ? $": {swarmNodeId}" : String.Empty;
|
||||
Console.WriteLine("TEST SERVER START" + messageAddition);
|
||||
System.Console.WriteLine("TEST SERVER START" + messageAddition);
|
||||
var firstRun = RealServer == null;
|
||||
var arrayArgs = args.Concat(swarmArgs).ToArray();
|
||||
RealServer = await Application
|
||||
@@ -213,7 +214,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
? LogContext.PushProperty(SerilogContextHelper.SwarmIdentifierContextProperty, swarmNodeId)
|
||||
: null)
|
||||
await RealServer.Run(cancellationToken);
|
||||
Console.WriteLine($"TEST SERVER END" + messageAddition);
|
||||
System.Console.WriteLine($"TEST SERVER END" + messageAddition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Data.SqlClient;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
@@ -46,52 +47,88 @@ namespace Tgstation.Server.Tests.Live
|
||||
[TestCategory("SkipWhenLiveUnitTesting")]
|
||||
public sealed class TestLiveServer
|
||||
{
|
||||
public static ushort DDPort { get; } = FreeTcpPort();
|
||||
public static ushort DMPort { get; } = GetDMPort();
|
||||
|
||||
public static readonly Version TestUpdateVersion = new(5, 11, 0);
|
||||
|
||||
static readonly ushort mainDDPort = FreeTcpPort();
|
||||
static readonly ushort mainDMPort = FreeTcpPort(mainDDPort);
|
||||
static readonly ushort compatDMPort = FreeTcpPort(mainDDPort, mainDMPort);
|
||||
static readonly ushort compatDDPort = FreeTcpPort(mainDDPort, mainDMPort, compatDMPort);
|
||||
|
||||
readonly IServerClientFactory clientFactory = new ServerClientFactory(new ProductHeaderValue(Assembly.GetExecutingAssembly().GetName().Name, Assembly.GetExecutingAssembly().GetName().Version.ToString()));
|
||||
|
||||
public static List<System.Diagnostics.Process> GetAllDDProcesses()
|
||||
public static List<System.Diagnostics.Process> GetDDProcessesOnPort(ushort? port)
|
||||
{
|
||||
var result = new List<System.Diagnostics.Process>();
|
||||
result.AddRange(System.Diagnostics.Process.GetProcessesByName("DreamDaemon"));
|
||||
if(new PlatformIdentifier().IsWindows)
|
||||
if (new PlatformIdentifier().IsWindows)
|
||||
result.AddRange(System.Diagnostics.Process.GetProcessesByName("dd"));
|
||||
|
||||
if (port.HasValue)
|
||||
result = result.Where(x =>
|
||||
{
|
||||
if (GetCommandLine(x).Contains($"-port {port.Value}"))
|
||||
return true;
|
||||
|
||||
x.Dispose();
|
||||
return false;
|
||||
}).ToList();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetCommandLine(System.Diagnostics.Process process)
|
||||
{
|
||||
if (new PlatformIdentifier().IsWindows)
|
||||
{
|
||||
var searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + process.Id);
|
||||
var objects = searcher.Get();
|
||||
return objects.Cast<ManagementBaseObject>().SingleOrDefault()?["CommandLine"]?.ToString();
|
||||
}
|
||||
|
||||
var cmdlineFile = File.ReadAllText($"/proc/{process.Id}/cmdline");
|
||||
var parsed = cmdlineFile.Replace('\0', ' ');
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static void TerminateAllDDs()
|
||||
{
|
||||
foreach (var proc in GetAllDDProcesses())
|
||||
foreach (var proc in GetDDProcessesOnPort(null))
|
||||
using (proc)
|
||||
proc.Kill();
|
||||
}
|
||||
|
||||
static ushort GetDMPort()
|
||||
static ushort FreeTcpPort(params ushort[] usedPorts)
|
||||
{
|
||||
ushort result;
|
||||
do
|
||||
{
|
||||
result = FreeTcpPort();
|
||||
} while (result == DDPort);
|
||||
return result;
|
||||
}
|
||||
|
||||
static ushort FreeTcpPort()
|
||||
{
|
||||
var l = new TcpListener(IPAddress.Loopback, 0);
|
||||
l.Start();
|
||||
var listeners = new List<TcpListener>();
|
||||
try
|
||||
{
|
||||
return (ushort)((IPEndPoint)l.LocalEndpoint).Port;
|
||||
do
|
||||
{
|
||||
var l = new TcpListener(IPAddress.Loopback, 0);
|
||||
l.Start();
|
||||
try
|
||||
{
|
||||
listeners.Add(l);
|
||||
}
|
||||
catch
|
||||
{
|
||||
l.Stop();
|
||||
throw;
|
||||
}
|
||||
|
||||
result = (ushort)((IPEndPoint)l.LocalEndpoint).Port;
|
||||
}
|
||||
while (usedPorts.Contains(result));
|
||||
}
|
||||
finally
|
||||
{
|
||||
l.Stop();
|
||||
foreach(var l in listeners)
|
||||
{
|
||||
l.Stop();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[ClassInitialize]
|
||||
@@ -1016,6 +1053,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
// main run
|
||||
var serverTask = server.Run(cancellationToken);
|
||||
|
||||
var fileDownloader = ((Host.Server)server.RealServer).Host.Services.GetRequiredService<Host.IO.IFileDownloader>();
|
||||
try
|
||||
{
|
||||
Api.Models.Instance instance;
|
||||
@@ -1041,11 +1079,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
{
|
||||
await task;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
{
|
||||
Console.WriteLine($"[{DateTimeOffset.UtcNow}] TEST ERROR: {ex}");
|
||||
serverCts.Cancel();
|
||||
@@ -1056,27 +1090,42 @@ namespace Tgstation.Server.Tests.Live
|
||||
var rootTest = FailFast(RawRequestTests.Run(clientFactory, adminClient, cancellationToken));
|
||||
var adminTest = FailFast(new AdministrationTest(adminClient.Administration).Run(cancellationToken));
|
||||
var usersTest = FailFast(new UsersTest(adminClient).Run(cancellationToken));
|
||||
var instanceMangagerTest = new InstanceManagerTest(adminClient, server.Directory);
|
||||
instance = await instanceMangagerTest.CreateTestInstance(cancellationToken);
|
||||
var instancesTest = FailFast(instanceMangagerTest.RunPreTest(cancellationToken));
|
||||
var instanceManagerTest = new InstanceManagerTest(adminClient, server.Directory);
|
||||
var compatInstanceTask = instanceManagerTest.CreateTestInstance("LiveTestsInstance", cancellationToken);
|
||||
instance = await instanceManagerTest.CreateTestInstance("CompatTestsInstance", cancellationToken);
|
||||
var compatInstance = await compatInstanceTask;
|
||||
var instancesTest = FailFast(instanceManagerTest.RunPreTest(cancellationToken));
|
||||
Assert.IsTrue(Directory.Exists(instance.Path));
|
||||
var instanceClient = adminClient.Instances.CreateClient(instance);
|
||||
|
||||
Assert.IsTrue(Directory.Exists(instanceClient.Metadata.Path));
|
||||
|
||||
var instanceTests = FailFast(
|
||||
new InstanceTest(
|
||||
instanceClient,
|
||||
var instanceTest = new InstanceTest(
|
||||
adminClient.Instances,
|
||||
((Host.Server)server.RealServer).Host.Services.GetRequiredService<Host.IO.IFileDownloader>(),
|
||||
fileDownloader,
|
||||
GetInstanceManager(),
|
||||
(ushort)server.Url.Port)
|
||||
.RunTests(
|
||||
server.HighPriorityDreamDaemon,
|
||||
server.LowPriorityDeployments,
|
||||
cancellationToken));
|
||||
(ushort)server.Url.Port);
|
||||
|
||||
await Task.WhenAll(rootTest, adminTest, instancesTest, instanceTests, usersTest);
|
||||
var instanceTests = FailFast(
|
||||
instanceTest
|
||||
.RunTests(
|
||||
instanceClient,
|
||||
mainDMPort,
|
||||
mainDDPort,
|
||||
server.HighPriorityDreamDaemon,
|
||||
server.LowPriorityDeployments,
|
||||
cancellationToken));
|
||||
|
||||
var compatTests = FailFast(
|
||||
instanceTest
|
||||
.RunCompatTests(
|
||||
adminClient.Instances.CreateClient(compatInstance),
|
||||
compatDMPort,
|
||||
compatDDPort,
|
||||
server.HighPriorityDreamDaemon,
|
||||
cancellationToken));
|
||||
|
||||
await Task.WhenAll(rootTest, adminTest, instancesTest, instanceTests, usersTest, compatTests);
|
||||
|
||||
var dd = await instanceClient.DreamDaemon.Read(cancellationToken);
|
||||
Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value);
|
||||
@@ -1093,10 +1142,10 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
// test the reattach message queueing
|
||||
// for the code coverage really...
|
||||
var topicRequestResult = await WatchdogTest.TopicClient.SendTopic(
|
||||
var topicRequestResult = await WatchdogTest.StaticTopicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics6=1",
|
||||
DDPort,
|
||||
mainDDPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
@@ -1169,10 +1218,10 @@ namespace Tgstation.Server.Tests.Live
|
||||
var chatReadTask = instanceClient.ChatBots.List(null, cancellationToken);
|
||||
|
||||
// Check the DMAPI got the channels again https://github.com/tgstation/tgstation-server/issues/1490
|
||||
topicRequestResult = await WatchdogTest.TopicClient.SendTopic(
|
||||
topicRequestResult = await WatchdogTest.StaticTopicClient.SendTopic(
|
||||
IPAddress.Loopback,
|
||||
$"tgs_integration_test_tactics7=1",
|
||||
DDPort,
|
||||
mainDDPort,
|
||||
cancellationToken);
|
||||
|
||||
Assert.IsNotNull(topicRequestResult);
|
||||
@@ -1186,7 +1235,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
|
||||
Assert.AreEqual(connectedChannelCount, channelsPresent);
|
||||
|
||||
await WatchdogTest.TellWorldToReboot2(instanceClient, cancellationToken);
|
||||
await WatchdogTest.TellWorldToReboot2(instanceClient, mainDDPort, cancellationToken);
|
||||
|
||||
dd = await instanceClient.DreamDaemon.Read(cancellationToken);
|
||||
Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value);
|
||||
@@ -1238,6 +1287,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
preStartupTime = DateTimeOffset.UtcNow;
|
||||
serverTask = server.Run(cancellationToken);
|
||||
long expectedCompileJobId, expectedStaged;
|
||||
var edgeByond = await ByondTest.GetEdgeVersion(fileDownloader, cancellationToken);
|
||||
using (var adminClient = await CreateAdminClient(server.Url, cancellationToken))
|
||||
{
|
||||
var instanceClient = adminClient.Instances.CreateClient(instance);
|
||||
@@ -1248,7 +1298,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
Assert.AreEqual(WatchdogStatus.Online, dd.Status.Value);
|
||||
|
||||
var compileJob = await instanceClient.DreamMaker.Compile(cancellationToken);
|
||||
var wdt = new WatchdogTest(instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon);
|
||||
var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort);
|
||||
await wdt.WaitForJob(compileJob, 30, false, null, cancellationToken);
|
||||
|
||||
dd = await instanceClient.DreamDaemon.Read(cancellationToken);
|
||||
@@ -1295,7 +1345,7 @@ namespace Tgstation.Server.Tests.Live
|
||||
Assert.AreEqual(WatchdogStatus.Online, currentDD.Status);
|
||||
Assert.AreEqual(expectedStaged, currentDD.StagedCompileJob.Job.Id.Value);
|
||||
|
||||
var wdt = new WatchdogTest(instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon);
|
||||
var wdt = new WatchdogTest(edgeByond, instanceClient, GetInstanceManager(), (ushort)server.Url.Port, server.HighPriorityDreamDaemon, mainDDPort);
|
||||
currentDD = await wdt.TellWorldToReboot(cancellationToken);
|
||||
Assert.AreEqual(expectedStaged, currentDD.ActiveCompileJob.Job.Id.Value);
|
||||
Assert.IsNull(currentDD.StagedCompileJob);
|
||||
|
||||
Reference in New Issue
Block a user