mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-30 08:33:19 +01:00
Merge pull request #1021 from tgstation/965-FixBrokenTests [DMDeploy][NugetDeploy]
Wrapping up v4.3.0
This commit is contained in:
+8
-8
@@ -102,6 +102,14 @@ jobs:
|
||||
name: "Docker Build"
|
||||
services:
|
||||
- docker
|
||||
- env:
|
||||
- DoxGeneration=true
|
||||
name: "Dox Generation"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- doxygen
|
||||
- graphviz
|
||||
- env:
|
||||
- DoxGeneration=false
|
||||
- DockerBuild=false
|
||||
@@ -118,14 +126,6 @@ jobs:
|
||||
packages:
|
||||
- libc6-i386
|
||||
- libstdc++6:i386
|
||||
- env:
|
||||
- DoxGeneration=true
|
||||
name: "Dox Generation"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- doxygen
|
||||
- graphviz
|
||||
|
||||
install:
|
||||
- if [ $DoxGeneration = false ] && [ $DockerBuild = false ] && [ $DMAPI = true ]; then build/install_byond.sh; fi
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ test_script:
|
||||
- OpenCover.Console.exe -returntargetcode -register:user -target:"C:/Program Files/dotnet/dotnet.exe" -targetargs:"test -c %CONFIGURATION% --logger:trx;LogFileName=results.trx /p:DebugType=full tests/Tgstation.Server.Host.Watchdog.Tests/Tgstation.Server.Host.Watchdog.Tests.csproj" -filter:"+[Tgstation.Server*]* -[Tgstation.Server.Host.Watchdog.Tests*]*" -output:".\watchdog_coverage.xml" -oldstyle
|
||||
- ps: $wc = New-Object 'System.Net.WebClient'
|
||||
- ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\tests\Tgstation.Server.Host.Watchdog.Tests\TestResults\results.trx))
|
||||
- OpenCover.Console.exe -returntargetcode -register:user -target:"C:/Program Files/dotnet/dotnet.exe" -targetargs:"test -c %CONFIGURATION% --logger:trx;LogFileName=results.trx /p:DebugType=full tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj" -filter:"+[Tgstation.Server*]* -[Tgstation.Server.Tests*]* -[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations..*" -output:".\server_coverage.xml" -oldstyle
|
||||
- OpenCover.Console.exe -returntargetcode -register:user -target:"C:/Program Files/dotnet/dotnet.exe" -targetargs:"test -c %CONFIGURATION% --logger:trx;LogFileName=results.trx --logger:console;noprogress=true /p:DebugType=full tests/Tgstation.Server.Tests/Tgstation.Server.Tests.csproj" -filter:"+[Tgstation.Server*]* -[Tgstation.Server.Tests*]* -[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations..*" -output:".\server_coverage.xml" -oldstyle
|
||||
- ps: $wc = New-Object 'System.Net.WebClient'
|
||||
- ps: $wc.UploadFile("https://ci.appveyor.com/api/testresults/mstest/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\tests\Tgstation.Server.Tests\TestResults\results.trx))
|
||||
- lint-openapi -p -c build/OpenApiValidationSettings.json C:/swagger.json
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<TgsCoreVersion>4.3.0</TgsCoreVersion>
|
||||
<TgsApiVersion>6.5.0</TgsApiVersion>
|
||||
<TgsClientVersion>7.1.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>5.2.1</TgsDmapiVersion>
|
||||
<TgsDmapiVersion>5.2.2</TgsDmapiVersion>
|
||||
<TgsControlPanelVersion>0.4.0</TgsControlPanelVersion>
|
||||
<TgsHostWatchdogVersion>1.1.0</TgsHostWatchdogVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -10,7 +10,7 @@ cd tests/Tgstation.Server.Tests
|
||||
|
||||
dotnet build -c $CONFIG
|
||||
|
||||
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG --no-build" --format opencover --output "../../TestResults/integration_test.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Tests*]*" --exclude "[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations.*"
|
||||
$HOME/.dotnet/tools/coverlet bin/$CONFIG/netcoreapp3.1/Tgstation.Server.Tests.dll --target "dotnet" --targetargs "test -c $CONFIG --no-build --logger:\"console;noprogress=true\"" --format opencover --output "../../TestResults/integration_test.xml" --include "[Tgstation.Server*]*" --exclude "[Tgstation.Server.Tests*]*" --exclude "[Tgstation.Server.Host]Tgstation.Server.Host.Database.Migrations.*"
|
||||
|
||||
cd ../../TestResults
|
||||
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
// tgstation-server DMAPI
|
||||
|
||||
#define TGS_DMAPI_VERSION "5.2.1"
|
||||
#define TGS_DMAPI_VERSION "5.2.2"
|
||||
|
||||
// All functions and datums outside this document are subject to change with any version and should not be relied on.
|
||||
|
||||
@@ -127,6 +127,7 @@
|
||||
* Call this when your initializations are complete and your game is ready to play before any player interactions happen.
|
||||
*
|
||||
* This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running.
|
||||
* Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184
|
||||
* Before this point, note that any static files or directories may be in use by another server. Your code should account for this.
|
||||
* This function should not be called before ..() in [/world/proc/New].
|
||||
*/
|
||||
|
||||
@@ -114,12 +114,14 @@
|
||||
/datum/tgs_api/v4/OnInitializationComplete()
|
||||
Export(TGS4_COMM_SERVER_PRIMED)
|
||||
|
||||
var/tgs4_secret_sleep_offline_sauce = 24051994
|
||||
var/tgs4_secret_sleep_offline_sauce = 29051994
|
||||
var/old_sleep_offline = world.sleep_offline
|
||||
world.sleep_offline = tgs4_secret_sleep_offline_sauce
|
||||
sleep(1)
|
||||
if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
|
||||
world.sleep_offline = old_sleep_offline
|
||||
else
|
||||
TGS_WARNING_LOG("world.sleep_offline unexpectedly changed!")
|
||||
|
||||
/datum/tgs_api/v4/OnTopic(T)
|
||||
var/list/params = params2list(T)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
var/list/chat_channels
|
||||
|
||||
/datum/tgs_api/v5/ApiVersion()
|
||||
return new /datum/tgs_version("5.2.1")
|
||||
return new /datum/tgs_version("5.2.2")
|
||||
|
||||
/datum/tgs_api/v5/OnWorldNew(minimum_required_security_level)
|
||||
server_port = world.params[DMAPI5_PARAM_SERVER_PORT]
|
||||
@@ -94,6 +94,8 @@
|
||||
sleep(1)
|
||||
if(world.sleep_offline == tgs4_secret_sleep_offline_sauce) //if not someone changed it
|
||||
world.sleep_offline = old_sleep_offline
|
||||
else
|
||||
TGS_WARNING_LOG("world.sleep_offline unexpectedly changed!")
|
||||
|
||||
/datum/tgs_api/v5/proc/TopicResponse(error_message = null)
|
||||
var/list/response = list()
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Tgstation.Server.Host.Components.Interop
|
||||
/// <summary>
|
||||
/// The DMAPI <see cref="Version"/> being used.
|
||||
/// </summary>
|
||||
public static readonly Version Version = new Version(5, 2, 1);
|
||||
public static readonly Version Version = new Version(5, 2, 2);
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="JsonSerializerSettings"/> for use when communicating with the DMAPI.
|
||||
|
||||
@@ -192,7 +192,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
};
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DisposeAndNullControllers()
|
||||
protected override void DisposeAndNullControllersImpl()
|
||||
{
|
||||
Server?.Dispose();
|
||||
Server = null;
|
||||
|
||||
@@ -392,10 +392,8 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
}
|
||||
#pragma warning restore CA1502
|
||||
|
||||
/// <summary>
|
||||
/// Call <see cref="IDisposable.Dispose"/> on <see cref="alphaServer"/> and <see cref="bravoServer"/> and set them to <see langword="null"/>
|
||||
/// </summary>
|
||||
protected override void DisposeAndNullControllers()
|
||||
/// <inheritdoc />
|
||||
protected override void DisposeAndNullControllersImpl()
|
||||
{
|
||||
alphaServer?.Dispose();
|
||||
alphaServer = null;
|
||||
|
||||
@@ -112,6 +112,11 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
/// </summary>
|
||||
readonly IRestartRegistration restartRegistration;
|
||||
|
||||
/// <summary>
|
||||
/// <see langword="lock"/> <see cref="object"/> used for <see cref="DisposeAndNullControllers"/>.
|
||||
/// </summary>
|
||||
readonly object controllerDisposeLock;
|
||||
|
||||
/// <summary>
|
||||
/// If the <see cref="WatchdogBase"/> should <see cref="LaunchImplNoLock(bool, bool, DualReattachInformation, CancellationToken)"/> in <see cref="StartAsync(CancellationToken)"/>
|
||||
/// </summary>
|
||||
@@ -201,6 +206,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
ActiveLaunchParameters = initialLaunchParameters;
|
||||
releaseServers = false;
|
||||
ActiveParametersUpdated = new TaskCompletionSource<object>();
|
||||
controllerDisposeLock = new object();
|
||||
|
||||
restartRegistration = serverControl.RegisterForRestart(this);
|
||||
try
|
||||
@@ -463,7 +469,16 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
/// <summary>
|
||||
/// Call <see cref="IDisposable.Dispose"/> and null the fields for all <see cref="ISessionController"/>s and set <see cref="Running"/> to <see langword="false"/>.
|
||||
/// </summary>
|
||||
protected abstract void DisposeAndNullControllers();
|
||||
protected abstract void DisposeAndNullControllersImpl();
|
||||
|
||||
/// <summary>
|
||||
/// Wrapper for <see cref="DisposeAndNullControllersImpl"/> under a locked context.
|
||||
/// </summary>
|
||||
protected void DisposeAndNullControllers()
|
||||
{
|
||||
lock (controllerDisposeLock)
|
||||
DisposeAndNullControllersImpl();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the active <see cref="ISessionController"/>.
|
||||
|
||||
@@ -101,9 +101,9 @@ namespace Tgstation.Server.Host.Components.Watchdog
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DisposeAndNullControllers()
|
||||
protected override void DisposeAndNullControllersImpl()
|
||||
{
|
||||
base.DisposeAndNullControllers();
|
||||
base.DisposeAndNullControllersImpl();
|
||||
|
||||
// If we reach this point, we can guarantee PrepServerForLaunch will be called before starting again.
|
||||
activeSwappable = null;
|
||||
|
||||
@@ -4,7 +4,7 @@ using Newtonsoft.Json.Converters;
|
||||
namespace Tgstation.Server.Host.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Configuration options for the <see cref="Database.DatabaseContext{TParentContext}"/>
|
||||
/// Configuration options for the <see cref="Database.DatabaseContext"/>
|
||||
/// </summary>
|
||||
sealed class DatabaseConfiguration
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Tgstation.Server.Host.Configuration
|
||||
/// <summary>
|
||||
/// The default value for <see cref="RestartTimeout"/>
|
||||
/// </summary>
|
||||
const int DefaultRestartTimeout = 10000;
|
||||
const int DefaultRestartTimeout = 60000;
|
||||
|
||||
/// <summary>
|
||||
/// The port the TGS API listens on.
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace Tgstation.Server.Host.Controllers
|
||||
|
||||
if (ApiHeaders != null)
|
||||
Logger.LogDebug(
|
||||
"Request made by User ID {0}. Api version: {1}. User-Agent: {2}. Type: {3}. Route {4}{5} to Instance {6}",
|
||||
"Request details: User ID {0}. Api version: {1}. User-Agent: {2}. Type: {3}. Route {4}{5} to Instance {6}",
|
||||
AuthenticationContext?.User.Id.Value.ToString(CultureInfo.InvariantCulture),
|
||||
ApiHeaders.ApiVersion.Semver(),
|
||||
ApiHeaders.RawUserAgent,
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace Tgstation.Server.Host.Core
|
||||
// CORS conditionally enabled later
|
||||
services.AddCors();
|
||||
|
||||
void AddTypedContext<TContext>() where TContext : DatabaseContext<TContext>
|
||||
void AddTypedContext<TContext>() where TContext : DatabaseContext
|
||||
{
|
||||
services.AddDbContext<TContext>(builder =>
|
||||
{
|
||||
@@ -357,6 +357,8 @@ namespace Tgstation.Server.Host.Core
|
||||
// Final point where we wrap exceptions in a 500 (ErrorMessage) response
|
||||
applicationBuilder.UseServerErrorHandling();
|
||||
|
||||
applicationBuilder.UseRequestCounting();
|
||||
|
||||
// 503 requests made while the application is starting
|
||||
applicationBuilder.UseAsyncInitialization(async (cancellationToken) =>
|
||||
{
|
||||
|
||||
@@ -18,95 +18,94 @@ namespace Tgstation.Server.Host.Database
|
||||
/// <summary>
|
||||
/// Backend abstract implementation of <see cref="IDatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TParentContext">The child <see cref="Type"/> used to implement a backend.</typeparam>
|
||||
#pragma warning disable CA1506 // TODO: Decomplexify
|
||||
abstract class DatabaseContext<TParentContext> : DbContext, IDatabaseContext where TParentContext : DbContext
|
||||
abstract class DatabaseContext : DbContext, IDatabaseContext
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public DatabaseType DatabaseType => DatabaseConfiguration.DatabaseType;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="User"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="User"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<User> Users { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Instance"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="Instance"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<Instance> Instances { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="CompileJob"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="CompileJob"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<CompileJob> CompileJobs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RevisionInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="RevisionInformation"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<RevisionInformation> RevisionInformations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.DreamMakerSettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="Models.DreamMakerSettings"/> in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<DreamMakerSettings> DreamMakerSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ChatBot"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="ChatBot"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<ChatBot> ChatBots { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.DreamDaemonSettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="Models.DreamDaemonSettings"/> in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<DreamDaemonSettings> DreamDaemonSettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Models.RepositorySettings"/> in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="Models.RepositorySettings"/> in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<RepositorySettings> RepositorySettings { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="InstanceUser"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="InstanceUser"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<InstanceUser> InstanceUsers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ChatChannel"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="ChatChannel"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<ChatChannel> ChatChannels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Job"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="Job"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<Job> Jobs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ReattachInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="ReattachInformation"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<ReattachInformation> ReattachInformations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DualReattachInformation"/>s in the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="DualReattachInformation"/>s in the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
public DbSet<DualReattachInformation> WatchdogReattachInformations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TestMerge"/>s in the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="TestMerge"/>s in the <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
public DbSet<TestMerge> TestMerges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="RevInfoTestMerge"/>s om the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="RevInfoTestMerge"/>s om the <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
public DbSet<RevInfoTestMerge> RevInfoTestMerges { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="ILogger"/> for the <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
protected DatabaseConfiguration DatabaseConfiguration { get; }
|
||||
|
||||
@@ -150,7 +149,7 @@ namespace Tgstation.Server.Host.Database
|
||||
IDatabaseCollection<DualReattachInformation> IDatabaseContext.WatchdogReattachInformations => watchdogReattachInformationsCollection;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
readonly IDatabaseSeeder databaseSeeder;
|
||||
|
||||
@@ -220,13 +219,13 @@ namespace Tgstation.Server.Host.Database
|
||||
readonly IDatabaseCollection<DualReattachInformation> watchdogReattachInformationsCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// Construct a <see cref="DatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TParentContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions"/> for the <see cref="DatabaseContext"/>.</param>
|
||||
/// <param name="databaseConfigurationOptions">The <see cref="IOptions{TOptions}"/> containing the value of <see cref="DatabaseConfiguration"/></param>
|
||||
/// <param name="databaseSeeder">The value of <see cref="databaseSeeder"/></param>
|
||||
/// <param name="logger">The value of <see cref="Logger"/></param>
|
||||
public DatabaseContext(DbContextOptions<TParentContext> dbContextOptions, IOptions<DatabaseConfiguration> databaseConfigurationOptions, IDatabaseSeeder databaseSeeder, ILogger logger) : base(dbContextOptions)
|
||||
public DatabaseContext(DbContextOptions dbContextOptions, IOptions<DatabaseConfiguration> databaseConfigurationOptions, IDatabaseSeeder databaseSeeder, ILogger logger) : base(dbContextOptions)
|
||||
{
|
||||
DatabaseConfiguration = databaseConfigurationOptions?.Value ?? throw new ArgumentNullException(nameof(databaseConfigurationOptions));
|
||||
this.databaseSeeder = databaseSeeder ?? throw new ArgumentNullException(nameof(databaseSeeder));
|
||||
@@ -410,7 +409,7 @@ namespace Tgstation.Server.Host.Database
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure the <see cref="DatabaseType"/> is correct for the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// Ensure the <see cref="DatabaseType"/> is correct for the <see cref="DatabaseContext"/>.
|
||||
/// </summary>
|
||||
protected abstract void ValidateDatabaseType();
|
||||
}
|
||||
|
||||
@@ -14,12 +14,12 @@ namespace Tgstation.Server.Host.Database
|
||||
sealed class DatabaseSeeder : IDatabaseSeeder
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ICryptographySuite"/> for the <see cref="DatabaseContext{TParentContext}"/>
|
||||
/// The <see cref="ICryptographySuite"/> for the <see cref="DatabaseSeeder"/>
|
||||
/// </summary>
|
||||
readonly ICryptographySuite cryptographySuite;
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IPlatformIdentifier"/> for the <see cref="DatabaseContext{TParentContext}"/>.
|
||||
/// The <see cref="IPlatformIdentifier"/> for the <see cref="DatabaseSeeder"/>.
|
||||
/// </summary>
|
||||
readonly IPlatformIdentifier platformIdentifier;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using Tgstation.Server.Host.Configuration;
|
||||
namespace Tgstation.Server.Host.Database.Design
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains helpers for creating design time <see cref="DatabaseContext{TParentContext}"/>s
|
||||
/// Contains helpers for creating design time <see cref="DatabaseContext"/>s
|
||||
/// </summary>
|
||||
static class DesignTimeDbContextFactoryHelpers
|
||||
{
|
||||
@@ -14,7 +14,7 @@ namespace Tgstation.Server.Host.Database.Design
|
||||
/// <param name="databaseType">The <see cref="DatabaseConfiguration.DatabaseType"/>.</param>
|
||||
/// <param name="connectionString">The <see cref="DatabaseConfiguration.ConnectionString"/>.</param>
|
||||
/// <returns>The <see cref="IOptions{TOptions}"/> for the <see cref="DatabaseConfiguration"/></returns>
|
||||
public static IOptions<DatabaseConfiguration> GetDbContextOptions(DatabaseType databaseType, string connectionString)
|
||||
public static IOptions<DatabaseConfiguration> GetDatabaseConfiguration(DatabaseType databaseType, string connectionString)
|
||||
{
|
||||
var dbConfig = new DatabaseConfiguration
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Database.Design
|
||||
using var loggerFactory = new LoggerFactory();
|
||||
return new MySqlDatabaseContext(
|
||||
new DbContextOptions<MySqlDatabaseContext>(),
|
||||
DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
|
||||
DesignTimeDbContextFactoryHelpers.GetDatabaseConfiguration(
|
||||
DatabaseType.MariaDB,
|
||||
"Server=127.0.0.1;User Id=root;Password=fake;Database=TGS_Design"),
|
||||
new DatabaseSeeder(
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Tgstation.Server.Host.Database.Design
|
||||
using var loggerFactory = new LoggerFactory();
|
||||
return new PostgresSqlDatabaseContext(
|
||||
new DbContextOptions<PostgresSqlDatabaseContext>(),
|
||||
DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
|
||||
DesignTimeDbContextFactoryHelpers.GetDatabaseConfiguration(
|
||||
DatabaseType.PostgresSql,
|
||||
"Application Name=tgstation-server;Host=127.0.0.1;Password=qCkWimNgLfWwpr7TnUHs;Username=postgres;Database=TGS_Design"),
|
||||
new DatabaseSeeder(
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Database.Design
|
||||
using var loggerFactory = new LoggerFactory();
|
||||
return new SqlServerDatabaseContext(
|
||||
new DbContextOptions<SqlServerDatabaseContext>(),
|
||||
DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
|
||||
DesignTimeDbContextFactoryHelpers.GetDatabaseConfiguration(
|
||||
DatabaseType.SqlServer,
|
||||
"Data Source=fake;Initial Catalog=TGS_Design;Integrated Security=True;Application Name=tgstation-server"),
|
||||
new DatabaseSeeder(
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Tgstation.Server.Host.Database.Design
|
||||
using var loggerFactory = new LoggerFactory();
|
||||
return new SqliteDatabaseContext(
|
||||
new DbContextOptions<SqliteDatabaseContext>(),
|
||||
DesignTimeDbContextFactoryHelpers.GetDbContextOptions(
|
||||
DesignTimeDbContextFactoryHelpers.GetDatabaseConfiguration(
|
||||
DatabaseType.Sqlite,
|
||||
"Data Source=tgs_design.sqlite3;Mode=ReadWriteCreate"),
|
||||
new DatabaseSeeder(
|
||||
|
||||
@@ -9,17 +9,17 @@ using Tgstation.Server.Host.Configuration;
|
||||
namespace Tgstation.Server.Host.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DatabaseContext{TParentContext}"/> for MySQL
|
||||
/// <see cref="DatabaseContext"/> for MySQL
|
||||
/// </summary>
|
||||
sealed class MySqlDatabaseContext : DatabaseContext<MySqlDatabaseContext>
|
||||
sealed class MySqlDatabaseContext : DatabaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct a <see cref="MySqlDatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext"/></param>
|
||||
public MySqlDatabaseContext(DbContextOptions<MySqlDatabaseContext> dbContextOptions, IOptions<DatabaseConfiguration> databaseConfiguration, IDatabaseSeeder databaseSeeder, ILogger<MySqlDatabaseContext> logger) : base(dbContextOptions, databaseConfiguration, databaseSeeder, logger)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -8,17 +8,17 @@ using Tgstation.Server.Host.Configuration;
|
||||
namespace Tgstation.Server.Host.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DatabaseContext{TParentContext}"/> for PostgresSQL.
|
||||
/// <see cref="DatabaseContext"/> for PostgresSQL.
|
||||
/// </summary>
|
||||
sealed class PostgresSqlDatabaseContext : DatabaseContext<PostgresSqlDatabaseContext>
|
||||
sealed class PostgresSqlDatabaseContext : DatabaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct a <see cref="SqlServerDatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext"/></param>
|
||||
public PostgresSqlDatabaseContext(
|
||||
DbContextOptions<PostgresSqlDatabaseContext> dbContextOptions,
|
||||
IOptions<DatabaseConfiguration> databaseConfiguration,
|
||||
|
||||
@@ -7,17 +7,17 @@ using Tgstation.Server.Host.Configuration;
|
||||
namespace Tgstation.Server.Host.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DatabaseContext{TParentContext}"/> for Sqlserver
|
||||
/// <see cref="DatabaseContext"/> for Sqlserver
|
||||
/// </summary>
|
||||
sealed class SqlServerDatabaseContext : DatabaseContext<SqlServerDatabaseContext>
|
||||
sealed class SqlServerDatabaseContext : DatabaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct a <see cref="SqlServerDatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext"/></param>
|
||||
public SqlServerDatabaseContext(DbContextOptions<SqlServerDatabaseContext> dbContextOptions, IOptions<DatabaseConfiguration> databaseConfiguration, IDatabaseSeeder databaseSeeder, ILogger<SqlServerDatabaseContext> logger) : base(dbContextOptions, databaseConfiguration, databaseSeeder, logger)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -9,17 +9,17 @@ using Tgstation.Server.Host.Configuration;
|
||||
namespace Tgstation.Server.Host.Database
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="DatabaseContext{TParentContext}"/> for MySQL
|
||||
/// <see cref="DatabaseContext"/> for MySQL
|
||||
/// </summary>
|
||||
sealed class SqliteDatabaseContext : DatabaseContext<SqliteDatabaseContext>
|
||||
sealed class SqliteDatabaseContext : DatabaseContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Construct a <see cref="MySqlDatabaseContext"/>
|
||||
/// </summary>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext{TParentContext}"/></param>
|
||||
/// <param name="dbContextOptions">The <see cref="DbContextOptions{TContext}"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseConfiguration">The <see cref="IOptions{TOptions}"/> of <see cref="DatabaseConfiguration"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="databaseSeeder">The <see cref="IDatabaseSeeder"/> for the <see cref="DatabaseContext"/></param>
|
||||
/// <param name="logger">The <see cref="ILogger"/> for the <see cref="DatabaseContext"/></param>
|
||||
public SqliteDatabaseContext(DbContextOptions<SqliteDatabaseContext> dbContextOptions, IOptions<DatabaseConfiguration> databaseConfiguration, IDatabaseSeeder databaseSeeder, ILogger<SqliteDatabaseContext> logger) : base(dbContextOptions, databaseConfiguration, databaseSeeder, logger)
|
||||
{ }
|
||||
|
||||
|
||||
@@ -107,5 +107,32 @@ namespace Tgstation.Server.Host.Extensions
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add middleware for logging the request number.
|
||||
/// </summary>
|
||||
/// <param name="applicationBuilder">The <see cref="IApplicationBuilder"/> to configure.</param>
|
||||
public static void UseRequestCounting(this IApplicationBuilder applicationBuilder)
|
||||
{
|
||||
if (applicationBuilder == null)
|
||||
throw new ArgumentNullException(nameof(applicationBuilder));
|
||||
|
||||
ulong requestCounter = 0;
|
||||
|
||||
applicationBuilder.Use(async (context, next) =>
|
||||
{
|
||||
var logger = GetLogger(context);
|
||||
var requestNumber = ++requestCounter;
|
||||
logger.LogTrace("Starting request #{0}...", requestNumber);
|
||||
try
|
||||
{
|
||||
await next().ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
logger.LogTrace("Finished request #{0}", requestNumber);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +299,10 @@ namespace Tgstation.Server.Host
|
||||
{
|
||||
await eventsTask.ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
logger.LogError("Restart timeout hit! Existing DreamDaemon processes will be lost and must be killed manually before being restarted with TGS!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError("Restart handlers error! Exception: {0}", e);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"GitHubAccessToken": null,
|
||||
"SetupWizardMode": "AutoDetect",
|
||||
"ByondTopicTimeout": 5000,
|
||||
"RestartTimeout": 10000,
|
||||
"RestartTimeout": 60000,
|
||||
"UseExperimentalWatchdog": false,
|
||||
"UseBasicWatchdogOnWindows": false,
|
||||
"UserLimit": 100,
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
|
||||
world.log << "You really shouldn't be able to read this"
|
||||
|
||||
/world/Export(url)
|
||||
log << "Export: [url]"
|
||||
return ..()
|
||||
|
||||
/world/Topic(T, Addr, Master, Keys)
|
||||
world.log << "Topic: [T]"
|
||||
. = HandleTopic(T)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/world
|
||||
sleep_offline = FALSE
|
||||
|
||||
/world/New()
|
||||
log << "Initial value of sleep_offline: [sleep_offline]"
|
||||
TgsNew(new /datum/tgs_event_handler/impl, TGS_SECURITY_ULTRASAFE)
|
||||
StartAsync()
|
||||
|
||||
@@ -9,17 +13,16 @@
|
||||
/proc/Run()
|
||||
sleep(60)
|
||||
world.TgsChatBroadcast("World Initialized")
|
||||
world.TgsInitializationComplete()
|
||||
// world.TgsInitializationComplete()
|
||||
|
||||
/world/Topic(T, Addr, Master, Keys)
|
||||
world.log << "Topic: [T]"
|
||||
log << "Topic: [T]"
|
||||
. = HandleTopic(T)
|
||||
world.log << "Response: [.]"
|
||||
log << "Response: [.]"
|
||||
|
||||
/world/proc/HandleTopic(T)
|
||||
TGS_TOPIC
|
||||
|
||||
world.sleep_offline = FALSE
|
||||
TgsChatBroadcast("Recieved non-tgs topic: [T]")
|
||||
|
||||
var/list/data = params2list(T)
|
||||
@@ -40,9 +43,14 @@
|
||||
|
||||
world.TgsChatBroadcast("Recieved event: [json_encode(args)]")
|
||||
|
||||
/world/Export(url)
|
||||
log << "Export: [url]"
|
||||
return ..()
|
||||
|
||||
/proc/RebootAsync()
|
||||
set waitfor = FALSE
|
||||
world.sleep_offline = FALSE
|
||||
world.TgsChatBroadcast("Rebooting after 3 seconds");
|
||||
world.log << "About to sleep. sleep_offline: [world.sleep_offline]"
|
||||
sleep(30)
|
||||
world.log << "Done sleep, calling Reboot"
|
||||
world.Reboot()
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
public async Task Run(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: START WATCHDOG TESTS");
|
||||
// Increase startup timeout, disable heartbeats
|
||||
await instanceClient.DreamDaemon.Update(new DreamDaemon
|
||||
{
|
||||
@@ -46,17 +47,18 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
// await RunLongRunningTestThenUpdate(cancellationToken);
|
||||
// await RunLongRunningTestThenUpdateWithByondVersionSwitch(cancellationToken);
|
||||
|
||||
// Remove this deploy when the above tests are reenabled
|
||||
await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, cancellationToken);
|
||||
|
||||
await RunHeartbeatTest(cancellationToken);
|
||||
|
||||
await StartAndLeaveRunning(cancellationToken);
|
||||
global::System.Console.WriteLine("TEST: END WATCHDOG TESTS");
|
||||
}
|
||||
|
||||
async Task RunBasicTest(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: WATCHDOG BASIC TEST");
|
||||
var daemonStatus = await DeployTestDme("BasicOperation/basic_operation_test", DreamDaemonSecurity.Ultrasafe, cancellationToken);
|
||||
|
||||
Assert.IsFalse(daemonStatus.Running.Value);
|
||||
@@ -84,6 +86,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
async Task RunHeartbeatTest(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: WATCHDOG HEARTBEAT TEST");
|
||||
// enable heartbeats
|
||||
await instanceClient.DreamDaemon.Update(new DreamDaemon
|
||||
{
|
||||
@@ -144,6 +147,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
async Task RunLongRunningTestThenUpdate(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: WATCHDOG LONG RUNNING TEST");
|
||||
const string DmeName = "LongRunning/long_running_test";
|
||||
|
||||
var daemonStatus = await DeployTestDme(DmeName, DreamDaemonSecurity.Trusted, cancellationToken);
|
||||
@@ -184,6 +188,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
async Task RunLongRunningTestThenUpdateWithByondVersionSwitch(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: WATCHDOG BYOND VERSION UPDATE TEST");
|
||||
var versionToInstall = new Version(511, 1384, 0);
|
||||
var byondInstallJobTask = instanceClient.Byond.SetActiveVersion(
|
||||
new Api.Models.Byond
|
||||
@@ -232,6 +237,7 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
public async Task StartAndLeaveRunning(CancellationToken cancellationToken)
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: WATCHDOG ENDLESS TEST");
|
||||
var dd = await instanceClient.DreamDaemon.Read(cancellationToken);
|
||||
if(dd.ActiveCompileJob == null)
|
||||
await DeployTestDme("LongRunning/long_running_test", DreamDaemonSecurity.Trusted, cancellationToken);
|
||||
@@ -253,18 +259,16 @@ namespace Tgstation.Server.Tests.Instance
|
||||
|
||||
try
|
||||
{
|
||||
global::System.Console.WriteLine("TEST: Sending world reboot topic...");
|
||||
var result = await bts.SendTopic(IPAddress.Loopback, "tgs_integration_test_special_tactics=1", 1337, cancellationToken);
|
||||
Assert.AreEqual("ack", result.StringData);
|
||||
|
||||
await Task.Delay(7000, cancellationToken);
|
||||
await Task.Delay(10000, cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
async Task<DreamDaemon> DeployTestDme(string dmeName, DreamDaemonSecurity deploymentSecurity, CancellationToken cancellationToken)
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Tgstation.Server.Tests
|
||||
using var hardTimeoutCts = new CancellationTokenSource();
|
||||
hardTimeoutCts.CancelAfter(new TimeSpan(0, 9, 45));
|
||||
var hardTimeoutCancellationToken = hardTimeoutCts.Token;
|
||||
hardTimeoutCancellationToken.Register(() => Console.WriteLine("TEST TIMEOUT HARD!"));
|
||||
hardTimeoutCancellationToken.Register(() => Console.WriteLine($"[{DateTimeOffset.Now}] TEST TIMEOUT HARD!"));
|
||||
|
||||
using var softTimeoutCts = CancellationTokenSource.CreateLinkedTokenSource(hardTimeoutCancellationToken);
|
||||
softTimeoutCts.CancelAfter(new TimeSpan(0, 9, 15));
|
||||
@@ -127,7 +127,7 @@ namespace Tgstation.Server.Tests
|
||||
softTimeoutCancellationToken.Register(() =>
|
||||
{
|
||||
if (!tooLateForSoftTimeout)
|
||||
Console.WriteLine("TEST TIMEOUT SOFT!");
|
||||
Console.WriteLine($"[{DateTimeOffset.Now}] TEST TIMEOUT SOFT!");
|
||||
});
|
||||
|
||||
using var serverCts = CancellationTokenSource.CreateLinkedTokenSource(softTimeoutCancellationToken);
|
||||
@@ -297,7 +297,7 @@ namespace Tgstation.Server.Tests
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"TEST ERROR: {ex.GetType()} in flight!");
|
||||
Console.WriteLine($"[{DateTimeOffset.Now}] TEST ERROR: {ex}");
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
|
||||
Reference in New Issue
Block a user