@oneuptime/common 12.0.34 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/GlobalConfig.ts +12 -12
- package/Models/DatabaseModels/InventoryItem.ts +44 -1
- package/Models/DatabaseModels/NetworkDevice.ts +126 -0
- package/Server/EnvironmentConfig.ts +47 -16
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Redis.ts +8 -8
- package/Server/Infrastructure/Status.ts +10 -4
- package/Server/Services/DatabaseService.ts +65 -13
- package/Server/Services/InventoryItemService.ts +31 -1
- package/Server/Services/MonitorTemplateService.ts +140 -19
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +349 -41
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
- package/Server/Services/NetworkDeviceService.ts +69 -0
- package/Server/Services/UserNotificationRuleService.ts +76 -25
- package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
- package/Server/Types/Database/QueryUtil.ts +56 -0
- package/Server/Types/Markdown.ts +93 -1
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +10 -1
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +82 -35
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +202 -37
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
- package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
- package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
- package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
- package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
- package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
- package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
- package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
- package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
- package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
- package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
- package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
- package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
- package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
- package/Tests/Models/InventoryItemStatus.test.ts +147 -0
- package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
- package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
- package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +62 -23
- package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
- package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
- package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
- package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
- package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
- package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1133 -81
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
- package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
- package/Tests/Server/Types/Markdown.test.ts +194 -1
- package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
- package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
- package/Tests/Server/Utils/EventLoop.test.ts +359 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +13 -7
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +224 -10
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
- package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
- package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
- package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
- package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
- package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
- package/Tests/Types/JSONFunctions.test.ts +40 -0
- package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
- package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
- package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +10 -2
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
- package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
- package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
- package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
- package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
- package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
- package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
- package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
- package/Types/Dashboard/DashboardVariable.ts +8 -0
- package/Types/JSON.ts +4 -0
- package/Types/JSONFunctions.ts +16 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
- package/Types/SerializableObjectDictionary.ts +4 -0
- package/Types/Telemetry/InventoryLiveness.ts +56 -0
- package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +46 -21
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
- package/UI/esbuild-config.js +6 -0
- package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
- package/Utils/Dashboard/LabelVariable.ts +152 -0
- package/Utils/Dashboard/VariableUrlState.ts +27 -5
- package/Utils/MetricUnitUtil.ts +34 -0
- package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
- package/Utils/Monitor/MetricValueFormatter.ts +342 -0
- package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
- package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
- package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
- package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +44 -12
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Redis.js +8 -8
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Infrastructure/Status.js +10 -4
- package/build/dist/Server/Infrastructure/Status.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +58 -13
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +28 -1
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +270 -37
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +75 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +10 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +58 -35
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +166 -35
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
- package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
- package/build/dist/Types/JSON.js +1 -0
- package/build/dist/Types/JSON.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +13 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +4 -0
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +9 -2
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
- package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
- package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
- package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +26 -0
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/test-setup.sh +9 -9
- package/tsconfig.json +51 -11
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +0 -399
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AutoImportRuleRunResult,
|
|
3
|
+
RuleRunResultUtil,
|
|
4
|
+
} from "../../../Types/NetworkAutomation/RuleRunResult";
|
|
5
|
+
import { describe, expect, it } from "@jest/globals";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* One press of "Run Rule" is now several capped server passes
|
|
9
|
+
* (OneUptime issue #3642), and this is the arithmetic that turns them back
|
|
10
|
+
* into one report. It is the part most easily got wrong: every pass re-reads
|
|
11
|
+
* the SAME scans, so most counters describe the estate rather than the work,
|
|
12
|
+
* and summing them would multiply the estate by the pass count.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
function pass(
|
|
16
|
+
overrides: Partial<AutoImportRuleRunResult>,
|
|
17
|
+
): AutoImportRuleRunResult {
|
|
18
|
+
return {
|
|
19
|
+
hostsEvaluated: 0,
|
|
20
|
+
hostsMatched: 0,
|
|
21
|
+
hostsExcluded: 0,
|
|
22
|
+
hostsSkippedAlreadyRegistered: 0,
|
|
23
|
+
devicesCreated: 0,
|
|
24
|
+
devicesFailed: 0,
|
|
25
|
+
monitorsWouldCreate: 0,
|
|
26
|
+
monitorsCreated: 0,
|
|
27
|
+
monitorsSkippedAlreadyExisting: 0,
|
|
28
|
+
monitorsSkippedUnsupportedHost: 0,
|
|
29
|
+
monitorsFailed: 0,
|
|
30
|
+
deviceFailureReasons: [],
|
|
31
|
+
monitorFailureReasons: [],
|
|
32
|
+
monitorProvisioningHalted: false,
|
|
33
|
+
isTruncated: false,
|
|
34
|
+
hostsPendingImport: 0,
|
|
35
|
+
monitorsPendingCreation: 0,
|
|
36
|
+
hasUnevaluatedScans: false,
|
|
37
|
+
hasMoreScans: false,
|
|
38
|
+
isDryRun: false,
|
|
39
|
+
matchedIpAddressSample: [],
|
|
40
|
+
...overrides,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("RuleRunResultUtil.mergeAutoImportRunPasses", () => {
|
|
45
|
+
it("returns a single pass unchanged", () => {
|
|
46
|
+
const only: AutoImportRuleRunResult = pass({ devicesCreated: 7 });
|
|
47
|
+
|
|
48
|
+
expect(RuleRunResultUtil.mergeAutoImportRunPasses([only])).toBe(only);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("refuses to invent a report out of no passes", () => {
|
|
52
|
+
expect(() => {
|
|
53
|
+
return RuleRunResultUtil.mergeAutoImportRunPasses([]);
|
|
54
|
+
}).toThrow("at least one run result");
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/*
|
|
58
|
+
* The issue's own numbers: 909 hosts, a 500-per-pass cap, two passes.
|
|
59
|
+
*/
|
|
60
|
+
it("sums the work done and keeps the estate from the first pass", () => {
|
|
61
|
+
const merged: AutoImportRuleRunResult =
|
|
62
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
63
|
+
pass({
|
|
64
|
+
hostsEvaluated: 909,
|
|
65
|
+
hostsMatched: 909,
|
|
66
|
+
devicesCreated: 500,
|
|
67
|
+
hostsPendingImport: 409,
|
|
68
|
+
isTruncated: true,
|
|
69
|
+
}),
|
|
70
|
+
pass({
|
|
71
|
+
hostsEvaluated: 909,
|
|
72
|
+
hostsMatched: 909,
|
|
73
|
+
hostsSkippedAlreadyRegistered: 500,
|
|
74
|
+
devicesCreated: 409,
|
|
75
|
+
}),
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
expect(merged.devicesCreated).toBe(909);
|
|
79
|
+
// Not 1,818: the second pass looked at the same 909 hosts.
|
|
80
|
+
expect(merged.hostsEvaluated).toBe(909);
|
|
81
|
+
expect(merged.hostsMatched).toBe(909);
|
|
82
|
+
/*
|
|
83
|
+
* And not 500 either. Reporting the run's own creates back as
|
|
84
|
+
* "already registered" would contradict "imported 909" in the same
|
|
85
|
+
* paragraph.
|
|
86
|
+
*/
|
|
87
|
+
expect(merged.hostsSkippedAlreadyRegistered).toBe(0);
|
|
88
|
+
expect(merged.isTruncated).toBe(false);
|
|
89
|
+
expect(merged.hostsPendingImport).toBe(0);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("sums monitor work and failures across passes", () => {
|
|
93
|
+
const merged: AutoImportRuleRunResult =
|
|
94
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
95
|
+
pass({
|
|
96
|
+
monitorsCreated: 500,
|
|
97
|
+
monitorsFailed: 2,
|
|
98
|
+
devicesFailed: 1,
|
|
99
|
+
monitorsSkippedAlreadyExisting: 4,
|
|
100
|
+
monitorsSkippedUnsupportedHost: 3,
|
|
101
|
+
isTruncated: true,
|
|
102
|
+
}),
|
|
103
|
+
pass({ monitorsCreated: 409, monitorsFailed: 1 }),
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
expect(merged.monitorsCreated).toBe(909);
|
|
107
|
+
expect(merged.monitorsFailed).toBe(3);
|
|
108
|
+
expect(merged.devicesFailed).toBe(1);
|
|
109
|
+
// Estate state, not work: taken from the first pass, never doubled.
|
|
110
|
+
expect(merged.monitorsSkippedAlreadyExisting).toBe(4);
|
|
111
|
+
expect(merged.monitorsSkippedUnsupportedHost).toBe(3);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("carries the last pass's leftovers, not the first pass's", () => {
|
|
115
|
+
const merged: AutoImportRuleRunResult =
|
|
116
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
117
|
+
pass({
|
|
118
|
+
devicesCreated: 500,
|
|
119
|
+
hostsPendingImport: 900,
|
|
120
|
+
monitorsPendingCreation: 900,
|
|
121
|
+
hasUnevaluatedScans: true,
|
|
122
|
+
isTruncated: true,
|
|
123
|
+
}),
|
|
124
|
+
pass({
|
|
125
|
+
devicesCreated: 500,
|
|
126
|
+
hostsPendingImport: 400,
|
|
127
|
+
monitorsPendingCreation: 400,
|
|
128
|
+
hasUnevaluatedScans: false,
|
|
129
|
+
hasMoreScans: true,
|
|
130
|
+
isTruncated: true,
|
|
131
|
+
}),
|
|
132
|
+
]);
|
|
133
|
+
|
|
134
|
+
expect(merged.hostsPendingImport).toBe(400);
|
|
135
|
+
expect(merged.monitorsPendingCreation).toBe(400);
|
|
136
|
+
expect(merged.hasUnevaluatedScans).toBe(false);
|
|
137
|
+
expect(merged.hasMoreScans).toBe(true);
|
|
138
|
+
expect(merged.isTruncated).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* The sample answers "which hosts is this rule claiming". Drawn before the
|
|
143
|
+
* run changed anything, it still does; drawn from the final pass it would
|
|
144
|
+
* be whatever happened to be left over.
|
|
145
|
+
*/
|
|
146
|
+
it("keeps the first pass's host sample", () => {
|
|
147
|
+
const merged: AutoImportRuleRunResult =
|
|
148
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
149
|
+
pass({
|
|
150
|
+
devicesCreated: 1,
|
|
151
|
+
isTruncated: true,
|
|
152
|
+
matchedIpAddressSample: ["10.0.0.1"],
|
|
153
|
+
}),
|
|
154
|
+
pass({ devicesCreated: 1, matchedIpAddressSample: ["10.9.9.9"] }),
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
expect(merged.matchedIpAddressSample).toEqual(["10.0.0.1"]);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* Failure reasons are what issue #3643 added to this report, and across a
|
|
162
|
+
* chain they are a set: the same fault reappears in every pass, and a
|
|
163
|
+
* different fault in a later pass is exactly what has to be surfaced.
|
|
164
|
+
*/
|
|
165
|
+
it("deduplicates failure reasons across passes and keeps new ones", () => {
|
|
166
|
+
const merged: AutoImportRuleRunResult =
|
|
167
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
168
|
+
pass({
|
|
169
|
+
devicesCreated: 500,
|
|
170
|
+
monitorsFailed: 1,
|
|
171
|
+
monitorFailureReasons: ["Template could not be loaded."],
|
|
172
|
+
deviceFailureReasons: ["Name already taken."],
|
|
173
|
+
isTruncated: true,
|
|
174
|
+
}),
|
|
175
|
+
pass({
|
|
176
|
+
devicesCreated: 400,
|
|
177
|
+
monitorsFailed: 2,
|
|
178
|
+
monitorFailureReasons: [
|
|
179
|
+
"Template could not be loaded.",
|
|
180
|
+
"Monitor limit reached.",
|
|
181
|
+
],
|
|
182
|
+
deviceFailureReasons: ["Name already taken."],
|
|
183
|
+
}),
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
expect(merged.monitorFailureReasons).toEqual([
|
|
187
|
+
"Template could not be loaded.",
|
|
188
|
+
"Monitor limit reached.",
|
|
189
|
+
]);
|
|
190
|
+
expect(merged.deviceFailureReasons).toEqual(["Name already taken."]);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("caps the merged reason list the way one pass is capped", () => {
|
|
194
|
+
const merged: AutoImportRuleRunResult =
|
|
195
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
196
|
+
pass({
|
|
197
|
+
devicesCreated: 1,
|
|
198
|
+
isTruncated: true,
|
|
199
|
+
monitorFailureReasons: ["one", "two"],
|
|
200
|
+
}),
|
|
201
|
+
pass({ devicesCreated: 1, monitorFailureReasons: ["three", "four"] }),
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
expect(merged.monitorFailureReasons).toEqual(["one", "two", "three"]);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
/*
|
|
208
|
+
* Halting is a property of the pass that halted, and the chain stops after
|
|
209
|
+
* one — so reading only the last pass would lose it.
|
|
210
|
+
*/
|
|
211
|
+
it("reports a halt from any pass, not only the last", () => {
|
|
212
|
+
const merged: AutoImportRuleRunResult =
|
|
213
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
214
|
+
pass({
|
|
215
|
+
devicesCreated: 500,
|
|
216
|
+
monitorProvisioningHalted: true,
|
|
217
|
+
isTruncated: true,
|
|
218
|
+
}),
|
|
219
|
+
pass({ devicesCreated: 400, monitorProvisioningHalted: false }),
|
|
220
|
+
]);
|
|
221
|
+
|
|
222
|
+
expect(merged.monitorProvisioningHalted).toBe(true);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("keeps the dry-run flag so a preview never reads as a write", () => {
|
|
226
|
+
const merged: AutoImportRuleRunResult =
|
|
227
|
+
RuleRunResultUtil.mergeAutoImportRunPasses([
|
|
228
|
+
pass({ isDryRun: true, monitorsWouldCreate: 500, isTruncated: true }),
|
|
229
|
+
pass({ isDryRun: true, monitorsWouldCreate: 9 }),
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
expect(merged.isDryRun).toBe(true);
|
|
233
|
+
expect(merged.monitorsWouldCreate).toBe(509);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AutoImportRuleRunResult,
|
|
3
3
|
LabelRuleRunResult,
|
|
4
|
+
MAX_RUN_FAILURE_REASON_LENGTH,
|
|
4
5
|
RuleRunResultUtil,
|
|
5
6
|
SiteAssignmentRuleRunResult,
|
|
6
7
|
} from "../../../Types/NetworkAutomation/RuleRunResult";
|
|
@@ -199,6 +200,9 @@ describe("RuleRunResultUtil.parseAutoImportRuleRunResult", () => {
|
|
|
199
200
|
monitorsSkippedAlreadyExisting: 2,
|
|
200
201
|
monitorsSkippedUnsupportedHost: 1,
|
|
201
202
|
monitorsFailed: 1,
|
|
203
|
+
deviceFailureReasons: ["Name too long"],
|
|
204
|
+
monitorFailureReasons: ["Plan limit reached"],
|
|
205
|
+
monitorProvisioningHalted: true,
|
|
202
206
|
isTruncated: true,
|
|
203
207
|
hasMoreScans: true,
|
|
204
208
|
isDryRun: false,
|
|
@@ -217,13 +221,75 @@ describe("RuleRunResultUtil.parseAutoImportRuleRunResult", () => {
|
|
|
217
221
|
monitorsSkippedAlreadyExisting: 2,
|
|
218
222
|
monitorsSkippedUnsupportedHost: 1,
|
|
219
223
|
monitorsFailed: 1,
|
|
224
|
+
deviceFailureReasons: ["Name too long"],
|
|
225
|
+
monitorFailureReasons: ["Plan limit reached"],
|
|
226
|
+
monitorProvisioningHalted: true,
|
|
220
227
|
isTruncated: true,
|
|
228
|
+
/*
|
|
229
|
+
* Absent from the payload above, which is what a pre-#3642 server
|
|
230
|
+
* sends: a truncated run from one of those reports nothing pending
|
|
231
|
+
* rather than NaN, and the summary falls back to its unquantified
|
|
232
|
+
* "stopped at the run cap" sentence.
|
|
233
|
+
*/
|
|
234
|
+
hostsPendingImport: 0,
|
|
235
|
+
monitorsPendingCreation: 0,
|
|
236
|
+
hasUnevaluatedScans: false,
|
|
221
237
|
hasMoreScans: true,
|
|
222
238
|
isDryRun: false,
|
|
223
239
|
matchedIpAddressSample: ["10.0.0.1", "10.0.0.2"],
|
|
224
240
|
});
|
|
225
241
|
});
|
|
226
242
|
|
|
243
|
+
/*
|
|
244
|
+
* The reasons come from a server that may be older than this dashboard, or
|
|
245
|
+
* from a hand-rolled client. Anything that is not a usable string is dropped
|
|
246
|
+
* rather than rendered into the modal, and the list is bounded on both axes
|
|
247
|
+
* so a pathological payload cannot become the whole dialog.
|
|
248
|
+
*/
|
|
249
|
+
it("reads absent failure reasons as empty rather than undefined", () => {
|
|
250
|
+
const parsed: AutoImportRuleRunResult =
|
|
251
|
+
RuleRunResultUtil.parseAutoImportRuleRunResult({ hostsEvaluated: 1 });
|
|
252
|
+
|
|
253
|
+
expect(parsed.deviceFailureReasons).toEqual([]);
|
|
254
|
+
expect(parsed.monitorFailureReasons).toEqual([]);
|
|
255
|
+
expect(parsed.monitorProvisioningHalted).toBe(false);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("drops non-string, blank and surplus failure reasons", () => {
|
|
259
|
+
const parsed: AutoImportRuleRunResult =
|
|
260
|
+
RuleRunResultUtil.parseAutoImportRuleRunResult({
|
|
261
|
+
monitorFailureReasons: [
|
|
262
|
+
" plan limit ",
|
|
263
|
+
"",
|
|
264
|
+
" ",
|
|
265
|
+
42,
|
|
266
|
+
null,
|
|
267
|
+
"duplicate key",
|
|
268
|
+
"third",
|
|
269
|
+
"fourth",
|
|
270
|
+
],
|
|
271
|
+
deviceFailureReasons: "not an array",
|
|
272
|
+
} as unknown as JSONObject);
|
|
273
|
+
|
|
274
|
+
expect(parsed.monitorFailureReasons).toEqual([
|
|
275
|
+
"plan limit",
|
|
276
|
+
"duplicate key",
|
|
277
|
+
"third",
|
|
278
|
+
]);
|
|
279
|
+
expect(parsed.deviceFailureReasons).toEqual([]);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("truncates an over-long failure reason", () => {
|
|
283
|
+
const parsed: AutoImportRuleRunResult =
|
|
284
|
+
RuleRunResultUtil.parseAutoImportRuleRunResult({
|
|
285
|
+
monitorFailureReasons: ["x".repeat(MAX_RUN_FAILURE_REASON_LENGTH + 50)],
|
|
286
|
+
} as unknown as JSONObject);
|
|
287
|
+
|
|
288
|
+
expect(parsed.monitorFailureReasons[0]!.length).toBe(
|
|
289
|
+
MAX_RUN_FAILURE_REASON_LENGTH,
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
|
|
227
293
|
it("reads every missing monitor counter as zero for older servers", () => {
|
|
228
294
|
const parsed: AutoImportRuleRunResult =
|
|
229
295
|
RuleRunResultUtil.parseAutoImportRuleRunResult({
|
|
@@ -27,7 +27,13 @@ function result(
|
|
|
27
27
|
monitorsSkippedAlreadyExisting: 0,
|
|
28
28
|
monitorsSkippedUnsupportedHost: 0,
|
|
29
29
|
monitorsFailed: 0,
|
|
30
|
+
deviceFailureReasons: [],
|
|
31
|
+
monitorFailureReasons: [],
|
|
32
|
+
monitorProvisioningHalted: false,
|
|
30
33
|
isTruncated: false,
|
|
34
|
+
hostsPendingImport: 0,
|
|
35
|
+
monitorsPendingCreation: 0,
|
|
36
|
+
hasUnevaluatedScans: false,
|
|
31
37
|
hasMoreScans: false,
|
|
32
38
|
isDryRun: false,
|
|
33
39
|
matchedIpAddressSample: [],
|
|
@@ -59,7 +65,29 @@ describe("RuleRunResultUtil.describeAutoImportRun", () => {
|
|
|
59
65
|
hostsEvaluated: 12,
|
|
60
66
|
});
|
|
61
67
|
expect(summary).toContain("No devices were imported.");
|
|
62
|
-
expect(summary).toContain(
|
|
68
|
+
expect(summary).toContain(
|
|
69
|
+
"matched 0 hosts out of the 12 discovered hosts it looked at",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* The denominator used to compose two nouns — "out of the 501 hosts
|
|
75
|
+
* discovered hosts it looked at" — which is what the report on issue #3643
|
|
76
|
+
* actually read.
|
|
77
|
+
*/
|
|
78
|
+
it("does not double the noun in the matched-out-of sentence", () => {
|
|
79
|
+
expect(describe_({ hostsMatched: 501, hostsEvaluated: 501 })).not.toContain(
|
|
80
|
+
"hosts discovered hosts",
|
|
81
|
+
);
|
|
82
|
+
expect(
|
|
83
|
+
describe_({ isDryRun: true, hostsMatched: 0, hostsEvaluated: 501 }),
|
|
84
|
+
).not.toContain("hosts discovered hosts");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("uses singular grammar for a single discovered host", () => {
|
|
88
|
+
expect(describe_({ hostsMatched: 0, hostsEvaluated: 1 })).toContain(
|
|
89
|
+
"out of the 1 discovered host it looked at",
|
|
90
|
+
);
|
|
63
91
|
});
|
|
64
92
|
|
|
65
93
|
it("a dry run that would import reports the projection and writes nothing", () => {
|
|
@@ -137,9 +165,289 @@ describe("RuleRunResultUtil.describeAutoImportRun", () => {
|
|
|
137
165
|
expect(dry).not.toContain("run again to continue");
|
|
138
166
|
});
|
|
139
167
|
|
|
168
|
+
/*
|
|
169
|
+
* Issue #3643. A run that reached the cap having created nothing has nothing
|
|
170
|
+
* to resume: the identical run would fail identically. "Run again to
|
|
171
|
+
* continue" was the advice that report gave, and it was an instruction to
|
|
172
|
+
* repeat a doomed run.
|
|
173
|
+
*/
|
|
174
|
+
it("does not promise progress for a truncated run that created nothing", () => {
|
|
175
|
+
const summary: string = describe_({
|
|
176
|
+
isTruncated: true,
|
|
177
|
+
hostsMatched: 501,
|
|
178
|
+
hostsEvaluated: 501,
|
|
179
|
+
hostsSkippedAlreadyRegistered: 501,
|
|
180
|
+
devicesCreated: 0,
|
|
181
|
+
monitorsCreated: 0,
|
|
182
|
+
monitorsFailed: 500,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
expect(summary).not.toContain("run again to continue");
|
|
186
|
+
expect(summary).toContain(
|
|
187
|
+
"Stopped at the run cap without creating anything",
|
|
188
|
+
);
|
|
189
|
+
expect(summary).toContain("fix the failures reported above first");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("still promises progress for a truncated run that created monitors only", () => {
|
|
193
|
+
expect(
|
|
194
|
+
describe_({
|
|
195
|
+
isTruncated: true,
|
|
196
|
+
devicesCreated: 0,
|
|
197
|
+
monitorsCreated: 12,
|
|
198
|
+
}),
|
|
199
|
+
).toContain("run again to continue");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("gives the reason monitors could not be created instead of pointing at logs", () => {
|
|
203
|
+
const summary: string = describe_({
|
|
204
|
+
hostsMatched: 501,
|
|
205
|
+
hostsEvaluated: 501,
|
|
206
|
+
monitorsFailed: 501,
|
|
207
|
+
monitorFailureReasons: [
|
|
208
|
+
"This rule's Monitor Template could not be loaded",
|
|
209
|
+
],
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(summary).toContain(
|
|
213
|
+
"Reason: This rule's Monitor Template could not be loaded.",
|
|
214
|
+
);
|
|
215
|
+
expect(summary).not.toContain("check the server logs");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("still points at the logs when the server recorded no reason", () => {
|
|
219
|
+
expect(describe_({ monitorsFailed: 2 })).toContain(
|
|
220
|
+
"Their network devices remain imported. Check the server logs for the reason.",
|
|
221
|
+
);
|
|
222
|
+
expect(describe_({ devicesFailed: 2 })).toContain(
|
|
223
|
+
"2 hosts could not be imported. Check the server logs for the reason.",
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("renders several distinct reasons as one list and punctuates each", () => {
|
|
228
|
+
const summary: string = describe_({
|
|
229
|
+
monitorsFailed: 4,
|
|
230
|
+
monitorFailureReasons: ["Plan limit reached", "Duplicate key."],
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
expect(summary).toContain("Reasons: Plan limit reached. Duplicate key.");
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("gives the reason devices could not be imported", () => {
|
|
237
|
+
expect(
|
|
238
|
+
describe_({
|
|
239
|
+
devicesFailed: 3,
|
|
240
|
+
deviceFailureReasons: ["Device name is too long"],
|
|
241
|
+
}),
|
|
242
|
+
).toContain(
|
|
243
|
+
"3 hosts could not be imported. Reason: Device name is too long.",
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("says monitor provisioning stopped rather than leaving it implied", () => {
|
|
248
|
+
const summary: string = describe_({
|
|
249
|
+
hostsMatched: 501,
|
|
250
|
+
hostsEvaluated: 501,
|
|
251
|
+
monitorsFailed: 501,
|
|
252
|
+
monitorProvisioningHalted: true,
|
|
253
|
+
monitorFailureReasons: ["Plan limit reached"],
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
expect(summary).toContain(
|
|
257
|
+
"Monitor provisioning stopped for the rest of this run",
|
|
258
|
+
);
|
|
259
|
+
expect(summary).toContain("Fix it and run this rule again.");
|
|
260
|
+
});
|
|
261
|
+
|
|
140
262
|
it("warns when older scans went unread", () => {
|
|
141
263
|
expect(describe_({ hasMoreScans: true, devicesCreated: 1 })).toContain(
|
|
142
264
|
"Only the newest 100 completed scans were read",
|
|
143
265
|
);
|
|
144
266
|
});
|
|
267
|
+
|
|
268
|
+
/*
|
|
269
|
+
* OneUptime issue #3642: "909 discovered, 500+ imported, the rest silently
|
|
270
|
+
* skipped". The cap itself was working as designed; what made it read as
|
|
271
|
+
* silence was a report that named neither how much was left nor the fact
|
|
272
|
+
* that the monitor half of the work had its own separate ceiling.
|
|
273
|
+
*/
|
|
274
|
+
describe("what a capped run says it left behind (issue #3642)", () => {
|
|
275
|
+
it("names the hosts a device cap left un-imported", () => {
|
|
276
|
+
const summary: string = describe_({
|
|
277
|
+
isTruncated: true,
|
|
278
|
+
devicesCreated: 500,
|
|
279
|
+
hostsEvaluated: 909,
|
|
280
|
+
hostsMatched: 909,
|
|
281
|
+
hostsPendingImport: 409,
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
expect(summary).toContain("Imported 500 hosts as network devices.");
|
|
285
|
+
expect(summary).toContain(
|
|
286
|
+
"Stopped at the run cap with 409 hosts still to import.",
|
|
287
|
+
);
|
|
288
|
+
expect(summary).toContain("Run again to continue");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("names the devices a monitor cap left unmonitored", () => {
|
|
292
|
+
const summary: string = describe_({
|
|
293
|
+
isTruncated: true,
|
|
294
|
+
devicesCreated: 0,
|
|
295
|
+
monitorsCreated: 500,
|
|
296
|
+
hostsEvaluated: 909,
|
|
297
|
+
hostsMatched: 909,
|
|
298
|
+
hostsSkippedAlreadyRegistered: 909,
|
|
299
|
+
monitorsPendingCreation: 409,
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
expect(summary).toContain(
|
|
303
|
+
"Stopped at the run cap with 409 active Network Device monitors still to create.",
|
|
304
|
+
);
|
|
305
|
+
// The device half is not claimed as pending — it was already imported.
|
|
306
|
+
expect(summary).not.toContain("still to import");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("reports both halves when both caps left work behind", () => {
|
|
310
|
+
expect(
|
|
311
|
+
describe_({
|
|
312
|
+
isTruncated: true,
|
|
313
|
+
devicesCreated: 500,
|
|
314
|
+
monitorsCreated: 500,
|
|
315
|
+
hostsPendingImport: 12,
|
|
316
|
+
monitorsPendingCreation: 3,
|
|
317
|
+
}),
|
|
318
|
+
).toContain(
|
|
319
|
+
"12 hosts still to import and 3 active Network Device monitors still to create",
|
|
320
|
+
);
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
it("uses singular grammar for a remainder of one", () => {
|
|
324
|
+
const summary: string = describe_({
|
|
325
|
+
isTruncated: true,
|
|
326
|
+
devicesCreated: 500,
|
|
327
|
+
hostsPendingImport: 1,
|
|
328
|
+
monitorsPendingCreation: 1,
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
expect(summary).toContain("1 host still to import");
|
|
332
|
+
expect(summary).toContain("1 active Network Device monitor still to");
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
/*
|
|
336
|
+
* A capped run stops opening scans, so what it counted is a floor. It
|
|
337
|
+
* must not be reported as the total, or the operator reads "409 left",
|
|
338
|
+
* runs it again, and finds more than 409 appear.
|
|
339
|
+
*/
|
|
340
|
+
it("reports the remainder as a floor when scans went unread", () => {
|
|
341
|
+
expect(
|
|
342
|
+
describe_({
|
|
343
|
+
isTruncated: true,
|
|
344
|
+
devicesCreated: 500,
|
|
345
|
+
hostsPendingImport: 409,
|
|
346
|
+
hasUnevaluatedScans: true,
|
|
347
|
+
}),
|
|
348
|
+
).toContain("at least 409 hosts still to import");
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("quantifies a dry run's remainder without promising a resume", () => {
|
|
352
|
+
const summary: string = describe_({
|
|
353
|
+
isDryRun: true,
|
|
354
|
+
isTruncated: true,
|
|
355
|
+
hostsMatched: 909,
|
|
356
|
+
hostsEvaluated: 909,
|
|
357
|
+
hostsPendingImport: 409,
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
expect(summary).toContain(
|
|
361
|
+
"Stopped counting at the run cap with 409 hosts still to import",
|
|
362
|
+
);
|
|
363
|
+
expect(summary).toContain("device-import and active-monitor creation");
|
|
364
|
+
expect(summary).not.toContain("run again to continue");
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
/*
|
|
368
|
+
* A pre-#3642 server sends no pending counters, so they parse as zero.
|
|
369
|
+
* The sentence must fall back rather than print "with —".
|
|
370
|
+
*/
|
|
371
|
+
/*
|
|
372
|
+
* The two truncation truths compose. A run that created nothing resumes
|
|
373
|
+
* nowhere (issue #3643), but the remainder is still the size of the
|
|
374
|
+
* problem to fix, so it is named without the "run again" advice.
|
|
375
|
+
*/
|
|
376
|
+
it("names the remainder without promising a resume when nothing was created", () => {
|
|
377
|
+
const summary: string = describe_({
|
|
378
|
+
isTruncated: true,
|
|
379
|
+
devicesCreated: 0,
|
|
380
|
+
monitorsCreated: 0,
|
|
381
|
+
monitorsFailed: 500,
|
|
382
|
+
monitorsPendingCreation: 409,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
expect(summary).toContain(
|
|
386
|
+
"Stopped at the run cap without creating anything, with 409 active Network Device monitors still to create.",
|
|
387
|
+
);
|
|
388
|
+
expect(summary).toContain("would repeat the same failures");
|
|
389
|
+
expect(summary).not.toContain("Run again to continue");
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("falls back to the unquantified sentence with nothing counted", () => {
|
|
393
|
+
const summary: string = describe_({
|
|
394
|
+
isTruncated: true,
|
|
395
|
+
devicesCreated: 5,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(summary).toContain(
|
|
399
|
+
"Stopped at the run cap — run again to continue",
|
|
400
|
+
);
|
|
401
|
+
expect(summary).not.toContain("still to import");
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
/*
|
|
405
|
+
* A monitor backfill over an already-imported estate creates no devices
|
|
406
|
+
* at all. "No devices were imported" read as total failure directly
|
|
407
|
+
* above "Created 500 active Network Device monitors".
|
|
408
|
+
*/
|
|
409
|
+
it("does not read a monitor backfill as an import that did nothing", () => {
|
|
410
|
+
const summary: string = describe_({
|
|
411
|
+
devicesCreated: 0,
|
|
412
|
+
monitorsCreated: 500,
|
|
413
|
+
hostsEvaluated: 909,
|
|
414
|
+
hostsMatched: 909,
|
|
415
|
+
hostsSkippedAlreadyRegistered: 909,
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
expect(summary).toContain("No new network devices were imported.");
|
|
419
|
+
expect(summary).toContain(
|
|
420
|
+
"Created 500 active Network Device monitors from the selected Monitor Template.",
|
|
421
|
+
);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("still says nothing happened when nothing happened", () => {
|
|
425
|
+
expect(describe_({ hostsEvaluated: 9, hostsMatched: 0 })).toContain(
|
|
426
|
+
"No devices were imported. This rule matched 0 hosts out of the 9 discovered hosts it looked at.",
|
|
427
|
+
);
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
/*
|
|
432
|
+
* The "still working" line a chained press shows between passes. It exists
|
|
433
|
+
* because a run that now spans several requests must not look like a hang.
|
|
434
|
+
*/
|
|
435
|
+
describe("progress while the passes are still chaining", () => {
|
|
436
|
+
it("names what has landed so far", () => {
|
|
437
|
+
const progress: string = RuleRunResultUtil.describeAutoImportProgress(
|
|
438
|
+
result({ devicesCreated: 500, monitorsCreated: 500 }),
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
expect(progress).toContain(
|
|
442
|
+
"500 hosts imported, 500 active Network Device monitors created so far",
|
|
443
|
+
);
|
|
444
|
+
expect(progress).toContain("leave this open");
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
it("says something even before the first pass has created anything", () => {
|
|
448
|
+
expect(RuleRunResultUtil.describeAutoImportProgress(result({}))).toBe(
|
|
449
|
+
"Still importing…",
|
|
450
|
+
);
|
|
451
|
+
});
|
|
452
|
+
});
|
|
145
453
|
});
|