Make shutdown checkpoint dialogs unmistakable
This commit is contained in:
+2
-1
@@ -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.3.3.
|
||||
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.3.4.
|
||||
|
||||
## Installerinvarianten
|
||||
|
||||
@@ -37,6 +37,7 @@ Die zentrale Implementierung liegt in `src/BizTalkPlatformManagementTool.Setup/I
|
||||
- Emergency Restore überschreibt niemals die Eingabe-`before.json`, erzeugt eine timestamp-basierte Kopie und stellt `ENTSSO` vor Host Instances sicher.
|
||||
- Emergency Restore muss mit genau einer validen `before.json` funktionieren; Dateien eines vorherigen fehlgeschlagenen Laufs dürfen keine Voraussetzung sein.
|
||||
- Ein älterer kompatibler Snapshot, insbesondere aus 2.1.3, darf nicht allein anhand seines `ToolVersion`-Werts abgelehnt werden.
|
||||
- Alle laufzeitrelevanten Bestätigungsdialoge müssen mit dem Hauptformular als Owner angezeigt werden. Vor dem echten Drain-Checkpoint muss der Status sichtbar `ACTION REQUIRED`/pausiert melden; Dry-run muss ausdrücklich erklären, dass keine Runtime-Änderung und keine echte Drain-Entscheidung erfolgt.
|
||||
- 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.
|
||||
|
||||
@@ -1,6 +1,20 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
## [2.3.4] - 2026-08-27
|
||||
### Fixed
|
||||
- Shutdown plan review, inbound-drain and emergency-restore confirmations are now owned by the main window, preventing a modal decision from being hidden behind the application in RDP and multi-monitor sessions.
|
||||
- The shutdown status now changes from a generic preparation message to an explicit `ACTION REQUIRED` / paused state before the real inbound-drain decision.
|
||||
|
||||
### Changed
|
||||
- Dry-run and real execution are distinguished with prominent mode text, color and persistent status guidance; execution settings cannot be changed while an operation is active.
|
||||
- A shutdown Dry-run now displays an owned informational notice explaining that it changes no receive locations and therefore does not open the real drain decision dialog.
|
||||
- The prepared real-shutdown confirmation explicitly announces the second decision after the receive-location phase; closing the real checkpoint dialog is explicitly documented as a safe stop.
|
||||
|
||||
### Added
|
||||
- Regression coverage for checkpoint creation when later shutdown work exists without enabled receive locations, and for distinct Dry-run, prepared-plan and paused-checkpoint operator guidance.
|
||||
- A dedicated PROD root-cause analysis, validation runbook and plain-text handoff for shutdown-dialog visibility.
|
||||
|
||||
## [2.3.3] - 2026-08-27
|
||||
### Fixed
|
||||
- Snapshot, shutdown and restore rows no longer show every Send Port, Receive Location and Orchestration under `(Unknown Application)` when the BizTalk runtime WMI classes omit application ownership.
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ Das Release erzeugt folgende Dateien unter `artifacts`:
|
||||
- `BizTalkPlatformManagementTool-Setup.zip.b64.txt`: Certutil-kompatible Base64-Übertragung
|
||||
- `BizTalkPlatformManagementTool-Setup.zip.sha256.txt`: SHA-256 des ZIP-Archivs
|
||||
- `BizTalkPlatformManagementTool-Setup.zip`: direkt entpackbares Installationspaket
|
||||
- `BizTalkPlatformManagementTool-2.3.3-source.zip.b64.txt`: vollständiger Quellstand als Base64-TXT
|
||||
- `BizTalkPlatformManagementTool-2.3.3-source.zip.sha256.txt`: SHA-256 des Quellarchivs
|
||||
- `BizTalkPlatformManagementTool-2.3.4-source.zip.b64.txt`: vollständiger Quellstand als Base64-TXT
|
||||
- `BizTalkPlatformManagementTool-2.3.4-source.zip.sha256.txt`: SHA-256 des Quellarchivs
|
||||
|
||||
Auf dem Zielsystem wird die TXT-Datei so rekonstruiert und geprüft:
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
PROD-RUNBOOK: SCHEDULEDTASK-STEUERUNG UND PERSISTENTES LAUFZEITLOGGING
|
||||
Stand: 2026-08-26
|
||||
Zielversion: 2.3.3
|
||||
Zielversion: 2.3.4
|
||||
Adapter: BizTalk ScheduledTask Adapter 7.0.2
|
||||
Adapterpfad: C:\Program Files (x86)\BizTalk ScheduledTask Adapter 7.0.2
|
||||
|
||||
@@ -13,8 +13,8 @@ laufenden Toolprozess. Das Tool kopiert keine DLL und aendert den GAC nicht.
|
||||
|
||||
VORBEREITUNG
|
||||
1. before.json, Reports und vorhandene Logs extern sichern.
|
||||
2. Setup 2.3.3 als Administrator installieren/aktualisieren.
|
||||
3. setup_version=2.3.3.0 und erfolgreichen Ziel-Self-Test pruefen.
|
||||
2. Setup 2.3.4 als Administrator installieren/aktualisieren.
|
||||
3. setup_version=2.3.4.0 und erfolgreichen Ziel-Self-Test pruefen.
|
||||
4. Tool als Administrator starten, gruenen Startup-Log-Pruefeintrag kontrollieren,
|
||||
dann Log Folder oeffnen. Normalfall: %ProgramData%\BizTalkPlatformManagementTool\Logs.
|
||||
5. Im lokalen BizTalk-Ordner Microsoft.BizTalk.Scheduler.dll pruefen.
|
||||
@@ -74,7 +74,7 @@ ABNAHME
|
||||
- Teilfehler bleibt Failed, spaetere unabhaengige Schritte laufen weiter.
|
||||
- Historie erscheint nach Neustart im Grid.
|
||||
- Vortage komprimiert, 30 Kalendertage aufbewahrt.
|
||||
- Setup/Tool/Reports zeigen 2.3.3 bzw. 2.3.3-net461.
|
||||
- Setup/Tool/Reports zeigen 2.3.4 bzw. 2.3.4-net461.
|
||||
|
||||
Detailfassung:
|
||||
docs\PROD-ScheduledTask-und-Laufzeitlogging-2026-08-26.md
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
PROD-HANDOFF: SHUTDOWN-DIALOG-SICHTBARKEIT - VERSION 2.3.4
|
||||
Datum: 2026-08-27
|
||||
|
||||
BEFUND
|
||||
Nach der Receive-Location-Phase wurde kein sichtbarer Dialog zur Bestaetigung
|
||||
des Leerlaufens wahrgenommen.
|
||||
|
||||
URSACHEN
|
||||
1. Dry run ist standardmaessig aktiv. Er deaktiviert keine Receive Location und
|
||||
ruft deshalb bewusst keinen echten Drain-Entscheidungsdialog auf. Dieser
|
||||
Unterschied war waehrend der Ausfuehrung nicht deutlich genug sichtbar.
|
||||
2. Die bisherigen MessageBoxen hatten keinen Owner. In RDP-/Multi-Monitor-
|
||||
Sitzungen konnte ein modaler Plan- oder Drain-Dialog hinter dem Hauptfenster
|
||||
liegen, waehrend dort nur "Preparing shutdown..." sichtbar blieb.
|
||||
|
||||
SICHERHEIT
|
||||
Der persistierte OperatorCheckpoint war vorhanden. Ohne Dialog-Callback, bei
|
||||
Fehler, Nein oder Schliessen stoppt der echte Shutdown fail-closed. Spaetere
|
||||
Orchestrierungen, Send Ports und Host Instances bleiben NotExecuted.
|
||||
|
||||
FIX 2.3.4
|
||||
- Alle runtime-relevanten Bestaetigungen sind an das Hauptfenster gebunden.
|
||||
- Am echten Checkpoint steht sichtbar ACTION REQUIRED / Shutdown paused.
|
||||
- Der erste Realbetrieb-Dialog kuendigt die zweite Drain-Entscheidung an.
|
||||
- Dry run und REAL EXECUTION sind farblich und textlich eindeutig.
|
||||
- Dry run zeigt einen eigenen Hinweis: keine Mutation, keine echte Drain-
|
||||
Entscheidung.
|
||||
- Einstellungen sind waehrend einer laufenden Operation gesperrt.
|
||||
|
||||
PROD-ABNAHME
|
||||
1. Setup 2.3.4 installieren; setup_version=2.3.4.0 und Ziel-Self-Test pruefen.
|
||||
2. Dry run: Shutdown Dry Run - No Runtime Changes muss sichtbar sein; keine
|
||||
BizTalk-Mutation.
|
||||
3. shutdown-plan.json: OperatorCheckpoint muss vor jeder spaeteren Shutdown-
|
||||
Phase stehen.
|
||||
4. Freigegebenes Wartungsfenster: Dry run deaktivieren; REAL EXECUTION muss
|
||||
sichtbar sein.
|
||||
5. Ersten gespeicherten Plan bestaetigen.
|
||||
6. Nach Receive Locations: ACTION REQUIRED und owner-gebundener Drain-Dialog.
|
||||
7. Zuerst Nein testen: CheckpointDecision=Stop, alle spaeteren Zeilen
|
||||
NotExecuted.
|
||||
8. Danach kontrolliert wiederholen; Group Hub und Monitoring pruefen; erst bei
|
||||
bestaetigtem Leerlauf Ja auswaehlen.
|
||||
9. RDP minimieren/wiederherstellen und ggf. Monitorwechsel testen.
|
||||
|
||||
ALTE LAEUFE UNTERSCHEIDEN
|
||||
- DryRun=true + keine CheckpointDecision: erwartete Simulation.
|
||||
- Kein Ergebnis + UI bleibt Preparing shutdown: moeglicherweise verdeckter
|
||||
Dialog; Alt+Tab pruefen, Prozess nicht blind beenden.
|
||||
- CheckpointDecision=Stop/Error: sicher vor spaeteren Phasen gestoppt.
|
||||
- CheckpointDecision=Continue: positive Bedienerentscheidung wurde erfasst.
|
||||
|
||||
Portable Verifikation: Release-Build aller vier Projekte, 43 Regressionstests,
|
||||
Runtime-Self-Test und manifest-/hashgepruefte Paketierung. Die finale Dialog-
|
||||
und BizTalk-Pruefung erfolgt auf Windows/PROD.
|
||||
@@ -29,6 +29,7 @@ WinForms tool for controlled Microsoft BizTalk Server 2020 platform operations d
|
||||
- Thirty-day runtime-log retention with GZip compression for completed daily logs
|
||||
- Process-local ScheduledTask adapter dependency resolution for `scheduler:` receive locations without modifying the GAC
|
||||
- Fail-closed operator drain checkpoint after all receive locations and before later shutdown phases
|
||||
- Owner-bound shutdown confirmations with an explicit paused/action-required status and an unambiguous Dry-run notice
|
||||
- Best-effort plan execution: one isolated WMI failure is recorded while remaining independent steps continue
|
||||
- Idempotent execution that skips artifacts already in the requested target state
|
||||
- Durable per-step result reports even when a shutdown or restore completes only partially
|
||||
@@ -78,7 +79,7 @@ Restore:
|
||||
|
||||
Orchestrations that were `Bound` are deliberately left unchanged during restore to avoid accidentally making them `Unbound`.
|
||||
|
||||
The drain checkpoint is part of `shutdown-plan.json`. In a real run, **Yes** records `CheckpointDecision=Continue`; **No**, a closed dialog or a callback error fails closed before orchestrations, send ports and host instances. All later rows are persisted as `NotExecuted`, followed by a partial-state snapshot and `shutdown-result.json`. Dry-run shows the checkpoint but never opens a decision dialog.
|
||||
The drain checkpoint is part of `shutdown-plan.json`. In a real run, the status changes to **ACTION REQUIRED**, and the owned dialog remains in front of the main window. **Yes** records `CheckpointDecision=Continue`; **No**, a closed dialog or a callback error fails closed before orchestrations, send ports and host instances. All later rows are persisted as `NotExecuted`, followed by a partial-state snapshot and `shutdown-result.json`. Dry-run shows the checkpoint but never opens a decision dialog; it displays a separate notice explaining that no receive location was changed.
|
||||
|
||||
BizTalk applications displaying `Partially Started` immediately after receive locations are disabled is expected. Microsoft defines “Partial Stop - Allow running instances to continue” as disabling only receive locations so in-flight instances can finish. The tool deliberately does not issue an additional application-level stop: its stronger variants can stop or unenlist artifacts, remove subscriptions, undeploy policies or terminate instances. The existing artifact-level plan preserves exact snapshot state and controlled global ordering.
|
||||
|
||||
@@ -148,5 +149,6 @@ Targeted German inline comments explain non-obvious operational decisions such a
|
||||
- [PROD runtime-log storage validation and 2.3.1 fix](docs/PROD-Laufzeitlog-Ablage-2026-08-26.md)
|
||||
- [PROD shutdown drain checkpoint and application-status analysis](docs/PROD-Shutdown-Drain-Checkpoint-2026-08-26.md)
|
||||
- [PROD application-association analysis and 2.3.3 validation](docs/PROD-Application-Zuordnung-2026-08-27.md)
|
||||
- [PROD shutdown-dialog visibility analysis and 2.3.4 validation](docs/PROD-Shutdown-Dialog-Sichtbarkeit-2026-08-27.md)
|
||||
- [AI maintainer handoff](AI-README.md)
|
||||
- [References](REFERENCES.md)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**Stand:** 2026-08-26
|
||||
|
||||
**Zielversion:** 2.3.3
|
||||
**Zielversion:** 2.3.4
|
||||
|
||||
**Betroffener Adapter:** BizTalk ScheduledTask Adapter 7.0.2
|
||||
|
||||
@@ -17,8 +17,8 @@ Version 2.3.1 erkennt ScheduledTask-Schritte an Adaptername oder `scheduler:`-UR
|
||||
## Vorbereitung
|
||||
|
||||
1. Vorhandene `before.json`, Ergebnisdateien und Laufzeitlogs außerhalb des Installationsordners sichern.
|
||||
2. Setup 2.3.3 als Administrator installieren beziehungsweise aktualisieren.
|
||||
3. Im Setup-Log `setup_version=2.3.3.0` und erfolgreichen Ziel-Self-Test prüfen.
|
||||
2. Setup 2.3.4 als Administrator installieren beziehungsweise aktualisieren.
|
||||
3. Im Setup-Log `setup_version=2.3.4.0` und erfolgreichen Ziel-Self-Test prüfen.
|
||||
4. Tool als Administrator starten, den grünen Eintrag `Runtime log storage verified by startup append` prüfen und mit **Log Folder** den dort genannten aktiven Pfad öffnen. Normalfall ist `%ProgramData%\BizTalkPlatformManagementTool\Logs`.
|
||||
5. Prüfen, dass der lokale BizTalk-Installationsordner `Microsoft.BizTalk.Scheduler.dll` enthält.
|
||||
6. Nur wenn BizTalk oder der Adapter abweichend installiert wurde: `AdapterAssemblySearchPaths` in `BizTalkPlatformManagementTool.exe.config` um den vorhandenen lokalen Ordner ergänzen. Mehrere Pfade werden mit Semikolon getrennt. Keine DLL aus ACC, einer alten BizTalk-Version oder einem Downloadordner kopieren.
|
||||
@@ -78,6 +78,6 @@ Der Fehlerdatensatz enthält Exceptiontyp, HRESULT, innere Ausnahmen, vorhandene
|
||||
- Ergebnisreport und Nachher-Snapshot werden auch bei einem Teilfehler soweit möglich geschrieben.
|
||||
- Historisches Log erscheint nach Neustart wieder im Grid.
|
||||
- Vortagslogs werden komprimiert und exakt 30 Kalendertage aufbewahrt.
|
||||
- Setup, Tool und Ergebnisdateien melden Version 2.3.3 beziehungsweise `2.3.3-net461`.
|
||||
- Setup, Tool und Ergebnisdateien melden Version 2.3.4 beziehungsweise `2.3.4-net461`.
|
||||
|
||||
Die lokale Mono-Toolchain prüft Resolverlogik, Identitätsgrenze, Persistenz, Kompression und Aufbewahrung ohne BizTalk. Die endgültige Freigabe erfordert diesen realen Windows-/BizTalk-/PROD-Test.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# PROD-Analyse: Shutdown-Dialog nicht sichtbar
|
||||
|
||||
**Datum:** 27.08.2026
|
||||
|
||||
**Zielversion:** 2.3.4
|
||||
|
||||
**Befund:** Nach der Receive-Location-Phase wurde kein sichtbarer Dialog zur Bestätigung des Leerlaufens wahrgenommen.
|
||||
|
||||
## Ergebnis der Ursachenanalyse
|
||||
|
||||
Der fachliche Checkpoint war in Version 2.3.3 vorhanden: Jeder Shutdown-Plan mit nachgelagerter Arbeit enthält genau eine persistierte `OperatorCheckpoint`-Zeile vor Orchestrierungen, Send Ports und lokalen Host Instances. Ohne Callback, bei einem Fehler oder bei **Nein** stoppt der Executor fail-closed; keine geschützte spätere Phase wird ausgeführt.
|
||||
|
||||
Die Oberfläche hatte aber zwei voneinander unabhängige Sichtbarkeitsprobleme:
|
||||
|
||||
1. **Dry run ist standardmäßig aktiv.** In diesem Modus wird keine Receive Location deaktiviert. Deshalb wird der echte Entscheidungsdialog absichtlich nicht aufgerufen; nur die Checkpoint-Zeile wird simuliert. Der kleine Haken und der generische Status machten diesen Unterschied während der Ausführung nicht eindeutig.
|
||||
2. **Die Bestätigungen hatten keinen Fenster-Owner.** `MessageBox.Show(...)` wurde aus dem UI-Thread aufgerufen, aber nicht an das Hauptformular gebunden. Unter RDP, nach Monitorwechseln oder bei abweichender Z-Order konnte der modale Dialog hinter dem Hauptfenster beziehungsweise außerhalb des erwarteten Vordergrunds liegen. Der Background-Worker wartete dann korrekt auf `Invoke`, während das Hauptfenster weiterhin nur `Preparing shutdown...` zeigte und deaktiviert wirkte.
|
||||
|
||||
Der Screenshot allein unterscheidet die beiden Fälle nicht, weil der Einstellungsbereich mit **Dry run** nicht sichtbar und kein `shutdown-result.json` beigefügt ist. Der sichtbare Zustand `Preparing shutdown...` bei bereits dargestelltem Plan ist jedoch mit einem wartenden, owner-losen Plan- oder Drain-Dialog vereinbar. Ein abgeschlossenes `DryRun=true` mit leerer `CheckpointDecision` belegt dagegen die beabsichtigte Simulation.
|
||||
|
||||
## Korrektur in 2.3.4
|
||||
|
||||
- Planfreigabe, Drain-Entscheidung und Emergency-Restore-Bestätigung verwenden das Hauptformular explizit als Owner und holen es vor dem Anzeigen nach vorn.
|
||||
- Unmittelbar vor der echten Drain-Entscheidung meldet die Statuszeile: `ACTION REQUIRED: Shutdown paused`.
|
||||
- Der Titel des Checkpoints beginnt mit `ACTION REQUIRED`; der Text erklärt, dass der Shutdown pausiert ist und **Nein oder Schließen** sicher stoppt.
|
||||
- Die erste Freigabe eines echten Shutdowns kündigt den zweiten Dialog nach der Receive-Location-Phase ausdrücklich an.
|
||||
- Dry-run und Realbetrieb haben gut sichtbare, farblich getrennte Texte. Während einer Operation sind diese Einstellungen gesperrt.
|
||||
- Ein Shutdown-Dry-run zeigt einen eigenen owner-gebundenen Hinweis: keine Runtime-Änderung, keine deaktivierte Receive Location und daher keine echte Drain-Entscheidung.
|
||||
|
||||
Die Sicherheitssemantik bleibt unverändert: Das Tool behauptet keinen automatisch erkannten Leerlauf. Nur der Operator kann nach Prüfung von Group Hub und Enterprise-Monitoring mit **Ja** fortsetzen.
|
||||
|
||||
## Diagnose vorhandener 2.3.2/2.3.3-Läufe
|
||||
|
||||
`shutdown-result.json` und `shutdown-plan.json` sichern und wie folgt bewerten:
|
||||
|
||||
| Evidenz | Bedeutung |
|
||||
|---|---|
|
||||
| `DryRun=true`, Checkpoint-Outcome `DryRun`, keine `CheckpointDecision` | Erwartete Simulation; es gab keine Runtime-Änderung und bewusst keinen Entscheidungsdialog. |
|
||||
| Kein Ergebnisreport, UI bleibt bei `Preparing shutdown...` | Lauf wartet möglicherweise auf einen verdeckten Plan- oder Drain-Dialog; Taskwechsel/Alt+Tab prüfen. Prozess nicht blind beenden. |
|
||||
| `DryRun=false`, `CheckpointDecision=Stop` | Operator hat Nein gewählt oder sicher gestoppt; spätere Zeilen müssen `NotExecuted` sein. |
|
||||
| `DryRun=false`, `CheckpointDecision=Error` | Dialogmechanismus fehlte/fehlerhaft; fail-closed, spätere Zeilen müssen `NotExecuted` sein. |
|
||||
| `DryRun=false`, `CheckpointDecision=Continue` | Eine positive Entscheidung wurde erfasst; spätere Phasen durften laufen. |
|
||||
| Plan ohne `OperatorCheckpoint` | Nur zulässig, wenn keine Orchestrierung, kein Send Port und keine lokale Host Instance nachgelagert herunterzufahren war. |
|
||||
|
||||
## PROD-Abnahme 2.3.4
|
||||
|
||||
1. Setup 2.3.4 als Administrator installieren und im Setup-Log `setup_version=2.3.4.0` sowie den erfolgreichen Ziel-Self-Test prüfen.
|
||||
2. Tooldateiversion und Self-Test-Ausgabe `2.3.4-net461` prüfen.
|
||||
3. **Dry run** aktiviert lassen, **Shutdown** wählen und den Hinweis `Shutdown Dry Run - No Runtime Changes` prüfen. Es darf keine BizTalk-Mutation stattfinden.
|
||||
4. `shutdown-plan.json` prüfen: Bei späterer Shutdown-Arbeit steht `OperatorCheckpoint` vor Orchestrierungen, Send Ports und Host Instances.
|
||||
5. In einem freigegebenen Wartungsfenster **Dry run** deaktivieren. Der Modus muss `REAL EXECUTION - drain dialog required` anzeigen.
|
||||
6. Den gespeicherten Plan im ersten owner-gebundenen Dialog bestätigen.
|
||||
7. Nach den Receive Locations muss die Statuszeile `ACTION REQUIRED` zeigen und der Dialog `ACTION REQUIRED - Confirm BizTalk Inbound Drain` vor dem Hauptfenster stehen.
|
||||
8. Zuerst **Nein** testen. `shutdown-result.json` muss `CheckpointDecision=Stop` und für alle späteren Zeilen `NotExecuted` enthalten.
|
||||
9. Den kontrollierten Test wiederholen, Group Hub/Monitoring prüfen und erst nach bestätigtem Leerlauf **Ja** wählen. Danach dürfen Orchestrierungen, Send Ports und Host Instances folgen.
|
||||
10. RDP minimieren/wiederherstellen und, falls im Betrieb üblich, Monitorwechsel testen. Der owner-gebundene Dialog muss dem Hauptfenster zugeordnet bleiben.
|
||||
|
||||
Die portable Verifikation umfasst Release-Build aller vier Projekte, 43 Regressionstests, Runtime-Self-Test und die manifest-/hashgeprüfte Paketierung. Die abschließende Sichtbarkeits- und BizTalk-Abnahme bleibt ein Windows-/PROD-Test.
|
||||
@@ -23,7 +23,7 @@ namespace BizTalkPlatformManagementTool.Setup
|
||||
private const string ProductName = "BizTalk Platform Management Tool";
|
||||
|
||||
/// <summary>Aktuelle Produktversion des Installers und Uninstall-Eintrags.</summary>
|
||||
private const string ProductVersion = "2.3.3";
|
||||
private const string ProductVersion = "2.3.4";
|
||||
|
||||
/// <summary>
|
||||
/// Wartezeiten zwischen Wiederholungen atomarer Verzeichnisverschiebungen.
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace BizTalkPlatformManagementTool.Setup
|
||||
{
|
||||
AutoSize = true,
|
||||
Font = new Font(Font.FontFamily, 14, FontStyle.Bold),
|
||||
Text = "BizTalk Platform Management Tool 2.3.3"
|
||||
Text = "BizTalk Platform Management Tool 2.3.4"
|
||||
});
|
||||
root.Controls.Add(new Label
|
||||
{
|
||||
|
||||
@@ -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.3.3.0")]
|
||||
[assembly: AssemblyFileVersion("2.3.3.0")]
|
||||
[assembly: AssemblyVersion("2.3.4.0")]
|
||||
[assembly: AssemblyFileVersion("2.3.4.0")]
|
||||
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="2.3.3.0" name="BizTalkPlatformManagementTool.Setup" />
|
||||
<assemblyIdentity version="2.3.4.0" name="BizTalkPlatformManagementTool.Setup" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security><requestedPrivileges><requestedExecutionLevel level="requireAdministrator" uiAccess="false" /></requestedPrivileges></security>
|
||||
</trustInfo>
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<Compile Include="Services\SnapshotValidator.cs" />
|
||||
<Compile Include="Services\SnapshotStore.cs" />
|
||||
<Compile Include="Services\BizTalkOperationService.cs" />
|
||||
<Compile Include="Ui\ShutdownOperatorPrompts.cs" />
|
||||
<Compile Include="Ui\MainForm.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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.3.3.0")]
|
||||
[assembly: AssemblyFileVersion("2.3.3.0")]
|
||||
[assembly: AssemblyVersion("2.3.4.0")]
|
||||
[assembly: AssemblyFileVersion("2.3.4.0")]
|
||||
[assembly: InternalsVisibleTo("BizTalkPlatformManagementTool.Tests")]
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace BizTalkPlatformManagementTool.Services
|
||||
/// <summary>
|
||||
/// Current tool version written into generated snapshots.
|
||||
/// </summary>
|
||||
public const string Version = "2.3.3-net461";
|
||||
public const string Version = "2.3.4-net461";
|
||||
|
||||
/// <summary>
|
||||
/// Fallback application name used when neither WMI nor the ExplorerOM catalog can resolve ownership.
|
||||
|
||||
@@ -238,6 +238,8 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
_dryRunCheckBox.Dock = DockStyle.Fill;
|
||||
_dryRunCheckBox.Margin = new Padding(8, 7, 8, 7);
|
||||
_dryRunCheckBox.TextAlign = ContentAlignment.MiddleLeft;
|
||||
_dryRunCheckBox.CheckedChanged += DryRunCheckBoxCheckedChanged;
|
||||
UpdateDryRunPresentation();
|
||||
|
||||
var browseButton = new Button { Text = "Browse...", Dock = DockStyle.Fill, Margin = new Padding(8, 5, 8, 5) };
|
||||
browseButton.Click += BrowseButtonClick;
|
||||
@@ -404,7 +406,9 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
private void ShutdownClick(object sender, EventArgs e)
|
||||
{
|
||||
var options = GetOptions();
|
||||
RunAsync("Preparing shutdown...", () =>
|
||||
RunAsync(options.DryRun
|
||||
? "DRY RUN: Preparing shutdown plan; no runtime state will be changed."
|
||||
: "REAL SHUTDOWN: Preparing snapshot and saved plan.", () =>
|
||||
{
|
||||
var snapshot = _service.CreateSnapshot(options.Server);
|
||||
_service.SaveSnapshot(options.OutputDirectory, "before.json", snapshot);
|
||||
@@ -412,7 +416,11 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
// Der exakte, frisch erzeugte Plan wird vor Bestätigung und jeder Laufzeitänderung gespeichert.
|
||||
var planPath = _service.SavePlan(options.OutputDirectory, "shutdown-plan.json", plan);
|
||||
ShowPlan(plan);
|
||||
if (!options.DryRun && !ConfirmPreparedPlan("Shutdown", plan, options.Server, planPath))
|
||||
if (options.DryRun)
|
||||
{
|
||||
ShowShutdownDryRunNotice(plan, planPath);
|
||||
}
|
||||
else if (!ConfirmPreparedPlan("Shutdown", plan, options.Server, planPath))
|
||||
{
|
||||
_logger.Warning("Shutdown cancelled after plan review. No runtime state was changed.");
|
||||
return;
|
||||
@@ -706,13 +714,13 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
var confirmed = false;
|
||||
Action showConfirmation = () =>
|
||||
{
|
||||
var executableSteps = plan.Steps.Count(x => x.Execute && !string.Equals(x.Kind, OperationStepKind.OperatorCheckpoint.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
var checkpointCount = plan.Steps.Count(x => x.Execute && string.Equals(x.Kind, OperationStepKind.OperatorCheckpoint.ToString(), StringComparison.OrdinalIgnoreCase));
|
||||
_statusLabel.Text = "ACTION REQUIRED: Review the saved " + actionName.ToLowerInvariant() + " plan and answer the owned confirmation dialog.";
|
||||
Activate();
|
||||
BringToFront();
|
||||
var result = MessageBox.Show(
|
||||
actionName + " will execute " + executableSteps + " step(s) on server '" + server + "'.\n\n"
|
||||
+ (checkpointCount == 0 ? string.Empty : "The saved plan contains an operator drain checkpoint after all receive locations.\n\n")
|
||||
+ "The exact plan was saved to:\n" + planPath + "\n\nContinue now?",
|
||||
"Confirm Prepared BizTalk Plan",
|
||||
this,
|
||||
ShutdownOperatorPrompts.BuildPreparedPlanConfirmation(actionName, plan, server, planPath),
|
||||
ShutdownOperatorPrompts.PreparedPlanTitle,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning,
|
||||
MessageBoxDefaultButton.Button2);
|
||||
@@ -730,6 +738,37 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
return confirmed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the dry-run boundary explicit: the prepared checkpoint is visible in
|
||||
/// the plan, but no receive location changes and no real drain decision occurs.
|
||||
/// </summary>
|
||||
/// <param name="plan">The prepared shutdown plan.</param>
|
||||
/// <param name="planPath">The durable path of the prepared plan.</param>
|
||||
private void ShowShutdownDryRunNotice(OperationPlan plan, string planPath)
|
||||
{
|
||||
Action showNotice = () =>
|
||||
{
|
||||
_statusLabel.Text = "DRY RUN: Plan prepared. No runtime changes and no real drain decision dialog.";
|
||||
Activate();
|
||||
BringToFront();
|
||||
MessageBox.Show(
|
||||
this,
|
||||
ShutdownOperatorPrompts.BuildDryRunNotice(plan, planPath),
|
||||
ShutdownOperatorPrompts.DryRunTitle,
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Information);
|
||||
};
|
||||
|
||||
if (InvokeRequired)
|
||||
{
|
||||
Invoke(showNotice);
|
||||
}
|
||||
else
|
||||
{
|
||||
showNotice();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pauses a real shutdown after the receive-location phase until the operator
|
||||
/// confirms that the enterprise environment has drained.
|
||||
@@ -742,25 +781,13 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
var confirmed = false;
|
||||
Action showConfirmation = () =>
|
||||
{
|
||||
var receiveResults = progress.Steps
|
||||
.Where(x => string.Equals(x.Kind, OperationStepKind.ReceiveLocation.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
var succeeded = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.Succeeded);
|
||||
var alreadyDisabled = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.AlreadySatisfied);
|
||||
var failed = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.Failed);
|
||||
var failureWarning = failed == 0
|
||||
? string.Empty
|
||||
: "\nWARNING: " + failed + " receive location(s) failed. Review the red Operation Log entries before continuing.\n";
|
||||
_statusLabel.Text = ShutdownOperatorPrompts.WaitingForInboundDrainStatus;
|
||||
Activate();
|
||||
BringToFront();
|
||||
var result = MessageBox.Show(
|
||||
"The receive-location shutdown phase has finished.\n\n"
|
||||
+ "Disabled successfully: " + succeeded + "\n"
|
||||
+ "Already disabled: " + alreadyDisabled + "\n"
|
||||
+ "Failed: " + failed + "\n"
|
||||
+ failureWarning + "\n"
|
||||
+ "Keep this dialog open while you verify in BizTalk Group Hub and your enterprise monitoring that no new inbound work arrives and all in-flight service instances/messages have drained.\n\n"
|
||||
+ "Continue with orchestrations, send ports and host instances?\n\n"
|
||||
+ "Yes = continue shutdown. No = stop safely and persist all remaining steps as NotExecuted.",
|
||||
"Confirm BizTalk Inbound Drain",
|
||||
this,
|
||||
ShutdownOperatorPrompts.BuildInboundDrainConfirmation(progress),
|
||||
ShutdownOperatorPrompts.InboundDrainTitle,
|
||||
MessageBoxButtons.YesNo,
|
||||
MessageBoxIcon.Warning,
|
||||
MessageBoxDefaultButton.Button2);
|
||||
@@ -792,8 +819,12 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
var confirmed = false;
|
||||
Action showConfirmation = () =>
|
||||
{
|
||||
_statusLabel.Text = "ACTION REQUIRED: Review the emergency restore plan and answer the owned confirmation dialog.";
|
||||
Activate();
|
||||
BringToFront();
|
||||
var executableSteps = plan.Steps.Count(x => x.Execute);
|
||||
var result = MessageBox.Show(
|
||||
this,
|
||||
"EMERGENCY RESTORE will reconcile " + executableSteps + " step(s) on server '" + server + "'.\n\n"
|
||||
+ "Source snapshot (will not be overwritten):\n" + sourcePath + "\n\n"
|
||||
+ "Enterprise Single Sign-On will be ensured Running first. Already-correct states are skipped; isolated failures are recorded and later steps continue.\n\n"
|
||||
@@ -983,10 +1014,43 @@ namespace BizTalkPlatformManagementTool.Ui
|
||||
_clearButton.Enabled = !busy;
|
||||
_openLogsButton.Enabled = !busy;
|
||||
_closeButton.Enabled = !busy;
|
||||
_statusLabel.Text = status;
|
||||
_serverTextBox.Enabled = !busy;
|
||||
_outputTextBox.Enabled = !busy;
|
||||
_stateFileTextBox.Enabled = !busy;
|
||||
_timeoutInput.Enabled = !busy;
|
||||
_pollInput.Enabled = !busy;
|
||||
_dryRunCheckBox.Enabled = !busy;
|
||||
_statusLabel.Text = !busy && string.Equals(status, "Ready.", StringComparison.Ordinal)
|
||||
? "Ready. " + (_dryRunCheckBox.Checked
|
||||
? "DRY RUN is enabled; shutdown will not change runtime state or request a drain decision."
|
||||
: "REAL EXECUTION is enabled; shutdown will pause for the owned drain decision.")
|
||||
: status;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>Updates the prominent execution-mode warning when Dry run changes.</summary>
|
||||
/// <param name="sender">The checkbox that raised the event.</param>
|
||||
/// <param name="e">The event arguments.</param>
|
||||
private void DryRunCheckBoxCheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateDryRunPresentation();
|
||||
if (!_isBusy)
|
||||
{
|
||||
_statusLabel.Text = _dryRunCheckBox.Checked
|
||||
? "Ready. DRY RUN is enabled; shutdown will not change runtime state or request a drain decision."
|
||||
: "Ready. REAL EXECUTION is enabled; shutdown will pause for the owned drain decision.";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Uses explicit text and color instead of relying on a small check mark.</summary>
|
||||
private void UpdateDryRunPresentation()
|
||||
{
|
||||
_dryRunCheckBox.Text = _dryRunCheckBox.Checked
|
||||
? "DRY RUN - no changes / no drain dialog"
|
||||
: "REAL EXECUTION - drain dialog required";
|
||||
_dryRunCheckBox.BackColor = _dryRunCheckBox.Checked ? Color.LightGoldenrodYellow : Color.MistyRose;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the output directory Browse button click.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using BizTalkPlatformManagementTool.Models;
|
||||
|
||||
namespace BizTalkPlatformManagementTool.Ui
|
||||
{
|
||||
/// <summary>
|
||||
/// Builds stable, testable operator guidance for shutdown plan review, dry-run
|
||||
/// simulation and the real inbound-drain checkpoint.
|
||||
/// </summary>
|
||||
internal static class ShutdownOperatorPrompts
|
||||
{
|
||||
/// <summary>Title of the non-mutating dry-run explanation.</summary>
|
||||
public const string DryRunTitle = "Shutdown Dry Run - No Runtime Changes";
|
||||
|
||||
/// <summary>Title of the saved-plan confirmation.</summary>
|
||||
public const string PreparedPlanTitle = "Confirm Prepared BizTalk Plan";
|
||||
|
||||
/// <summary>Title of the real inbound-drain decision.</summary>
|
||||
public const string InboundDrainTitle = "ACTION REQUIRED - Confirm BizTalk Inbound Drain";
|
||||
|
||||
/// <summary>Status displayed while the real shutdown waits for drain verification.</summary>
|
||||
public const string WaitingForInboundDrainStatus = "ACTION REQUIRED: Shutdown paused. Verify inbound drain and answer the owned confirmation dialog.";
|
||||
|
||||
/// <summary>Builds the explicit explanation shown for a shutdown dry-run.</summary>
|
||||
/// <param name="plan">The prepared shutdown plan.</param>
|
||||
/// <param name="planPath">The durable path of the prepared plan.</param>
|
||||
/// <returns>Operator-facing dry-run guidance.</returns>
|
||||
public static string BuildDryRunNotice(OperationPlan plan, string planPath)
|
||||
{
|
||||
if (plan == null)
|
||||
{
|
||||
throw new ArgumentNullException("plan");
|
||||
}
|
||||
|
||||
var checkpointCount = CountCheckpoints(plan);
|
||||
return "DRY RUN is enabled. This run only simulates the saved shutdown plan.\n\n"
|
||||
+ "No receive location is disabled and no runtime state is changed. Therefore the real inbound-drain decision dialog will not open during this run.\n\n"
|
||||
+ (checkpointCount == 0
|
||||
? "This plan has no later shutdown phase and therefore needs no drain checkpoint.\n\n"
|
||||
: "The plan contains the inbound-drain checkpoint. It will require an explicit Yes/No decision when the same plan is prepared with Dry run disabled.\n\n")
|
||||
+ "Prepared plan:\n" + planPath;
|
||||
}
|
||||
|
||||
/// <summary>Builds the confirmation for a fully prepared real operation.</summary>
|
||||
/// <param name="actionName">The operation name.</param>
|
||||
/// <param name="plan">The prepared operation plan.</param>
|
||||
/// <param name="server">The selected target server.</param>
|
||||
/// <param name="planPath">The durable path of the prepared plan.</param>
|
||||
/// <returns>Operator-facing prepared-plan confirmation.</returns>
|
||||
public static string BuildPreparedPlanConfirmation(string actionName, OperationPlan plan, string server, string planPath)
|
||||
{
|
||||
if (plan == null)
|
||||
{
|
||||
throw new ArgumentNullException("plan");
|
||||
}
|
||||
|
||||
var executableSteps = plan.Steps.Count(x => x.Execute && !IsCheckpoint(x));
|
||||
var checkpointCount = CountCheckpoints(plan);
|
||||
return actionName + " will execute " + executableSteps + " step(s) on server '" + server + "'.\n\n"
|
||||
+ (checkpointCount == 0
|
||||
? string.Empty
|
||||
: "The saved plan contains an operator drain checkpoint after all receive locations. The real shutdown will visibly pause there for a second, explicit decision.\n\n")
|
||||
+ "The exact plan was saved to:\n" + planPath + "\n\nContinue now?";
|
||||
}
|
||||
|
||||
/// <summary>Builds the real inbound-drain decision from completed receive-location results.</summary>
|
||||
/// <param name="progress">The execution results already reached.</param>
|
||||
/// <returns>Operator-facing drain verification guidance.</returns>
|
||||
public static string BuildInboundDrainConfirmation(OperationExecutionReport progress)
|
||||
{
|
||||
if (progress == null)
|
||||
{
|
||||
throw new ArgumentNullException("progress");
|
||||
}
|
||||
|
||||
var receiveResults = progress.Steps
|
||||
.Where(x => string.Equals(x.Kind, OperationStepKind.ReceiveLocation.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
var succeeded = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.Succeeded);
|
||||
var alreadyDisabled = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.AlreadySatisfied);
|
||||
var failed = receiveResults.Count(x => x.Outcome == OperationStepOutcomes.Failed);
|
||||
var failureWarning = failed == 0
|
||||
? string.Empty
|
||||
: "\nWARNING: " + failed + " receive location(s) failed. Review the red Operation Log entries before continuing.\n";
|
||||
|
||||
return "The receive-location shutdown phase has finished. The shutdown is PAUSED and no later phase can run until you decide.\n\n"
|
||||
+ "Disabled successfully: " + succeeded + "\n"
|
||||
+ "Already disabled: " + alreadyDisabled + "\n"
|
||||
+ "Failed: " + failed + "\n"
|
||||
+ failureWarning + "\n"
|
||||
+ "Keep this dialog open while you verify in BizTalk Group Hub and your enterprise monitoring that no new inbound work arrives and all in-flight service instances/messages have drained.\n\n"
|
||||
+ "Continue with orchestrations, send ports and host instances?\n\n"
|
||||
+ "Yes = continue shutdown. No or closing this dialog = stop safely and persist all remaining steps as NotExecuted.";
|
||||
}
|
||||
|
||||
/// <summary>Counts executable drain checkpoints in a plan.</summary>
|
||||
private static int CountCheckpoints(OperationPlan plan)
|
||||
{
|
||||
return plan.Steps.Count(x => x.Execute && IsCheckpoint(x));
|
||||
}
|
||||
|
||||
/// <summary>Checks whether a plan row is the stable operator checkpoint kind.</summary>
|
||||
private static bool IsCheckpoint(OperationStep step)
|
||||
{
|
||||
return step != null && string.Equals(step.Kind, OperationStepKind.OperatorCheckpoint.ToString(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="2.3.3.0" name="BizTalkPlatformManagementTool" />
|
||||
<assemblyIdentity version="2.3.4.0" name="BizTalkPlatformManagementTool" />
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Text;
|
||||
using BizTalkPlatformManagementTool.Models;
|
||||
using BizTalkPlatformManagementTool.Services;
|
||||
using BizTalkPlatformManagementTool.Setup;
|
||||
using BizTalkPlatformManagementTool.Ui;
|
||||
|
||||
namespace BizTalkPlatformManagementTool.Tests
|
||||
{
|
||||
@@ -28,10 +29,12 @@ namespace BizTalkPlatformManagementTool.Tests
|
||||
Run("Legacy213SnapshotIsAcceptedForRecovery", Legacy213SnapshotIsAcceptedForRecovery);
|
||||
Run("RestorePlanUsesSafeOrder", RestorePlanUsesSafeOrder);
|
||||
Run("ShutdownPlanUsesGlobalSafeOrder", ShutdownPlanUsesGlobalSafeOrder);
|
||||
Run("ShutdownPlanRequiresCheckpointBeforeLaterWorkWithoutReceiveLocations", ShutdownPlanRequiresCheckpointBeforeLaterWorkWithoutReceiveLocations);
|
||||
Run("ShutdownContinuesAcrossArtifactCategoriesAfterReceiveLocationFailure", ShutdownContinuesAcrossArtifactCategoriesAfterReceiveLocationFailure);
|
||||
Run("ShutdownCheckpointDeclineStopsLaterPhases", ShutdownCheckpointDeclineStopsLaterPhases);
|
||||
Run("ShutdownCheckpointMissingHandlerFailsClosed", ShutdownCheckpointMissingHandlerFailsClosed);
|
||||
Run("ShutdownCheckpointDryRunDoesNotPrompt", ShutdownCheckpointDryRunDoesNotPrompt);
|
||||
Run("ShutdownOperatorPromptsDistinguishDryRunAndRealDecision", ShutdownOperatorPromptsDistinguishDryRunAndRealDecision);
|
||||
Run("EmergencyRestorePlanStartsSsoFirst", EmergencyRestorePlanStartsSsoFirst);
|
||||
Run("HostInstancePlanAcceptsShortAndFqdnServer", HostInstancePlanAcceptsShortAndFqdnServer);
|
||||
Run("PlanExecutionContinuesAfterSchedulerFailure", PlanExecutionContinuesAfterSchedulerFailure);
|
||||
@@ -182,6 +185,18 @@ namespace BizTalkPlatformManagementTool.Tests
|
||||
Assert(lastSendPort < firstHost, "host instances were not globally last");
|
||||
}
|
||||
|
||||
/// <summary>Prüft den Checkpoint auch dann, wenn keine aktive Receive Location als Planzeile existiert.</summary>
|
||||
private static void ShutdownPlanRequiresCheckpointBeforeLaterWorkWithoutReceiveLocations()
|
||||
{
|
||||
var snapshot = Snapshot("APP", "SEND", ArtifactStates.SendPortStarted);
|
||||
var plan = new BizTalkOperationService(null).CreateShutdownPlan(snapshot, snapshot.Server);
|
||||
var checkpoint = plan.Steps.FindIndex(x => x.Kind == OperationStepKind.OperatorCheckpoint.ToString());
|
||||
var sendPort = plan.Steps.FindIndex(x => x.Kind == OperationStepKind.SendPort.ToString());
|
||||
|
||||
Assert(checkpoint >= 0, "later shutdown work did not create an inbound-drain checkpoint");
|
||||
Assert(checkpoint < sendPort, "checkpoint was not placed before later shutdown work");
|
||||
}
|
||||
|
||||
/// <summary>Prüft, dass Scheduler-Erkennung auch nach Planpersistenz möglich bleibt.</summary>
|
||||
private static void ScheduledReceivePlanCarriesAdapterMetadata()
|
||||
{
|
||||
@@ -430,6 +445,25 @@ namespace BizTalkPlatformManagementTool.Tests
|
||||
Assert(!report.OperatorStopped && string.IsNullOrWhiteSpace(report.CheckpointDecision), "dry-run persisted a real checkpoint decision");
|
||||
}
|
||||
|
||||
/// <summary>Prüft, dass Dry-run-Hinweis und echter Entscheidungsdialog nicht verwechselt werden können.</summary>
|
||||
private static void ShutdownOperatorPromptsDistinguishDryRunAndRealDecision()
|
||||
{
|
||||
var snapshot = Snapshot("APP", "SEND", ArtifactStates.SendPortStarted);
|
||||
snapshot.Applications[0].ReceiveLocations.Add(new ReceiveLocationState { Application = "APP", Name = "RL", Enabled = true });
|
||||
var plan = new BizTalkOperationService(null).CreateShutdownPlan(snapshot, snapshot.Server);
|
||||
var dryRun = ShutdownOperatorPrompts.BuildDryRunNotice(plan, @"C:\evidence\shutdown-plan.json");
|
||||
var prepared = ShutdownOperatorPrompts.BuildPreparedPlanConfirmation("Shutdown", plan, snapshot.Server, @"C:\evidence\shutdown-plan.json");
|
||||
var progress = new OperationExecutionReport();
|
||||
progress.Steps.Add(new OperationStepResult { Kind = OperationStepKind.ReceiveLocation.ToString(), Outcome = OperationStepOutcomes.Succeeded });
|
||||
progress.Steps.Add(new OperationStepResult { Kind = OperationStepKind.ReceiveLocation.ToString(), Outcome = OperationStepOutcomes.Failed });
|
||||
var checkpoint = ShutdownOperatorPrompts.BuildInboundDrainConfirmation(progress);
|
||||
|
||||
Assert(dryRun.Contains("No receive location is disabled") && dryRun.Contains("will not open"), "dry-run notice does not explain the missing real dialog");
|
||||
Assert(prepared.Contains("second, explicit decision"), "real-plan confirmation does not announce the later checkpoint dialog");
|
||||
Assert(checkpoint.Contains("shutdown is PAUSED") && checkpoint.Contains("Disabled successfully: 1") && checkpoint.Contains("Failed: 1"), "checkpoint decision does not expose its blocking state and receive results");
|
||||
Assert(checkpoint.Contains("closing this dialog = stop safely"), "checkpoint close behavior is not explicit");
|
||||
}
|
||||
|
||||
/// <summary>Prüft ENTSSO als erste Voraussetzung des Emergency Restore.</summary>
|
||||
private static void EmergencyRestorePlanStartsSsoFirst()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user