320 lines
13 KiB
C#
320 lines
13 KiB
C#
using System.Text.Json;
|
|
|
|
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
|
|
|
|
public sealed class LegacyDevelopmentLiveStartupContractTests
|
|
{
|
|
private const string ParityProjectGuid =
|
|
"{0F72B3C8-8A81-4D1E-8E57-0C0E9A9960C1}";
|
|
private const string PrototypeProjectGuid =
|
|
"{E6F5F1A0-D0FD-4E6B-A76D-1E8E3DAE8606}";
|
|
private const string ExactArgument = "--development-live";
|
|
|
|
private static readonly string RepositoryRoot = FindRepositoryRoot();
|
|
private static readonly string ParityRoot = Path.Combine(
|
|
RepositoryRoot,
|
|
"src",
|
|
"MBN_STOCK_WEBVIEW.LegacyParityApp");
|
|
|
|
[Fact]
|
|
public void VisualStudioExposesOneLivePackageProfileWithoutDryRun()
|
|
{
|
|
using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(
|
|
ParityRoot,
|
|
"Properties",
|
|
"launchSettings.json")));
|
|
var profile = Assert.Single(document.RootElement.GetProperty("profiles")
|
|
.EnumerateObject());
|
|
|
|
Assert.Contains("Live", profile.Name, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("DryRun", profile.Name, StringComparison.Ordinal);
|
|
Assert.Equal("MsixPackage", profile.Value.GetProperty("commandName").GetString());
|
|
var arguments = profile.Value.TryGetProperty("commandLineArgs", out var value)
|
|
? value.GetString()
|
|
: null;
|
|
Assert.True(
|
|
string.IsNullOrEmpty(arguments) ||
|
|
string.Equals(arguments, ExactArgument, StringComparison.Ordinal),
|
|
"The sole Live package profile may use only the normal launch or exact Live argument.");
|
|
}
|
|
|
|
[Fact]
|
|
public void SharedSolutionLaunchStartsOnlyTheLegacyParityApp()
|
|
{
|
|
using var document = JsonDocument.Parse(File.ReadAllText(Path.Combine(
|
|
RepositoryRoot,
|
|
"MBN_STOCK_WEBVIEW.slnLaunch")));
|
|
var profile = Assert.Single(document.RootElement.EnumerateArray());
|
|
Assert.Equal("Legacy Parity App (VS F5)", profile.GetProperty("Name").GetString());
|
|
var project = Assert.Single(profile.GetProperty("Projects").EnumerateArray());
|
|
Assert.Equal(
|
|
"src\\MBN_STOCK_WEBVIEW.LegacyParityApp\\MBN_STOCK_WEBVIEW.LegacyParityApp.csproj",
|
|
project.GetProperty("Path").GetString());
|
|
Assert.Equal("Start", project.GetProperty("Action").GetString());
|
|
}
|
|
|
|
[Fact]
|
|
public void NormalDebugDeployTargetsParityInsteadOfThePrototype()
|
|
{
|
|
var solution = File.ReadAllText(Path.Combine(
|
|
RepositoryRoot,
|
|
"MBN_STOCK_WEBVIEW.sln"));
|
|
|
|
Assert.Contains(
|
|
$"{ParityProjectGuid}.Debug|x64.Deploy.0 = Debug|x64",
|
|
solution,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain(
|
|
$"{PrototypeProjectGuid}.Debug|x64.Deploy.0 = Debug|x64",
|
|
solution,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppAppliesRuntimeGateBeforeConstructingAnyRuntimeWindow()
|
|
{
|
|
var app = File.ReadAllText(Path.Combine(ParityRoot, "App.xaml.cs"));
|
|
var bootstrap = app.IndexOf(
|
|
"DevelopmentLiveLaunchBootstrap.TryApply(",
|
|
StringComparison.Ordinal);
|
|
var constructSetupWindow = app.IndexOf(
|
|
"new FirstRunSetupWindow()",
|
|
StringComparison.Ordinal);
|
|
var constructMainWindow = app.IndexOf(
|
|
"new MainWindow();",
|
|
StringComparison.Ordinal);
|
|
var sourceOnlyDirective = app.IndexOf(
|
|
"#if SOURCE_ONLY_RUNTIME",
|
|
StringComparison.Ordinal);
|
|
var fullRuntimeDirective = app.IndexOf(
|
|
"#else",
|
|
constructSetupWindow,
|
|
StringComparison.Ordinal);
|
|
var runtimeEndDirective = app.IndexOf(
|
|
"#endif",
|
|
constructMainWindow,
|
|
StringComparison.Ordinal);
|
|
|
|
Assert.True(bootstrap >= 0);
|
|
Assert.True(sourceOnlyDirective >= 0);
|
|
Assert.True(constructSetupWindow > sourceOnlyDirective);
|
|
Assert.True(fullRuntimeDirective > constructSetupWindow);
|
|
Assert.True(bootstrap > fullRuntimeDirective);
|
|
Assert.True(constructMainWindow > bootstrap);
|
|
Assert.True(runtimeEndDirective > constructMainWindow);
|
|
Assert.Contains("args.Arguments", app, StringComparison.Ordinal);
|
|
Assert.Contains("Environment.GetCommandLineArgs()", app, StringComparison.Ordinal);
|
|
Assert.Contains("ResolveLaunchArguments(", app, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"IsDevelopmentLiveLaunchRequested = developmentLive.IsRequested;",
|
|
app,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"IsDevelopmentLiveLaunch = developmentLive.IsApplied;",
|
|
app,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("#if DEBUG", app, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliedDevelopmentLiveUsesSelectedRuntimePathsAndSelectedResDatabaseAuthority()
|
|
{
|
|
var window = File.ReadAllText(Path.Combine(ParityRoot, "MainWindow.xaml.cs"));
|
|
var playout = File.ReadAllText(Path.Combine(
|
|
ParityRoot,
|
|
"MainWindow.Playout.cs"));
|
|
|
|
Assert.Contains(
|
|
"_isDevelopmentLiveLaunch = App.IsDevelopmentLiveLaunch;",
|
|
window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"_isDevelopmentLiveLaunchRequested = App.IsDevelopmentLiveLaunchRequested;",
|
|
window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"var selectedResourceDirectory =\n" +
|
|
" _appliedOperatorSettings.ResourceDirectory;",
|
|
window.ReplaceLineEndings("\n"),
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"LegacyRuntimeStockCutMenuLoader.ResolveFromResourceDirectory(",
|
|
window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"var selectedLegacyDatabaseIni =\n" +
|
|
" selectedResourceDirectory is null\n" +
|
|
" ? null",
|
|
window.ReplaceLineEndings("\n"),
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"? DatabaseRuntime.CreateDevelopmentLiveLocalOverride(\n" +
|
|
" selectedResourceDirectory)",
|
|
window.ReplaceLineEndings("\n"),
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"? PlayoutOptionsLoader.LoadDevelopmentLive(",
|
|
playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"operatorSceneDirectory:\n" +
|
|
" _appliedOperatorSettings.SceneDirectory",
|
|
playout.ReplaceLineEndings("\n"),
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("forceSafeDryRun", playout, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"if (_playoutOptions.Mode != PlayoutMode.Live)",
|
|
playout,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void InvalidDevelopmentLiveDatabaseConfigurationBlocksEngineAndAutomaticConnect()
|
|
{
|
|
var window = File.ReadAllText(Path.Combine(ParityRoot, "MainWindow.xaml.cs"))
|
|
.ReplaceLineEndings("\n");
|
|
var playout = File.ReadAllText(Path.Combine(
|
|
ParityRoot,
|
|
"MainWindow.Playout.cs"))
|
|
.ReplaceLineEndings("\n");
|
|
|
|
var databaseFailureCondition = window.IndexOf(
|
|
"_isDevelopmentLiveLaunch &&\n" +
|
|
" exception is DatabaseConfigurationException;",
|
|
StringComparison.Ordinal);
|
|
var startupBlock = window.IndexOf(
|
|
"_developmentLiveStartupBlocked = true;",
|
|
databaseFailureCondition,
|
|
StringComparison.Ordinal);
|
|
var safeMessage = window.IndexOf(
|
|
"\"Development Live 데이터베이스 설정을 확인할 수 없습니다.\"",
|
|
startupBlock,
|
|
StringComparison.Ordinal);
|
|
var playoutInitialization = window.IndexOf(
|
|
"InitializePlayoutRuntime();",
|
|
safeMessage,
|
|
StringComparison.Ordinal);
|
|
var automaticConnectGuard = window.IndexOf(
|
|
"if (!_developmentLiveStartupBlocked)",
|
|
playoutInitialization,
|
|
StringComparison.Ordinal);
|
|
var automaticConnect = window.IndexOf(
|
|
"await ConnectPlayoutAsync(_lifetimeCancellation.Token);",
|
|
automaticConnectGuard,
|
|
StringComparison.Ordinal);
|
|
var earlyBlock = playout.IndexOf(
|
|
"if (_developmentLiveStartupBlocked)",
|
|
StringComparison.Ordinal);
|
|
var earlyReturn = playout.IndexOf(
|
|
"return;",
|
|
earlyBlock,
|
|
StringComparison.Ordinal);
|
|
var createEngine = playout.IndexOf(
|
|
"_playoutEngine = PlayoutEngineFactory.Create(",
|
|
StringComparison.Ordinal);
|
|
|
|
Assert.True(databaseFailureCondition >= 0);
|
|
Assert.True(startupBlock > databaseFailureCondition);
|
|
Assert.True(safeMessage > startupBlock);
|
|
Assert.True(playoutInitialization > safeMessage);
|
|
Assert.True(automaticConnectGuard > playoutInitialization);
|
|
Assert.True(automaticConnect > automaticConnectGuard);
|
|
Assert.True(earlyBlock >= 0);
|
|
Assert.True(earlyReturn > earlyBlock);
|
|
Assert.True(createEngine > earlyReturn);
|
|
}
|
|
|
|
[Fact]
|
|
public void BootstrapOrPlayoutInvariantFailureBlocksEngineAndAutomaticConnect()
|
|
{
|
|
var window = File.ReadAllText(Path.Combine(ParityRoot, "MainWindow.xaml.cs"))
|
|
.ReplaceLineEndings("\n");
|
|
var playout = File.ReadAllText(Path.Combine(
|
|
ParityRoot,
|
|
"MainWindow.Playout.cs"))
|
|
.ReplaceLineEndings("\n");
|
|
|
|
var initialBlock = window.IndexOf(
|
|
"_developmentLiveStartupBlocked =\n" +
|
|
" _isDevelopmentLiveLaunchRequested &&\n" +
|
|
" !_isDevelopmentLiveLaunch;",
|
|
StringComparison.Ordinal);
|
|
var earlyBlock = playout.IndexOf(
|
|
"if (_developmentLiveStartupBlocked)",
|
|
StringComparison.Ordinal);
|
|
var earlyReturn = playout.IndexOf("return;", earlyBlock, StringComparison.Ordinal);
|
|
var loadLive = playout.IndexOf(
|
|
"PlayoutOptionsLoader.LoadDevelopmentLive(",
|
|
StringComparison.Ordinal);
|
|
var requireLive = playout.IndexOf(
|
|
"if (_playoutOptions.Mode != PlayoutMode.Live)",
|
|
StringComparison.Ordinal);
|
|
var createEngine = playout.IndexOf(
|
|
"_playoutEngine = PlayoutEngineFactory.Create(",
|
|
StringComparison.Ordinal);
|
|
var blockOnInitializationFailure = playout.IndexOf(
|
|
"_developmentLiveStartupBlocked = true;",
|
|
createEngine,
|
|
StringComparison.Ordinal);
|
|
|
|
Assert.True(initialBlock >= 0);
|
|
Assert.True(earlyBlock >= 0);
|
|
Assert.True(earlyReturn > earlyBlock);
|
|
Assert.True(loadLive > earlyReturn);
|
|
Assert.True(requireLive > loadLive);
|
|
Assert.True(createEngine > requireLive);
|
|
Assert.True(blockOnInitializationFailure > createEngine);
|
|
Assert.DoesNotContain("forceSafeDryRun", playout, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"if (!_developmentLiveStartupBlocked)\n" +
|
|
" {\n" +
|
|
" await ConnectPlayoutAsync(_lifetimeCancellation.Token);",
|
|
window,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void TrackedExampleContainsOnlyNonUsableHashPlaceholders()
|
|
{
|
|
var example = File.ReadAllText(Path.Combine(
|
|
RepositoryRoot,
|
|
"Config",
|
|
"playout.development-live.example.json"));
|
|
using var document = JsonDocument.Parse(example);
|
|
var root = document.RootElement;
|
|
|
|
Assert.Equal(1, root.GetProperty("schemaVersion").GetInt32());
|
|
Assert.Equal("Live", root.GetProperty("mode").GetString());
|
|
Assert.StartsWith("<64-HEX-", root.GetProperty("nativeSha256").GetString());
|
|
Assert.StartsWith("<64-HEX-", root.GetProperty("interopSha256").GetString());
|
|
Assert.DoesNotContain(":\\", example, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void RealDevelopmentAuthorizationFileIsIgnoredEverywhere()
|
|
{
|
|
var ignore = File.ReadAllText(Path.Combine(RepositoryRoot, ".gitignore"));
|
|
|
|
Assert.Contains("Config/playout.development-live.local.json", ignore,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("**/playout.development-live.local.json", ignore,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
private static string FindRepositoryRoot()
|
|
{
|
|
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (current is not null)
|
|
{
|
|
if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln")))
|
|
{
|
|
return current.FullName;
|
|
}
|
|
|
|
current = current.Parent;
|
|
}
|
|
|
|
throw new DirectoryNotFoundException("Repository root was not found.");
|
|
}
|
|
}
|