@oneuptime/common 14.0.2 → 14.0.5
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/Alert.ts +55 -0
- package/Models/DatabaseModels/AlertFeed.ts +2 -0
- package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
- package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
- package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
- package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
- package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
- package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/IncidentAlert.ts +540 -0
- package/Models/DatabaseModels/IncidentFeed.ts +2 -0
- package/Models/DatabaseModels/Index.ts +18 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
- package/Models/DatabaseModels/Project.ts +60 -0
- package/Models/DatabaseModels/RumApplication.ts +52 -1
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Middleware/MultipartFormData.ts +1 -1
- package/Server/Middleware/TelemetryIngest.ts +15 -8
- package/Server/Services/AlertReminderRuleService.ts +100 -24
- package/Server/Services/DatabaseServerEndpointService.ts +895 -0
- package/Server/Services/DatabaseServerFeedService.ts +128 -0
- package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
- package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
- package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
- package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
- package/Server/Services/DatabaseServerService.ts +4546 -0
- package/Server/Services/DatabaseService.ts +14 -8
- package/Server/Services/DockerResourceService.ts +43 -2
- package/Server/Services/IncidentAlertService.ts +1811 -0
- package/Server/Services/IncidentReminderRuleService.ts +103 -23
- package/Server/Services/IncidentService.ts +210 -10
- package/Server/Services/IncidentStateTimelineService.ts +24 -0
- package/Server/Services/Index.ts +18 -0
- package/Server/Services/InventoryItemService.ts +113 -5
- package/Server/Services/IoTDeviceService.ts +145 -37
- package/Server/Services/OpenTelemetryIngestService.ts +19 -0
- package/Server/Services/PodmanResourceService.ts +43 -2
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
- package/Server/Services/ServiceService.ts +1 -1
- package/Server/Services/TelemetryUsageBillingService.ts +29 -2
- package/Server/Services/UserProjectSsoConsentService.ts +74 -0
- package/Server/Services/UserService.ts +14 -1
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
- package/Server/Types/Database/QueryHelper.ts +30 -1
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
- package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
- package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
- package/Server/Utils/Monitor/MonitorResource.ts +47 -11
- package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
- package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
- package/Server/Utils/StartServer.ts +26 -6
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
- package/Server/Utils/Telemetry/Telemetry.ts +16 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
- package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
- package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
- package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
- package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
- package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
- package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
- package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
- package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
- package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
- package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
- package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
- package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
- package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
- package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
- package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
- package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
- package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
- package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
- package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
- package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
- package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
- package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
- package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
- package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
- package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
- package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
- package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
- package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
- package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
- package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
- package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
- package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
- package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +38 -18
- package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
- package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
- package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
- package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
- package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
- package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
- package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
- package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
- package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
- package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
- package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
- package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
- package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
- package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
- package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
- package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
- package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
- package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
- package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
- package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
- package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
- package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
- package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
- package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
- package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
- package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
- package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
- package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
- package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
- package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
- package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
- package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
- package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
- package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
- package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
- package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
- package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
- package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
- package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
- package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
- package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
- package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
- package/Tests/ClassStrings.ts +178 -0
- package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
- package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
- package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
- package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/RenderedMarkup.ts +518 -0
- package/Tests/ResponsiveVisibility.test.ts +490 -4
- package/Tests/ResponsiveVisibility.ts +505 -52
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
- package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
- package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
- package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
- package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
- package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
- package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
- package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
- package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
- package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
- package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
- package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
- package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
- package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
- package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
- package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
- package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
- package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
- package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
- package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
- package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
- package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
- package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
- package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
- package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
- package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
- package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
- package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
- package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
- package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
- package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
- package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
- package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
- package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
- package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
- package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
- package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
- package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
- package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
- package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
- package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
- package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
- package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
- package/Tests/Types/Rum/WebVitals.test.ts +173 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
- package/Tests/UI/Components/Card.test.tsx +93 -2
- package/Tests/UI/Components/FeedOptions.test.ts +6 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
- package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
- package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
- package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
- package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
- package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
- package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
- package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
- package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
- package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
- package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
- package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
- package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
- package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
- package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
- package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
- package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
- package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
- package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
- package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
- package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
- package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
- package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +80 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +23 -0
- package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
- package/Tests/UI/Utils/Navigation.test.ts +102 -0
- package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
- package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
- package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
- package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
- package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
- package/Tests/Utils/ValueFormatter.test.ts +50 -0
- package/Tests/tsconfig.json +16 -0
- package/Types/AI/AIResourceContext.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +2 -1
- package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
- package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
- package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
- package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
- package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
- package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
- package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
- package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Incident/IncidentAlertLink.ts +38 -0
- package/Types/Monitor/CephAlertTemplates.ts +18 -0
- package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
- package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
- package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
- package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
- package/Types/Permission.ts +315 -0
- package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
- package/Types/Rules/RuleRun.ts +12 -0
- package/Types/Rum/SessionReplay.ts +25 -6
- package/Types/Rum/WebVitals.ts +52 -0
- package/Types/Telemetry/EntityType.ts +23 -0
- package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
- package/Types/Telemetry/ServiceType.ts +8 -0
- package/UI/Components/Banner/Banner.tsx +1 -1
- package/UI/Components/Card/Card.tsx +1 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
- package/UI/Components/Charts/Line/LineChart.tsx +7 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
- package/UI/Components/Date/StartAndEndDate.tsx +5 -5
- package/UI/Components/Detail/FieldLabel.tsx +8 -0
- package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
- package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
- package/UI/Components/Forms/BasicForm.tsx +1 -1
- package/UI/Components/Header/Header.tsx +1 -1
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
- package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
- package/UI/Components/InfoCard/InfoCard.tsx +47 -1
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
- package/UI/Components/Modal/ModalFooter.tsx +1 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +99 -21
- package/UI/Components/ModelTable/Column.ts +5 -0
- package/UI/Components/Navbar/NavBar.tsx +9 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
- package/UI/Components/Page/Page.tsx +1 -1
- package/UI/Components/Pagination/Pagination.tsx +3 -3
- package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
- package/UI/Components/SideMenu/SideMenu.tsx +4 -1
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
- package/UI/Components/StatusPage/ResourceList.tsx +6 -6
- package/UI/Components/Table/TableHeader.tsx +47 -2
- package/UI/Components/Table/Types/Column.ts +7 -0
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
- package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
- package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
- package/UI/Styles/Theme.css +8 -1
- package/UI/Utils/Navigation.ts +89 -42
- package/UI/Utils/PermissionGate.ts +11 -2
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
- package/UI/Utils/TelemetryService.ts +4 -3
- package/Utils/Incident/IncidentFromAlerts.ts +516 -0
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/MetricUnitUtil.ts +103 -11
- package/Utils/Monitor/MetricValueFormatter.ts +66 -13
- package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
- package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
- package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
- package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
- package/Utils/Rum/SessionTraceState.ts +212 -0
- package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
- package/Utils/Telemetry/EntityKey.ts +176 -0
- package/Utils/ValueFormatter.ts +16 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
- package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +18 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +62 -0
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
- package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
- package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +8 -4
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +30 -3
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
- package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
- package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/IncidentService.js +164 -12
- package/build/dist/Server/Services/IncidentService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +21 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +18 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +88 -5
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceService.js +111 -24
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +30 -3
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +1 -1
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
- package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
- package/build/dist/Server/Services/UserService.js +13 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +20 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
- package/build/dist/Types/AI/AIResourceContext.js +7 -0
- package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Incident/IncidentAlertLink.js +34 -0
- package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +276 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +25 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +23 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +8 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Banner/Banner.js +1 -1
- package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
- package/build/dist/UI/Components/Card/Card.js +1 -1
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
- package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
- package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
- package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
- package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +70 -18
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +1 -1
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/Table/TableHeader.js +18 -2
- package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
- package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +66 -33
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +4 -2
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
- package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +77 -13
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
- package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
- package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/ValueFormatter.js +15 -0
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.tests.json +7 -5
|
@@ -0,0 +1,1348 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import {
|
|
5
|
+
NETWORK_DEVICE_METRIC_DESCRIPTIONS,
|
|
6
|
+
NetworkDeviceMetric,
|
|
7
|
+
} from "../../../../App/FeatureSet/Dashboard/src/Components/MetricDescriptions/NetworkDeviceMetricDescriptions";
|
|
8
|
+
import {
|
|
9
|
+
NETWORK_SITE_METRIC_DESCRIPTIONS,
|
|
10
|
+
NetworkSiteMetric,
|
|
11
|
+
} from "../../../../App/FeatureSet/Dashboard/src/Components/MetricDescriptions/NetworkSiteMetricDescriptions";
|
|
12
|
+
import { summarizeLatencySeries } from "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/DeviceDiagnosticsViewModel";
|
|
13
|
+
import AggregationInterval from "../../../Types/BaseDatabase/AggregationInterval";
|
|
14
|
+
import { AggregationIntervalUtil } from "../../../Types/BaseDatabase/AggregationIntervalUtil";
|
|
15
|
+
import OneUptimeDate from "../../../Types/Date";
|
|
16
|
+
import DeviceReachabilityUtil, {
|
|
17
|
+
NetworkDeviceReachability,
|
|
18
|
+
} from "../../../Utils/NetworkDevice/DeviceReachabilityUtil";
|
|
19
|
+
import SiteUptimeUtil, {
|
|
20
|
+
SiteStatusTimelineRow,
|
|
21
|
+
SiteUptimeMeasurement,
|
|
22
|
+
} from "../../../Utils/NetworkSite/SiteUptimeUtil";
|
|
23
|
+
import NetworkDeviceMonitoringMethod from "../../../Types/NetworkDevice/NetworkDeviceMonitoringMethod";
|
|
24
|
+
import SiteHealthRollupPolicy, {
|
|
25
|
+
DefaultSiteHealthRollupPolicy,
|
|
26
|
+
} from "../../../Types/NetworkSite/SiteHealthRollupPolicy";
|
|
27
|
+
import LatencyMatrixUtil from "../../../Utils/Monitor/LatencyMatrixUtil";
|
|
28
|
+
import LatencyMatrix from "../../../Types/Monitor/LatencyMatrix";
|
|
29
|
+
import { deviceHealthState } from "../../../Utils/NetworkDevice/DeviceHealthStateUtil";
|
|
30
|
+
import NetworkDeviceDiscoveryScan from "../../../Models/DatabaseModels/NetworkDeviceDiscoveryScan";
|
|
31
|
+
import {
|
|
32
|
+
DiscoveryScanOutcome,
|
|
33
|
+
summarizeDiscoveryScan,
|
|
34
|
+
} from "../../../../App/FeatureSet/Dashboard/src/Components/NetworkDevice/DiscoveryScanOutcome";
|
|
35
|
+
import NetworkSiteHierarchyUtil, {
|
|
36
|
+
ChildAggregate,
|
|
37
|
+
DEFAULT_UPTIME_WINDOW_DAYS,
|
|
38
|
+
} from "../../../../App/FeatureSet/BaseAPI/Utils/NetworkSiteHierarchyUtil";
|
|
39
|
+
import {
|
|
40
|
+
expectReadableDescriptionRecord,
|
|
41
|
+
expectTitleExplained,
|
|
42
|
+
} from "./MetricDescriptionRules";
|
|
43
|
+
|
|
44
|
+
/*
|
|
45
|
+
* The (i) texts on the network device and network site pages.
|
|
46
|
+
*
|
|
47
|
+
* The readability rules are shared with every other resource type. What is
|
|
48
|
+
* pinned here on top of them is ACCURACY: each text makes a claim about how
|
|
49
|
+
* its number is computed — a window, a denominator, a cap, a rule — and each
|
|
50
|
+
* claim is checked against the code that computes it, by running that code
|
|
51
|
+
* where it lives in Common and by reading the constant where it does not.
|
|
52
|
+
* Change the computation and the matching test here fails, which is the
|
|
53
|
+
* prompt to change the words.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
const PACKAGES_ROOT: string = path.join(__dirname, "..", "..", "..", "..");
|
|
57
|
+
const DASHBOARD_SRC: string = path.join(
|
|
58
|
+
PACKAGES_ROOT,
|
|
59
|
+
"App",
|
|
60
|
+
"FeatureSet",
|
|
61
|
+
"Dashboard",
|
|
62
|
+
"src",
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
function readFrom(root: string, ...parts: Array<string>): string {
|
|
66
|
+
return fs
|
|
67
|
+
.readFileSync(path.join(root, ...parts), "utf8")
|
|
68
|
+
.replace(/\s+/g, " ");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function readDashboard(...parts: Array<string>): string {
|
|
72
|
+
return readFrom(DASHBOARD_SRC, ...parts);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const DEVICE: Record<NetworkDeviceMetric, string> =
|
|
76
|
+
NETWORK_DEVICE_METRIC_DESCRIPTIONS;
|
|
77
|
+
const SITE: Record<NetworkSiteMetric, string> =
|
|
78
|
+
NETWORK_SITE_METRIC_DESCRIPTIONS;
|
|
79
|
+
|
|
80
|
+
const MS_PER_DAY: number = 24 * 60 * 60 * 1000;
|
|
81
|
+
|
|
82
|
+
describe("the network description records read as short, finished sentences", () => {
|
|
83
|
+
test("NETWORK_DEVICE_METRIC_DESCRIPTIONS", () => {
|
|
84
|
+
expectReadableDescriptionRecord(
|
|
85
|
+
DEVICE,
|
|
86
|
+
"NETWORK_DEVICE_METRIC_DESCRIPTIONS",
|
|
87
|
+
);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("NETWORK_SITE_METRIC_DESCRIPTIONS", () => {
|
|
91
|
+
expectReadableDescriptionRecord(SITE, "NETWORK_SITE_METRIC_DESCRIPTIONS");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("no text is shared between the device and the site records", () => {
|
|
95
|
+
const deviceTexts: Set<string> = new Set<string>(Object.values(DEVICE));
|
|
96
|
+
|
|
97
|
+
for (const [key, text] of Object.entries(SITE)) {
|
|
98
|
+
expect({ key, reused: deviceTexts.has(text) }).toEqual({
|
|
99
|
+
key,
|
|
100
|
+
reused: false,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("every text stays well inside a small tooltip (aim: 260 characters)", () => {
|
|
106
|
+
for (const [key, text] of [
|
|
107
|
+
...Object.entries(DEVICE),
|
|
108
|
+
...Object.entries(SITE),
|
|
109
|
+
]) {
|
|
110
|
+
expect({ key, length: text.length <= 260 }).toEqual({
|
|
111
|
+
key,
|
|
112
|
+
length: true,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("no text leaks an internal metric name or OID", () => {
|
|
118
|
+
for (const [key, text] of [
|
|
119
|
+
...Object.entries(DEVICE),
|
|
120
|
+
...Object.entries(SITE),
|
|
121
|
+
]) {
|
|
122
|
+
expect({ key, text }).not.toEqual({
|
|
123
|
+
key,
|
|
124
|
+
text: expect.stringMatching(
|
|
125
|
+
/oneuptime\.|isReachable|sysUpTime|ifHighSpeed|\d+\.\d+\.\d+\.\d+\.\d+/,
|
|
126
|
+
),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test.each([
|
|
132
|
+
["Reachability", DEVICE.reachability],
|
|
133
|
+
["Round-trip time, past hour", DEVICE.latencyTrend],
|
|
134
|
+
["Packet loss (1h max)", DEVICE.packetLossPeak],
|
|
135
|
+
["Average RTT", DEVICE.pingAverageRtt],
|
|
136
|
+
["Min / Max RTT", DEVICE.pingMinMaxRtt],
|
|
137
|
+
["RTT", DEVICE.tracerouteRtt],
|
|
138
|
+
["Uptime (24h)", SITE.uptime24h],
|
|
139
|
+
["Uptime (30d)", SITE.uptime30d],
|
|
140
|
+
])("the %s title is explained by its text", (title: string, text: string) => {
|
|
141
|
+
expectTitleExplained(title, text);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("jargon is explained where it is used", () => {
|
|
145
|
+
// RTT is never left as three letters.
|
|
146
|
+
for (const text of [
|
|
147
|
+
DEVICE.pingAverageRtt,
|
|
148
|
+
DEVICE.tracerouteRtt,
|
|
149
|
+
DEVICE.pingMinMaxRtt,
|
|
150
|
+
]) {
|
|
151
|
+
expect(text.toLowerCase()).toContain("round");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
expect(DEVICE.pingJitter).toContain("varied");
|
|
155
|
+
expect(DEVICE.fleetEndpoints).toContain("ARP and MAC forwarding tables");
|
|
156
|
+
expect(SITE.endpoints).toContain("ARP and MAC forwarding tables");
|
|
157
|
+
expect(DEVICE.interfaceUtilization).toContain("percentage of link speed");
|
|
158
|
+
expect(DEVICE.flowCount).toContain("Each record sums up one conversation");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("device status texts match DeviceReachabilityUtil", () => {
|
|
163
|
+
test("a monitor-backed device is up unless its monitor reports it OFFLINE (a Degraded monitor still reads up)", () => {
|
|
164
|
+
const degraded: NetworkDeviceReachability =
|
|
165
|
+
DeviceReachabilityUtil.getStatus({
|
|
166
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Monitor,
|
|
167
|
+
monitorStatusIsOffline: false,
|
|
168
|
+
});
|
|
169
|
+
const offline: NetworkDeviceReachability = DeviceReachabilityUtil.getStatus(
|
|
170
|
+
{
|
|
171
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Monitor,
|
|
172
|
+
monitorStatusIsOffline: true,
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(degraded).toBe(NetworkDeviceReachability.Up);
|
|
177
|
+
expect(offline).toBe(NetworkDeviceReachability.Down);
|
|
178
|
+
|
|
179
|
+
expect(DEVICE.reachability).toContain("reports it offline");
|
|
180
|
+
expect(DEVICE.devicesUp).toContain("does not report it offline");
|
|
181
|
+
expect(DEVICE.devicesDown).toContain("reports it offline");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("never polled is Pending, and Pending is named in the texts that show it", () => {
|
|
185
|
+
expect(
|
|
186
|
+
DeviceReachabilityUtil.getStatus({
|
|
187
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Probe,
|
|
188
|
+
}),
|
|
189
|
+
).toBe(NetworkDeviceReachability.Pending);
|
|
190
|
+
|
|
191
|
+
expect(DEVICE.reachability).toContain("Pending means no result yet");
|
|
192
|
+
expect(DEVICE.deviceStatus).toContain("Pending means no result yet");
|
|
193
|
+
expect(DEVICE.devicesPending).toContain("never polled");
|
|
194
|
+
expect(DEVICE.fleetDevices).toContain("pending");
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("the probe's check is a ping plus an SNMP walk, and either answer is enough", () => {
|
|
198
|
+
expect(
|
|
199
|
+
DeviceReachabilityUtil.getStatus({
|
|
200
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Probe,
|
|
201
|
+
isReachable: true,
|
|
202
|
+
isSnmpReachable: false,
|
|
203
|
+
lastPolledAt: OneUptimeDate.getCurrentDate(),
|
|
204
|
+
lastSeenAt: OneUptimeDate.getCurrentDate(),
|
|
205
|
+
}),
|
|
206
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
207
|
+
|
|
208
|
+
expect(DEVICE.reachability).toContain("ping, plus an SNMP walk");
|
|
209
|
+
expect(DEVICE.devicesDown).toContain("neither ping nor the SNMP walk");
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test("the strip's three status counts partition the fleet, and the texts say so", () => {
|
|
213
|
+
const service: string = readFrom(
|
|
214
|
+
PACKAGES_ROOT,
|
|
215
|
+
"Common",
|
|
216
|
+
"Server",
|
|
217
|
+
"Services",
|
|
218
|
+
"NetworkDeviceService.ts",
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
expect(service).toContain(
|
|
222
|
+
'COUNT(*) FILTER (WHERE "NetworkDevice"."isReachable" = true)',
|
|
223
|
+
);
|
|
224
|
+
expect(service).toContain(
|
|
225
|
+
'COUNT(*) FILTER (WHERE "NetworkDevice"."isReachable" = false)',
|
|
226
|
+
);
|
|
227
|
+
expect(service).toContain(
|
|
228
|
+
'COUNT(*) FILTER (WHERE "NetworkDevice"."isReachable" IS NULL)',
|
|
229
|
+
);
|
|
230
|
+
expect(DEVICE.devicesPending).toContain(
|
|
231
|
+
"Up, Down and Pending together add up to every device in the project",
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("Monitor Status is whatever a watching monitor last stamped, which can disagree with Reachability", () => {
|
|
236
|
+
const siteService: string = readFrom(
|
|
237
|
+
PACKAGES_ROOT,
|
|
238
|
+
"Common",
|
|
239
|
+
"Server",
|
|
240
|
+
"Services",
|
|
241
|
+
"NetworkSiteService.ts",
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* Every device a monitor references gets the stamp, but only a
|
|
246
|
+
* monitor-backed device has its reachability moved by it — a Probe
|
|
247
|
+
* device's Reachability stays the poll's, so the two can differ.
|
|
248
|
+
*/
|
|
249
|
+
expect(siteService).toContain(
|
|
250
|
+
"const stamp: PartialEntity<NetworkDevice> = { currentMonitorStatusId: data.monitorStatusId, };",
|
|
251
|
+
);
|
|
252
|
+
expect(siteService).toContain(
|
|
253
|
+
"monitorBackedIsReachable !== undefined && NetworkDeviceMonitoringMethodUtil.isMonitorBacked( device.monitoringMethod, )",
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// A Probe device answering its poll is Up whatever a monitor stamped.
|
|
257
|
+
expect(
|
|
258
|
+
DeviceReachabilityUtil.getStatus({
|
|
259
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Probe,
|
|
260
|
+
isReachable: true,
|
|
261
|
+
monitorStatusIsOffline: true,
|
|
262
|
+
}),
|
|
263
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
264
|
+
|
|
265
|
+
expect(DEVICE.monitorStatus).toContain("can differ from Reachability");
|
|
266
|
+
expect(DEVICE.monitorStatus).toContain(
|
|
267
|
+
"Not monitored means no monitor has reported yet",
|
|
268
|
+
);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
test("the strip counts the project, not the filtered list", () => {
|
|
272
|
+
const cards: string = readDashboard(
|
|
273
|
+
"Components",
|
|
274
|
+
"NetworkDevice",
|
|
275
|
+
"DeviceSummaryCards.tsx",
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// No filter is handed to the summary endpoint.
|
|
279
|
+
expect(cards).toContain("await fetchDeviceSummary()");
|
|
280
|
+
|
|
281
|
+
for (const text of [DEVICE.devicesUp, DEVICE.devicesDown]) {
|
|
282
|
+
expect(text).toContain(
|
|
283
|
+
"Counts the whole project, whatever filters are set below",
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
expect(SITE.unhealthySites).toContain(
|
|
287
|
+
"Counts the whole project, whatever filters are set below",
|
|
288
|
+
);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
describe("interface texts match how the walk computes them", () => {
|
|
293
|
+
const rateUtil: string = readFrom(
|
|
294
|
+
PACKAGES_ROOT,
|
|
295
|
+
"Common",
|
|
296
|
+
"Server",
|
|
297
|
+
"Utils",
|
|
298
|
+
"Monitor",
|
|
299
|
+
"SnmpInterfaceRateUtil.ts",
|
|
300
|
+
);
|
|
301
|
+
const inventoryUtil: string = readFrom(
|
|
302
|
+
PACKAGES_ROOT,
|
|
303
|
+
"Common",
|
|
304
|
+
"Server",
|
|
305
|
+
"Utils",
|
|
306
|
+
"Monitor",
|
|
307
|
+
"NetworkInventoryUtil.ts",
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
test("rates, utilization and errors are averages between the last two walks", () => {
|
|
311
|
+
expect(rateUtil).toContain("(inOctetsDelta * 8) / elapsedSeconds");
|
|
312
|
+
expect(rateUtil).toContain(
|
|
313
|
+
"((inErrorsDelta || 0) + (outErrorsDelta || 0)) / elapsedSeconds",
|
|
314
|
+
);
|
|
315
|
+
|
|
316
|
+
for (const text of [
|
|
317
|
+
DEVICE.interfaceInOutRate,
|
|
318
|
+
DEVICE.interfaceUtilization,
|
|
319
|
+
DEVICE.interfaceErrorsPerSecond,
|
|
320
|
+
DEVICE.interfacesPreview,
|
|
321
|
+
]) {
|
|
322
|
+
expect(text).toContain("between the last two SNMP walks");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
expect(DEVICE.interfaceErrorsPerSecond).toContain("Inbound plus outbound");
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("utilization is the BUSIER direction over link speed, never the sum", () => {
|
|
329
|
+
expect(rateUtil).toContain("const busiestDirectionBps: number = Math.max(");
|
|
330
|
+
expect(rateUtil).toContain(
|
|
331
|
+
"(busiestDirectionBps / currentInterface.speedInBitsPerSecond) * 100",
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
expect(DEVICE.interfaceUtilization).toContain("busier direction");
|
|
335
|
+
expect(DEVICE.interfacesPreview).toContain("busier direction");
|
|
336
|
+
expect(DEVICE.interfaceSpeed).toContain(
|
|
337
|
+
"what Utilization is measured against",
|
|
338
|
+
);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test("a counter that went backwards gives no rate, which the dash is for", () => {
|
|
342
|
+
expect(rateUtil).toContain("return delta >= 0 ? delta : undefined;");
|
|
343
|
+
expect(DEVICE.interfaceInOutRate).toContain("counter reset");
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("up is enabled-with-link and down is enabled-without-link; switched-off ports are in neither", () => {
|
|
347
|
+
expect(inventoryUtil).toContain(
|
|
348
|
+
"return walked.isAdministrativelyUp && walked.isOperationallyUp;",
|
|
349
|
+
);
|
|
350
|
+
expect(inventoryUtil).toContain(
|
|
351
|
+
"return walked.isAdministrativelyUp && !walked.isOperationallyUp;",
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
expect(DEVICE.interfacesUp).toContain("enabled and have a working link");
|
|
355
|
+
expect(DEVICE.interfacesDown).toContain("enabled but have no link");
|
|
356
|
+
expect(DEVICE.interfacesDown).toContain(
|
|
357
|
+
"Ports an administrator switched off are not counted",
|
|
358
|
+
);
|
|
359
|
+
expect(DEVICE.heroInterfaces).toContain("count in neither");
|
|
360
|
+
expect(DEVICE.deviceInterfacesUpDown).toContain("count in neither");
|
|
361
|
+
expect(DEVICE.interfaceStatus).toContain("Disabled means an administrator");
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
test("counts come from the last SUCCESSFUL walk (a failed walk keeps them)", () => {
|
|
365
|
+
expect(inventoryUtil).toContain(
|
|
366
|
+
"A failed walk in snmp mode, by contrast, leaves them alone",
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
for (const text of [
|
|
370
|
+
DEVICE.heroInterfaces,
|
|
371
|
+
DEVICE.totalInterfaces,
|
|
372
|
+
DEVICE.interfacesUp,
|
|
373
|
+
DEVICE.interfacesDown,
|
|
374
|
+
DEVICE.deviceInterfacesUpDown,
|
|
375
|
+
DEVICE.totalInterfacesDown,
|
|
376
|
+
DEVICE.fleetInterfacesDown,
|
|
377
|
+
]) {
|
|
378
|
+
expect(text).toContain("last successful SNMP walk");
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test("the fleet-wide down count is a SUM of ports, so it says ports, not devices", () => {
|
|
383
|
+
const service: string = readFrom(
|
|
384
|
+
PACKAGES_ROOT,
|
|
385
|
+
"Common",
|
|
386
|
+
"Server",
|
|
387
|
+
"Services",
|
|
388
|
+
"NetworkDeviceService.ts",
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
expect(service).toContain(
|
|
392
|
+
'COALESCE(SUM("NetworkDevice"."interfacesDown"), 0)',
|
|
393
|
+
);
|
|
394
|
+
expect(DEVICE.totalInterfacesDown).toContain("counts ports, not devices");
|
|
395
|
+
expect(DEVICE.totalInterfacesDown).toContain("adds three");
|
|
396
|
+
expect(DEVICE.fleetInterfacesDown).toContain("adds three");
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
test("muted interfaces stay in the inventory counts but out of metrics and criteria", () => {
|
|
400
|
+
expect(inventoryUtil).toContain(
|
|
401
|
+
"Prune the in-flight response to monitored interfaces only",
|
|
402
|
+
);
|
|
403
|
+
expect(DEVICE.interfacesMonitored).toContain("not charted or alerted on");
|
|
404
|
+
expect(DEVICE.totalInterfaces).toContain("muted interfaces");
|
|
405
|
+
expect(DEVICE.interfacesUp).toContain("Muted interfaces are counted too");
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
test("the preview names its row cap and the order it ranks ports in", () => {
|
|
409
|
+
const preview: string = readDashboard(
|
|
410
|
+
"Components",
|
|
411
|
+
"NetworkDevice",
|
|
412
|
+
"DeviceInterfacesPreview.tsx",
|
|
413
|
+
);
|
|
414
|
+
const ranking: string = readDashboard(
|
|
415
|
+
"Components",
|
|
416
|
+
"NetworkDevice",
|
|
417
|
+
"InterfaceAttentionUtil.ts",
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
expect(preview).toContain("const PREVIEW_ROW_COUNT: number = 6;");
|
|
421
|
+
expect(DEVICE.interfacesPreview).toContain("Up to six ports");
|
|
422
|
+
|
|
423
|
+
// Down, then errored, then busiest — in that order.
|
|
424
|
+
const downBand: number = ranking.indexOf("return 3_000_000;");
|
|
425
|
+
const errorBand: number = ranking.indexOf("return 2_000_000 +");
|
|
426
|
+
expect(downBand).toBeGreaterThan(-1);
|
|
427
|
+
expect(errorBand).toBeGreaterThan(downBand);
|
|
428
|
+
expect(DEVICE.interfacesPreview).toContain(
|
|
429
|
+
"down ones first, then ports with errors, then the busiest",
|
|
430
|
+
);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
test("hardware uptime is the SNMP agent's sysUpTime, which wraps after ~497 days", () => {
|
|
434
|
+
const snmp: string = readFrom(
|
|
435
|
+
PACKAGES_ROOT,
|
|
436
|
+
"Probe",
|
|
437
|
+
"Utils",
|
|
438
|
+
"Monitors",
|
|
439
|
+
"MonitorTypes",
|
|
440
|
+
"SnmpMonitor.ts",
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
expect(snmp).toContain('sysUpTime: "1.3.6.1.2.1.1.3.0"');
|
|
444
|
+
expect(inventoryUtil).toContain(
|
|
445
|
+
"now.getTime() - systemInfo.sysUpTimeSeconds * 1000",
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
// 2^32 hundredths of a second, in days.
|
|
449
|
+
expect(Math.round(2 ** 32 / 100 / 86400)).toBe(497);
|
|
450
|
+
expect(DEVICE.hardwareUptime).toContain("497 days");
|
|
451
|
+
expect(DEVICE.hardwareUptime).toContain("restarts with the SNMP agent");
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
describe("latency and ping texts match what is fetched", () => {
|
|
456
|
+
const trend: string = readDashboard(
|
|
457
|
+
"Components",
|
|
458
|
+
"NetworkDevice",
|
|
459
|
+
"DeviceLatencyTrend.tsx",
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
test("the trend is fixed to the past hour, whatever else the page shows", () => {
|
|
463
|
+
expect(trend).toContain("range: TimeRange.PAST_ONE_HOUR");
|
|
464
|
+
expect(DEVICE.latencyTrend).toContain("over the past hour");
|
|
465
|
+
expect(DEVICE.packetLossPeak).toContain("of the past hour");
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test("an hour is bucketed per minute, so max is the slowest MINUTE, not the slowest ping", () => {
|
|
469
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
470
|
+
|
|
471
|
+
expect(
|
|
472
|
+
AggregationIntervalUtil.getAggregationIntervalForWindow({
|
|
473
|
+
startDate: new Date(now.getTime() - 60 * 60 * 1000),
|
|
474
|
+
endDate: now,
|
|
475
|
+
}),
|
|
476
|
+
).toBe(AggregationInterval.Minute);
|
|
477
|
+
|
|
478
|
+
// RTT is averaged per bucket, loss is the worst per bucket.
|
|
479
|
+
expect(trend).toContain("aggegationType: AggregationType.Avg");
|
|
480
|
+
expect(trend).toContain("aggegationType: AggregationType.Max");
|
|
481
|
+
|
|
482
|
+
expect(DEVICE.latencyTrend).toContain("averaged per minute");
|
|
483
|
+
expect(DEVICE.latencyTrend).toContain(
|
|
484
|
+
"the slowest minute rather than the slowest single ping",
|
|
485
|
+
);
|
|
486
|
+
expect(DEVICE.packetLossPeak).toContain("in any one minute");
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
test("'now' is the latest minute WITH A REPLY: a poll no ping answered writes no RTT point", () => {
|
|
490
|
+
const ping: string = readFrom(
|
|
491
|
+
PACKAGES_ROOT,
|
|
492
|
+
"Probe",
|
|
493
|
+
"Utils",
|
|
494
|
+
"Monitors",
|
|
495
|
+
"MonitorTypes",
|
|
496
|
+
"PingMonitor.ts",
|
|
497
|
+
);
|
|
498
|
+
const metricUtil: string = readFrom(
|
|
499
|
+
PACKAGES_ROOT,
|
|
500
|
+
"Common",
|
|
501
|
+
"Server",
|
|
502
|
+
"Utils",
|
|
503
|
+
"Monitor",
|
|
504
|
+
"NetworkDeviceMetricUtil.ts",
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
// No replies -> no average RTT...
|
|
508
|
+
expect(ping).toContain(
|
|
509
|
+
"(times.length > 0 ? times.reduce((sum: number, time: number) => { return sum + time; }, 0) / times.length : undefined);",
|
|
510
|
+
);
|
|
511
|
+
// ...and an undefined value is never written as a point.
|
|
512
|
+
expect(metricUtil).toContain(
|
|
513
|
+
"if (metric.value === undefined || metric.value === null) { return; }",
|
|
514
|
+
);
|
|
515
|
+
expect(metricUtil).toContain(
|
|
516
|
+
"value: data.pingResponse.avgRoundTripTimeInMs,",
|
|
517
|
+
);
|
|
518
|
+
|
|
519
|
+
// The summary's "now" is simply the last point there is.
|
|
520
|
+
const summary: ReturnType<typeof summarizeLatencySeries> =
|
|
521
|
+
summarizeLatencySeries([
|
|
522
|
+
{ time: "2026-09-24T10:00:00.000Z", value: 12 },
|
|
523
|
+
{ time: "2026-09-24T10:05:00.000Z", value: 30 },
|
|
524
|
+
]);
|
|
525
|
+
|
|
526
|
+
expect(summary?.latest).toBe(30);
|
|
527
|
+
expect(summary?.max).toBe(30);
|
|
528
|
+
expect(summary?.avg).toBe(21);
|
|
529
|
+
|
|
530
|
+
expect(DEVICE.latencyTrend).toContain(
|
|
531
|
+
"Now is the latest minute with a reply",
|
|
532
|
+
);
|
|
533
|
+
expect(DEVICE.latencyTrend).not.toContain("Now is the latest minute,");
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
test("jitter is the standard deviation the ping reports", () => {
|
|
537
|
+
const ping: string = readFrom(
|
|
538
|
+
PACKAGES_ROOT,
|
|
539
|
+
"Probe",
|
|
540
|
+
"Utils",
|
|
541
|
+
"Monitors",
|
|
542
|
+
"MonitorTypes",
|
|
543
|
+
"PingMonitor.ts",
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
expect(ping).toContain(
|
|
547
|
+
"let jitter: number | undefined = parseStat(res.stddev);",
|
|
548
|
+
);
|
|
549
|
+
expect(DEVICE.pingJitter).toContain("standard deviation");
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
test("the loss row's bracket is received out of sent, as the text says", () => {
|
|
553
|
+
const viewModel: string = readDashboard(
|
|
554
|
+
"Components",
|
|
555
|
+
"NetworkDevice",
|
|
556
|
+
"DeviceDiagnosticsViewModel.ts",
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
expect(viewModel).toContain(
|
|
560
|
+
"(${result.pingResponse.packetsReceived}/${ result.pingResponse.packetsSent } received)",
|
|
561
|
+
);
|
|
562
|
+
expect(DEVICE.pingPacketLoss).toContain(
|
|
563
|
+
"how many replies came back out of the pings sent",
|
|
564
|
+
);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
test("a traceroute hop's RTT is the FIRST reply on its line", () => {
|
|
568
|
+
const pathMonitor: string = readFrom(
|
|
569
|
+
PACKAGES_ROOT,
|
|
570
|
+
"Probe",
|
|
571
|
+
"Utils",
|
|
572
|
+
"Monitors",
|
|
573
|
+
"MonitorTypes",
|
|
574
|
+
"NetworkPathMonitor.ts",
|
|
575
|
+
);
|
|
576
|
+
|
|
577
|
+
// A non-global match returns the first "N ms" on the hop's line.
|
|
578
|
+
expect(pathMonitor).toContain("trimmedLine.match(/(\\d+\\.?\\d*)\\s*ms/)");
|
|
579
|
+
expect(DEVICE.tracerouteRtt).toContain("from the first reply the hop sent");
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
describe("flow texts match the top-talkers query", () => {
|
|
584
|
+
const flowApi: string = readFrom(
|
|
585
|
+
PACKAGES_ROOT,
|
|
586
|
+
"App",
|
|
587
|
+
"FeatureSet",
|
|
588
|
+
"BaseAPI",
|
|
589
|
+
"API",
|
|
590
|
+
"NetworkDeviceFlow.ts",
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
test("the top tables are capped at ten rows", () => {
|
|
594
|
+
expect(flowApi).toContain("const TOP_LIMIT: number = 10;");
|
|
595
|
+
|
|
596
|
+
for (const text of [
|
|
597
|
+
DEVICE.flowTopSources,
|
|
598
|
+
DEVICE.flowTopDestinations,
|
|
599
|
+
DEVICE.flowTopConversations,
|
|
600
|
+
DEVICE.flowTopProtocolsPorts,
|
|
601
|
+
]) {
|
|
602
|
+
expect(text).toContain("The 10 ");
|
|
603
|
+
expect(text).toContain("Bytes and Packets are");
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
test("records count by when the flow STARTED", () => {
|
|
608
|
+
expect(flowApi).toContain("AND flowStartAt >= ${startSql}");
|
|
609
|
+
expect(flowApi).toContain(
|
|
610
|
+
"toStartOfInterval(flowStartAt, INTERVAL ${bucketSeconds} second)",
|
|
611
|
+
);
|
|
612
|
+
expect(DEVICE.flowTotalTraffic).toContain("flows that started in");
|
|
613
|
+
expect(DEVICE.flowPackets).toContain("flows that started in");
|
|
614
|
+
expect(DEVICE.flowBandwidth).toContain("started in that slice");
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
test("the Flows count is records by start time too, not by when they arrived", () => {
|
|
618
|
+
// The three totals come from one statement over the same WHERE clause.
|
|
619
|
+
expect(flowApi).toContain(
|
|
620
|
+
"sum(octets) AS totalOctets, sum(packets) AS totalPackets, count() AS totalFlows FROM ${tableRef} ${whereClause}",
|
|
621
|
+
);
|
|
622
|
+
expect(DEVICE.flowCount).toContain(
|
|
623
|
+
"records this device exported for flows that started in the selected range",
|
|
624
|
+
);
|
|
625
|
+
expect(DEVICE.flowCount).not.toContain("arrived");
|
|
626
|
+
});
|
|
627
|
+
|
|
628
|
+
test("conversations are directional pairs", () => {
|
|
629
|
+
expect(flowApi).toContain("GROUP BY srcIp, dstIp");
|
|
630
|
+
expect(DEVICE.flowTopConversations).toContain(
|
|
631
|
+
"counting each direction separately",
|
|
632
|
+
);
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
test("protocol/port pairs key on the DESTINATION port", () => {
|
|
636
|
+
expect(flowApi).toContain("GROUP BY protocol, dstPort");
|
|
637
|
+
expect(DEVICE.flowTopProtocolsPorts).toContain("destination port");
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
test("sampled exports are not scaled up, and the text admits it", () => {
|
|
641
|
+
// A plain sum of what was exported; the sampling rate is never applied.
|
|
642
|
+
expect(flowApi).toContain("sum(octets) AS totalOctets");
|
|
643
|
+
expect(flowApi).not.toContain("samplingInterval");
|
|
644
|
+
expect(DEVICE.flowTotalTraffic).toContain("it is not scaled up");
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
test("the bandwidth chart fills empty slices with zero before Min / Avg / Max", () => {
|
|
648
|
+
const talkers: string = readDashboard(
|
|
649
|
+
"Components",
|
|
650
|
+
"NetworkDevice",
|
|
651
|
+
"FlowTopTalkers.tsx",
|
|
652
|
+
);
|
|
653
|
+
|
|
654
|
+
expect(talkers).toContain("series={fillFlowSeriesGaps(");
|
|
655
|
+
expect(talkers).toContain("(point.octets * 8) / 1_000_000 / bucketSeconds");
|
|
656
|
+
expect(DEVICE.flowBandwidth).toContain(
|
|
657
|
+
"slices with no records count as zero",
|
|
658
|
+
);
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
describe("Network Overview texts match the overview endpoint", () => {
|
|
663
|
+
const summaryApi: string = readFrom(
|
|
664
|
+
PACKAGES_ROOT,
|
|
665
|
+
"App",
|
|
666
|
+
"FeatureSet",
|
|
667
|
+
"BaseAPI",
|
|
668
|
+
"API",
|
|
669
|
+
"NetworkSummary.ts",
|
|
670
|
+
);
|
|
671
|
+
|
|
672
|
+
test("only the six biggest vendors are listed, and devices with no vendor are Unknown", () => {
|
|
673
|
+
expect(summaryApi).toContain("const VENDOR_LIST_LIMIT: number = 6;");
|
|
674
|
+
expect(summaryApi).toContain(
|
|
675
|
+
'const UNKNOWN_VENDOR_LABEL: string = "Unknown";',
|
|
676
|
+
);
|
|
677
|
+
expect(DEVICE.fleetByVendor).toContain("six most common vendors");
|
|
678
|
+
expect(DEVICE.fleetByVendor).toContain("grouped as Unknown");
|
|
679
|
+
expect(DEVICE.fleetByVendor).toContain("relative to the largest vendor");
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
test("the endpoint count is every endpoint row, with no recency filter", () => {
|
|
683
|
+
expect(summaryApi).toContain(
|
|
684
|
+
"NetworkEndpointService.countBy({ query: { projectId: projectId, }, props: props, })",
|
|
685
|
+
);
|
|
686
|
+
expect(DEVICE.fleetEndpoints).toContain("including ones not seen recently");
|
|
687
|
+
expect(SITE.endpoints).toContain("including ones not seen recently");
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
test("a site with no rollup is 'no data', not unhealthy", () => {
|
|
691
|
+
expect(summaryApi).toContain("sitesWithNoData += statusCount.siteCount;");
|
|
692
|
+
expect(DEVICE.fleetSites).toContain(
|
|
693
|
+
"sites with no data yet are not counted as unhealthy",
|
|
694
|
+
);
|
|
695
|
+
expect(SITE.sitesWithoutData).toContain("not counted as unhealthy");
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
|
|
699
|
+
describe("site texts match SiteUptimeUtil and the rollup", () => {
|
|
700
|
+
function row(
|
|
701
|
+
startsAt: Date,
|
|
702
|
+
endsAt: Date | null,
|
|
703
|
+
isOperationalState: boolean,
|
|
704
|
+
): SiteStatusTimelineRow {
|
|
705
|
+
return {
|
|
706
|
+
monitorStatusId: isOperationalState ? "operational" : "degraded",
|
|
707
|
+
startsAt: startsAt,
|
|
708
|
+
endsAt: endsAt,
|
|
709
|
+
priority: isOperationalState ? 1 : 2,
|
|
710
|
+
isOperationalState: isOperationalState,
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const END: Date = new Date("2026-09-24T12:00:00.000Z");
|
|
715
|
+
|
|
716
|
+
test("any non-operational status is downtime — Degraded as well as Offline", () => {
|
|
717
|
+
const measurement: SiteUptimeMeasurement = SiteUptimeUtil.measureUptime(
|
|
718
|
+
[row(new Date(END.getTime() - MS_PER_DAY), null, false)],
|
|
719
|
+
new Date(END.getTime() - 2 * MS_PER_DAY),
|
|
720
|
+
END,
|
|
721
|
+
);
|
|
722
|
+
|
|
723
|
+
expect(measurement.uptimePercent).toBeCloseTo(50, 5);
|
|
724
|
+
|
|
725
|
+
for (const text of [SITE.uptime24h, SITE.uptimeWindow]) {
|
|
726
|
+
expect(text).toContain(
|
|
727
|
+
"non-operational status such as Degraded or Offline",
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
expect(SITE.uptime30d).toContain("non-operational status");
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
test("one full day down in thirty costs about 3.3 points", () => {
|
|
734
|
+
const measurement: SiteUptimeMeasurement = SiteUptimeUtil.measureUptime(
|
|
735
|
+
[
|
|
736
|
+
row(new Date(END.getTime() - 30 * MS_PER_DAY), null, true),
|
|
737
|
+
row(
|
|
738
|
+
new Date(END.getTime() - 2 * MS_PER_DAY),
|
|
739
|
+
new Date(END.getTime() - MS_PER_DAY),
|
|
740
|
+
false,
|
|
741
|
+
),
|
|
742
|
+
],
|
|
743
|
+
new Date(END.getTime() - 30 * MS_PER_DAY),
|
|
744
|
+
END,
|
|
745
|
+
);
|
|
746
|
+
|
|
747
|
+
expect(100 - measurement.uptimePercent).toBeCloseTo(3.33, 1);
|
|
748
|
+
expect(SITE.uptime30d).toContain("about 3.3 points");
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
test("time before the first rollup counts as UP in the totals", () => {
|
|
752
|
+
// A site first rolled up (healthy) a day ago, measured over 30 days.
|
|
753
|
+
const measurement: SiteUptimeMeasurement = SiteUptimeUtil.measureUptime(
|
|
754
|
+
[row(new Date(END.getTime() - MS_PER_DAY), null, true)],
|
|
755
|
+
new Date(END.getTime() - 30 * MS_PER_DAY),
|
|
756
|
+
END,
|
|
757
|
+
);
|
|
758
|
+
|
|
759
|
+
expect(measurement.measuredInMs).toBe(30 * MS_PER_DAY);
|
|
760
|
+
expect(measurement.uptimePercent).toBe(100);
|
|
761
|
+
|
|
762
|
+
expect(SITE.uptime24h).toContain(
|
|
763
|
+
"time before the site's first health rollup counts as up",
|
|
764
|
+
);
|
|
765
|
+
expect(SITE.uptime30d).toContain(
|
|
766
|
+
"time before the first rollup counts as up",
|
|
767
|
+
);
|
|
768
|
+
expect(SITE.uptimeWindow).toContain(
|
|
769
|
+
"Time before the first rollup counts as up",
|
|
770
|
+
);
|
|
771
|
+
});
|
|
772
|
+
|
|
773
|
+
test("...while the daily strip leaves those days blank, which its legend says", () => {
|
|
774
|
+
const entries: ReturnType<typeof SiteUptimeUtil.calculateDailyUptime> =
|
|
775
|
+
SiteUptimeUtil.calculateDailyUptime({
|
|
776
|
+
rows: [row(new Date(END.getTime() - MS_PER_DAY), null, true)],
|
|
777
|
+
days: 3,
|
|
778
|
+
endDate: END,
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
expect(entries[0]!.uptimePercent).toBeNull();
|
|
782
|
+
expect(entries[0]!.hasTimelineCoverage).toBe(false);
|
|
783
|
+
expect(entries[2]!.uptimePercent).toBe(100);
|
|
784
|
+
|
|
785
|
+
expect(SITE.dailyUptime).toContain(
|
|
786
|
+
"a hollow outline is a day before the site's first health rollup",
|
|
787
|
+
);
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
test("maintenance leaves the period entirely, so a fully maintained window has nothing to measure", () => {
|
|
791
|
+
const measurement: SiteUptimeMeasurement = SiteUptimeUtil.measureUptime(
|
|
792
|
+
[row(new Date(END.getTime() - 2 * MS_PER_DAY), null, false)],
|
|
793
|
+
new Date(END.getTime() - MS_PER_DAY),
|
|
794
|
+
END,
|
|
795
|
+
[{ startsAt: new Date(END.getTime() - 2 * MS_PER_DAY), endsAt: null }],
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
expect(measurement.measuredInMs).toBe(0);
|
|
799
|
+
expect(SITE.uptime24h).toContain("Scheduled maintenance is left out");
|
|
800
|
+
expect(SITE.uptime30d).toContain("scheduled maintenance left out");
|
|
801
|
+
expect(SITE.uptimeWindow).toContain(
|
|
802
|
+
"leaving out scheduled maintenance on the site or its parents",
|
|
803
|
+
);
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
test("the legend's colour thresholds are the strip's own", () => {
|
|
807
|
+
const strip: string = readDashboard(
|
|
808
|
+
"Components",
|
|
809
|
+
"NetworkSite",
|
|
810
|
+
"SiteDailyUptimeStrip.tsx",
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
expect(strip).toContain(
|
|
814
|
+
"const DEFAULT_GOOD_THRESHOLD_PERCENT: number = 99.9;",
|
|
815
|
+
);
|
|
816
|
+
expect(strip).toContain("if (entry.uptimePercent >= 95) {");
|
|
817
|
+
expect(SITE.dailyUptime).toContain("Green is 99.9% uptime or better");
|
|
818
|
+
expect(SITE.dailyUptime).toContain("amber 95% or better");
|
|
819
|
+
});
|
|
820
|
+
|
|
821
|
+
test("the red threshold on the uptime cards is the page's own", () => {
|
|
822
|
+
const timeline: string = readDashboard(
|
|
823
|
+
"Pages",
|
|
824
|
+
"NetworkSite",
|
|
825
|
+
"View",
|
|
826
|
+
"StatusTimeline.tsx",
|
|
827
|
+
);
|
|
828
|
+
|
|
829
|
+
expect(timeline).toContain("uptime !== undefined && uptime < 99");
|
|
830
|
+
expect(SITE.uptimeWindow).toContain("red means below 99%");
|
|
831
|
+
});
|
|
832
|
+
|
|
833
|
+
test("the hero's windows are 24 hours and 30 days", () => {
|
|
834
|
+
const hero: string = readDashboard(
|
|
835
|
+
"Components",
|
|
836
|
+
"NetworkSite",
|
|
837
|
+
"SiteStatusHero.tsx",
|
|
838
|
+
);
|
|
839
|
+
|
|
840
|
+
expect(hero).toContain("const UPTIME_WINDOW_DAYS: number = 30;");
|
|
841
|
+
expect(hero).toContain("const DAILY_UPTIME_WINDOW_DAYS: number = 1;");
|
|
842
|
+
expect(SITE.uptime24h).toContain("last 24 hours");
|
|
843
|
+
expect(SITE.uptime30d).toContain("last 30 days");
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
test("health rolls up the whole subtree; the hero's Devices and Endpoints are the site's own", () => {
|
|
847
|
+
const siteService: string = readFrom(
|
|
848
|
+
PACKAGES_ROOT,
|
|
849
|
+
"Common",
|
|
850
|
+
"Server",
|
|
851
|
+
"Services",
|
|
852
|
+
"NetworkSiteService.ts",
|
|
853
|
+
);
|
|
854
|
+
const hero: string = readDashboard(
|
|
855
|
+
"Components",
|
|
856
|
+
"NetworkSite",
|
|
857
|
+
"SiteStatusHero.tsx",
|
|
858
|
+
);
|
|
859
|
+
|
|
860
|
+
expect(siteService).toContain(
|
|
861
|
+
"...(await this.getDescendantSiteIds(site.id, site.projectId)),",
|
|
862
|
+
);
|
|
863
|
+
expect(SITE.health).toContain("at every site beneath it");
|
|
864
|
+
expect(SITE.childSiteStatus).toContain("at every site beneath it");
|
|
865
|
+
|
|
866
|
+
// The hero reads devices and endpoints by siteId — no subtree.
|
|
867
|
+
expect(hero).toContain(
|
|
868
|
+
"siteId: props.modelId.toString(), isArchived: false,",
|
|
869
|
+
);
|
|
870
|
+
expect(hero).toContain(
|
|
871
|
+
"modelType: NetworkEndpoint, query: { siteId: props.modelId.toString(), },",
|
|
872
|
+
);
|
|
873
|
+
expect(SITE.devices).toContain("not counting those in child sites");
|
|
874
|
+
expect(SITE.endpoints).toContain("devices assigned to this site");
|
|
875
|
+
|
|
876
|
+
// Child Sites is one level: parentSiteId, not the materialized path.
|
|
877
|
+
expect(hero).toContain("parentSiteId: props.modelId.toString(),");
|
|
878
|
+
expect(SITE.childSites).toContain("one level down");
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
test("the rollup rule is worst-of by default, with a threshold option in Settings", () => {
|
|
882
|
+
const settings: string = readDashboard(
|
|
883
|
+
"Pages",
|
|
884
|
+
"NetworkSite",
|
|
885
|
+
"View",
|
|
886
|
+
"Settings.tsx",
|
|
887
|
+
);
|
|
888
|
+
|
|
889
|
+
expect(settings).toContain("healthRollupPolicy");
|
|
890
|
+
expect(SITE.health).toContain("the worst device status by default");
|
|
891
|
+
expect(SITE.health).toContain("share-of-devices-down rule set in Settings");
|
|
892
|
+
});
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
describe("the site list and site Devices texts match what those columns draw", () => {
|
|
896
|
+
test("the Sites list Status is the same subtree rollup, worst-of unless Settings say otherwise", () => {
|
|
897
|
+
const siteService: string = readFrom(
|
|
898
|
+
PACKAGES_ROOT,
|
|
899
|
+
"Common",
|
|
900
|
+
"Server",
|
|
901
|
+
"Services",
|
|
902
|
+
"NetworkSiteService.ts",
|
|
903
|
+
);
|
|
904
|
+
|
|
905
|
+
expect(siteService).toContain(
|
|
906
|
+
"...(await this.getDescendantSiteIds(site.id, site.projectId)),",
|
|
907
|
+
);
|
|
908
|
+
expect(DefaultSiteHealthRollupPolicy).toBe(
|
|
909
|
+
SiteHealthRollupPolicy.WorstStatus,
|
|
910
|
+
);
|
|
911
|
+
expect(SITE.siteStatus).toContain("every site beneath it");
|
|
912
|
+
expect(SITE.siteStatus).toContain(
|
|
913
|
+
"the worst device status unless its Settings set a share-of-devices-down rule",
|
|
914
|
+
);
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
test("child sites inside a maintenance window do not vote in their ancestors' health", () => {
|
|
918
|
+
const siteService: string = readFrom(
|
|
919
|
+
PACKAGES_ROOT,
|
|
920
|
+
"Common",
|
|
921
|
+
"Server",
|
|
922
|
+
"Services",
|
|
923
|
+
"NetworkSiteService.ts",
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
/*
|
|
927
|
+
* A site that is itself in maintenance still shows its own outage; only
|
|
928
|
+
* an ancestor looking down past a maintained subtree drops it.
|
|
929
|
+
*/
|
|
930
|
+
expect(siteService).toContain(
|
|
931
|
+
"const suppressesDescendants: boolean = !isSiteUnderMaintenance && maintainedSiteIds.size > 0;",
|
|
932
|
+
);
|
|
933
|
+
expect(SITE.siteStatus).toContain(
|
|
934
|
+
"leaving out child sites under maintenance",
|
|
935
|
+
);
|
|
936
|
+
});
|
|
937
|
+
|
|
938
|
+
test("No Data is a site with no rolled-up status", () => {
|
|
939
|
+
const sites: string = readDashboard("Pages", "NetworkSite", "Sites.tsx");
|
|
940
|
+
|
|
941
|
+
expect(sites).toContain(
|
|
942
|
+
'if (!item.currentMonitorStatus) { return <span className="text-sm text-gray-400">No Data</span>; }',
|
|
943
|
+
);
|
|
944
|
+
expect(SITE.siteStatus).toContain(
|
|
945
|
+
"No Data means nothing below it has reported yet",
|
|
946
|
+
);
|
|
947
|
+
});
|
|
948
|
+
|
|
949
|
+
test("on the site's Devices tab a monitor-backed device is folded into Up / Down by the OFFLINE end", () => {
|
|
950
|
+
const siteDevices: string = readDashboard(
|
|
951
|
+
"Pages",
|
|
952
|
+
"NetworkSite",
|
|
953
|
+
"View",
|
|
954
|
+
"Devices.tsx",
|
|
955
|
+
);
|
|
956
|
+
const deviceList: string = readDashboard(
|
|
957
|
+
"Pages",
|
|
958
|
+
"NetworkDevice",
|
|
959
|
+
"Devices.tsx",
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
// The tab reads the shared rule for every device, monitor-backed or not.
|
|
963
|
+
expect(siteDevices).toContain(
|
|
964
|
+
"const reachability: DeviceReachabilityResult = DeviceStatusUtil.getReachability(item);",
|
|
965
|
+
);
|
|
966
|
+
expect(siteDevices).not.toContain("text={item.currentMonitorStatus.name}");
|
|
967
|
+
|
|
968
|
+
// ...where a monitor that is Degraded but not offline reads Up.
|
|
969
|
+
expect(
|
|
970
|
+
DeviceReachabilityUtil.getStatus({
|
|
971
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Monitor,
|
|
972
|
+
monitorStatusIsOffline: false,
|
|
973
|
+
}),
|
|
974
|
+
).toBe(NetworkDeviceReachability.Up);
|
|
975
|
+
expect(SITE.siteDeviceStatus).toContain(
|
|
976
|
+
"Down only when its bound monitor reports it offline and Up otherwise",
|
|
977
|
+
);
|
|
978
|
+
|
|
979
|
+
// The device list prints the monitor's own word instead, so its text differs.
|
|
980
|
+
expect(deviceList).toContain("text={item.currentMonitorStatus.name}");
|
|
981
|
+
expect(DEVICE.deviceStatus).toContain(
|
|
982
|
+
"shows its bound monitor's status instead",
|
|
983
|
+
);
|
|
984
|
+
expect(SITE.siteDeviceStatus).not.toBe(DEVICE.deviceStatus);
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
test("the tab's Interfaces column is the device list's, cell for cell", () => {
|
|
988
|
+
const siteDevices: string = readDashboard(
|
|
989
|
+
"Pages",
|
|
990
|
+
"NetworkSite",
|
|
991
|
+
"View",
|
|
992
|
+
"Devices.tsx",
|
|
993
|
+
);
|
|
994
|
+
|
|
995
|
+
expect(siteDevices).toContain("if (hasNoSnmpInventory(item)) {");
|
|
996
|
+
expect(siteDevices).toContain("{NO_SNMP_INTERFACES_LABEL.text}");
|
|
997
|
+
expect(DEVICE.deviceInterfacesUpDown).toContain(
|
|
998
|
+
"No SNMP means the device is only pinged",
|
|
999
|
+
);
|
|
1000
|
+
});
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
describe("Network Map card texts match the children endpoint", () => {
|
|
1004
|
+
const OPERATIONAL: string = "status-operational";
|
|
1005
|
+
const DEGRADED: string = "status-degraded";
|
|
1006
|
+
|
|
1007
|
+
/*
|
|
1008
|
+
* region (a child of the level in view)
|
|
1009
|
+
* market
|
|
1010
|
+
* store1 (unit, Operational)
|
|
1011
|
+
* store2 (unit, Degraded)
|
|
1012
|
+
* store3 (unit, never rolled up)
|
|
1013
|
+
*/
|
|
1014
|
+
function regionAggregate(): ChildAggregate {
|
|
1015
|
+
return NetworkSiteHierarchyUtil.aggregateChildStats({
|
|
1016
|
+
children: [{ id: "region", siteType: "Region", isUnitLevel: false }],
|
|
1017
|
+
descendants: [
|
|
1018
|
+
{
|
|
1019
|
+
id: "market",
|
|
1020
|
+
siteType: "Market",
|
|
1021
|
+
isUnitLevel: false,
|
|
1022
|
+
parentSiteId: "region",
|
|
1023
|
+
materializedPath: "/region/",
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
id: "store1",
|
|
1027
|
+
siteType: "Store",
|
|
1028
|
+
isUnitLevel: true,
|
|
1029
|
+
parentSiteId: "market",
|
|
1030
|
+
materializedPath: "/region/market/",
|
|
1031
|
+
currentMonitorStatusId: OPERATIONAL,
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
id: "store2",
|
|
1035
|
+
siteType: "Store",
|
|
1036
|
+
isUnitLevel: true,
|
|
1037
|
+
parentSiteId: "market",
|
|
1038
|
+
materializedPath: "/region/market/",
|
|
1039
|
+
currentMonitorStatusId: DEGRADED,
|
|
1040
|
+
},
|
|
1041
|
+
{
|
|
1042
|
+
id: "store3",
|
|
1043
|
+
siteType: "Store",
|
|
1044
|
+
isUnitLevel: true,
|
|
1045
|
+
parentSiteId: "market",
|
|
1046
|
+
materializedPath: "/region/market/",
|
|
1047
|
+
},
|
|
1048
|
+
],
|
|
1049
|
+
devices: [
|
|
1050
|
+
{ siteId: "store1", healthState: "degraded", deviceCount: 2 },
|
|
1051
|
+
{ siteId: "region", healthState: "healthy", deviceCount: 3 },
|
|
1052
|
+
],
|
|
1053
|
+
operationalStatusIds: new Set<string>([OPERATIONAL]),
|
|
1054
|
+
}).get("region")!;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
test("a unit that is not operational counts as down on the card - Degraded AND no data", () => {
|
|
1058
|
+
const card: string = readDashboard(
|
|
1059
|
+
"Components",
|
|
1060
|
+
"NetworkSite",
|
|
1061
|
+
"SiteCard.tsx",
|
|
1062
|
+
);
|
|
1063
|
+
const aggregate: ChildAggregate = regionAggregate();
|
|
1064
|
+
|
|
1065
|
+
// Three units below, one operational: the card reads "2 of 3 units down".
|
|
1066
|
+
expect(aggregate.unitStats).toEqual({ totalUnits: 3, operationalUnits: 1 });
|
|
1067
|
+
expect(card).toContain(
|
|
1068
|
+
"const downUnits: number = totalUnits - operationalUnits;",
|
|
1069
|
+
);
|
|
1070
|
+
expect(card).toContain(
|
|
1071
|
+
"leadCaption = `of ${totalUnits} ${pluralUnits(totalUnits)} down`;",
|
|
1072
|
+
);
|
|
1073
|
+
|
|
1074
|
+
expect(SITE.siteCards).toContain("Units are unit-level sites");
|
|
1075
|
+
expect(SITE.siteCards).toContain(
|
|
1076
|
+
"any not operational, even with no data yet, count as down",
|
|
1077
|
+
);
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
test("devices span the whole subtree, and a degraded one answers with a port down", () => {
|
|
1081
|
+
const aggregate: ChildAggregate = regionAggregate();
|
|
1082
|
+
|
|
1083
|
+
// Two at a grandchild unit plus three on the region itself.
|
|
1084
|
+
expect(aggregate.deviceCount).toBe(5);
|
|
1085
|
+
expect(aggregate.deviceStats.degraded).toBe(2);
|
|
1086
|
+
|
|
1087
|
+
const now: Date = OneUptimeDate.getCurrentDate();
|
|
1088
|
+
|
|
1089
|
+
expect(
|
|
1090
|
+
deviceHealthState(
|
|
1091
|
+
{
|
|
1092
|
+
monitoringMethod: NetworkDeviceMonitoringMethod.Probe,
|
|
1093
|
+
isReachable: true,
|
|
1094
|
+
lastPolledAt: now,
|
|
1095
|
+
lastSeenAt: now,
|
|
1096
|
+
interfacesDown: 2,
|
|
1097
|
+
},
|
|
1098
|
+
now,
|
|
1099
|
+
),
|
|
1100
|
+
).toBe("degraded");
|
|
1101
|
+
|
|
1102
|
+
expect(SITE.siteCards).toContain("Devices span every site below");
|
|
1103
|
+
expect(SITE.siteCards).toContain(
|
|
1104
|
+
"a degraded one answers but has a port down",
|
|
1105
|
+
);
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
test("uptime is 30 days and 'today' is the last 24 hours, maintenance left out", () => {
|
|
1109
|
+
const hierarchyApi: string = readFrom(
|
|
1110
|
+
PACKAGES_ROOT,
|
|
1111
|
+
"App",
|
|
1112
|
+
"FeatureSet",
|
|
1113
|
+
"BaseAPI",
|
|
1114
|
+
"API",
|
|
1115
|
+
"NetworkSiteHierarchy.ts",
|
|
1116
|
+
);
|
|
1117
|
+
const map: string = readDashboard("Pages", "NetworkSite", "NetworkMap.tsx");
|
|
1118
|
+
const card: string = readDashboard(
|
|
1119
|
+
"Components",
|
|
1120
|
+
"NetworkSite",
|
|
1121
|
+
"SiteCard.tsx",
|
|
1122
|
+
);
|
|
1123
|
+
|
|
1124
|
+
// The map asks for no window, so the endpoint's default applies.
|
|
1125
|
+
expect(map).toContain("data: siteId ? { siteId: siteId } : {},");
|
|
1126
|
+
expect(map).not.toContain("uptimeWindowInDays");
|
|
1127
|
+
expect(DEFAULT_UPTIME_WINDOW_DAYS).toBe(30);
|
|
1128
|
+
|
|
1129
|
+
expect(hierarchyApi).toContain(
|
|
1130
|
+
"const dailyWindowStart: Date = SiteUptimeUtil.trailingWindowStart( windowEnd, 1, );",
|
|
1131
|
+
);
|
|
1132
|
+
expect(hierarchyApi).toContain(
|
|
1133
|
+
"SiteUptimeUtil.measureUptime( uptimeRows!, windowStart, windowEnd, childMaintenanceWindows, )",
|
|
1134
|
+
);
|
|
1135
|
+
expect(card).toContain("30d uptime");
|
|
1136
|
+
expect(card).toContain(
|
|
1137
|
+
"{formatUptimePercent(site.dailyUptimePercent)} today",
|
|
1138
|
+
);
|
|
1139
|
+
|
|
1140
|
+
// 'today' quoted: the card's own label, not "as of today".
|
|
1141
|
+
expect(SITE.siteCards).toContain(
|
|
1142
|
+
"Uptime covers 30 days and 'today' the last 24 hours, maintenance left out",
|
|
1143
|
+
);
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
describe("Probe Latency Matrix text matches LatencyMatrixUtil and the endpoint", () => {
|
|
1148
|
+
const T0: number = new Date("2026-09-24T10:00:00.000Z").getTime();
|
|
1149
|
+
const MINUTE: number = 60 * 1000;
|
|
1150
|
+
|
|
1151
|
+
function buildMatrix(): LatencyMatrix {
|
|
1152
|
+
return LatencyMatrixUtil.buildMatrix({
|
|
1153
|
+
monitors: [{ id: "web", name: "Website" }],
|
|
1154
|
+
probes: [
|
|
1155
|
+
{ id: "own-probe", name: "Rack 3" },
|
|
1156
|
+
{ id: "idle-probe", name: "Rack 4" },
|
|
1157
|
+
],
|
|
1158
|
+
results: [
|
|
1159
|
+
{
|
|
1160
|
+
monitorId: "web",
|
|
1161
|
+
probeId: "own-probe",
|
|
1162
|
+
lastMonitoringLog: {
|
|
1163
|
+
// Two steps: the cell is the one checked MOST RECENTLY.
|
|
1164
|
+
stepA: {
|
|
1165
|
+
monitoredAt: new Date(T0).toISOString(),
|
|
1166
|
+
responseTimeInMs: 80,
|
|
1167
|
+
isOnline: true,
|
|
1168
|
+
},
|
|
1169
|
+
stepB: {
|
|
1170
|
+
monitoredAt: new Date(T0 + 5 * MINUTE).toISOString(),
|
|
1171
|
+
responseTimeInMs: 20,
|
|
1172
|
+
isOnline: true,
|
|
1173
|
+
},
|
|
1174
|
+
},
|
|
1175
|
+
},
|
|
1176
|
+
{
|
|
1177
|
+
// A probe the axis does not list - a global probe - is dropped.
|
|
1178
|
+
monitorId: "web",
|
|
1179
|
+
probeId: "global-probe",
|
|
1180
|
+
lastMonitoringLog: {
|
|
1181
|
+
stepA: {
|
|
1182
|
+
monitoredAt: new Date(T0).toISOString(),
|
|
1183
|
+
responseTimeInMs: 5,
|
|
1184
|
+
isOnline: true,
|
|
1185
|
+
},
|
|
1186
|
+
},
|
|
1187
|
+
},
|
|
1188
|
+
],
|
|
1189
|
+
now: new Date(T0 + 20 * MINUTE),
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
test("each cell is the monitor's LATEST check from that probe", () => {
|
|
1194
|
+
const cell: LatencyMatrix["cells"][string][string] =
|
|
1195
|
+
buildMatrix().cells["web"]!["own-probe"]!;
|
|
1196
|
+
|
|
1197
|
+
expect(cell.latencyInMs).toBe(20);
|
|
1198
|
+
expect(cell.ageInSeconds).toBe(15 * 60);
|
|
1199
|
+
expect(DEVICE.latencyMatrix).toContain("each monitor's latest check");
|
|
1200
|
+
});
|
|
1201
|
+
|
|
1202
|
+
test("a probe with no result is a dash, and an old result is faded after 10 minutes", () => {
|
|
1203
|
+
const grid: string = readDashboard(
|
|
1204
|
+
"Components",
|
|
1205
|
+
"NetworkDevice",
|
|
1206
|
+
"LatencyMatrixGrid.tsx",
|
|
1207
|
+
);
|
|
1208
|
+
|
|
1209
|
+
expect(buildMatrix().cells["web"]!["idle-probe"]!.hasData).toBe(false);
|
|
1210
|
+
expect(grid).toContain("if (!cell || !cell.hasData) {");
|
|
1211
|
+
expect(grid).toContain("—");
|
|
1212
|
+
expect(grid).toContain("const STALE_AGE_IN_SECONDS: number = 600;");
|
|
1213
|
+
expect(grid).toContain("style={isStale ? { opacity: 0.5 } : undefined}");
|
|
1214
|
+
expect(grid).toContain("if (cell.isOnline === false) {");
|
|
1215
|
+
|
|
1216
|
+
expect(DEVICE.latencyMatrix).toContain("Offline means that check failed");
|
|
1217
|
+
expect(DEVICE.latencyMatrix).toContain("a dash means no result");
|
|
1218
|
+
expect(DEVICE.latencyMatrix).toContain(
|
|
1219
|
+
"faded cells are over 10 minutes old",
|
|
1220
|
+
);
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
test("only the project's own probes get a column", () => {
|
|
1224
|
+
const matrixApi: string = readFrom(
|
|
1225
|
+
PACKAGES_ROOT,
|
|
1226
|
+
"App",
|
|
1227
|
+
"FeatureSet",
|
|
1228
|
+
"BaseAPI",
|
|
1229
|
+
"API",
|
|
1230
|
+
"NetworkLatencyMatrix.ts",
|
|
1231
|
+
);
|
|
1232
|
+
|
|
1233
|
+
/*
|
|
1234
|
+
* Global probes have no projectId, so a projectId query never returns
|
|
1235
|
+
* them - and a result from a probe the axis does not list is dropped.
|
|
1236
|
+
*/
|
|
1237
|
+
expect(matrixApi).toContain(
|
|
1238
|
+
"const probes: Array<Probe> = await ProbeService.findBy({ query: { projectId: props.tenantId, },",
|
|
1239
|
+
);
|
|
1240
|
+
expect(Object.keys(buildMatrix().cells["web"]!)).toEqual([
|
|
1241
|
+
"own-probe",
|
|
1242
|
+
"idle-probe",
|
|
1243
|
+
]);
|
|
1244
|
+
expect(DEVICE.latencyMatrix).toContain("from each of your probes");
|
|
1245
|
+
expect(DEVICE.latencyMatrix).toContain("Global probes are not shown");
|
|
1246
|
+
});
|
|
1247
|
+
});
|
|
1248
|
+
|
|
1249
|
+
describe("the Discovery Scans text matches how the ingest counts responders", () => {
|
|
1250
|
+
function discoveryScan(data: {
|
|
1251
|
+
isSnmpEnabled: boolean;
|
|
1252
|
+
status: string;
|
|
1253
|
+
scannedHostCount: number;
|
|
1254
|
+
respondedHostCount: number;
|
|
1255
|
+
pingOnlyHosts: number;
|
|
1256
|
+
}): NetworkDeviceDiscoveryScan {
|
|
1257
|
+
const hosts: Array<{ ipAddress: string; snmpReachable: boolean }> = [];
|
|
1258
|
+
|
|
1259
|
+
for (let i: number = 0; i < data.respondedHostCount; i++) {
|
|
1260
|
+
hosts.push({ ipAddress: `10.0.0.${i + 1}`, snmpReachable: true });
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
for (let i: number = 0; i < data.pingOnlyHosts; i++) {
|
|
1264
|
+
hosts.push({ ipAddress: `10.0.1.${i + 1}`, snmpReachable: false });
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return Object.assign(new NetworkDeviceDiscoveryScan(), {
|
|
1268
|
+
cidr: "10.0.0.0/22",
|
|
1269
|
+
isSnmpEnabled: data.isSnmpEnabled,
|
|
1270
|
+
status: data.status,
|
|
1271
|
+
scannedHostCount: data.scannedHostCount,
|
|
1272
|
+
respondedHostCount: data.respondedHostCount,
|
|
1273
|
+
discoveredDevices: hosts,
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
test("on an SNMP scan the count is the SNMP responders; ping-only hosts are the line beneath", () => {
|
|
1278
|
+
const ingest: string = readFrom(
|
|
1279
|
+
PACKAGES_ROOT,
|
|
1280
|
+
"App",
|
|
1281
|
+
"FeatureSet",
|
|
1282
|
+
"Telemetry",
|
|
1283
|
+
"API",
|
|
1284
|
+
"ProbeIngest",
|
|
1285
|
+
"DiscoveryScan.ts",
|
|
1286
|
+
);
|
|
1287
|
+
|
|
1288
|
+
expect(ingest).toContain('return device["snmpReachable"] !== false;');
|
|
1289
|
+
expect(ingest).toContain(
|
|
1290
|
+
"const respondedHostCount: number = ScanModeUtil.isSnmpEnabled(scan) ? snmpResponderCount : discoveredDevices.length;",
|
|
1291
|
+
);
|
|
1292
|
+
|
|
1293
|
+
const outcome: DiscoveryScanOutcome = summarizeDiscoveryScan(
|
|
1294
|
+
discoveryScan({
|
|
1295
|
+
isSnmpEnabled: true,
|
|
1296
|
+
status: "Completed",
|
|
1297
|
+
scannedHostCount: 1022,
|
|
1298
|
+
respondedHostCount: 12,
|
|
1299
|
+
pingOnlyHosts: 30,
|
|
1300
|
+
}),
|
|
1301
|
+
);
|
|
1302
|
+
|
|
1303
|
+
expect(outcome.respondedHostSummary).toBe("12 of 1022 hosts");
|
|
1304
|
+
expect(outcome.pingOnlyHostCount).toBe(30);
|
|
1305
|
+
expect(DEVICE.discoveryRespondedHosts).toContain(
|
|
1306
|
+
"Hosts that answered SNMP out of the addresses swept",
|
|
1307
|
+
);
|
|
1308
|
+
expect(DEVICE.discoveryRespondedHosts).toContain(
|
|
1309
|
+
"hosts that answered only ping counted separately as alive without SNMP",
|
|
1310
|
+
);
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
test("on a ping-only scan the count is the hosts that answered ping", () => {
|
|
1314
|
+
const outcome: DiscoveryScanOutcome = summarizeDiscoveryScan(
|
|
1315
|
+
discoveryScan({
|
|
1316
|
+
isSnmpEnabled: false,
|
|
1317
|
+
status: "Completed",
|
|
1318
|
+
scannedHostCount: 1022,
|
|
1319
|
+
respondedHostCount: 40,
|
|
1320
|
+
pingOnlyHosts: 0,
|
|
1321
|
+
}),
|
|
1322
|
+
);
|
|
1323
|
+
|
|
1324
|
+
expect(outcome.respondedHostSummary).toBe("40 of 1022 hosts answered ping");
|
|
1325
|
+
expect(outcome.pingOnlyHostCount).toBe(0);
|
|
1326
|
+
expect(DEVICE.discoveryRespondedHosts).toContain(
|
|
1327
|
+
"On a ping-only scan it is the hosts that answered ping",
|
|
1328
|
+
);
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
test("mid-sweep, the denominator is what has been swept so far", () => {
|
|
1332
|
+
const outcome: DiscoveryScanOutcome = summarizeDiscoveryScan(
|
|
1333
|
+
discoveryScan({
|
|
1334
|
+
isSnmpEnabled: true,
|
|
1335
|
+
status: "In Progress",
|
|
1336
|
+
scannedHostCount: 256,
|
|
1337
|
+
respondedHostCount: 3,
|
|
1338
|
+
pingOnlyHosts: 1,
|
|
1339
|
+
}),
|
|
1340
|
+
);
|
|
1341
|
+
|
|
1342
|
+
expect(outcome.respondedHostSummary).toBe("3 of 256 hosts");
|
|
1343
|
+
expect(outcome.progressSummary).toContain("addresses swept so far");
|
|
1344
|
+
expect(DEVICE.discoveryRespondedHosts).toContain(
|
|
1345
|
+
"While a scan runs, both cover only what has been swept so far",
|
|
1346
|
+
);
|
|
1347
|
+
});
|
|
1348
|
+
});
|