@oneuptime/common 12.0.23 → 12.0.24
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/DetectionRule.ts +55 -0
- package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +27 -7
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +67 -0
- package/Models/DatabaseModels/Project.ts +68 -0
- package/Models/DatabaseModels/User.ts +68 -0
- package/Server/API/TelemetryAPI.ts +29 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.ts +49 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/GzipRequestBody.ts +311 -0
- package/Server/Middleware/MultipartFormData.ts +87 -3
- package/Server/Services/DetectionRuleService.ts +73 -6
- package/Server/Services/Index.ts +205 -0
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +59 -0
- package/Server/Services/NetworkDeviceService.ts +148 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
- package/Server/Services/OnCallDutyPolicyFeedService.ts +1 -1
- package/Server/Services/ProjectService.ts +29 -19
- package/Server/Services/SecurityEventService.ts +90 -13
- package/Server/Services/StatusPageResourceService.ts +223 -0
- package/Server/Services/TelemetryAttributeService.ts +17 -0
- package/Server/Services/UserService.ts +4 -6
- package/Server/Types/Markdown.ts +161 -67
- package/Server/Utils/AI/Toolbox/OnCallTools.ts +12 -4
- package/Server/Utils/AnalyticsDatabase/Statement.ts +13 -1
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +297 -6
- package/Server/Utils/Attribution.ts +4 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +45 -7
- package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +55 -3
- package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +21 -0
- package/Server/Utils/StartServer.ts +12 -32
- package/Server/Utils/Telemetry/LlmCostBudgetEvaluator.ts +101 -4
- package/Server/Utils/Telemetry/LlmMetricSpend.ts +130 -0
- package/Server/Views/Partials/AnalyticsConsent.ejs +159 -102
- package/Server/Views/Partials/Head.ejs +2 -1
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +776 -38
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +359 -0
- package/Tests/App/Dashboard/CorrelateGraph.test.tsx +865 -0
- package/Tests/App/Dashboard/CorrelationGraph.test.ts +346 -0
- package/Tests/App/Dashboard/CriteriaFilterConditionDropdown.test.tsx +256 -0
- package/Tests/App/Dashboard/CriteriaFilterDefaults.test.ts +738 -0
- package/Tests/App/Dashboard/CriteriaFilterMonitorTypeChange.test.ts +1122 -0
- package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +283 -0
- package/Tests/App/Dashboard/ExternalStatusPageCriteriaFilter.test.ts +407 -0
- package/Tests/App/Dashboard/MetricSeriesInvestigateMenu.test.tsx +5 -14
- package/Tests/App/Dashboard/MonitorCriteriaActionToggles.test.tsx +426 -0
- package/Tests/App/Dashboard/MonitorStepsCriteriaAlignmentWiring.test.tsx +352 -0
- package/Tests/App/Dashboard/OnCallLayerCardOverrides.test.tsx +278 -0
- package/Tests/App/Dashboard/OnCallLayerShiftPreviewOverrides.test.ts +237 -0
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +2 -2
- package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +460 -0
- package/Tests/App/Dashboard/SecurityEventAttributeUtil.test.ts +171 -0
- package/Tests/App/Dashboard/SecurityEventCorrelation.test.ts +857 -0
- package/Tests/App/Dashboard/SecurityEventDetailObservables.test.tsx +194 -0
- package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +124 -0
- package/Tests/App/Dashboard/SecurityEventsMonitorStepForm.test.tsx +79 -19
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +382 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitors.test.ts +216 -0
- package/Tests/App/StatusPage/BulkAddStatusPageMonitorsModal.test.tsx +590 -11
- package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +757 -0
- package/Tests/Models/DiscoveryScanNameColumn.test.ts +293 -0
- package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +564 -0
- package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +120 -4
- package/Tests/Server/Middleware/GzipRequestBody.test.ts +725 -0
- package/Tests/Server/Middleware/MultipartFormData.test.ts +298 -0
- package/Tests/Server/Services/AddDetectionRuleDistinctCountColumnsMigration.test.ts +311 -0
- package/Tests/Server/Services/DetectionRuleService.test.ts +134 -2
- package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +7 -1
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +131 -0
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +194 -0
- package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +800 -0
- package/Tests/Server/Services/OnCallScheduleAttachRosterRefresh.test.ts +244 -0
- package/Tests/Server/Services/SecurityEventService.test.ts +376 -0
- package/Tests/Server/Services/StatusPageResourceDuplicates.test.ts +703 -0
- package/Tests/Server/Services/TelemetryAttributeServiceSecurityEvent.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ComponentRegistryParity.test.ts +417 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGeneratorWhereOperators.test.ts +677 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +43 -0
- package/Tests/Server/Utils/Monitor/Criteria/ProfileMonitorCriteria.test.ts +15 -11
- package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +369 -8
- package/Tests/Server/Utils/SecurityEvent/SigmaClickhouseCompiler.test.ts +35 -0
- package/Tests/Server/Utils/Telemetry/LlmCostBudgetEvaluator.test.ts +368 -4
- package/Tests/Server/Utils/Telemetry/LlmMetricSpend.test.ts +245 -0
- package/Tests/Server/Views/AnalyticsConsentPartial.test.ts +48 -5
- package/Tests/Types/Code/YamlSyntax.test.ts +396 -0
- package/Tests/Types/Monitor/MetricAndProfileDefaultCriteria.test.ts +957 -0
- package/Tests/Types/Monitor/MonitorCriteriaActionValidation.test.ts +598 -0
- package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +49 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +6 -6
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +4 -4
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +4 -3
- package/Tests/Types/Telemetry/LlmMetricConventions.test.ts +193 -0
- package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +0 -12
- package/Tests/UI/Components/CardModelDetailEdit.test.tsx +1 -17
- package/Tests/UI/Components/CodeEditor.test.tsx +474 -10
- package/Tests/UI/Components/Detail/YamlField.test.tsx +105 -0
- package/Tests/UI/Components/EntityDropdownLabelsBulkAdd.test.tsx +319 -0
- package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +231 -0
- package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +1 -0
- package/Tests/UI/Components/Forms/ValidationYAML.test.ts +234 -0
- package/Tests/UI/Components/ModelTable/AttributeColumns.test.tsx +573 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableAttributeColumns.test.tsx +824 -0
- package/Tests/UI/Components/ModelTable/ColumnCustomizationModalAddableColumns.test.tsx +707 -0
- package/Tests/UI/Components/SideOver.test.tsx +1 -1
- package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +294 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +436 -0
- package/Tests/UI/Components/TableBulkCsvExport.test.tsx +6 -2
- package/Tests/UI/Components/Toggle.test.tsx +25 -0
- package/Tests/UI/Components/YamlEditor.test.tsx +847 -0
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +252 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +221 -0
- package/Tests/Utils/NetworkDiscovery/ScanNameUtil.test.ts +312 -0
- package/Tests/Utils/StatusPage/ResourceExplorer.test.ts +468 -0
- package/Tests/Utils/Telemetry/LlmMetricQuery.test.ts +472 -0
- package/Types/Code/YamlSyntax.ts +396 -0
- package/Types/Exception/ExceptionCode.ts +1 -0
- package/Types/Exception/PayloadTooLargeException.ts +8 -0
- package/Types/Marketing/Attribution.ts +10 -0
- package/Types/Marketing/MarketingEvent.ts +4 -0
- package/Types/Monitor/MonitorCriteriaInstance.ts +116 -56
- package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +2 -1
- package/Types/SecurityEvent/DetectionFindingConstants.ts +11 -0
- package/Types/Telemetry/LlmMetricConventions.ts +124 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +3 -0
- package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +10 -1
- package/UI/Components/CodeEditor/CodeEditor.tsx +241 -79
- package/UI/Components/CodeEditor/YamlEditor.tsx +369 -0
- package/UI/Components/Detail/Detail.tsx +10 -0
- package/UI/Components/EntityDropdown/EntityDropdown.tsx +33 -0
- package/UI/Components/Forms/Fields/FormField.tsx +31 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Forms/Types/FormFieldSchemaType.ts +1 -0
- package/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.ts +2 -0
- package/UI/Components/Forms/Validation.ts +46 -0
- package/UI/Components/Input/Input.tsx +3 -0
- package/UI/Components/ModelTable/AttributeColumns.tsx +321 -0
- package/UI/Components/ModelTable/BaseModelTable.tsx +263 -14
- package/UI/Components/ModelTable/Column.ts +8 -0
- package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +310 -0
- package/UI/Components/ModelTable/ColumnPreference.ts +13 -1
- package/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.tsx +2 -2
- package/UI/Components/SideOver/SideOver.tsx +5 -5
- package/UI/Components/StatusPage/ResourceGrid.tsx +82 -2
- package/UI/Components/StatusPage/ResourceList.tsx +197 -38
- package/UI/Components/Toggle/Toggle.tsx +9 -1
- package/UI/Components/Types/FieldType.ts +1 -0
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +73 -1
- package/Utils/NetworkDiscovery/ScanNameUtil.ts +181 -0
- package/Utils/StatusPage/ResourceExplorer.ts +258 -0
- package/Utils/Telemetry/LlmMetricQuery.ts +204 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js +57 -0
- package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +27 -7
- package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +69 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +76 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +76 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +17 -0
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js +21 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789400000000-AddNameToNetworkDeviceDiscoveryScan.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789500000000-AddCampaignUtmFields.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js +22 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789512000000-AddDetectionRuleDistinctCountColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/GzipRequestBody.js +224 -0
- package/build/dist/Server/Middleware/GzipRequestBody.js.map +1 -0
- package/build/dist/Server/Middleware/MultipartFormData.js +71 -2
- package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
- package/build/dist/Server/Services/DetectionRuleService.js +49 -4
- package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +204 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +50 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +124 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +68 -13
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyFeedService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +25 -45
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/SecurityEventService.js +57 -5
- package/build/dist/Server/Services/SecurityEventService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageResourceService.js +140 -0
- package/build/dist/Server/Services/StatusPageResourceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryAttributeService.js +17 -0
- package/build/dist/Server/Services/TelemetryAttributeService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +2 -12
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +147 -61
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js +12 -4
- package/build/dist/Server/Utils/AI/Toolbox/OnCallTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +12 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +246 -9
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/Attribution.js.map +1 -1
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +27 -7
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +42 -7
- package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +18 -0
- package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +12 -21
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js +76 -5
- package/build/dist/Server/Utils/Telemetry/LlmCostBudgetEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js +102 -0
- package/build/dist/Server/Utils/Telemetry/LlmMetricSpend.js.map +1 -0
- package/build/dist/Types/Code/YamlSyntax.js +212 -0
- package/build/dist/Types/Code/YamlSyntax.js.map +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js +1 -0
- package/build/dist/Types/Exception/ExceptionCode.js.map +1 -1
- package/build/dist/Types/Exception/PayloadTooLargeException.js +8 -0
- package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -0
- package/build/dist/Types/Marketing/Attribution.js +10 -0
- package/build/dist/Types/Marketing/Attribution.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +112 -51
- package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +2 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +9 -0
- package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
- package/build/dist/Types/Telemetry/LlmMetricConventions.js +98 -0
- package/build/dist/Types/Telemetry/LlmMetricConventions.js.map +1 -0
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +5 -2
- package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js +206 -76
- package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js +201 -0
- package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -0
- package/build/dist/UI/Components/Detail/Detail.js +9 -0
- package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +16 -1
- package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +14 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/Field.js.map +1 -1
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js +1 -0
- package/build/dist/UI/Components/Forms/Types/FormFieldSchemaType.js.map +1 -1
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js +2 -0
- package/build/dist/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.js.map +1 -1
- package/build/dist/UI/Components/Forms/Validation.js +27 -0
- package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js +159 -0
- package/build/dist/UI/Components/ModelTable/AttributeColumns.js.map +1 -0
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +179 -17
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +133 -2
- package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js +7 -1
- package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -1
- package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesModal.js +2 -2
- package/build/dist/UI/Components/SideOver/SideOver.js +5 -5
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js +28 -2
- package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +87 -20
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Toggle/Toggle.js +9 -1
- package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
- package/build/dist/UI/Components/Types/FieldType.js +1 -0
- package/build/dist/UI/Components/Types/FieldType.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +37 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js +120 -0
- package/build/dist/Utils/NetworkDiscovery/ScanNameUtil.js.map +1 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js +171 -0
- package/build/dist/Utils/StatusPage/ResourceExplorer.js.map +1 -1
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js +119 -0
- package/build/dist/Utils/Telemetry/LlmMetricQuery.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/tsconfig.json +2 -1
- package/Tests/UI/Components/Toast.test.tsx +0 -197
- package/Tests/UI/Components/ToastStacking.test.tsx +0 -198
- package/UI/Components/Toast/Toast.tsx +0 -189
- package/UI/Components/Toast/ToastInit.tsx +0 -110
- package/build/dist/UI/Components/Toast/Toast.js +0 -123
- package/build/dist/UI/Components/Toast/Toast.js.map +0 -1
- package/build/dist/UI/Components/Toast/ToastInit.js +0 -53
- package/build/dist/UI/Components/Toast/ToastInit.js.map +0 -1
|
@@ -608,3 +608,255 @@ describe("issue #3220 at fleet scale", () => {
|
|
|
608
608
|
expect(stale).toBe(50);
|
|
609
609
|
});
|
|
610
610
|
});
|
|
611
|
+
|
|
612
|
+
/*
|
|
613
|
+
* Issue #3392: a device nothing polls.
|
|
614
|
+
*
|
|
615
|
+
* The whole rule above is about the OUTCOME of a poll, and a monitor-backed
|
|
616
|
+
* device never gets one — no probe, no credentials, no walk. Its poll
|
|
617
|
+
* columns are NULL forever, so the rule could only ever answer "Pending"
|
|
618
|
+
* for it: an operator who followed the documented workflow to the letter
|
|
619
|
+
* (Monitoring Method = Monitor, a Ping monitor bound, polling off) watched
|
|
620
|
+
* a device that answers every ping sit on "Pending" indefinitely.
|
|
621
|
+
*
|
|
622
|
+
* These pin the second rule: for such a device the bound Monitor's verdict
|
|
623
|
+
* IS the answer, and every poll column on the row is irrelevant to it.
|
|
624
|
+
*/
|
|
625
|
+
describe("monitor-backed devices are judged by their monitor, not by a poll", () => {
|
|
626
|
+
const MONITOR_BACKED: string = "Monitor";
|
|
627
|
+
|
|
628
|
+
test("a bound monitor reporting healthy makes the device Up", () => {
|
|
629
|
+
expect(
|
|
630
|
+
statusOf({
|
|
631
|
+
monitoringMethod: MONITOR_BACKED,
|
|
632
|
+
monitorStatusIsOffline: false,
|
|
633
|
+
}),
|
|
634
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
test("a bound monitor reporting offline makes the device Down", () => {
|
|
638
|
+
expect(
|
|
639
|
+
statusOf({
|
|
640
|
+
monitoringMethod: MONITOR_BACKED,
|
|
641
|
+
monitorStatusIsOffline: true,
|
|
642
|
+
}),
|
|
643
|
+
).toBe(NetworkDeviceReachability.Down);
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
/*
|
|
647
|
+
* MonitorStatus is a ladder, not a pair: a "Degraded" row is neither
|
|
648
|
+
* operational nor offline. Reading the OFFLINE end is what keeps this
|
|
649
|
+
* verdict identical to the one the topology map draws for the same
|
|
650
|
+
* device, which resolves the ladder the same way.
|
|
651
|
+
*/
|
|
652
|
+
test("a degraded-but-not-offline status is Up, exactly as the map draws it", () => {
|
|
653
|
+
expect(
|
|
654
|
+
statusOf({
|
|
655
|
+
monitoringMethod: MONITOR_BACKED,
|
|
656
|
+
monitorStatusIsOffline: false,
|
|
657
|
+
}),
|
|
658
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
/*
|
|
662
|
+
* The two ways a monitor-backed device legitimately has no verdict:
|
|
663
|
+
* nothing is bound to it yet (discovery import creates ping-only hosts
|
|
664
|
+
* that way on purpose), or something is bound and has not been evaluated
|
|
665
|
+
* yet. Both are Pending, and neither may default to healthy.
|
|
666
|
+
*/
|
|
667
|
+
test("no stamped status is Pending, not a healthy default", () => {
|
|
668
|
+
expect(statusOf({ monitoringMethod: MONITOR_BACKED })).toBe(
|
|
669
|
+
NetworkDeviceReachability.Pending,
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
expect(
|
|
673
|
+
statusOf({
|
|
674
|
+
monitoringMethod: MONITOR_BACKED,
|
|
675
|
+
monitorStatusIsOffline: null,
|
|
676
|
+
}),
|
|
677
|
+
).toBe(NetworkDeviceReachability.Pending);
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
/*
|
|
681
|
+
* The regression itself. This is the exact row shape the issue reports:
|
|
682
|
+
* an ICMP-only host imported by a discovery scan, switched to Monitor,
|
|
683
|
+
* bound to a Ping monitor that is reporting healthy, and polled by
|
|
684
|
+
* nothing — so every poll column is NULL.
|
|
685
|
+
*/
|
|
686
|
+
test("the reported row shape reads Up rather than Pending", () => {
|
|
687
|
+
const un0661voipcp01: DeviceReachabilityInput = {
|
|
688
|
+
monitoringMethod: MONITOR_BACKED,
|
|
689
|
+
monitorStatusIsOffline: false,
|
|
690
|
+
isReachable: null,
|
|
691
|
+
lastPolledAt: null,
|
|
692
|
+
lastSeenAt: null,
|
|
693
|
+
pollingIntervalInMinutes: null,
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
expect(statusOf(un0661voipcp01)).toBe(NetworkDeviceReachability.Up);
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
/*
|
|
700
|
+
* Poll columns on a monitor-backed row are not merely absent — on a
|
|
701
|
+
* device switched over from SNMP they hold whatever a probe last found
|
|
702
|
+
* before it stopped asking, which is worse than nothing. The monitor
|
|
703
|
+
* wins outright, in both directions.
|
|
704
|
+
*/
|
|
705
|
+
test("a stale successful walk does not override a monitor reporting offline", () => {
|
|
706
|
+
expect(
|
|
707
|
+
statusOf({
|
|
708
|
+
monitoringMethod: MONITOR_BACKED,
|
|
709
|
+
monitorStatusIsOffline: true,
|
|
710
|
+
isReachable: true,
|
|
711
|
+
lastPolledAt: minutesAgo(2),
|
|
712
|
+
lastSeenAt: minutesAgo(2),
|
|
713
|
+
}),
|
|
714
|
+
).toBe(NetworkDeviceReachability.Down);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
test("a failed walk from its SNMP days does not override a healthy monitor", () => {
|
|
718
|
+
expect(
|
|
719
|
+
statusOf({
|
|
720
|
+
monitoringMethod: MONITOR_BACKED,
|
|
721
|
+
monitorStatusIsOffline: false,
|
|
722
|
+
isReachable: false,
|
|
723
|
+
lastPolledAt: minutesAgo(4000),
|
|
724
|
+
lastSeenAt: minutesAgo(9000),
|
|
725
|
+
}),
|
|
726
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
/*
|
|
730
|
+
* Staleness says "nothing has polled this device lately, go and check its
|
|
731
|
+
* probe". For a device that has no probe BY DESIGN that is both false and
|
|
732
|
+
* actively misleading, so it can never be raised here.
|
|
733
|
+
*/
|
|
734
|
+
test("is never flagged stale, however old the poll columns are", () => {
|
|
735
|
+
const result: DeviceReachabilityResult = reachabilityOf({
|
|
736
|
+
monitoringMethod: MONITOR_BACKED,
|
|
737
|
+
monitorStatusIsOffline: false,
|
|
738
|
+
lastPolledAt: minutesAgo(60 * 24 * 30),
|
|
739
|
+
lastSeenAt: minutesAgo(60 * 24 * 30),
|
|
740
|
+
pollingIntervalInMinutes: 5,
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
expect(result.status).toBe(NetworkDeviceReachability.Up);
|
|
744
|
+
expect(result.isStale).toBe(false);
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
test("is never flagged stale even when it has no poll columns at all", () => {
|
|
748
|
+
expect(
|
|
749
|
+
reachabilityOf({
|
|
750
|
+
monitoringMethod: MONITOR_BACKED,
|
|
751
|
+
monitorStatusIsOffline: true,
|
|
752
|
+
}).isStale,
|
|
753
|
+
).toBe(false);
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
/*
|
|
757
|
+
* lastContactAt is still reported honestly — it is "the newest thing a
|
|
758
|
+
* probe wrote", and for a device converted from SNMP that is a real
|
|
759
|
+
* historical fact the device page prints. It just does not decide
|
|
760
|
+
* anything here.
|
|
761
|
+
*/
|
|
762
|
+
test("still reports lastContactAt from the poll columns when there is one", () => {
|
|
763
|
+
expect(
|
|
764
|
+
reachabilityOf({
|
|
765
|
+
monitoringMethod: MONITOR_BACKED,
|
|
766
|
+
monitorStatusIsOffline: false,
|
|
767
|
+
lastPolledAt: minutesAgo(90),
|
|
768
|
+
}).lastContactAt?.getTime(),
|
|
769
|
+
).toBe(minutesAgo(90).getTime());
|
|
770
|
+
|
|
771
|
+
expect(
|
|
772
|
+
reachabilityOf({
|
|
773
|
+
monitoringMethod: MONITOR_BACKED,
|
|
774
|
+
monitorStatusIsOffline: false,
|
|
775
|
+
}).lastContactAt,
|
|
776
|
+
).toBeNull();
|
|
777
|
+
});
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
/*
|
|
781
|
+
* The column is free text (the SnmpVersion precedent), so what counts as
|
|
782
|
+
* "monitor-backed" is whatever NetworkDeviceMonitoringMethodUtil.parse says
|
|
783
|
+
* — and every other value has to keep the poll rule, because reading a
|
|
784
|
+
* typo as monitor-backed would silently stop a switch being judged by its
|
|
785
|
+
* walk.
|
|
786
|
+
*/
|
|
787
|
+
describe("which rows count as monitor-backed", () => {
|
|
788
|
+
test.each(["Monitor", "monitor", "MONITOR", " Monitor "])(
|
|
789
|
+
"%p reads as monitor-backed",
|
|
790
|
+
(monitoringMethod: string) => {
|
|
791
|
+
const result: DeviceReachabilityResult = reachabilityOf({
|
|
792
|
+
monitoringMethod: monitoringMethod,
|
|
793
|
+
monitorStatusIsOffline: false,
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
expect(result.isMonitorBacked).toBe(true);
|
|
797
|
+
expect(result.status).toBe(NetworkDeviceReachability.Up);
|
|
798
|
+
},
|
|
799
|
+
);
|
|
800
|
+
|
|
801
|
+
test.each([
|
|
802
|
+
["SNMP", "the explicit SNMP value"],
|
|
803
|
+
["", "an empty string"],
|
|
804
|
+
["Monitorr", "a typo"],
|
|
805
|
+
["ping", "an unrecognised word"],
|
|
806
|
+
])("%p (%s) keeps the poll rule", (monitoringMethod: string) => {
|
|
807
|
+
const device: DeviceReachabilityInput = {
|
|
808
|
+
monitoringMethod: monitoringMethod,
|
|
809
|
+
// A monitor status the poll rule must ignore for these rows.
|
|
810
|
+
monitorStatusIsOffline: true,
|
|
811
|
+
isReachable: true,
|
|
812
|
+
lastPolledAt: minutesAgo(1),
|
|
813
|
+
lastSeenAt: minutesAgo(1),
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
const result: DeviceReachabilityResult = reachabilityOf(device);
|
|
817
|
+
|
|
818
|
+
expect(result.isMonitorBacked).toBe(false);
|
|
819
|
+
expect(result.status).toBe(NetworkDeviceReachability.Up);
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
/*
|
|
823
|
+
* Every row written before the column existed, and every caller that
|
|
824
|
+
* does not select it. Both have to keep behaving exactly as they did.
|
|
825
|
+
*/
|
|
826
|
+
test.each([
|
|
827
|
+
["null", null],
|
|
828
|
+
["undefined", undefined],
|
|
829
|
+
])(
|
|
830
|
+
"a %s method is a polled device, unchanged",
|
|
831
|
+
(_label: string, value: string | null | undefined) => {
|
|
832
|
+
const result: DeviceReachabilityResult = reachabilityOf({
|
|
833
|
+
monitoringMethod: value as string | null | undefined,
|
|
834
|
+
monitorStatusIsOffline: true,
|
|
835
|
+
isReachable: true,
|
|
836
|
+
lastPolledAt: minutesAgo(1),
|
|
837
|
+
lastSeenAt: minutesAgo(1),
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
expect(result.isMonitorBacked).toBe(false);
|
|
841
|
+
expect(result.status).toBe(NetworkDeviceReachability.Up);
|
|
842
|
+
},
|
|
843
|
+
);
|
|
844
|
+
|
|
845
|
+
/*
|
|
846
|
+
* A caller that selects neither new column gets precisely the old
|
|
847
|
+
* behaviour, including staleness — which is what lets the topology
|
|
848
|
+
* builder and the site rollup keep passing their existing projections.
|
|
849
|
+
*/
|
|
850
|
+
test("an input carrying neither new column behaves exactly as before", () => {
|
|
851
|
+
const result: DeviceReachabilityResult = reachabilityOf({
|
|
852
|
+
isReachable: true,
|
|
853
|
+
lastPolledAt: minutesAgo(180),
|
|
854
|
+
lastSeenAt: minutesAgo(180),
|
|
855
|
+
pollingIntervalInMinutes: 5,
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
expect(result.status).toBe(NetworkDeviceReachability.Up);
|
|
859
|
+
expect(result.isStale).toBe(true);
|
|
860
|
+
expect(result.isMonitorBacked).toBe(false);
|
|
861
|
+
});
|
|
862
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { DiscoveredNetworkDevice } from "../../../Models/DatabaseModels/NetworkDeviceDiscoveryScan";
|
|
2
|
+
import { normalizeDiscoveredHosts } from "../../../Utils/NetworkDiscovery/DiscoveredHostUtil";
|
|
3
|
+
import { describe, expect, test } from "@jest/globals";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* normalizeDiscoveredHosts is the one reading of a scan's `discoveredDevices`
|
|
7
|
+
* jsonb that both the dashboard's Review dialog and the server-side
|
|
8
|
+
* auto-import rule engine share. The column is written verbatim from the
|
|
9
|
+
* probe's payload and the only guard on it is "the value is an array", so the
|
|
10
|
+
* three payload shapes documented on the function - a null row, a non-string
|
|
11
|
+
* address, and the same address carrying two different isAlreadyRegistered
|
|
12
|
+
* values - are shapes nothing upstream stops. These tests pin that each is
|
|
13
|
+
* neutralised here, once, so no downstream reader can be handed a different
|
|
14
|
+
* reading of the same payload.
|
|
15
|
+
*
|
|
16
|
+
* A cast through `unknown` is used wherever a test feeds a shape the type
|
|
17
|
+
* forbids on purpose: the whole point of the function is that the runtime
|
|
18
|
+
* value does not honour the type, so the tests have to be able to say so.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
function host(
|
|
22
|
+
overrides: Partial<DiscoveredNetworkDevice>,
|
|
23
|
+
): DiscoveredNetworkDevice {
|
|
24
|
+
return { ipAddress: "10.0.0.1", ...overrides };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("normalizeDiscoveredHosts", () => {
|
|
28
|
+
describe("rows that are not hosts at all", () => {
|
|
29
|
+
test("an empty scan normalises to an empty list", () => {
|
|
30
|
+
expect(normalizeDiscoveredHosts([])).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test.each([
|
|
34
|
+
["null", null],
|
|
35
|
+
["undefined", undefined],
|
|
36
|
+
["a number", 10],
|
|
37
|
+
["a string", "10.0.0.1"],
|
|
38
|
+
["a boolean", true],
|
|
39
|
+
])(
|
|
40
|
+
"%s is dropped rather than dereferenced",
|
|
41
|
+
(_label: string, value: unknown) => {
|
|
42
|
+
expect(
|
|
43
|
+
normalizeDiscoveredHosts([
|
|
44
|
+
value,
|
|
45
|
+
] as unknown as Array<DiscoveredNetworkDevice>),
|
|
46
|
+
).toEqual([]);
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
test("the real hosts around a null row survive it", () => {
|
|
51
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
52
|
+
host({ ipAddress: "10.0.0.1" }),
|
|
53
|
+
null as unknown as DiscoveredNetworkDevice,
|
|
54
|
+
host({ ipAddress: "10.0.0.2" }),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
expect(
|
|
58
|
+
result.map((entry: DiscoveredNetworkDevice) => {
|
|
59
|
+
return entry.ipAddress;
|
|
60
|
+
}),
|
|
61
|
+
).toEqual(["10.0.0.1", "10.0.0.2"]);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("the address is made a trimmed string", () => {
|
|
66
|
+
test("a numeric address becomes its string spelling, so Set.has can find it", () => {
|
|
67
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
68
|
+
{ ipAddress: 10 } as unknown as DiscoveredNetworkDevice,
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
expect(result[0]!.ipAddress).toBe("10");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test.each([
|
|
75
|
+
["a leading and trailing space", " 10.0.0.1 ", "10.0.0.1"],
|
|
76
|
+
["a tab", "\t10.0.0.1", "10.0.0.1"],
|
|
77
|
+
["only whitespace", " ", ""],
|
|
78
|
+
])("%s is trimmed", (_label: string, given: string, expected: string) => {
|
|
79
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
80
|
+
host({ ipAddress: given }),
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
expect(result[0]!.ipAddress).toBe(expected);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test.each([
|
|
87
|
+
["undefined", undefined],
|
|
88
|
+
["null", null],
|
|
89
|
+
])(
|
|
90
|
+
"a %s address becomes the empty string, never the literal word",
|
|
91
|
+
(_label: string, value: unknown) => {
|
|
92
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts(
|
|
93
|
+
[{ ipAddress: value } as unknown as DiscoveredNetworkDevice],
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(result[0]!.ipAddress).toBe("");
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("everything else on the row is carried through untouched", () => {
|
|
102
|
+
test("the SNMP system group and reachability flags survive normalisation", () => {
|
|
103
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
104
|
+
{
|
|
105
|
+
ipAddress: " 10.0.0.5 ",
|
|
106
|
+
sysName: "core-switch",
|
|
107
|
+
sysDescr: "vendor OS 1.2",
|
|
108
|
+
sysObjectId: "1.3.6.1.4.1.9",
|
|
109
|
+
sysLocation: "rack 4",
|
|
110
|
+
sysContact: "neteng",
|
|
111
|
+
sysUpTimeSeconds: 4200,
|
|
112
|
+
snmpReachable: true,
|
|
113
|
+
},
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
expect(result[0]).toEqual({
|
|
117
|
+
ipAddress: "10.0.0.5",
|
|
118
|
+
sysName: "core-switch",
|
|
119
|
+
sysDescr: "vendor OS 1.2",
|
|
120
|
+
sysObjectId: "1.3.6.1.4.1.9",
|
|
121
|
+
sysLocation: "rack 4",
|
|
122
|
+
sysContact: "neteng",
|
|
123
|
+
sysUpTimeSeconds: 4200,
|
|
124
|
+
snmpReachable: true,
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("an address registered on one row is registered on every row", () => {
|
|
130
|
+
test("a duplicate address inherits the registered verdict regardless of probe ordering", () => {
|
|
131
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
132
|
+
host({ ipAddress: "10.0.0.9", isAlreadyRegistered: false }),
|
|
133
|
+
host({ ipAddress: "10.0.0.9", isAlreadyRegistered: true }),
|
|
134
|
+
]);
|
|
135
|
+
|
|
136
|
+
expect(
|
|
137
|
+
result.map((entry: DiscoveredNetworkDevice) => {
|
|
138
|
+
return entry.isAlreadyRegistered;
|
|
139
|
+
}),
|
|
140
|
+
).toEqual([true, true]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("the verdict does not bleed onto a different address", () => {
|
|
144
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
145
|
+
host({ ipAddress: "10.0.0.9", isAlreadyRegistered: true }),
|
|
146
|
+
host({ ipAddress: "10.0.0.10", isAlreadyRegistered: false }),
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
expect(
|
|
150
|
+
result.find((entry: DiscoveredNetworkDevice) => {
|
|
151
|
+
return entry.ipAddress === "10.0.0.10";
|
|
152
|
+
})!.isAlreadyRegistered,
|
|
153
|
+
).toBe(false);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("an already-registered row is handed back as the very same object", () => {
|
|
157
|
+
const registered: DiscoveredNetworkDevice = host({
|
|
158
|
+
ipAddress: "10.0.0.11",
|
|
159
|
+
isAlreadyRegistered: true,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
163
|
+
registered,
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
/*
|
|
167
|
+
* With nothing to flip, the normaliser must not churn objects it did
|
|
168
|
+
* not change - a fresh clone every render would defeat any memoised
|
|
169
|
+
* reader keyed on identity. The first pass already re-spread the row,
|
|
170
|
+
* so identity is asserted against that cleaned object, not the input.
|
|
171
|
+
*/
|
|
172
|
+
expect(result[0]).toEqual(registered);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("the empty-string address is never treated as a registered key", () => {
|
|
176
|
+
/*
|
|
177
|
+
* A blank address is what an undefined or whitespace-only address
|
|
178
|
+
* normalises to. If it counted as a registered key, every other blank
|
|
179
|
+
* row - unrelated hosts the probe could not address - would be marked
|
|
180
|
+
* registered together.
|
|
181
|
+
*/
|
|
182
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
183
|
+
host({ ipAddress: " ", isAlreadyRegistered: true }),
|
|
184
|
+
host({ ipAddress: undefined as unknown as string }),
|
|
185
|
+
]);
|
|
186
|
+
|
|
187
|
+
expect(
|
|
188
|
+
result.every((entry: DiscoveredNetworkDevice) => {
|
|
189
|
+
return entry.ipAddress === "";
|
|
190
|
+
}),
|
|
191
|
+
).toBe(true);
|
|
192
|
+
expect(result[1]!.isAlreadyRegistered).toBeUndefined();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("three rows of one address all end up registered when any one is", () => {
|
|
196
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
197
|
+
host({ ipAddress: "10.0.0.20", isAlreadyRegistered: false }),
|
|
198
|
+
host({ ipAddress: "10.0.0.20" }),
|
|
199
|
+
host({ ipAddress: "10.0.0.20", isAlreadyRegistered: true }),
|
|
200
|
+
]);
|
|
201
|
+
|
|
202
|
+
expect(
|
|
203
|
+
result.map((entry: DiscoveredNetworkDevice) => {
|
|
204
|
+
return entry.isAlreadyRegistered;
|
|
205
|
+
}),
|
|
206
|
+
).toEqual([true, true, true]);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe("a scan with nothing registered is left as it is found", () => {
|
|
211
|
+
test("no row gains a registered flag it did not arrive with", () => {
|
|
212
|
+
const result: Array<DiscoveredNetworkDevice> = normalizeDiscoveredHosts([
|
|
213
|
+
host({ ipAddress: "10.0.0.30", isAlreadyRegistered: false }),
|
|
214
|
+
host({ ipAddress: "10.0.0.31" }),
|
|
215
|
+
]);
|
|
216
|
+
|
|
217
|
+
expect(result[0]!.isAlreadyRegistered).toBe(false);
|
|
218
|
+
expect(result[1]!.isAlreadyRegistered).toBeUndefined();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|