Stufe 4c (#764): Bezeichner auf Englisch - Typen, Methoden, Felder, Parameter, Locals, Testnamen
Mit Roslyn umbenannt (Verweise folgen, Zeichenketten bleiben unberuehrt). Nicht umbenannt, weil gespeichert oder ueber die API gebunden (Stufe 4e): Properties, Record-Parameter, Enum-Member sowie die Parameter der Endpunkt-Handler (Routen-/Query-Bindung ueber den Namen). Die JSON-Felder anonymer Objekte bleiben ausdruecklich benannt (JsonFilter: pfad). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
837a634a22
commit
77062facc9
@@ -23,8 +23,8 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
Path.GetTempPath(), "clawd-tests", "sup-" + Guid.NewGuid().ToString("N")[..8]);
|
||||
|
||||
private readonly FakeLauncher _launcher = new();
|
||||
private readonly FakeChannel _kanal = new();
|
||||
private readonly List<SupervisionEvent> _ereignisse = [];
|
||||
private readonly FakeChannel _channel = new();
|
||||
private readonly List<SupervisionEvent> _events = [];
|
||||
|
||||
private static readonly InstanceIdentity Test = new("i-1", "Test", "0.1.2");
|
||||
|
||||
@@ -50,7 +50,7 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
// The socket only answers if a process is really running - exactly as in
|
||||
// operation. An answer stored in advance would otherwise mean "already running", and
|
||||
// supervision would take over instead of starting.
|
||||
_kanal.Launcher = _launcher;
|
||||
_channel.Launcher = _launcher;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -59,29 +59,29 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
catch { /* A leftover test folder does not turn a run red. */ }
|
||||
}
|
||||
|
||||
private InstanceSupervisor Aufsicht(SupervisionOptions? options = null)
|
||||
private InstanceSupervisor Supervisor(SupervisionOptions? options = null)
|
||||
{
|
||||
var supervisor = new InstanceSupervisor(
|
||||
_dir, _launcher, _kanal, NullLogger.Instance, options ?? Options);
|
||||
_dir, _launcher, _channel, NullLogger.Instance, options ?? Options);
|
||||
|
||||
supervisor.Observed += _ereignisse.Add;
|
||||
supervisor.Observed += _events.Add;
|
||||
return supervisor;
|
||||
}
|
||||
|
||||
private IEnumerable<InstanceEventKind> Arten => _ereignisse.Select(e => e.Kind);
|
||||
private IEnumerable<InstanceEventKind> Arten => _events.Select(e => e.Kind);
|
||||
|
||||
// ─── Starting ───
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_Start_gilt_erst_wenn_die_Instanz_antwortet()
|
||||
public async Task A_start_only_counts_when_the_instance_answers()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
(await aufsicht.StartAsync()).ShouldBeTrue();
|
||||
await using var supervisor = Supervisor();
|
||||
(await supervisor.StartAsync()).ShouldBeTrue();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Running);
|
||||
aufsicht.InstanceName.ShouldBe("Test");
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Running);
|
||||
supervisor.InstanceName.ShouldBe("Test");
|
||||
Arten.ShouldBe([InstanceEventKind.Started]);
|
||||
|
||||
var state = InstanceStateStore.Read(_dir).ShouldNotBeNull();
|
||||
@@ -98,14 +98,14 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
/// broken configuration.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Ein_Prozess_der_sich_nie_meldet_gilt_nicht_als_gestartet()
|
||||
public async Task A_process_that_never_reports_does_not_count_as_started()
|
||||
{
|
||||
_kanal.Answer = null; // runs, but says nothing
|
||||
_channel.Answer = null; // runs, but says nothing
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
(await aufsicht.StartAsync()).ShouldBeFalse();
|
||||
await using var supervisor = Supervisor();
|
||||
(await supervisor.StartAsync()).ShouldBeFalse();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
Arten.ShouldBe([InstanceEventKind.StartFailed]);
|
||||
|
||||
// Do not leave it standing: a process that runs and stays silent keeps the socket
|
||||
@@ -115,39 +115,39 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_Prozess_der_gar_nicht_startet_meldet_das()
|
||||
public async Task A_process_that_does_not_start_at_all_reports_it()
|
||||
{
|
||||
_launcher.FailStartWith = new InvalidOperationException("Programmdatei fehlt");
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
(await aufsicht.StartAsync()).ShouldBeFalse();
|
||||
await using var supervisor = Supervisor();
|
||||
(await supervisor.StartAsync()).ShouldBeFalse();
|
||||
|
||||
Arten.ShouldBe([InstanceEventKind.StartFailed]);
|
||||
_ereignisse[0].Message.ShouldContain("Programmdatei fehlt");
|
||||
_events[0].Message.ShouldContain("Programmdatei fehlt");
|
||||
}
|
||||
|
||||
// ─── The case this is about ───
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_abgeschossener_Prozess_wird_bemerkt_und_gemeldet()
|
||||
public async Task A_killed_process_is_noticed_and_reported()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
// Someone kills the instance. Nobody asked for it.
|
||||
_launcher.Last!.Exit(code: 137);
|
||||
_kanal.Answer = null;
|
||||
_channel.Answer = null;
|
||||
|
||||
await aufsicht.CheckAsync();
|
||||
await supervisor.CheckAsync();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Crashed);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Crashed);
|
||||
|
||||
var absturz = _ereignisse.Single(e => e.Kind == InstanceEventKind.Crashed);
|
||||
absturz.ExitCode.ShouldBe(137);
|
||||
absturz.InstanceName.ShouldBe("Test");
|
||||
absturz.WorthReporting.ShouldBeTrue("Das ist die Meldung, die es 2026-09-08 nicht gab.");
|
||||
var crash = _events.Single(e => e.Kind == InstanceEventKind.Crashed);
|
||||
crash.ExitCode.ShouldBe(137);
|
||||
crash.InstanceName.ShouldBe("Test");
|
||||
crash.WorthReporting.ShouldBeTrue("Das ist die Meldung, die es 2026-09-08 nicht gab.");
|
||||
|
||||
// And the state file no longer points to a process that does not exist.
|
||||
InstanceStateStore.Read(_dir).ShouldBeNull();
|
||||
@@ -161,106 +161,106 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
/// supervision that only counts processes sees nothing of it.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Ein_lebender_aber_stummer_Prozess_faellt_auf()
|
||||
public async Task A_living_but_silent_process_is_noticed()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
_kanal.Answer = null; // hangs - the process lives on
|
||||
_channel.Answer = null; // hangs - the process lives on
|
||||
|
||||
// Not at the first hiccup: that would be everyday life, and an alarm at every
|
||||
// hiccup is after a week the alarm nobody reads any more.
|
||||
await aufsicht.CheckAsync();
|
||||
await aufsicht.CheckAsync();
|
||||
await supervisor.CheckAsync();
|
||||
await supervisor.CheckAsync();
|
||||
Arten.ShouldNotContain(InstanceEventKind.Unresponsive);
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Running);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Running);
|
||||
|
||||
await aufsicht.CheckAsync();
|
||||
await supervisor.CheckAsync();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Silent);
|
||||
var alarm = _ereignisse.Single(e => e.Kind == InstanceEventKind.Unresponsive);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Silent);
|
||||
var alarm = _events.Single(e => e.Kind == InstanceEventKind.Unresponsive);
|
||||
alarm.WorthReporting.ShouldBeTrue();
|
||||
_launcher.Last!.HasExited.ShouldBeFalse("Der Prozess laeuft ja - das ist der Punkt.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_stummer_Prozess_wird_einmal_gemeldet_und_nicht_bei_jedem_Durchgang()
|
||||
public async Task A_silent_process_is_reported_once_and_not_on_every_pass()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
_kanal.Answer = null;
|
||||
_channel.Answer = null;
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
await aufsicht.CheckAsync();
|
||||
await supervisor.CheckAsync();
|
||||
|
||||
_ereignisse.Count(e => e.Kind == InstanceEventKind.Unresponsive).ShouldBe(1);
|
||||
_events.Count(e => e.Kind == InstanceEventKind.Unresponsive).ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Wer_wieder_antwortet_wird_wieder_als_laufend_gefuehrt()
|
||||
public async Task Whoever_answers_again_is_listed_as_running_again()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
_kanal.Answer = null;
|
||||
for (var i = 0; i < 3; i++) await aufsicht.CheckAsync();
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Silent);
|
||||
_channel.Answer = null;
|
||||
for (var i = 0; i < 3; i++) await supervisor.CheckAsync();
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Silent);
|
||||
|
||||
_kanal.Answer = Test;
|
||||
await aufsicht.CheckAsync();
|
||||
_channel.Answer = Test;
|
||||
await supervisor.CheckAsync();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Running);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Running);
|
||||
Arten.ShouldContain(InstanceEventKind.Recovered);
|
||||
}
|
||||
|
||||
// ─── Stopping ───
|
||||
|
||||
[Fact]
|
||||
public async Task Ein_erbetenes_Ende_ist_kein_Absturz()
|
||||
public async Task A_requested_exit_is_not_a_crash()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
// The instance ends upon the request - as in operation.
|
||||
_launcher.Last!.Exit(code: 0);
|
||||
_kanal.Answer = null;
|
||||
_channel.Answer = null;
|
||||
|
||||
(await aufsicht.StopAsync()).ShouldBeTrue();
|
||||
(await supervisor.StopAsync()).ShouldBeTrue();
|
||||
|
||||
_kanal.StopRequests.ShouldBe(1, "Erst bitten, nicht schiessen.");
|
||||
_channel.StopRequests.ShouldBe(1, "Erst bitten, nicht schiessen.");
|
||||
_launcher.Last.WasKilled.ShouldBeFalse();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
Arten.ShouldNotContain(InstanceEventKind.Crashed);
|
||||
_ereignisse.Last().Kind.ShouldBe(InstanceEventKind.StoppedOrderly);
|
||||
_ereignisse.Last().WorthReporting.ShouldBeFalse();
|
||||
_events.Last().Kind.ShouldBe(InstanceEventKind.StoppedOrderly);
|
||||
_events.Last().WorthReporting.ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Wer_nicht_hoert_wird_nach_der_Frist_beendet()
|
||||
public async Task Whoever_does_not_listen_is_stopped_after_the_deadline()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
// Keeps answering and does not end - the request goes unheard.
|
||||
_kanal.StopRequestArrives = false;
|
||||
_channel.StopRequestArrives = false;
|
||||
|
||||
(await aufsicht.StopAsync()).ShouldBeTrue();
|
||||
(await supervisor.StopAsync()).ShouldBeTrue();
|
||||
|
||||
_kanal.StopRequests.ShouldBe(1);
|
||||
_channel.StopRequests.ShouldBe(1);
|
||||
_launcher.Last!.WasKilled.ShouldBeTrue();
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -274,25 +274,25 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
/// the damage this project is built against.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Ein_stummer_aber_lebender_Prozess_gilt_nicht_als_beendet()
|
||||
public async Task A_silent_but_living_process_does_not_count_as_ended()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.StartAsync();
|
||||
|
||||
var prozess = _launcher.Last.ShouldNotBeNull();
|
||||
var process = _launcher.Last.ShouldNotBeNull();
|
||||
|
||||
// It hangs: the socket is silent, the process lives.
|
||||
_kanal.Verstummen(_dir);
|
||||
_channel.GoSilent(_dir);
|
||||
|
||||
(await aufsicht.StopAsync()).ShouldBeTrue();
|
||||
(await supervisor.StopAsync()).ShouldBeTrue();
|
||||
|
||||
prozess.WasKilled.ShouldBeTrue(
|
||||
process.WasKilled.ShouldBeTrue(
|
||||
"Wer schweigt und lebt, muss beendet werden - nicht fuer beendet erklaert.");
|
||||
|
||||
prozess.HasExited.ShouldBeTrue();
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
process.HasExited.ShouldBeTrue();
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -303,34 +303,34 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
/// for.</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Wer_aufraeumt_bekommt_die_Frist_nachgezogen()
|
||||
public async Task Whoever_cleans_up_gets_the_deadline_extended()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
// #722: Supervision asks every 250 ms and only extends the deadline on "cleaning up".
|
||||
// With a 300 ms deadline the next question came too late under parallel load, and the test saw
|
||||
// a kill where none belongs. A one-second deadline leaves the tick room; the
|
||||
// instance still cleans up considerably longer than the deadline alone allows.
|
||||
await using var aufsicht = Aufsicht(Options with { StopGrace = TimeSpan.FromSeconds(1), MaxDrainWait = TimeSpan.FromSeconds(20) });
|
||||
await aufsicht.StartAsync();
|
||||
await using var supervisor = Supervisor(Options with { StopGrace = TimeSpan.FromSeconds(1), MaxDrainWait = TimeSpan.FromSeconds(20) });
|
||||
await supervisor.StartAsync();
|
||||
|
||||
var prozess = _launcher.Last.ShouldNotBeNull();
|
||||
var process = _launcher.Last.ShouldNotBeNull();
|
||||
|
||||
// It answers and reports: I am cleaning up. Longer than StopGrace (1 s), but
|
||||
// shorter than MaxDrainWait.
|
||||
_kanal.Answer = Test with { Phase = ShutdownPhase.Draining, OpenWork = 1 };
|
||||
_channel.Answer = Test with { Phase = ShutdownPhase.Draining, OpenWork = 1 };
|
||||
|
||||
_kanal.OnStopRequest = _ => Task.Run(async () =>
|
||||
_channel.OnStopRequest = _ => Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(2500);
|
||||
prozess.Exit(0);
|
||||
_kanal.Answer = null;
|
||||
process.Exit(0);
|
||||
_channel.Answer = null;
|
||||
});
|
||||
|
||||
(await aufsicht.StopAsync()).ShouldBeTrue();
|
||||
(await supervisor.StopAsync()).ShouldBeTrue();
|
||||
|
||||
prozess.WasKilled.ShouldBeFalse("Wer aufraeumt, wird nicht abgeschossen.");
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
process.WasKilled.ShouldBeFalse("Wer aufraeumt, wird nicht abgeschossen.");
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -341,48 +341,48 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
/// be grabbed (see <see cref="Eine_wiederverwendete_Prozesskennung_wird_nicht_fuer_die_Instanz_gehalten"/>).</para>
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Was_nicht_zu_fassen_ist_wird_nicht_als_beendet_gemeldet()
|
||||
public async Task What_cannot_be_grasped_is_not_reported_as_ended()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_kanal.StopRequestArrives = false;
|
||||
_channel.Answer = Test;
|
||||
_channel.StopRequestArrives = false;
|
||||
|
||||
// It was already running before this manager came - and without a state file its
|
||||
// process cannot be grabbed by it.
|
||||
_launcher.Fremdstart(_dir, 4711);
|
||||
_launcher.StartedElsewhere(_dir, 4711);
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
await aufsicht.ReattachAsync(); // taken over, but without a process
|
||||
aufsicht.ProcessId.ShouldBeNull();
|
||||
await using var supervisor = Supervisor();
|
||||
await supervisor.ReattachAsync(); // taken over, but without a process
|
||||
supervisor.ProcessId.ShouldBeNull();
|
||||
|
||||
(await aufsicht.StopAsync()).ShouldBeFalse();
|
||||
(await supervisor.StopAsync()).ShouldBeFalse();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Running);
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Running);
|
||||
Arten.ShouldNotContain(InstanceEventKind.StoppedOrderly);
|
||||
}
|
||||
|
||||
// ─── Rediscovering (E-M6) ───
|
||||
|
||||
[Fact]
|
||||
public async Task Eine_laufende_Instanz_wird_nach_einem_Managerneustart_uebernommen()
|
||||
public async Task A_running_instance_is_adopted_after_a_manager_restart()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
// The first manager starts it.
|
||||
await using (var erster = Aufsicht())
|
||||
await erster.StartAsync();
|
||||
await using (var firstOne = Supervisor())
|
||||
await firstOne.StartAsync();
|
||||
|
||||
_ereignisse.Clear();
|
||||
_events.Clear();
|
||||
|
||||
// Second manager, the same machine, the same running instance.
|
||||
await using var zweiter = Aufsicht();
|
||||
(await zweiter.ReattachAsync()).ShouldBeTrue();
|
||||
await using var secondOne = Supervisor();
|
||||
(await secondOne.ReattachAsync()).ShouldBeTrue();
|
||||
|
||||
zweiter.Condition.ShouldBe(InstanceCondition.Running);
|
||||
zweiter.InstanceName.ShouldBe("Test");
|
||||
zweiter.ProcessId.ShouldBe(_launcher.Last!.Id);
|
||||
secondOne.Condition.ShouldBe(InstanceCondition.Running);
|
||||
secondOne.InstanceName.ShouldBe("Test");
|
||||
secondOne.ProcessId.ShouldBe(_launcher.Last!.Id);
|
||||
|
||||
// Taking over is not starting - there is nothing to report.
|
||||
_ereignisse.ShouldBeEmpty();
|
||||
_events.ShouldBeEmpty();
|
||||
_launcher.Starts.ShouldBe(1);
|
||||
}
|
||||
|
||||
@@ -397,57 +397,57 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
[Fact]
|
||||
public async Task Eine_wiederverwendete_Prozesskennung_wird_nicht_fuer_die_Instanz_gehalten()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using (var erster = Aufsicht())
|
||||
await erster.StartAsync();
|
||||
await using (var firstOne = Supervisor())
|
||||
await firstOne.StartAsync();
|
||||
|
||||
var alte = _launcher.Last!;
|
||||
var oldOnes = _launcher.Last!;
|
||||
|
||||
// The same ID, started much later: a different process.
|
||||
_launcher.Running[alte.Id] = new FakeProcess(alte.Id, alte.StartedAt.AddHours(3));
|
||||
_launcher.Running[oldOnes.Id] = new FakeProcess(oldOnes.Id, oldOnes.StartedAt.AddHours(3));
|
||||
|
||||
await using var zweiter = Aufsicht();
|
||||
(await zweiter.ReattachAsync()).ShouldBeTrue("Der Socket antwortet ja.");
|
||||
await using var secondOne = Supervisor();
|
||||
(await secondOne.ReattachAsync()).ShouldBeTrue("Der Socket antwortet ja.");
|
||||
|
||||
zweiter.ProcessId.ShouldBeNull(
|
||||
secondOne.ProcessId.ShouldBeNull(
|
||||
"Der fremde Prozess darf nicht als der eigene uebernommen werden.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Eine_Zustandsdatei_ohne_laufende_Instanz_wird_weggeraeumt()
|
||||
public async Task A_state_file_without_a_running_instance_is_cleared_away()
|
||||
{
|
||||
_kanal.Answer = Test;
|
||||
_channel.Answer = Test;
|
||||
|
||||
await using (var erster = Aufsicht())
|
||||
await erster.StartAsync();
|
||||
await using (var firstOne = Supervisor())
|
||||
await firstOne.StartAsync();
|
||||
|
||||
InstanceStateStore.Read(_dir).ShouldNotBeNull();
|
||||
|
||||
// The manager was gone, the instance is gone by now too.
|
||||
_kanal.Answer = null;
|
||||
_channel.Answer = null;
|
||||
|
||||
await using var zweiter = Aufsicht();
|
||||
(await zweiter.ReattachAsync()).ShouldBeFalse();
|
||||
await using var secondOne = Supervisor();
|
||||
(await secondOne.ReattachAsync()).ShouldBeFalse();
|
||||
|
||||
zweiter.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
secondOne.Condition.ShouldBe(InstanceCondition.Stopped);
|
||||
InstanceStateStore.Read(_dir).ShouldBeNull(
|
||||
"Eine Datei, die auf niemanden zeigt, laesst es aussehen, als liefe etwas.");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Ohne_Zustandsdatei_wird_eine_antwortende_Instanz_trotzdem_uebernommen()
|
||||
public async Task Without_state_file_an_answering_instance_is_still_adopted()
|
||||
{
|
||||
// The case after a crash of the manager before it could write - or
|
||||
// after someone deleted the file. The socket answers, so it is running.
|
||||
_kanal.Answer = Test;
|
||||
_launcher.Fremdstart(_dir, 4711);
|
||||
_channel.Answer = Test;
|
||||
_launcher.StartedElsewhere(_dir, 4711);
|
||||
|
||||
await using var aufsicht = Aufsicht();
|
||||
(await aufsicht.ReattachAsync()).ShouldBeTrue();
|
||||
await using var supervisor = Supervisor();
|
||||
(await supervisor.ReattachAsync()).ShouldBeTrue();
|
||||
|
||||
aufsicht.Condition.ShouldBe(InstanceCondition.Running);
|
||||
aufsicht.ProcessId.ShouldBeNull("Es gibt keinen Prozess, den dieser Manager kennt.");
|
||||
supervisor.Condition.ShouldBe(InstanceCondition.Running);
|
||||
supervisor.ProcessId.ShouldBeNull("Es gibt keinen Prozess, den dieser Manager kennt.");
|
||||
InstanceStateStore.Read(_dir).ShouldNotBeNull();
|
||||
}
|
||||
|
||||
@@ -465,9 +465,9 @@ public sealed class InstanceSupervisorTests : IDisposable
|
||||
[InlineData(InstanceEventKind.Started, false)]
|
||||
[InlineData(InstanceEventKind.StoppedOrderly, false)]
|
||||
[InlineData(InstanceEventKind.Recovered, false)]
|
||||
public void Gemeldet_wird_nur_was_niemand_bestellt_hat(InstanceEventKind kind, bool erwartet)
|
||||
public void Only_what_nobody_ordered_is_reported(InstanceEventKind kind, bool expected)
|
||||
{
|
||||
new SupervisionEvent(kind, _dir, "Test", 1, null, "", DateTimeOffset.UtcNow)
|
||||
.WorthReporting.ShouldBe(erwartet);
|
||||
.WorthReporting.ShouldBe(expected);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user