mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-04 19:45:00 +03:00
fix(webapi): preserve Unix environment names and isolate test fixtures (#10455)
* fix(webapi): preserve Unix environment names and isolate local test fixtures * test(webapi): isolate launcher fixtures from host process IDs * test(webapi): allow auth fixture scheduling headroom
This commit is contained in:
committed by
GitHub
parent
ebabf79017
commit
743eb323c2
@@ -109,7 +109,8 @@ public static class LauncherEnvironment
|
|||||||
public static Dictionary<string, string?> ReadCurrentEnvironment() =>
|
public static Dictionary<string, string?> ReadCurrentEnvironment() =>
|
||||||
Environment.GetEnvironmentVariables()
|
Environment.GetEnvironmentVariables()
|
||||||
.Cast<System.Collections.DictionaryEntry>()
|
.Cast<System.Collections.DictionaryEntry>()
|
||||||
.ToDictionary(entry => (string)entry.Key, entry => entry.Value?.ToString(), StringComparer.OrdinalIgnoreCase);
|
.ToDictionary(entry => (string)entry.Key, entry => entry.Value?.ToString(),
|
||||||
|
OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal);
|
||||||
|
|
||||||
private static bool HasValue(IReadOnlyDictionary<string, string?> environment, string key) =>
|
private static bool HasValue(IReadOnlyDictionary<string, string?> environment, string key) =>
|
||||||
environment.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value);
|
environment.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value);
|
||||||
|
|||||||
@@ -178,7 +178,8 @@ public class CoreProcessTrackerTests
|
|||||||
|
|
||||||
private static string CopySleepExecutable(string directory)
|
private static string CopySleepExecutable(string directory)
|
||||||
{
|
{
|
||||||
var executable = Path.Combine(directory, "sleep-core-test");
|
// Multicall implementations dispatch by basename, so preserve the sleep utility name.
|
||||||
|
var executable = Path.Combine(directory, "sleep");
|
||||||
File.Copy("/bin/sleep", executable);
|
File.Copy("/bin/sleep", executable);
|
||||||
return executable;
|
return executable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using v2rayN.WebAPI.Launcher;
|
||||||
|
|
||||||
|
namespace v2rayN.WebAPI.Tests;
|
||||||
|
|
||||||
|
[NotInParallel]
|
||||||
|
public class LauncherEnvironmentTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
[Arguments("same-value", "same-value")]
|
||||||
|
[Arguments("upper-value", "lower-value")]
|
||||||
|
public async Task CurrentEnvironmentPreservesPlatformVariableNameSemantics(string upperValue, string lowerValue)
|
||||||
|
{
|
||||||
|
var upperName = $"V2RAYN_ENVIRONMENT_TEST_{Guid.NewGuid():N}".ToUpperInvariant();
|
||||||
|
var lowerName = upperName.ToLowerInvariant();
|
||||||
|
using var environmentScope = new TemporaryEnvironment((upperName, upperValue), (lowerName, lowerValue));
|
||||||
|
|
||||||
|
var environment = LauncherEnvironment.ReadCurrentEnvironment();
|
||||||
|
|
||||||
|
await environment[upperName].Should().BeEqualTo(OperatingSystem.IsWindows() ? lowerValue : upperValue);
|
||||||
|
await environment[lowerName].Should().BeEqualTo(lowerValue);
|
||||||
|
await environment.Keys.Count(key => string.Equals(key, upperName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Should().BeEqualTo(OperatingSystem.IsWindows() ? 1 : 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Arguments("V2RAYN_WEB_API_KEY")]
|
||||||
|
[Arguments("LC_ALL")]
|
||||||
|
public async Task CurrentEnvironmentRequiresCanonicalSettingNamesOnUnix(string canonicalName)
|
||||||
|
{
|
||||||
|
var lowerName = canonicalName.ToLowerInvariant();
|
||||||
|
using var environmentScope = new TemporaryEnvironment((canonicalName, null), (lowerName, "wrong-case-value"));
|
||||||
|
|
||||||
|
var environment = LauncherEnvironment.ReadCurrentEnvironment();
|
||||||
|
|
||||||
|
await environment.GetValueOrDefault(canonicalName).Should()
|
||||||
|
.BeEqualTo(OperatingSystem.IsWindows() ? "wrong-case-value" : null);
|
||||||
|
await environment[lowerName].Should().BeEqualTo("wrong-case-value");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CurrentEnvironmentKeepsCanonicalManagementKeyDistinctOnUnix()
|
||||||
|
{
|
||||||
|
using var environmentScope = new TemporaryEnvironment(
|
||||||
|
("V2RAYN_WEB_API_KEY", "canonical-management-key-123456"),
|
||||||
|
("v2rayn_web_api_key", "other-management-key-123456"));
|
||||||
|
|
||||||
|
var environment = LauncherEnvironment.ReadCurrentEnvironment();
|
||||||
|
|
||||||
|
await environment.GetValueOrDefault("V2RAYN_WEB_API_KEY").Should()
|
||||||
|
.BeEqualTo(OperatingSystem.IsWindows() ? "other-management-key-123456" : "canonical-management-key-123456");
|
||||||
|
await environment["v2rayn_web_api_key"].Should().BeEqualTo("other-management-key-123456");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task CurrentEnvironmentUsesCanonicalInteractiveLaunchMarkerOnUnix()
|
||||||
|
{
|
||||||
|
using var environmentScope = new TemporaryEnvironment(
|
||||||
|
(LauncherEnvironment.InteractiveLaunchEnvironmentVariable, null),
|
||||||
|
(LauncherEnvironment.InteractiveLaunchEnvironmentVariable.ToLowerInvariant(), "1"));
|
||||||
|
|
||||||
|
var environment = LauncherEnvironment.ReadCurrentEnvironment();
|
||||||
|
|
||||||
|
await LauncherEnvironment.IsInteractiveLaunchMarker(environment).Should().BeEqualTo(OperatingSystem.IsWindows());
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TemporaryEnvironment : IDisposable
|
||||||
|
{
|
||||||
|
private readonly string[] _names;
|
||||||
|
private readonly (string Name, string? Value)[] _originalValues;
|
||||||
|
|
||||||
|
public TemporaryEnvironment(params (string Name, string? Value)[] values)
|
||||||
|
{
|
||||||
|
_names = values.Select(value => value.Name).ToArray();
|
||||||
|
var comparer = OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal;
|
||||||
|
_originalValues = Environment.GetEnvironmentVariables()
|
||||||
|
.Cast<DictionaryEntry>()
|
||||||
|
.Where(entry => _names.Contains((string)entry.Key, comparer))
|
||||||
|
.Select(entry => ((string)entry.Key, entry.Value?.ToString()))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var (name, value) in values)
|
||||||
|
{
|
||||||
|
Environment.SetEnvironmentVariable(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (var name in _names)
|
||||||
|
{
|
||||||
|
Environment.SetEnvironmentVariable(name, null);
|
||||||
|
}
|
||||||
|
foreach (var (name, value) in _originalValues)
|
||||||
|
{
|
||||||
|
Environment.SetEnvironmentVariable(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -495,7 +495,8 @@ public class WebAuthEndpointTests
|
|||||||
var client = new HttpClient(new SocketsHttpHandler { UseProxy = false })
|
var client = new HttpClient(new SocketsHttpHandler { UseProxy = false })
|
||||||
{
|
{
|
||||||
BaseAddress = new Uri(addresses.Single()),
|
BaseAddress = new Uri(addresses.Single()),
|
||||||
Timeout = TimeSpan.FromSeconds(5),
|
// Allow headroom for real authentication work under parallel test load.
|
||||||
|
Timeout = TimeSpan.FromSeconds(20),
|
||||||
};
|
};
|
||||||
return new ApiHarness(app, client, app.Services.GetRequiredService<EventHub>());
|
return new ApiHarness(app, client, app.Services.GetRequiredService<EventHub>());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,7 @@ public class WebAuthRateLimitTests
|
|||||||
await app.StartAsync();
|
await app.StartAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var server = app.Services.GetRequiredService<IServer>();
|
using var client = CreateClient(app);
|
||||||
var address = server.Features.Get<IServerAddressesFeature>()!.Addresses.Single();
|
|
||||||
using var client = new HttpClient { BaseAddress = new Uri(address), Timeout = TimeSpan.FromSeconds(20) };
|
|
||||||
var statuses = new List<HttpStatusCode>();
|
var statuses = new List<HttpStatusCode>();
|
||||||
int? retryAfterSeconds = null;
|
int? retryAfterSeconds = null;
|
||||||
|
|
||||||
@@ -118,6 +116,38 @@ public class WebAuthRateLimitTests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[NotInParallel]
|
||||||
|
public async Task LocalRateLimitRequestsDoNotUseTheDefaultProxy()
|
||||||
|
{
|
||||||
|
var proxyBuilder = WebApplication.CreateBuilder();
|
||||||
|
proxyBuilder.WebHost.ConfigureKestrel(options => options.Listen(IPAddress.Loopback, 0));
|
||||||
|
await using var proxy = proxyBuilder.Build();
|
||||||
|
proxy.Run(context =>
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = StatusCodes.Status502BadGateway;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
await proxy.StartAsync();
|
||||||
|
await using var app = CreatePartitionTestApp();
|
||||||
|
await app.StartAsync();
|
||||||
|
var proxyAddress = proxy.Services.GetRequiredService<IServer>()
|
||||||
|
.Features.Get<IServerAddressesFeature>()!.Addresses.Single();
|
||||||
|
var previousProxy = HttpClient.DefaultProxy;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpClient.DefaultProxy = new FixedProxy(new Uri(proxyAddress));
|
||||||
|
using var client = CreateClient(app);
|
||||||
|
await (await GetLimitedStatusAsync(client, "/setup-limited", "192.0.2.1", 0))
|
||||||
|
.Should().BeEqualTo(HttpStatusCode.OK);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
HttpClient.DefaultProxy = previousProxy;
|
||||||
|
await app.StopAsync();
|
||||||
|
await proxy.StopAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
private static WebApplication CreatePartitionTestApp()
|
private static WebApplication CreatePartitionTestApp()
|
||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder();
|
var builder = WebApplication.CreateBuilder();
|
||||||
@@ -149,7 +179,11 @@ public class WebAuthRateLimitTests
|
|||||||
{
|
{
|
||||||
var server = app.Services.GetRequiredService<IServer>();
|
var server = app.Services.GetRequiredService<IServer>();
|
||||||
var address = server.Features.Get<IServerAddressesFeature>()!.Addresses.Single();
|
var address = server.Features.Get<IServerAddressesFeature>()!.Addresses.Single();
|
||||||
return new HttpClient { BaseAddress = new Uri(address), Timeout = TimeSpan.FromSeconds(20) };
|
return new HttpClient(new SocketsHttpHandler { UseProxy = false })
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(address),
|
||||||
|
Timeout = TimeSpan.FromSeconds(20),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<HttpStatusCode> GetLimitedStatusAsync(HttpClient client, string endpoint, string remoteIp, int requestIndex)
|
private static async Task<HttpStatusCode> GetLimitedStatusAsync(HttpClient client, string endpoint, string remoteIp, int requestIndex)
|
||||||
@@ -163,6 +197,12 @@ public class WebAuthRateLimitTests
|
|||||||
return response.StatusCode;
|
return response.StatusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class FixedProxy(Uri address) : IWebProxy
|
||||||
|
{
|
||||||
|
public ICredentials? Credentials { get; set; }
|
||||||
|
public Uri GetProxy(Uri destination) => address;
|
||||||
|
public bool IsBypassed(Uri host) => false;
|
||||||
|
}
|
||||||
private sealed class TemporaryDirectory : IDisposable
|
private sealed class TemporaryDirectory : IDisposable
|
||||||
{
|
{
|
||||||
public TemporaryDirectory()
|
public TemporaryDirectory()
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ namespace v2rayN.WebAPI.Tests;
|
|||||||
|
|
||||||
public class WebLauncherTests
|
public class WebLauncherTests
|
||||||
{
|
{
|
||||||
|
// Keep fixture PIDs outside Linux's assignable range so host services cannot affect stop tests.
|
||||||
|
private const int FakeOwnerProcessId = int.MaxValue - 1;
|
||||||
|
private const int OtherProcessId = int.MaxValue;
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public async Task InstanceLockOwnerCanBeReadWhileAnotherProcessHoldsTheLock()
|
public async Task InstanceLockOwnerCanBeReadWhileAnotherProcessHoldsTheLock()
|
||||||
{
|
{
|
||||||
@@ -228,13 +232,13 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
await File.WriteAllTextAsync(lockPath, "123\n");
|
await File.WriteAllTextAsync(lockPath, $"{FakeOwnerProcessId}\n");
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var stopper = new WebStopper(new FakeHealthProbe(true, 123), signals);
|
var stopper = new WebStopper(new FakeHealthProbe(true, FakeOwnerProcessId), signals);
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.NotRunning).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.NotRunning);
|
||||||
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,11 +249,11 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
using (heldLock)
|
using (heldLock)
|
||||||
{
|
{
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var health = new FakeHealthProbe(true, 123);
|
var health = new FakeHealthProbe(true, FakeOwnerProcessId);
|
||||||
signals.OnSignal = processId =>
|
signals.OnSignal = processId =>
|
||||||
{
|
{
|
||||||
_ = ReleaseLockAfterDelayAsync(heldLock, health);
|
_ = ReleaseLockAfterDelayAsync(heldLock, health);
|
||||||
@@ -262,8 +266,8 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.Stopped).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.Stopped);
|
||||||
await signals.ProcessIds.SequenceEqual([123]).Should().BeTrue();
|
await signals.ProcessIds.SequenceEqual([FakeOwnerProcessId]).Should().BeTrue();
|
||||||
await (health.ProbeCount >= 2).Should().BeTrue();
|
await (health.ProbeCount >= 2).Should().BeTrue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,18 +286,18 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
using (heldLock)
|
using (heldLock)
|
||||||
{
|
{
|
||||||
var health = new FakeHealthProbe(true, 123, [Environment.ProcessId]);
|
var health = new FakeHealthProbe(true, FakeOwnerProcessId, [Environment.ProcessId]);
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
signals.OnSignal = processId => _ = ReleaseLockAfterDelayAsync(heldLock, health);
|
signals.OnSignal = processId => _ = ReleaseLockAfterDelayAsync(heldLock, health);
|
||||||
var stopper = new WebStopper(health, signals, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(10));
|
var stopper = new WebStopper(health, signals, TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(10));
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.CoreProcessStillRunning).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.CoreProcessStillRunning);
|
||||||
await signals.ProcessIds.SequenceEqual([123]).Should().BeTrue();
|
await signals.ProcessIds.SequenceEqual([FakeOwnerProcessId]).Should().BeTrue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,13 +308,13 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var stopper = new WebStopper(new FakeHealthProbe(true, 456), signals);
|
var stopper = new WebStopper(new FakeHealthProbe(true, OtherProcessId), signals);
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.IdentityUnverified).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.IdentityUnverified);
|
||||||
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,13 +325,13 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var stopper = new WebStopper(new FakeHealthProbe(false, 123), signals);
|
var stopper = new WebStopper(new FakeHealthProbe(false, FakeOwnerProcessId), signals);
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.IdentityUnverified).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.IdentityUnverified);
|
||||||
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,18 +342,18 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var stopper = new WebStopper(new FakeHealthProbe(true, 123), signals);
|
var stopper = new WebStopper(new FakeHealthProbe(true, FakeOwnerProcessId), signals);
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, healthUri: null);
|
var result = await stopper.StopAsync(lockPath, healthUri: null);
|
||||||
|
|
||||||
await (result == WebStopResult.ProbeUnavailable).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.ProbeUnavailable);
|
||||||
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
await (signals.ProcessIds.Count == 0).Should().BeTrue();
|
||||||
|
|
||||||
var notRunning = await stopper.StopAsync(
|
var notRunning = await stopper.StopAsync(
|
||||||
Path.Combine(directory.Path, "missing-instance.lock"), healthUri: null);
|
Path.Combine(directory.Path, "missing-instance.lock"), healthUri: null);
|
||||||
await (notRunning == WebStopResult.NotRunning).Should().BeTrue();
|
await notRunning.Should().BeEqualTo(WebStopResult.NotRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -359,18 +363,18 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
var signals = new FakeSignalSender();
|
var signals = new FakeSignalSender();
|
||||||
var stopper = new WebStopper(
|
var stopper = new WebStopper(
|
||||||
new FakeHealthProbe(true, 123),
|
new FakeHealthProbe(true, FakeOwnerProcessId),
|
||||||
signals,
|
signals,
|
||||||
stopTimeout: TimeSpan.FromMilliseconds(60),
|
stopTimeout: TimeSpan.FromMilliseconds(60),
|
||||||
pollInterval: TimeSpan.FromMilliseconds(5));
|
pollInterval: TimeSpan.FromMilliseconds(5));
|
||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.TimedOut).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.TimedOut);
|
||||||
await signals.ProcessIds.SequenceEqual([123]).Should().BeTrue();
|
await signals.ProcessIds.SequenceEqual([FakeOwnerProcessId]).Should().BeTrue();
|
||||||
await WebInstanceLock.IsHeld(lockPath).Should().BeTrue();
|
await WebInstanceLock.IsHeld(lockPath).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,8 +385,8 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
using var directory = new TemporaryDirectory();
|
using var directory = new TemporaryDirectory();
|
||||||
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
var lockPath = Path.Combine(directory.Path, "instance.lock");
|
||||||
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, 123);
|
using var heldLock = await AcquireLockWithOwnerAsync(lockPath, FakeOwnerProcessId);
|
||||||
var health = new FakeHealthProbe(true, 123);
|
var health = new FakeHealthProbe(true, FakeOwnerProcessId);
|
||||||
health.SetShutdownStage("Core stop");
|
health.SetShutdownStage("Core stop");
|
||||||
var stopper = new WebStopper(
|
var stopper = new WebStopper(
|
||||||
health,
|
health,
|
||||||
@@ -392,7 +396,7 @@ public class WebLauncherTests
|
|||||||
|
|
||||||
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
var result = await stopper.StopAsync(lockPath, new Uri("http://127.0.0.1:5080/api/health"));
|
||||||
|
|
||||||
await (result == WebStopResult.TimedOut).Should().BeTrue();
|
await result.Should().BeEqualTo(WebStopResult.TimedOut);
|
||||||
await (stopper.LastObservedShutdownStage == "Core stop").Should().BeTrue();
|
await (stopper.LastObservedShutdownStage == "Core stop").Should().BeTrue();
|
||||||
await LauncherMessages.StopMessage(result, LauncherLocale.English, stopper.LastObservedShutdownStage)
|
await LauncherMessages.StopMessage(result, LauncherLocale.English, stopper.LastObservedShutdownStage)
|
||||||
.Contains("Core stop", StringComparison.Ordinal).Should().BeTrue();
|
.Contains("Core stop", StringComparison.Ordinal).Should().BeTrue();
|
||||||
|
|||||||
Reference in New Issue
Block a user