Harden RTM endpoint adapter handling
This commit is contained in:
@@ -30,11 +30,13 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
Run("ArtifactSummaryIsBounded", ArtifactSummaryIsBounded);
|
||||
Run("EndpointAddressesResolveWithoutSecrets", EndpointAddressesResolveWithoutSecrets);
|
||||
Run("AdapterSpecificEndpointAddressesResolve", AdapterSpecificEndpointAddressesResolve);
|
||||
Run("SchedulerDatabaseAndSapEndpointsAreClassifiedSafely", SchedulerDatabaseAndSapEndpointsAreClassifiedSafely);
|
||||
Run("EndpointClassificationSeparatesExpectedAndUnresolved", EndpointClassificationSeparatesExpectedAndUnresolved);
|
||||
Run("EndpointCatalogPreservesManualOverrides", EndpointCatalogPreservesManualOverrides);
|
||||
Run("EndpointRuntimeUsesCurrentAddressAndManualOverrides", EndpointRuntimeUsesCurrentAddressAndManualOverrides);
|
||||
Run("EndpointCatalogRoundTrip", EndpointCatalogRoundTrip);
|
||||
Run("EndpointOutputListsOnlyUnavailableTargets", EndpointOutputListsOnlyUnavailableTargets);
|
||||
Run("BestEffortEndpointFailuresRemainNonAlerting", BestEffortEndpointFailuresRemainNonAlerting);
|
||||
Run("EndpointOutputExplainsOnlyRealResolutionGaps", EndpointOutputExplainsOnlyRealResolutionGaps);
|
||||
Run("EndpointProbeBudgetFitsMinuteInterval", EndpointProbeBudgetFitsMinuteInterval);
|
||||
Run("ForcedEndpointRefreshRewritesFreshCatalog", ForcedEndpointRefreshRewritesFreshCatalog);
|
||||
@@ -470,6 +472,73 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
AssertEqual(8080, endpoint.Port, "wildcard listener port");
|
||||
}
|
||||
|
||||
private static void SchedulerDatabaseAndSapEndpointsAreClassifiedSafely()
|
||||
{
|
||||
var candidate = new EndpointCandidate
|
||||
{
|
||||
ArtifactType = "ReceiveLocation",
|
||||
ApplicationName = "Integration",
|
||||
ArtifactName = "RL Scheduler",
|
||||
TransportRole = "Inbound",
|
||||
AdapterName = "Schedule",
|
||||
Address = "schedule://weekday/06:00",
|
||||
Active = true
|
||||
};
|
||||
|
||||
AssertEqual(
|
||||
EndpointResolutionStatus.ExpectedNonProbeable,
|
||||
EndpointAddressParser.Analyze(candidate).Status,
|
||||
"scheduler must be excluded");
|
||||
|
||||
candidate.ArtifactType = "SendPort";
|
||||
candidate.ArtifactName = "SP Oracle";
|
||||
candidate.TransportRole = "Primary";
|
||||
candidate.AdapterName = "DATABASE";
|
||||
candidate.Address = "Database://oracle01/SAPUSER/Oracle";
|
||||
var resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual(EndpointResolutionStatus.Probeable, resolution.Status, "Oracle DATABASE classification");
|
||||
AssertEqual("oracle01", resolution.Entry.Host, "Oracle DATABASE host");
|
||||
AssertEqual(1521, resolution.Entry.Port, "Oracle DATABASE default port");
|
||||
Assert(resolution.Entry.BestEffort, "Oracle DATABASE probe must be best effort");
|
||||
|
||||
candidate.Address = "Database://oracle01:1526/SAPUSER/Oracle";
|
||||
resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual(1526, resolution.Entry.Port, "Oracle DATABASE explicit port");
|
||||
|
||||
candidate.Address = "Database://sql01/Lookup/SQLServer";
|
||||
resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual(
|
||||
EndpointResolutionStatus.ExpectedNonProbeable,
|
||||
resolution.Status,
|
||||
"non-Oracle DATABASE endpoint must not cause UNKNOWN");
|
||||
|
||||
candidate.ArtifactType = "ReceiveLocation";
|
||||
candidate.ArtifactName = "RL SAP";
|
||||
candidate.TransportRole = "Inbound";
|
||||
// WMI kann einen WCF-SAP-Port lediglich als WCF-Custom ausweisen;
|
||||
// das sap://-Schema muss deshalb fuer die Klassifizierung genuegen.
|
||||
candidate.AdapterName = "WCF-Custom";
|
||||
candidate.Address = "sap://Client=800;lang=DE@A/sap-app/00?ListenerGwHost=sap-gateway.example&ListenerGwServ=SAPGW00&ListenerProgramId=SECRET";
|
||||
resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual(EndpointResolutionStatus.Probeable, resolution.Status, "WCF-SAP listener classification");
|
||||
AssertEqual("sap-gateway.example", resolution.Entry.Host, "WCF-SAP gateway host");
|
||||
AssertEqual(3300, resolution.Entry.Port, "WCF-SAP sapgw00 port");
|
||||
Assert(resolution.Entry.BestEffort, "WCF-SAP probe must be best effort");
|
||||
Assert(resolution.Entry.Host.IndexOf("SECRET", StringComparison.OrdinalIgnoreCase) < 0, "SAP Program ID must not enter catalog");
|
||||
|
||||
candidate.Address = "sap://Client=800;lang=DE@A/sap-app/00?SAPROUTER=%2fH%2fsap-router.example%2fS%2f3400%2fH%2fsap-gateway.example&ListenerGwHost=sap-gateway.example&ListenerGwServ=sapgw00";
|
||||
resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual("sap-router.example", resolution.Entry.Host, "SAProuter first hop host");
|
||||
AssertEqual(3400, resolution.Entry.Port, "SAProuter explicit port");
|
||||
|
||||
candidate.Address = "sap://Client=800;lang=DE@D/DESTINATION";
|
||||
resolution = EndpointAddressParser.Analyze(candidate);
|
||||
AssertEqual(
|
||||
EndpointResolutionStatus.ExpectedNonProbeable,
|
||||
resolution.Status,
|
||||
"destination-based WCF-SAP endpoint must not cause UNKNOWN");
|
||||
}
|
||||
|
||||
private static void EndpointClassificationSeparatesExpectedAndUnresolved()
|
||||
{
|
||||
var candidate = new EndpointCandidate
|
||||
@@ -617,6 +686,33 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
Assert(line.IndexOf("up.example.test", StringComparison.Ordinal) < 0, "reachable host must not clutter output");
|
||||
}
|
||||
|
||||
private static void BestEffortEndpointFailuresRemainNonAlerting()
|
||||
{
|
||||
var result = new ProbeResult();
|
||||
result.EndpointConnectivity.RuntimeStateAvailable = true;
|
||||
result.EndpointConnectivity.CatalogAvailable = true;
|
||||
result.EndpointConnectivity.RefreshSucceeded = true;
|
||||
result.EndpointConnectivity.Configured = 1;
|
||||
result.EndpointConnectivity.Active = 1;
|
||||
result.EndpointConnectivity.BestEffortActive = 1;
|
||||
var endpoint = TestEndpoint("SAP Listener", "sap-gateway.example");
|
||||
endpoint.AdapterName = "WCF-SAP";
|
||||
endpoint.Port = 3300;
|
||||
endpoint.BestEffort = true;
|
||||
result.EndpointConnectivity.Results.Add(new EndpointProbeResult
|
||||
{
|
||||
Endpoint = endpoint,
|
||||
Available = false,
|
||||
Failure = "TCP timeout"
|
||||
});
|
||||
|
||||
var line = FindServiceLine(result, "Endpoint Reachability");
|
||||
Assert(line.StartsWith("0 \"BizTalk Endpoint Reachability\"", StringComparison.Ordinal), "best-effort failure must remain OK");
|
||||
Assert(line.Contains("biztalk_endpoints_failed=0"), "best-effort failure must not increment failed metric");
|
||||
Assert(line.Contains("biztalk_endpoints_best_effort_ignored=1"), "ignored best-effort metric missing");
|
||||
Assert(line.IndexOf("unavailable=", StringComparison.OrdinalIgnoreCase) < 0, "best-effort target must not appear as unavailable");
|
||||
}
|
||||
|
||||
private static void EndpointOutputExplainsOnlyRealResolutionGaps()
|
||||
{
|
||||
var result = new ProbeResult();
|
||||
@@ -652,7 +748,9 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
ActiveCandidates = 150,
|
||||
UnresolvedCandidates = 7
|
||||
};
|
||||
catalog.Entries.Add(TestEndpoint("Orders", "api.example.test"));
|
||||
var storedEndpoint = TestEndpoint("Orders", "api.example.test");
|
||||
storedEndpoint.BestEffort = true;
|
||||
catalog.Entries.Add(storedEndpoint);
|
||||
var store = new EndpointCatalogStore(path, 1048576, 100);
|
||||
store.Write(catalog);
|
||||
var loaded = store.Read("ACC");
|
||||
@@ -660,8 +758,18 @@ namespace BizTalkCheckmkPulse.Tests
|
||||
AssertEqual(1, loaded.Entries.Count, "catalog entry count");
|
||||
AssertEqual("api.example.test", loaded.Entries[0].Host, "catalog host");
|
||||
AssertEqual(443, loaded.Entries[0].Port, "catalog port");
|
||||
Assert(loaded.Entries[0].BestEffort, "catalog best-effort marker");
|
||||
AssertEqual(7, loaded.UnresolvedCandidates, "catalog unresolved candidate count");
|
||||
Assert(File.ReadAllText(path).IndexOf("top-secret", StringComparison.OrdinalIgnoreCase) < 0, "catalog must not contain URI secrets");
|
||||
|
||||
// Vorhandene Kataloge der Formatversion 1 besitzen das neue optionale
|
||||
// Attribut noch nicht und muessen beim Update weiterhin lesbar bleiben.
|
||||
var legacyXml = File.ReadAllText(path)
|
||||
.Replace(" bestEffort=\"true\"", string.Empty)
|
||||
.Replace(" bestEffort=\"True\"", string.Empty);
|
||||
File.WriteAllText(path, legacyXml, new UTF8Encoding(false));
|
||||
loaded = store.Read("ACC");
|
||||
Assert(!loaded.Entries[0].BestEffort, "legacy catalog best-effort default");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user