Merge branch 'dev' into 1169-DMAPISeparation

This commit is contained in:
Jordan Brown
2021-01-21 20:27:58 -05:00
committed by GitHub
22 changed files with 241 additions and 115 deletions
+1
View File
@@ -26,6 +26,7 @@ src/DMAPI
src/Tgstation.Server.Host/ClientApp
src/Tgstation.Server.Host/wwwroot
src/Tgstation.Server.Host/appsettings.Development.json
src/Tgstation.Server.Host/appsettings.Development.yml
src/Tgstation.Server.Host/tgs.bat
src/Tgstation.Server.Host/tgs.sh
src/Tgstation.Server.Client
+1 -1
View File
@@ -197,7 +197,7 @@ OAuth providers are hardcoded but it is fairly easy to add new ones. The flow do
1. Create an implementation of [IOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/IOAuthValidator.cs).
- Most providers can simply override the [GenericOAuthValidator](../src/Tgstation.Server.Host/Security/OAuth/GenericOAuthValidator.cs).
1. Construct the implementation in the [OAuthProviders](../src/Tgstation.Server.Host/Security/OAuth/OAuthProviders.cs) class.
1. Add a null entry to the default [appsettings.json](../src/Tgstation.Server.Host/appsettings.json).
1. Add a null entry to the default [appsettings.yml](../src/Tgstation.Server.Host/appsettings.yml).
1. Update the main [README.md](../README.md) to indicate the new provider.
1. Update the [API documentation](../docs/API.dox) to indicate the new provider.
+1
View File
@@ -15,6 +15,7 @@ artifacts/
*.int
*.lk
/src/Tgstation.Server.Host/appsettings.*.json
/src/Tgstation.Server.Host/appsettings.*.yml
/src/Tgstation.Server.Host/wwwroot
/src/Tgstation.Server.Host/ClientApp
/tools/ReleaseNotes/release_notes.md
+14 -19
View File
@@ -80,19 +80,19 @@ Note that this container is meant to be long running. Updates are handled intern
Note that automatic configuration reloading is currently not supported in the container. See #1143
If using manual configuration, before starting your container make sure the aforementioned `appsettings.Production.json` is setup properly. See below
If using manual configuration, before starting your container make sure the aforementioned `appsettings.Production.yml` is setup properly. See below
### Configuring
The first time you run TGS4 you should be prompted with a configuration wizard which will guide you through setting up your appsettings.Production.json
The first time you run TGS4 you should be prompted with a configuration wizard which will guide you through setting up your `appsettings.Production.yml`
This wizard will, generally, run whenever the server is launched without detecting the config json. Follow the instructions below to perform this process manually.
This wizard will, generally, run whenever the server is launched without detecting the config yml. Follow the instructions below to perform this process manually.
#### Configuration Methods
There are 3 primary supported ways to configure TGS:
- Modify the `appsettings.Production.json` file (Recommended).
- Modify the `appsettings.Production.yml` file (Recommended).
- Set environment variables in the form `Section__Subsection=value` or `Section__ArraySubsection__0=value` for arrays.
- Set command line arguments in the form `--Section:Subsection=value` or `--Section:ArraySubsection:0=value` for arrays.
@@ -100,7 +100,7 @@ The latter two are not recommended as they cannot be dynamically changed at runt
#### Manual Configuration
Create an `appsettings.Production.json` file next to `appsettings.json`. This will override the default settings in appsettings.json with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive:
Create an `appsettings.Production.yml` file next to `appsettings.yml`. This will override the default settings in `appsettings.yml` with your production settings. There are a few keys meant to be changed by hosts. Modifying any config files while the server is running will trigger a safe restart (Keeps DreamDaemon instances running). Note these are all case-sensitive:
- `General:ConfigVersion`: Suppresses warnings about out of date config versions. You should change this after updating TGS to one with a new config version. The current version can be found on the releases page for your server version (This field did not exist before v4.4.0).
@@ -143,19 +143,14 @@ Create an `appsettings.Production.json` file next to `appsettings.json`. This wi
- `Swarm:Identifier` should be set uniquely on all swarmed servers. Used to identify the current server. This is also used to select which instances exist on the current machine and should not be changed post-setup.
- `Security:OAuth:<Provider Name>`: Sets the OAuth client ID and secret for a given `<Provider Name>`. The currently supported providers are `GitHub`, `Discord`, and `TGForums`. Setting these fields to `null` disables logins with the provider, but does not stop users from associating their accounts using the API. Sample Entry:
```json
{
"Security": {
"OAuth": {
"Keycloak": {
"ClientId": "...",
"ClientSecret": "...",
"RedirectUrl": "...",
"ServerUrl": "..."
}
}
}
}
```yml
Security:
OAuth:
Keycloak:
ClientId: "..."
ClientSecret: "..."
RedirectUrl: "..."
ServerUrl: "..."
```
The following providers use the `RedirectUrl` setting:
@@ -252,7 +247,7 @@ var/global/client_count = 0
## Remote Access
tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) app based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration JSON. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details.
tgstation-server is an [ASP.Net Core](https://docs.microsoft.com/en-us/aspnet/core/) app based on the Kestrel web server. This section is meant to serve as a general use case overview, but the entire Kestrel configuration can be modified to your liking with the configuration YAML. See [the official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel) for details.
Exposing the builtin Kestrel server to the internet directly over HTTP is highly not reccommended due to the lack of security. The recommended way to expose tgstation-server to the internet is to host it through a reverse proxy with HTTPS support. Here are some step by step examples to achieve this for major web servers.
+1 -1
View File
@@ -4,7 +4,7 @@
<Import Project="ControlPanelVersion.props" />
<PropertyGroup>
<TgsCoreVersion>4.7.3</TgsCoreVersion>
<TgsConfigVersion>2.2.0</TgsConfigVersion>
<TgsConfigVersion>2.3.0</TgsConfigVersion>
<TgsApiVersion>8.3.0</TgsApiVersion>
<TgsClientVersion>9.1.2</TgsClientVersion>
<TgsDmapiVersion>6.0.0</TgsDmapiVersion>
+2 -2
View File
@@ -5,8 +5,8 @@ SCRIPT_VERSION="1.2.0"
echo "tgstation-server 4 container startup script v$SCRIPT_VERSION"
echo "PWD: $PWD"
PROD_CONFIG=/config_data/appsettings.Production.json
HOST_CONFIG=/app/appsettings.Production.json
PROD_CONFIG=/config_data/appsettings.Production.yml
HOST_CONFIG=/app/appsettings.Production.yml
if [ ! -f $PROD_CONFIG ]; then
echo "$PROD_CONFIG not detected! Creating empty and running setup wizard..."
+1 -1
View File
@@ -23,7 +23,7 @@ This is a second process spawned by the Host Watchdog which facilitates the vast
The server's entrypoint is in the @ref Tgstation.Server.Host.Program class. This class mainly determines if the Host watchdog is present and creates and runs the @ref Tgstation.Server.Host.Server class. That class then builds an ASP.NET Core web host using the @ref Tgstation.Server.Host.Core.Application class.
The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appSettings.json into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers:
The @ref Tgstation.Server.Host.Core.Application class has two methods called by the framework. First the @ref Tgstation.Server.Host.Core.Application.ConfigureServices method sets up dependency injection of interfaces for Controllers, the @ref Tgstation.Server.Host.Database.DatabaseContext, and the component factories of the server. The framework handles constructing these things once the application starts. Configuration is loaded from the appropriate appsettings.yml into the @ref Tgstation.Server.Host.Configuration classes for injection as well. Then @ref Tgstation.Server.Host.Core.Application.Configure method is run which sets up the web request pipeline which currently has the following stack of handlers:
- Catch any exceptions and respond with 500 and detailed HTML error page
- Respond with 503 if the application is still starting or shutting down
@@ -33,7 +33,7 @@
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<None Update="appsettings.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
@@ -96,10 +96,10 @@ namespace Tgstation.Server.Host.Watchdog
foreach (string newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories))
File.Copy(newPath, newPath.Replace(sourcePath, defaultAssemblyPath), true);
const string AppSettingsJson = "appsettings.json";
var rootJson = Path.Combine(rootLocation, AppSettingsJson);
File.Delete(rootJson);
File.Move(Path.Combine(defaultAssemblyPath, AppSettingsJson), rootJson);
const string AppSettingsYaml = "appsettings.yml";
var rootYaml = Path.Combine(rootLocation, AppSettingsYaml);
File.Delete(rootYaml);
File.Move(Path.Combine(defaultAssemblyPath, AppSettingsYaml), rootYaml);
}
else
Directory.CreateDirectory(assemblyStoragePath);
@@ -1,5 +1,5 @@
# Configuration Classes
These types map directly to the settings used in the [appsettings.json](../appsettings.json) file and its derivatives. See the [Microsoft Docs on the ASP .NET Core configuration system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1) for details.
These types map directly to the settings used in the [appsettings.yml](../appsettings.yml) file and its derivatives. See the [Microsoft Docs on the ASP .NET Core configuration system](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1) for details.
When making changes here, it's important to also update the config version in [build/Version.props](../../../build/Version.props) according to semver semantics. You'll also need to update the constant in [GeneralConfiguration.cs](./GeneralConfigration.cs).
When making changes here, it's important to also update the config version in [build/Version.props](../../../build/Version.props) according to semver semantics. You'll also need to update the constant in [GeneralConfiguration.cs](./GeneralConfigration.cs).
@@ -1,4 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using System;
using Tgstation.Server.Host.Configuration;
@@ -1,14 +1,35 @@
using Newtonsoft.Json;
using System;
using Tgstation.Server.Api;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;
namespace Tgstation.Server.Host.Extensions.Converters
{
/// <summary>
/// <see cref="JsonConverter"/> for serializing <see cref="Version"/>s for BYOND.
/// <see cref="JsonConverter"/> and <see cref="IYamlTypeConverter"/> for serializing <see cref="global::System.Version"/>s for BYOND.
/// </summary>
sealed class VersionConverter : JsonConverter
sealed class VersionConverter : JsonConverter, IYamlTypeConverter
{
/// <summary>
/// Check if the <see cref="VersionConverter"/> supports (de)serializing a given <paramref name="type"/>.
/// </summary>
/// <param name="type">The <see cref="Type"/> to check.</param>
/// <param name="validate">If the method should <see langword="throw"/> if validation fails.</param>
/// <returns><see langword="true"/> if <paramref name="type"/> is a <see cref="global::System.Version"/>, <see langword="false"/> otherwise.</returns>
static bool CheckSupportsType(Type type, bool validate)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
var supported = type == typeof(global::System.Version);
if (!supported && validate)
throw new NotSupportedException($"{nameof(VersionConverter)} does not convert {type}s!");
return supported;
}
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
@@ -16,7 +37,7 @@ namespace Tgstation.Server.Host.Extensions.Converters
{
writer.WriteNull();
}
else if (value is Version version)
else if (value is global::System.Version version)
{
writer.WriteValue(version.Semver().ToString());
}
@@ -29,6 +50,11 @@ namespace Tgstation.Server.Host.Extensions.Converters
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
CheckSupportsType(objectType, true);
if (reader.TokenType == JsonToken.Null)
return null;
@@ -36,7 +62,7 @@ namespace Tgstation.Server.Host.Extensions.Converters
{
try
{
Version v = new Version((string)reader.Value);
var v = global::System.Version.Parse((string)reader.Value);
return v.Semver();
}
catch (Exception ex)
@@ -50,6 +76,40 @@ namespace Tgstation.Server.Host.Extensions.Converters
}
/// <inheritdoc />
public override bool CanConvert(Type objectType) => objectType == typeof(Version);
public override bool CanConvert(Type objectType) => CheckSupportsType(objectType, false);
/// <inheritdoc />
public bool Accepts(Type type) => CheckSupportsType(type, false);
/// <inheritdoc />
public object ReadYaml(IParser parser, Type type)
{
if (parser == null)
throw new ArgumentNullException(nameof(parser));
CheckSupportsType(type, true);
var scalar = parser.Consume<Scalar>();
if (scalar == null)
return null;
return global::System.Version.Parse(scalar.Value);
}
/// <inheritdoc />
public void WriteYaml(IEmitter emitter, object value, Type type)
{
if (emitter == null)
throw new ArgumentNullException(nameof(emitter));
CheckSupportsType(type, true);
var version = (global::System.Version)value;
emitter.Emit(
new Scalar(
version
?.Semver()
.ToString()));
}
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ Here's a breakdown of things in this directory
- [.config](./.config) contains the dotnet-tools.json. At the time of writing, this is only used to set the version of the [dotnet ef tools](https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/) used to create database migrations.
- [ClientApp](./ClientApp) contains scripts to build and deploy the web control panel with TGS.
- [Components](./Components) is where the bulk of the TGS implementation lives.
- [Configuration](./Configuration) contains classes that partly make up the configuration json files (i.e. [appsettings.json](./appsettings.json)).
- [Configuration](./Configuration) contains classes that partly make up the configuration yaml files (i.e. [appsettings.yml](./appsettings.yml)).
- [Controllers](./Controllers) is where HTTP API code lives and bridges it with component code.
- [Core](./Core) contains [Application.cs](./Core/Application.cs) and other various helpers that don't belong anywhere else.
- [Database](./Database) contains all database related code.
+19 -1
View File
@@ -49,7 +49,25 @@ namespace Tgstation.Server.Host
var basePath = IOManager.ResolvePath();
IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, configuration) => configuration.SetBasePath(basePath));
.ConfigureAppConfiguration((context, builder) =>
{
builder.SetBasePath(basePath);
builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true)
.AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true);
// reorganize the builder so our yaml configs don't override the env/cmdline configs
// values obtained via debugger
var environmentJsonConfig = builder.Sources[2];
var envConfig = builder.Sources[3];
var cmdLineConfig = builder.Sources[4];
var baseYmlConfig = builder.Sources[5];
var environmentYmlConfig = builder.Sources[6];
builder.Sources[2] = baseYmlConfig;
builder.Sources[3] = environmentJsonConfig;
builder.Sources[4] = environmentYmlConfig;
builder.Sources[5] = envConfig;
builder.Sources[6] = cmdLineConfig;
});
var setupWizardHostBuilder = CreateDefaultBuilder()
.UseSetupApplication();
+12 -6
View File
@@ -4,7 +4,6 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MySql.Data.MySqlClient;
using Newtonsoft.Json;
using Npgsql;
using System;
using System.Collections.Generic;
@@ -20,8 +19,10 @@ using System.Threading.Tasks;
using Tgstation.Server.Host.Configuration;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Database;
using Tgstation.Server.Host.Extensions.Converters;
using Tgstation.Server.Host.IO;
using Tgstation.Server.Host.System;
using YamlDotNet.Serialization;
namespace Tgstation.Server.Host.Setup
{
@@ -841,8 +842,13 @@ namespace Tgstation.Server.Host.Setup
{ SwarmConfiguration.Section, swarmConfiguration },
};
var json = JsonConvert.SerializeObject(map, Formatting.Indented);
var configBytes = Encoding.UTF8.GetBytes(json);
var serializer = new SerializerBuilder()
.WithTypeConverter(new VersionConverter())
.Build();
var serializedYaml = serializer.Serialize(map);
var configBytes = Encoding.UTF8.GetBytes(serializedYaml);
reloadTcs = new TaskCompletionSource<object>();
@@ -863,9 +869,9 @@ namespace Tgstation.Server.Host.Setup
{
await console.WriteAsync(e.Message, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync("For your convienence, here's the json we tried to write out:", true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync("For your convienence, here's the yaml we tried to write out:", true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(json, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(serializedYaml, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync(null, true, cancellationToken).ConfigureAwait(false);
await console.WriteAsync("Press any key to exit...", true, cancellationToken).ConfigureAwait(false);
await console.PressAnyKeyAsync(cancellationToken).ConfigureAwait(false);
@@ -930,7 +936,7 @@ namespace Tgstation.Server.Host.Setup
return;
}
var userConfigFileName = String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.json", hostingEnvironment.EnvironmentName);
var userConfigFileName = String.Format(CultureInfo.InvariantCulture, "appsettings.{0}.yml", hostingEnvironment.EnvironmentName);
async Task HandleSetupCancel()
{
@@ -6,7 +6,7 @@ namespace Tgstation.Server.Host.Setup
public enum SetupWizardMode
{
/// <summary>
/// Run the wizard if the appsettings.{Environment}.json is not present or empty.
/// Run the wizard if the appsettings.{Environment}.yml is not present or empty.
/// </summary>
Autodetect,
@@ -84,6 +84,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.10" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" />
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="2.1.0" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Octokit" Version="0.48.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.2.4" />
@@ -119,7 +120,11 @@
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.json">
<Content Include="appsettings.yml" />
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.yml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
@@ -1,66 +0,0 @@
{
"General": {
"MinimumPasswordLength": 15,
"GitHubAccessToken": null,
"SetupWizardMode": "AutoDetect",
"ByondTopicTimeout": 5000,
"RestartTimeout": 60000,
"ApiPort": 5000,
"UseBasicWatchdog": false,
"UserLimit": 100,
"UserGroupLimit": 25,
"InstanceLimit": 10,
"ValidInstancePaths": null,
"HostApiDocumentation": false
},
"FileLogging": {
"Directory": null,
"Disable": false,
"LogLevel": "Debug",
"MicrosoftLogLevel": "Warning"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information"
}
},
"Console": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning"
}
}
},
"ControlPanel": {
"Enable": false,
"AllowAnyOrigin": false,
"AllowedOrigins": []
},
"Updates": {
"GitHubRepositoryId": 92952846,
"GitTagPrefix": "tgstation-server-v",
"UpdatePackageAssetName": "ServerUpdatePackage.zip"
},
"Database": {
"DropDatabase": false,
"DatabaseType": "SqlServer",
"ResetAdminPassword": false,
"ServerVersion": null,
"ConnectionString": "Data Source=(local);Initial Catalog=TGS;Integrated Security=True"
},
"Security": {
"TokenExpiryMinutes": 15,
"TokenClockSkewMinutes": 1,
"TokenSigningKeyByteAmount": 256,
"CustomTokenSigningKeyBase64": null,
"OAuth": {
"GitHub": null,
"Discord": null,
"TGForums": null,
"Keycloak": null
}
}
}
+52
View File
@@ -0,0 +1,52 @@
General:
MinimumPasswordLength: 15
GitHubAccessToken:
SetupWizardMode: AutoDetect
ByondTopicTimeout: 5000
RestartTimeout: 60000
ApiPort: 5000
UseBasicWatchdog: false
UserLimit: 100
UserGroupLimit: 25
InstanceLimit: 10
ValidInstancePaths:
HostApiDocumentation: false
FileLogging:
Directory:
Disable: false
LogLevel: Debug
MicrosoftLogLevel: Warning
Logging:
IncludeScopes: false
Debug:
LogLevel:
Default: Debug
Microsoft: Information
Console:
LogLevel:
Default: Trace
Microsoft: Warning
ControlPanel:
Enable: false
AllowAnyOrigin: false
AllowedOrigins: []
Updates:
GitHubRepositoryId: 92952846
GitTagPrefix: tgstation-server-v
UpdatePackageAssetName: ServerUpdatePackage.zip
Database:
DropDatabase: false
DatabaseType: SqlServer
ResetAdminPassword: false
ServerVersion:
ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True
Security:
TokenExpiryMinutes: 15
TokenClockSkewMinutes: 1
TokenSigningKeyByteAmount: 256
CustomTokenSigningKeyBase64:
OAuth:
GitHub:
Discord:
TGForums:
Keycloak:
@@ -0,0 +1,52 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using Tgstation.Server.Api;
using YamlDotNet.Serialization;
namespace Tgstation.Server.Host.Extensions.Converters.Tests
{
[TestClass]
public sealed class TestVersionConverter
{
class TestObject
{
public Version Version { get; set; }
}
readonly Version testVersion;
readonly string testYaml;
public TestVersionConverter()
{
testVersion = new Version(1, 2, 3);
testYaml = $@"{nameof(TestObject.Version)}: {testVersion.Semver()}";
}
[TestMethod]
public void TestYamlSerialization()
{
var testObj = new TestObject
{
Version = testVersion
};
var serializedString = new SerializerBuilder()
.WithTypeConverter(new VersionConverter())
.Build()
.Serialize(testObj);
Assert.AreEqual(testYaml, serializedString.Trim());
}
[TestMethod]
public void TestYamlDeserialization()
{
var deserialized = new DeserializerBuilder()
.WithTypeConverter(new VersionConverter())
.Build()
.Deserialize<TestObject>(testYaml);
Assert.AreEqual(testVersion, deserialized.Version);
}
}
}
@@ -1,4 +1,4 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
@@ -16,7 +16,9 @@ namespace Tgstation.Server.Host.Extensions.Tests
class BadConfig1
{
#pragma warning disable IDE0051 // Remove unused private members
const string Section = "asdf";
#pragma warning restore IDE0051 // Remove unused private members
}
class BadConfig2
@@ -110,7 +110,7 @@ namespace Tgstation.Server.Tests
args.Add($"Security:OAuth=null");
// SPECIFICALLY DELETE THE DEV APPSETTINGS, WE DON'T WANT IT IN THE WAY
File.Delete("appsettings.Development.json");
File.Delete("appsettings.Development.yml");
if (!String.IsNullOrEmpty(gitHubAccessToken))
args.Add(String.Format(CultureInfo.InvariantCulture, "General:GitHubAccessToken={0}", gitHubAccessToken));