diff --git a/AI-README.md b/AI-README.md
index 4a2d519..e1cc3d4 100644
--- a/AI-README.md
+++ b/AI-README.md
@@ -2,7 +2,7 @@
## Projekt und Sicherheitsziel
-Das Repository enthält ein .NET-Framework-4.6.1-WinForms-Tool für kontrollierte BizTalk-2020-Wartungsoperationen. Änderungen müssen Dry-run, explizite Freigabe realer Aktionen, sichere Reihenfolgen und wiederherstellbare Installergrenzen erhalten. Die aktuelle Produktversion ist 2.2.1.
+Das Repository enthält ein .NET-Framework-4.6.1-WinForms-Tool für kontrollierte BizTalk-2020-Wartungsoperationen. Änderungen müssen Dry-run, explizite Freigabe realer Aktionen, sichere Reihenfolgen und wiederherstellbare Installergrenzen erhalten. Die aktuelle Produktversion ist 2.2.2.
## Installerinvarianten
@@ -31,6 +31,7 @@ Die zentrale Implementierung liegt in `src/BizTalkPlatformManagementTool.Setup/I
- Ein älterer kompatibler Snapshot, insbesondere aus 2.1.3, darf nicht allein anhand seines `ToolVersion`-Werts abgelehnt werden.
- Der echte Emergency Restore erzeugt nach Möglichkeit automatisch einen timestamp-basierten Soll/Ist-Diff aus Recovery-Quelle und Nachher-Snapshot.
- Die zentrale best-effort Orchestrierung liegt in `OperationPlanExecutor`; die WMI-/Service-Zustandsprüfung bleibt im produktiven Runtime-Adapter.
+- Datei-Logging und optionale GUI-Logweiterleitung sind Diagnosekanäle und dürfen niemals einen fachlichen Planschritt oder dessen Fehlerbehandlung unterbrechen.
## Versionierung
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2670f76..7faae44 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,13 @@
# Changelog
+## [2.2.2] - 2026-08-19
+### Fixed
+- A failure in the optional GUI log sink can no longer escape step-level error handling or stop later independent shutdown/restore steps.
+
+### Added
+- Failure-injection coverage for multiple consecutive unexpected exception types and a permanently failing log-display sink.
+
## [2.2.1] - 2026-08-19
### Added
- WMI-free **Validate State** preflight with snapshot metadata, server matching and artifact counts.
diff --git a/Installation.md b/Installation.md
index a5a4315..a10f901 100644
--- a/Installation.md
+++ b/Installation.md
@@ -89,7 +89,7 @@ Ein erfolgreicher Installer-Self-Test bestätigt Paket, Programmstart und lokale
## Emergency Restore nach einem Teilabbruch
-Version 2.2.1 kann einen Wiederanlauf allein aus einer erhaltenen `before.json` vorbereiten und ausführen. Eine mit Version 2.1.3 erzeugte Datei ist kompatibel; zusätzliche Plan- oder Nachher-Dateien des fehlgeschlagenen Laufs sind nicht erforderlich.
+Version 2.2.2 kann einen Wiederanlauf allein aus einer erhaltenen `before.json` vorbereiten und ausführen. Eine mit Version 2.1.3 erzeugte Datei ist kompatibel; zusätzliche Plan- oder Nachher-Dateien des fehlgeschlagenen Laufs sind nicht erforderlich. Auch ein Fehler der GUI-Logweiterleitung ist vom fachlichen Executor isoliert und kann die späteren Planschritte nicht abbrechen.
1. Die erhaltene `before.json` außerhalb des Arbeitsverzeichnisses zusätzlich sichern.
2. Anwendung als Administrator starten und denselben Zielserver wählen, der im Snapshot gespeichert ist.
diff --git a/docs/ACC-Emergency-Restore-before-json-Runbook.md b/docs/ACC-Emergency-Restore-before-json-Runbook.md
index 718118a..b1f6fa2 100644
--- a/docs/ACC-Emergency-Restore-before-json-Runbook.md
+++ b/docs/ACC-Emergency-Restore-before-json-Runbook.md
@@ -3,11 +3,11 @@
Stand: 19.08.2026
Ausführung: Donnerstag, 20.08.2026, oder Montag, 24.08.2026
Zielserver: `AV23AGPWBI01`
-Benötigte Toolversion: `2.2.1`
+Benötigte Toolversion: `2.2.2`
## Kurzantwort
-Ja. Die vorhandene, mit Version 2.1.3 erzeugte `before.json` kann von Version 2.2.1 direkt als Recovery-Quelle verwendet werden. Zusätzliche Dateien des abgebrochenen Shutdowns sind nicht erforderlich. Die Kompatibilität wird durch einen Regressionstest abgedeckt; die echte BizTalk-/ACC-Ausführung muss noch vor Ort bestätigt werden.
+Ja. Die vorhandene, mit Version 2.1.3 erzeugte `before.json` kann von Version 2.2.2 direkt als Recovery-Quelle verwendet werden. Zusätzliche Dateien des abgebrochenen Shutdowns sind nicht erforderlich. Die Kompatibilität wird durch einen Regressionstest abgedeckt; die echte BizTalk-/ACC-Ausführung muss noch vor Ort bestätigt werden.
Für diesen Teilzustand ausschließlich **Emergency Restore** verwenden. Dieser Modus startet zuerst `ENTSSO`, arbeitet danach den gespeicherten Sollzustand idempotent ab, setzt nach Einzelfehlern fort und überschreibt die Quell-`before.json` nicht.
@@ -31,7 +31,7 @@ type BizTalkPlatformManagementTool-Setup.zip.sha256.txt
- [ ] Nur fortfahren, wenn beide ZIP-Hashes exakt gleich sind.
- [ ] ZIP in einen neuen Ordner entpacken, die laufende Toolinstanz schließen und `Setup.exe` als Administrator starten.
-- [ ] Installation/Update auf Version `2.2.1` vollständig abschließen.
+- [ ] Installation/Update auf Version `2.2.2` vollständig abschließen.
- [ ] Ein neues, leeres Ausgabeverzeichnis anlegen, zum Beispiel `C:\BizTalk-Recovery\2026-08-20` oder `C:\BizTalk-Recovery\2026-08-24`.
Wichtig: Die Recovery-Quelle außerhalb dieses Ausgabeverzeichnisses lassen. Während der Recovery nicht **Snapshot Before** anklicken, damit kein neuer Teilzustand als vermeintlicher Sollzustand gespeichert wird.
@@ -86,7 +86,7 @@ Die reale Reihenfolge ist:
4. Orchestrations abgleichen; im Snapshot nur `Bound` gebliebene Orchestrations werden bewusst zur manuellen Kontrolle markiert.
5. Receive Locations zuletzt abgleichen.
-Vor jeder Mutation liest Version 2.2.1 den Istzustand. Ein bereits korrekter Zustand wird als `AlreadySatisfied` protokolliert und nicht erneut per WMI geändert. Ein einzelner Fehler wird als `Failed` gespeichert; alle späteren unabhängigen Schritte werden trotzdem versucht.
+Vor jeder Mutation liest Version 2.2.2 den Istzustand. Ein bereits korrekter Zustand wird als `AlreadySatisfied` protokolliert und nicht erneut per WMI geändert. Ein einzelner Fehler wird als `Failed` gespeichert; alle späteren unabhängigen Schritte werden trotzdem versucht. Auch ein Fehler der optionalen GUI-Loganzeige kann die fachliche Ausführung nicht unterbrechen.
## 5. Ergebnis abnehmen
@@ -112,8 +112,8 @@ Wenn sie deaktiviert ist, obwohl `before.json` sie aktiviert erwartet, versucht
## Wenn der Lauf erneut unterbrochen wird
-Die ursprüngliche `before.json` bleibt unverändert. Version 2.2.1 kann mit derselben Recovery-Quelle erneut gestartet werden, weil bereits erreichte Zustände als `AlreadySatisfied` übersprungen werden. Vor dem Wiederholen immer den jüngsten Ergebnisreport sichern und prüfen, welcher Schritt tatsächlich fehlgeschlagen ist.
+Die ursprüngliche `before.json` bleibt unverändert. Version 2.2.2 kann mit derselben Recovery-Quelle erneut gestartet werden, weil bereits erreichte Zustände als `AlreadySatisfied` übersprungen werden. Vor dem Wiederholen immer den jüngsten Ergebnisreport sichern und prüfen, welcher Schritt tatsächlich fehlgeschlagen ist.
## Go/No-Go für PROD
-ACC ist erst ein belastbarer PROD-Nachweis, wenn der echte Emergency Restore abgeschlossen wurde, der Ergebnisreport vollständig ist, der automatische Diff geprüft wurde und jeder verbliebene `Failed`-Schritt fachlich behandelt wurde. Die lokalen 24 Regressionstests und der Self-Test ersetzen diesen realen BizTalk-/Windows-Nachweis nicht.
+ACC ist erst ein belastbarer PROD-Nachweis, wenn der echte Emergency Restore abgeschlossen wurde, der Ergebnisreport vollständig ist, der automatische Diff geprüft wurde und jeder verbliebene `Failed`-Schritt fachlich behandelt wurde. Die lokalen 27 Regressionstests und der Self-Test ersetzen diesen realen BizTalk-/Windows-Nachweis nicht.
diff --git a/docs/ACC-Runtime-Shutdown-Exception-2026-08-19.md b/docs/ACC-Runtime-Shutdown-Exception-2026-08-19.md
index ff691bd..57c25a4 100644
--- a/docs/ACC-Runtime-Shutdown-Exception-2026-08-19.md
+++ b/docs/ACC-Runtime-Shutdown-Exception-2026-08-19.md
@@ -55,6 +55,10 @@ Der neue Button **Emergency Restore** benötigt außer der erhaltenen `before.js
- Ein 2.1.3-Snapshot wird ausdrücklich als kompatible Recovery-Quelle regressionsgetestet; `ToolVersion` ist keine Versionssperre.
- Nach einem echten Emergency Restore wird bei erfolgreichem Nachher-Snapshot automatisch `emergency-restore-diff-*` als JSON, CSV und HTML geschrieben.
+## Zusätzliche Exception-Grenze in Version 2.2.2
+
+Ein erneuter Audit des gesamten Shutdown-Kontrollflusses bestätigte, dass WMI-Lookup, Istzustandsprüfung, Methodenaufruf, Zustandswartezeit und Objektfreigabe innerhalb der Per-Step-Exception-Grenze liegen. Zusätzlich ist nun auch die optionale GUI-Weiterleitung des Loggers vollständig isoliert: Selbst wenn die Anzeige eines Logeintrags eine Exception wirft, laufen der aktuelle fachliche Schritt und alle späteren unabhängigen Schritte weiter. Failure-Injection-Tests decken mehrere aufeinanderfolgende `InvalidOperationException`-, `IOException`- und `TimeoutException`-Fehler sowie einen dauerhaft werfenden Log-Sink ab.
+
### Globale Reihenfolge
Shutdown:
@@ -86,11 +90,11 @@ Die portable Regressionstestsuite enthält ab Version 2.2.0 unter anderem folgen
- globale Shutdown-/Restore-Reihenfolge mit mehreren Anwendungen,
- Kurzname/FQDN-Gleichheit für Host-Instance-Schritte.
-Die lokale Suite umfasst ab Version 2.2.1 insgesamt 24 Tests einschließlich der expliziten 2.1.3-Snapshot-Kompatibilität. Die abschließende Freigabe für PROD benötigt weiterhin einen Windows-/BizTalk-Test auf ACC: echter Scheduler-Fehlerpfad, vollständige Fortsetzung, Ergebnisreport, Emergency-Dry-run und realer Wiederanlauf aus einer Kopie der vorhandenen `before.json`.
+Die lokale Suite umfasst ab Version 2.2.2 insgesamt 27 Tests einschließlich der expliziten 2.1.3-Snapshot-Kompatibilität, zusätzlicher Failure-Injection für unerwartete Exceptions und eines vollständigen Shutdown-Fortsetzungstests über Receive Location, Orchestration, Send Port und Host Instance. Die abschließende Freigabe für PROD benötigt weiterhin einen Windows-/BizTalk-Test auf ACC: echter Scheduler-Fehlerpfad, vollständige Fortsetzung, Ergebnisreport, Emergency-Dry-run und realer Wiederanlauf aus einer Kopie der vorhandenen `before.json`.
## PROD-Freigabekriterien
-- Version 2.2.1 installieren und Installer-Self-Test bestätigen.
+- Version 2.2.2 installieren und Installer-Self-Test bestätigen.
- `Diagnose` und einen vollständigen Shutdown-Dry-run ausführen.
- Kontrolliert nachweisen, dass eine isolierte Scheduler-Exception spätere Schritte nicht blockiert.
- `shutdown-result.json` und Nachher-Snapshot prüfen.
diff --git a/src/BizTalkPlatformManagementTool.Setup/InstallerEngine.cs b/src/BizTalkPlatformManagementTool.Setup/InstallerEngine.cs
index fd577a6..a4d51bb 100644
--- a/src/BizTalkPlatformManagementTool.Setup/InstallerEngine.cs
+++ b/src/BizTalkPlatformManagementTool.Setup/InstallerEngine.cs
@@ -23,7 +23,7 @@ namespace BizTalkPlatformManagementTool.Setup
private const string ProductName = "BizTalk Platform Management Tool";
/// Aktuelle Produktversion des Installers und Uninstall-Eintrags.
- private const string ProductVersion = "2.2.1";
+ private const string ProductVersion = "2.2.2";
///
/// Wartezeiten zwischen Wiederholungen atomarer Verzeichnisverschiebungen.
diff --git a/src/BizTalkPlatformManagementTool.Setup/MainForm.cs b/src/BizTalkPlatformManagementTool.Setup/MainForm.cs
index e97d547..184593e 100644
--- a/src/BizTalkPlatformManagementTool.Setup/MainForm.cs
+++ b/src/BizTalkPlatformManagementTool.Setup/MainForm.cs
@@ -65,7 +65,7 @@ namespace BizTalkPlatformManagementTool.Setup
{
AutoSize = true,
Font = new Font(Font.FontFamily, 14, FontStyle.Bold),
- Text = "BizTalk Platform Management Tool 2.2.1"
+ Text = "BizTalk Platform Management Tool 2.2.2"
});
root.Controls.Add(new Label
{
diff --git a/src/BizTalkPlatformManagementTool.Setup/Properties/AssemblyInfo.cs b/src/BizTalkPlatformManagementTool.Setup/Properties/AssemblyInfo.cs
index 873a0e8..ae7ad8f 100644
--- a/src/BizTalkPlatformManagementTool.Setup/Properties/AssemblyInfo.cs
+++ b/src/BizTalkPlatformManagementTool.Setup/Properties/AssemblyInfo.cs
@@ -8,6 +8,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyProduct("BizTalk Platform Management Tool")]
[assembly: ComVisible(false)]
[assembly: Guid("675b68a9-bd80-46a5-b8c5-3b11b0b374e2")]
-[assembly: AssemblyVersion("2.2.1.0")]
-[assembly: AssemblyFileVersion("2.2.1.0")]
+[assembly: AssemblyVersion("2.2.2.0")]
+[assembly: AssemblyFileVersion("2.2.2.0")]
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
diff --git a/src/BizTalkPlatformManagementTool.Setup/app.manifest b/src/BizTalkPlatformManagementTool.Setup/app.manifest
index ef6a3f0..a8fde31 100644
--- a/src/BizTalkPlatformManagementTool.Setup/app.manifest
+++ b/src/BizTalkPlatformManagementTool.Setup/app.manifest
@@ -1,6 +1,6 @@
-
+
diff --git a/src/BizTalkPlatformManagementTool/Properties/AssemblyInfo.cs b/src/BizTalkPlatformManagementTool/Properties/AssemblyInfo.cs
index bbe9b00..292520c 100644
--- a/src/BizTalkPlatformManagementTool/Properties/AssemblyInfo.cs
+++ b/src/BizTalkPlatformManagementTool/Properties/AssemblyInfo.cs
@@ -9,6 +9,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: ComVisible(false)]
[assembly: Guid("2c5b2c0a-f407-46c2-9e3b-1fa09fa8445a")]
-[assembly: AssemblyVersion("2.2.1.0")]
-[assembly: AssemblyFileVersion("2.2.1.0")]
+[assembly: AssemblyVersion("2.2.2.0")]
+[assembly: AssemblyFileVersion("2.2.2.0")]
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
diff --git a/src/BizTalkPlatformManagementTool/Services/BizTalkOperationService.cs b/src/BizTalkPlatformManagementTool/Services/BizTalkOperationService.cs
index 1f09073..a48489b 100644
--- a/src/BizTalkPlatformManagementTool/Services/BizTalkOperationService.cs
+++ b/src/BizTalkPlatformManagementTool/Services/BizTalkOperationService.cs
@@ -16,7 +16,7 @@ namespace BizTalkPlatformManagementTool.Services
///
/// Current tool version written into generated snapshots.
///
- public const string Version = "2.2.1-net461";
+ public const string Version = "2.2.2-net461";
///
/// Fallback application name used when WMI does not expose an application property.
diff --git a/src/BizTalkPlatformManagementTool/Services/OperationLogger.cs b/src/BizTalkPlatformManagementTool/Services/OperationLogger.cs
index cab86b0..f45869d 100644
--- a/src/BizTalkPlatformManagementTool/Services/OperationLogger.cs
+++ b/src/BizTalkPlatformManagementTool/Services/OperationLogger.cs
@@ -171,7 +171,22 @@ namespace BizTalkPlatformManagementTool.Services
return;
}
- _sink(entry);
+ try
+ {
+ _sink(entry);
+ }
+ catch (Exception ex)
+ {
+ // Auch die optionale GUI-Weiterleitung ist nur ein Diagnosekanal. Ein Fehler
+ // dort darf insbesondere nicht die Exception-Behandlung eines BizTalk-Schritts
+ // erneut unterbrechen und dadurch alle späteren Planschritte verhindern.
+ WriteToFile(new LogEntry
+ {
+ Timestamp = DateTime.Now,
+ Level = LogLevel.Warning,
+ Message = "Log display sink failed; runtime operation continues. Error: " + ex.Message
+ });
+ }
}
///
diff --git a/src/BizTalkPlatformManagementTool/app.manifest b/src/BizTalkPlatformManagementTool/app.manifest
index 80e6843..c5c815a 100644
--- a/src/BizTalkPlatformManagementTool/app.manifest
+++ b/src/BizTalkPlatformManagementTool/app.manifest
@@ -1,6 +1,6 @@
-
+
diff --git a/tests/BizTalkPlatformManagementTool.Tests/Program.cs b/tests/BizTalkPlatformManagementTool.Tests/Program.cs
index f2a43c4..9f5df3e 100644
--- a/tests/BizTalkPlatformManagementTool.Tests/Program.cs
+++ b/tests/BizTalkPlatformManagementTool.Tests/Program.cs
@@ -27,9 +27,12 @@ namespace BizTalkPlatformManagementTool.Tests
Run("Legacy213SnapshotIsAcceptedForRecovery", Legacy213SnapshotIsAcceptedForRecovery);
Run("RestorePlanUsesSafeOrder", RestorePlanUsesSafeOrder);
Run("ShutdownPlanUsesGlobalSafeOrder", ShutdownPlanUsesGlobalSafeOrder);
+ Run("ShutdownContinuesAcrossArtifactCategoriesAfterReceiveLocationFailure", ShutdownContinuesAcrossArtifactCategoriesAfterReceiveLocationFailure);
Run("EmergencyRestorePlanStartsSsoFirst", EmergencyRestorePlanStartsSsoFirst);
Run("HostInstancePlanAcceptsShortAndFqdnServer", HostInstancePlanAcceptsShortAndFqdnServer);
Run("PlanExecutionContinuesAfterSchedulerFailure", PlanExecutionContinuesAfterSchedulerFailure);
+ Run("PlanExecutionContinuesAfterMultipleUnexpectedExceptions", PlanExecutionContinuesAfterMultipleUnexpectedExceptions);
+ Run("LoggerSinkFailureCannotAbortPlanExecution", LoggerSinkFailureCannotAbortPlanExecution);
Run("PlanExecutionSkipsAlreadySatisfiedState", PlanExecutionSkipsAlreadySatisfiedState);
Run("ExecutionReportRoundTripPreservesFailure", ExecutionReportRoundTripPreservesFailure);
Run("CsvNeutralizesFormulaValues", CsvNeutralizesFormulaValues);
@@ -163,6 +166,22 @@ namespace BizTalkPlatformManagementTool.Tests
Assert(lastSendPort < firstHost, "host instances were not globally last");
}
+ /// Prüft den vollständigen Shutdown-Fortgang von Receive Location bis Host Instance nach einem frühen Fehler.
+ private static void ShutdownContinuesAcrossArtifactCategoriesAfterReceiveLocationFailure()
+ {
+ var snapshot = Snapshot("APP", "SEND", ArtifactStates.SendPortStarted);
+ snapshot.Applications[0].ReceiveLocations.Add(new ReceiveLocationState { Application = "APP", Name = "RV_PMP_Trigger_Schedule", Enabled = true });
+ snapshot.Applications[0].Orchestrations.Add(new OrchestrationState { Application = "APP", Name = "ORCHESTRATION", OrchestrationStatus = ArtifactStates.OrchestrationStarted });
+ snapshot.HostInstances.Add(new HostInstanceState { InstanceName = "HOST:SERVER", HostName = "HOST", Server = snapshot.Server, RawState = ArtifactStates.HostStarted });
+
+ var plan = new BizTalkOperationService(null).CreateShutdownPlan(snapshot, snapshot.Server);
+ var runtime = new FakeOperationStepRuntime { FailingName = "RV_PMP_Trigger_Schedule" };
+ var report = new OperationPlanExecutor(null).Execute(plan, TestOptions(false), runtime);
+
+ Assert(runtime.Calls.SequenceEqual(new[] { "RV_PMP_Trigger_Schedule", "ORCHESTRATION", "SEND", "HOST:SERVER" }), "shutdown did not continue through every later artifact category");
+ Assert(report.FailedCount == 1 && report.SucceededCount == 3, "cross-category shutdown outcome is incomplete");
+ }
+
/// Prüft ENTSSO als erste Voraussetzung des Emergency Restore.
private static void EmergencyRestorePlanStartsSsoFirst()
{
@@ -202,6 +221,27 @@ namespace BizTalkPlatformManagementTool.Tests
Assert(report.Steps[1].Error.Contains("Microsoft.BizTalk.Scheduler"), "nested Scheduler exception missing from report");
}
+ /// Prüft die Fortsetzung auch bei mehreren unterschiedlichen, nicht adapterspezifischen Exceptions.
+ private static void PlanExecutionContinuesAfterMultipleUnexpectedExceptions()
+ {
+ var runtime = new MultipleFailureOperationStepRuntime();
+ var report = new OperationPlanExecutor(null).Execute(TestPlan("INVALID", "IO", "TIMEOUT", "CONTINUE"), TestOptions(false), runtime);
+ Assert(runtime.Calls.SequenceEqual(new[] { "INVALID", "IO", "TIMEOUT", "CONTINUE" }), "an unexpected exception stopped later independent steps");
+ Assert(report.FailedCount == 3 && report.SucceededCount == 1, "multiple failure summary is incomplete");
+ Assert(report.Steps.All(x => !string.IsNullOrWhiteSpace(x.FinishedAt)), "a failure result has no completion timestamp");
+ }
+
+ /// Prüft, dass selbst eine defekte GUI-Logweiterleitung keine fachlichen Schritte verhindert.
+ private static void LoggerSinkFailureCannotAbortPlanExecution()
+ {
+ var logger = new OperationLogger(entry => { throw new InvalidOperationException("simulated UI sink failure"); });
+ var runtime = new FakeOperationStepRuntime { FailingName = "TWO" };
+ var report = new OperationPlanExecutor(logger).Execute(TestPlan("ONE", "TWO", "THREE"), TestOptions(false), runtime);
+ Assert(runtime.Calls.SequenceEqual(new[] { "ONE", "TWO", "THREE" }), "logging failure stopped plan execution");
+ Assert(report.SucceededCount == 2 && report.FailedCount == 1, "logging failure changed business outcomes");
+ Assert(report.Steps[1].Error.Contains("Microsoft.BizTalk.Scheduler"), "business failure was lost while the log sink was failing");
+ }
+
/// Prüft idempotentes Überspringen eines bereits erreichten Sollzustands.
private static void PlanExecutionSkipsAlreadySatisfiedState()
{
@@ -610,6 +650,32 @@ namespace BizTalkPlatformManagementTool.Tests
}
}
+ /// Wirft verschiedene Exception-Typen und liefert danach wieder ein erfolgreiches Ergebnis.
+ private sealed class MultipleFailureOperationStepRuntime : IOperationStepRuntime
+ {
+ /// Initialisiert die vollständige Aufrufliste.
+ public MultipleFailureOperationStepRuntime()
+ {
+ Calls = new List();
+ }
+
+ /// Gets all attempted step names.
+ public List Calls { get; private set; }
+
+ /// Wirft je nach Testschritt eine andere unerwartete Ausnahme.
+ /// Der auszuführende Testschritt.
+ /// Die ungenutzten Testoptionen.
+ /// Erfolg für den abschließenden Fortsetzungsschritt.
+ public RuntimeStepOutcome Execute(OperationStep step, OperationOptions options)
+ {
+ Calls.Add(step.Name);
+ if (step.Name == "INVALID") throw new InvalidOperationException("unexpected state error");
+ if (step.Name == "IO") throw new IOException("unexpected provider I/O error");
+ if (step.Name == "TIMEOUT") throw new TimeoutException("unexpected provider timeout");
+ return RuntimeStepOutcome.Succeeded;
+ }
+ }
+
/// Erstellt einen minimalen Snapshot für Vergleiche und Planprüfungen.
/// Der Name der Testanwendung.
/// Der Name des Test-Send-Ports.