@oneuptime/common 12.0.6 → 12.0.7
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/AIInsight.ts +1 -1
- package/Models/DatabaseModels/DatabaseBaseModel/FileModel.ts +2 -3
- package/Models/DatabaseModels/DeletedProject.ts +595 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/Monitor.ts +111 -0
- package/Models/DatabaseModels/Project.ts +3 -3
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -1
- package/Server/API/FileAPI.ts +15 -2
- package/Server/API/MicrosoftTeamsAPI.ts +6 -1
- package/Server/API/ProjectAPI.ts +214 -0
- package/Server/API/StatusPageAPI.ts +39 -6
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.ts +50 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.ts +67 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.ts +39 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Services/AIAgentService.ts +20 -0
- package/Server/Services/DashboardDomainService.ts +73 -28
- package/Server/Services/DatabaseService.ts +1 -0
- package/Server/Services/DeletedProjectService.ts +138 -0
- package/Server/Services/FileService.ts +61 -0
- package/Server/Services/IncidentEpisodePublicNoteService.ts +18 -0
- package/Server/Services/IncidentPublicNoteService.ts +18 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/MonitorService.ts +311 -0
- package/Server/Services/ProbeService.ts +20 -0
- package/Server/Services/ProjectService.ts +297 -1
- package/Server/Services/PushNotificationService.ts +71 -0
- package/Server/Services/ScheduledMaintenancePublicNoteService.ts +18 -0
- package/Server/Services/StatusPageAnnouncementService.ts +53 -0
- package/Server/Services/StatusPageDomainService.ts +73 -28
- package/Server/Services/TeamMemberService.ts +117 -12
- package/Server/Services/TelemetryIngestionKeyService.ts +1 -0
- package/Server/Services/UserWebhookService.ts +34 -109
- package/Server/Services/WorkspaceNotificationRuleService.ts +69 -0
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +37 -1
- package/Server/Types/Database/DeleteById.ts +2 -0
- package/Server/Types/Database/DeleteOneBy.ts +6 -0
- package/Server/Types/Domain.ts +41 -0
- package/Server/Types/Workflow/Components/API/Delete.ts +2 -1
- package/Server/Types/Workflow/Components/API/Get.ts +2 -1
- package/Server/Types/Workflow/Components/API/Patch.ts +2 -1
- package/Server/Types/Workflow/Components/API/Post.ts +2 -1
- package/Server/Types/Workflow/Components/API/Put.ts +2 -1
- package/Server/Types/Workflow/Components/API/Utils.ts +41 -2
- package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +25 -19
- package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +6 -5
- package/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.ts +32 -14
- package/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.ts +31 -13
- package/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.ts +29 -20
- package/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.ts +28 -21
- package/Server/Types/Workflow/Components/BaseModel/LogComponentError.ts +89 -0
- package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +208 -0
- package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +11 -0
- package/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.ts +41 -18
- package/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.ts +45 -19
- package/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts +16 -9
- package/Server/Types/Workflow/Components/IncomingWebhookUtils.ts +66 -0
- package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +15 -9
- package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +17 -0
- package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
- package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +171 -0
- package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +3 -3
- package/Server/Utils/AI/SRE/Insights/FixRouting.ts +3 -2
- package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +1 -1
- package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +6 -6
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +43 -5
- package/Server/Utils/DataSource/EgressGuard.ts +176 -16
- package/Server/Utils/DataSource/HttpFetch.ts +6 -45
- package/Server/Utils/Execute.ts +8 -0
- package/Server/Utils/InlineImageAccessTokenSync.ts +23 -0
- package/Server/Utils/LLM/LLMService.ts +57 -12
- package/Server/Utils/Monitor/MonitorAlert.ts +40 -0
- package/Server/Utils/Monitor/MonitorDependencySuppression.ts +192 -0
- package/Server/Utils/Monitor/MonitorIncident.ts +40 -0
- package/Server/Utils/Monitor/MonitorResource.ts +36 -0
- package/Server/Utils/Response.ts +142 -6
- package/Server/Utils/SSRFProtection.ts +273 -60
- package/Server/Utils/StartServer.ts +8 -0
- package/Server/Utils/VM/VMRunner.ts +88 -1
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +555 -49
- package/Server/Utils/Workspace/Slack/Slack.ts +25 -2
- package/Server/Utils/Workspace/WorkspaceBase.ts +6 -0
- package/Tests/App/Dashboard/DangerZone.test.tsx +334 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +539 -0
- package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +678 -0
- package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +706 -0
- package/Tests/App/Dashboard/DashboardVariablesModal.test.tsx +508 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +470 -0
- package/Tests/App/StatusPage/StatusPageDetailPagesNotFound.test.tsx +308 -0
- package/Tests/Models/DatabaseModels/DeletedProjectModel.test.ts +251 -0
- package/Tests/Models/DatabaseModels/SavedViewJSONColumnTuples.test.ts +115 -0
- package/Tests/Server/API/FileAPIAccessControl.test.ts +316 -0
- package/Tests/Server/API/ProjectAPI.test.ts +299 -1
- package/Tests/Server/API/ProjectAPIAdjustBalance.test.ts +459 -0
- package/Tests/Server/API/ProjectAPIAdjustBalanceBillingDisabled.test.ts +177 -0
- package/Tests/Server/Services/DatabaseServiceDeletionReason.test.ts +123 -0
- package/Tests/Server/Services/DeletedProjectService.test.ts +415 -0
- package/Tests/Server/Services/DeletedProjectServiceSelfHosted.test.ts +70 -0
- package/Tests/Server/Services/DomainSubdomainHooks.test.ts +94 -0
- package/Tests/Server/Services/FileIsPublicBooleanMigration.test.ts +244 -0
- package/Tests/Server/Services/FileServiceMimeType.test.ts +89 -0
- package/Tests/Server/Services/MonitorServiceDependencyValidation.test.ts +702 -0
- package/Tests/Server/Services/ProjectServiceAdjustBalance.test.ts +615 -0
- package/Tests/Server/Services/ProjectServiceDeleteAudit.test.ts +406 -0
- package/Tests/Server/Services/PublishTimeImageVisibility.test.ts +450 -0
- package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +669 -0
- package/Tests/Server/Services/UserWebhookSSRF.test.ts +174 -0
- package/Tests/Server/Services/WebPushEndpointAllowlist.test.ts +133 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenRepoint.test.ts +618 -0
- package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +26 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +215 -0
- package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +742 -0
- package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +256 -0
- package/Tests/Server/Types/Workflow/Components/ModelArguments.test.ts +371 -0
- package/Tests/Server/Utils/AI/CodeAgentCommandGuard.test.ts +204 -0
- package/Tests/Server/Utils/AI/CodeAgentWriteLimits.test.ts +213 -0
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +52 -5
- package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceEgressGuard.test.ts +315 -0
- package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +3 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +17 -5
- package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +14 -1
- package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +35 -0
- package/Tests/Server/Utils/AI/StubLLMEgressGuard.ts +25 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +62 -7
- package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +69 -0
- package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +330 -0
- package/Tests/Server/Utils/GitHubCreatePullRequestWithToken.test.ts +393 -0
- package/Tests/Server/Utils/InlineImageAccessTokenSync.test.ts +202 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppression.test.ts +811 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +604 -0
- package/Tests/Server/Utils/ResponseSendFileResponse.test.ts +192 -0
- package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +406 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +194 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +1169 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +2 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +1605 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTenantResolution.test.ts +1218 -0
- package/Tests/Types/AI/AIChatMessageStatus.test.ts +79 -0
- package/Tests/Types/AI/AIInsightStatus.test.ts +40 -0
- package/Tests/Types/API/HostnameAuthorityParsing.test.ts +157 -0
- package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +27 -0
- package/Tests/Types/DataSource/DataSourceLimits.test.ts +71 -0
- package/Tests/Types/DataSource/DataSourceType.test.ts +181 -0
- package/Tests/Types/DomainSubdomainValidation.test.ts +90 -0
- package/Tests/Types/JSONFunctions.test.ts +252 -1
- package/Tests/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.test.ts +61 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.test.ts +62 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.test.ts +68 -0
- package/Tests/Types/Monitor/SnmpMonitor/SnmpVersion.test.ts +51 -0
- package/Tests/UI/Components/404.test.tsx +1 -1
- package/Tests/UI/Components/Alert.test.tsx +1 -1
- package/Tests/UI/Components/Badge.test.tsx +1 -1
- package/Tests/UI/Components/BasicForm.test.tsx +39 -10
- package/Tests/UI/Components/Button.test.tsx +1 -1
- package/Tests/UI/Components/Card.test.tsx +1 -1
- package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +1 -1
- package/Tests/UI/Components/ColorViewer.test.tsx +1 -1
- package/Tests/UI/Components/ComponentsModal.test.tsx +7 -1
- package/Tests/UI/Components/DictionaryOfStrings.test.tsx +1 -1
- package/Tests/UI/Components/Dropdown.test.tsx +1 -1
- package/Tests/UI/Components/FilePicker.test.tsx +1 -1
- package/Tests/UI/Components/HiddenText.test.tsx +1 -1
- package/Tests/UI/Components/Input.test.tsx +1 -1
- package/Tests/UI/Components/Loader.test.tsx +1 -1
- package/Tests/UI/Components/LogTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/MasterPage.test.tsx +1 -1
- package/Tests/UI/Components/ModalPortalDismissal.test.tsx +489 -0
- package/Tests/UI/Components/ModelDelete.test.tsx +214 -0
- package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +1 -1
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1 -1
- package/Tests/UI/Components/NavBar.test.tsx +1 -1
- package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +1 -1
- package/Tests/UI/Components/Pagination.test.tsx +1 -1
- package/Tests/UI/Components/Pill.test.tsx +1 -1
- package/Tests/UI/Components/Probe.test.tsx +1 -1
- package/Tests/UI/Components/ProgressBar.test.tsx +1 -1
- package/Tests/UI/Components/RadioButtons.test.tsx +1 -1
- package/Tests/UI/Components/SideMenuItem.test.tsx +1 -1
- package/Tests/UI/Components/SideOver.test.tsx +500 -6
- package/Tests/UI/Components/Tabs.test.tsx +1 -1
- package/Tests/UI/Components/TelemetrySearchBar.test.tsx +1 -1
- package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +1 -1
- package/Tests/UI/Components/TextArea.test.tsx +1 -1
- package/Tests/UI/Components/Toast.test.tsx +1 -1
- package/Tests/UI/Components/Toggle.test.tsx +1 -1
- package/Tests/UI/Components/TopSection.test.tsx +1 -1
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayScrubber.test.tsx +1 -1
- package/Tests/UI/Rum/ReplayStage.test.tsx +1 -1
- package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +1 -1
- package/Tests/UI/Utils/LocalStorageArrayRoundTrip.test.ts +72 -0
- package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +19 -2
- package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +44 -0
- package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +288 -5
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +42 -0
- package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +27 -0
- package/Tests/Utils/LegacySerializedArray.test.ts +139 -0
- package/Tests/Utils/Monitor/MonitorDependencyRule.test.ts +190 -0
- package/Tests/Utils/Realtime.test.ts +78 -0
- package/Tests/Utils/Telemetry/SavedViewFilters.test.ts +246 -0
- package/Tests/__mocks__/i18next-browser-languagedetector.js +21 -0
- package/Types/AI/FixPullRequestCiStatus.ts +1 -1
- package/Types/AI/FixVerificationStatus.ts +2 -2
- package/Types/API/Hostname.ts +92 -4
- package/Types/API/URL.ts +43 -25
- package/Types/Billing/BalanceAdjustmentType.ts +14 -0
- package/Types/Billing/ProjectBalanceType.ts +13 -0
- package/Types/Domain.ts +26 -0
- package/Types/File/MimeType.ts +11 -0
- package/Types/JSONFunctions.ts +15 -0
- package/Types/Telemetry/TelemetrySavedViewState.ts +9 -1
- package/Types/Workflow/Components/BaseModel.ts +92 -28
- package/Typings/Index.d.ts +12 -0
- package/UI/Components/GanttChart/ChartContainer.tsx +4 -3
- package/UI/Components/Modal/ConfirmModal.tsx +10 -5
- package/UI/Components/Modal/Modal.tsx +27 -47
- package/UI/Components/ModelDelete/ModelDelete.tsx +23 -6
- package/UI/Components/SideOver/SideOver.tsx +195 -68
- package/UI/Utils/PageScrollLock.ts +66 -0
- package/Utils/Dashboard/HtmlWidgetDocument.ts +4 -2
- package/Utils/Dashboard/VariableInterpolation.ts +19 -1
- package/Utils/LegacySerializedArray.ts +60 -0
- package/Utils/Monitor/MonitorDependencyRule.ts +88 -0
- package/Utils/Telemetry/SavedViewFilters.ts +88 -0
- package/build/dist/Models/DatabaseModels/AIInsight.js +1 -1
- package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js +2 -3
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DeletedProject.js +640 -0
- package/build/dist/Models/DatabaseModels/DeletedProject.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +106 -0
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +3 -3
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/FileAPI.js +14 -2
- package/build/dist/Server/API/FileAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +6 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectAPI.js +157 -4
- package/build/dist/Server/API/ProjectAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +27 -3
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js +30 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js +20 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AIAgentService.js +17 -0
- package/build/dist/Server/Services/AIAgentService.js.map +1 -1
- package/build/dist/Server/Services/DashboardDomainService.js +55 -18
- package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +1 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DeletedProjectService.js +124 -0
- package/build/dist/Server/Services/DeletedProjectService.js.map +1 -0
- package/build/dist/Server/Services/FileService.js +52 -0
- package/build/dist/Server/Services/FileService.js.map +1 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js +10 -1
- package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +232 -0
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ProbeService.js +17 -0
- package/build/dist/Server/Services/ProbeService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +228 -6
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/PushNotificationService.js +56 -0
- package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +10 -1
- package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageAnnouncementService.js +54 -0
- package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageDomainService.js +55 -18
- package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +97 -6
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js +1 -0
- package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
- package/build/dist/Server/Services/UserWebhookService.js +31 -87
- package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +65 -0
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +23 -0
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Types/Domain.js +37 -0
- package/build/dist/Server/Types/Domain.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js +2 -1
- package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js +35 -2
- package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +15 -11
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +2 -3
- package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js +21 -10
- package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js +18 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js +43 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +116 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +7 -0
- package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js +24 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js +27 -13
- package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js +14 -6
- package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js +42 -0
- package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js.map +1 -0
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +15 -6
- package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +10 -2
- package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
- package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +141 -0
- package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
- package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +6 -6
- package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +39 -5
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/EgressGuard.js +94 -10
- package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
- package/build/dist/Server/Utils/DataSource/HttpFetch.js +1 -19
- package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
- package/build/dist/Server/Utils/Execute.js +2 -2
- package/build/dist/Server/Utils/Execute.js.map +1 -1
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js +13 -0
- package/build/dist/Server/Utils/InlineImageAccessTokenSync.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +43 -12
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +44 -24
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js +158 -0
- package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +50 -30
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +32 -0
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Response.js +112 -5
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/SSRFProtection.js +219 -53
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +7 -0
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/VM/VMRunner.js +73 -1
- package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +445 -43
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +18 -1
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
- package/build/dist/Types/AI/FixPullRequestCiStatus.js +1 -1
- package/build/dist/Types/AI/FixVerificationStatus.js +2 -2
- package/build/dist/Types/API/Hostname.js +73 -4
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/URL.js +42 -24
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/BalanceAdjustmentType.js +15 -0
- package/build/dist/Types/Billing/BalanceAdjustmentType.js.map +1 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js +14 -0
- package/build/dist/Types/Billing/ProjectBalanceType.js.map +1 -0
- package/build/dist/Types/Domain.js +22 -0
- package/build/dist/Types/Domain.js.map +1 -1
- package/build/dist/Types/File/MimeType.js +11 -0
- package/build/dist/Types/File/MimeType.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +14 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/Workflow/Components/BaseModel.js +83 -28
- package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
- package/build/dist/UI/Components/GanttChart/ChartContainer.js +4 -3
- package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +1 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js +3 -1
- package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
- package/build/dist/UI/Components/Modal/Modal.js +24 -34
- package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js +11 -6
- package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
- package/build/dist/UI/Components/SideOver/SideOver.js +105 -30
- package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
- package/build/dist/UI/Utils/PageScrollLock.js +52 -0
- package/build/dist/UI/Utils/PageScrollLock.js.map +1 -0
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +4 -2
- package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js +19 -1
- package/build/dist/Utils/Dashboard/VariableInterpolation.js.map +1 -1
- package/build/dist/Utils/LegacySerializedArray.js +51 -0
- package/build/dist/Utils/LegacySerializedArray.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js +47 -0
- package/build/dist/Utils/Monitor/MonitorDependencyRule.js.map +1 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js +52 -0
- package/build/dist/Utils/Telemetry/SavedViewFilters.js.map +1 -0
- package/jest.config.json +3 -0
- package/package.json +1 -1
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PasswordHash fails to COMPILE under ts-jest (TS 5.9 + @types/node Buffer
|
|
3
|
+
* mismatch) and DatabaseService (which every concrete service, including
|
|
4
|
+
* MonitorService, extends) imports it. Nothing password-related is under
|
|
5
|
+
* test here, so the module is replaced WITH A FACTORY — an automock would
|
|
6
|
+
* still require (and type-check) the real file.
|
|
7
|
+
*/
|
|
8
|
+
jest.mock("../../../../Server/Utils/PasswordHash", () => {
|
|
9
|
+
return {
|
|
10
|
+
__esModule: true,
|
|
11
|
+
default: {
|
|
12
|
+
hash: jest.fn(),
|
|
13
|
+
verify: jest.fn(),
|
|
14
|
+
generateSalt: jest.fn(),
|
|
15
|
+
needsUpgrade: jest.fn(),
|
|
16
|
+
applyPepper: jest.fn(),
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
import MonitorDependencySuppression, {
|
|
22
|
+
DependencySuppressionResult,
|
|
23
|
+
ParentMonitorStatusRef,
|
|
24
|
+
SuppressingParent,
|
|
25
|
+
} from "../../../../Server/Utils/Monitor/MonitorDependencySuppression";
|
|
26
|
+
import MonitorService from "../../../../Server/Services/MonitorService";
|
|
27
|
+
import logger from "../../../../Server/Utils/Logger";
|
|
28
|
+
import Monitor from "../../../../Models/DatabaseModels/Monitor";
|
|
29
|
+
import MonitorStatus from "../../../../Models/DatabaseModels/MonitorStatus";
|
|
30
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
31
|
+
import MonitorDependencyRule from "../../../../Utils/Monitor/MonitorDependencyRule";
|
|
32
|
+
import { LIMIT_PER_PROJECT } from "../../../../Types/Database/LimitMax";
|
|
33
|
+
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Alert-dependency suppression: when a monitor declares dependsOnMonitors
|
|
37
|
+
* and a parent is currently in a suppressing status, alert/incident
|
|
38
|
+
* creation for the child is skipped for the evaluation. These tests pin
|
|
39
|
+
* the pure decision step (getSuppressingParents), the human-readable
|
|
40
|
+
* reason string shared by the alert and incident skip events, and the
|
|
41
|
+
* query orchestration (getDependencySuppression) — including its
|
|
42
|
+
* zero-query contract for monitors with no dependencies, which sits on
|
|
43
|
+
* the hottest Postgres path in the product.
|
|
44
|
+
*/
|
|
45
|
+
|
|
46
|
+
// The house workaround for @jest/globals vs @types/jest spy typing.
|
|
47
|
+
type SpyLike = {
|
|
48
|
+
mock: { calls: Array<Array<unknown>> };
|
|
49
|
+
mockRestore: () => void;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const PARENT_A_ID: string = "11111111-1111-4111-8111-111111111111";
|
|
53
|
+
const PARENT_B_ID: string = "22222222-2222-4222-8222-222222222222";
|
|
54
|
+
const PARENT_C_ID: string = "33333333-3333-4333-8333-333333333333";
|
|
55
|
+
const CHILD_ID: string = "dddddddd-dddd-4ddd-8ddd-dddddddddddd";
|
|
56
|
+
const STATUS_OFFLINE_ID: string = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
|
|
57
|
+
const STATUS_DEGRADED_ID: string = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
|
|
58
|
+
const STATUS_OPERATIONAL_ID: string = "cccccccc-cccc-4ccc-8ccc-cccccccccccc";
|
|
59
|
+
|
|
60
|
+
type MakeParentRef = (overrides: {
|
|
61
|
+
monitorId?: string;
|
|
62
|
+
monitorName?: string;
|
|
63
|
+
statusId?: string | undefined;
|
|
64
|
+
statusName?: string | undefined;
|
|
65
|
+
isOfflineState?: boolean;
|
|
66
|
+
}) => ParentMonitorStatusRef;
|
|
67
|
+
|
|
68
|
+
const makeParentRef: MakeParentRef = (overrides: {
|
|
69
|
+
monitorId?: string;
|
|
70
|
+
monitorName?: string;
|
|
71
|
+
statusId?: string | undefined;
|
|
72
|
+
statusName?: string | undefined;
|
|
73
|
+
isOfflineState?: boolean;
|
|
74
|
+
}): ParentMonitorStatusRef => {
|
|
75
|
+
return {
|
|
76
|
+
monitorId: overrides.monitorId || PARENT_A_ID,
|
|
77
|
+
monitorName: overrides.monitorName || "Router",
|
|
78
|
+
statusId: overrides.statusId,
|
|
79
|
+
statusName: overrides.statusName,
|
|
80
|
+
isOfflineState: overrides.isOfflineState || false,
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type MakeStatus = (input: {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
isOfflineState: boolean;
|
|
88
|
+
}) => MonitorStatus;
|
|
89
|
+
|
|
90
|
+
const makeStatus: MakeStatus = (input: {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
isOfflineState: boolean;
|
|
94
|
+
}): MonitorStatus => {
|
|
95
|
+
const status: MonitorStatus = new MonitorStatus();
|
|
96
|
+
status.id = new ObjectID(input.id);
|
|
97
|
+
status.name = input.name;
|
|
98
|
+
status.isOfflineState = input.isOfflineState;
|
|
99
|
+
return status;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
type MakeParentRow = (input: {
|
|
103
|
+
id: string;
|
|
104
|
+
name?: string | undefined;
|
|
105
|
+
currentMonitorStatus?: MonitorStatus | undefined;
|
|
106
|
+
// The parent's OWN parent ids, as the mutual-cycle guard reads them.
|
|
107
|
+
dependsOnMonitorIds?: Array<string> | undefined;
|
|
108
|
+
}) => Monitor;
|
|
109
|
+
|
|
110
|
+
const makeParentRow: MakeParentRow = (input: {
|
|
111
|
+
id: string;
|
|
112
|
+
name?: string | undefined;
|
|
113
|
+
currentMonitorStatus?: MonitorStatus | undefined;
|
|
114
|
+
dependsOnMonitorIds?: Array<string> | undefined;
|
|
115
|
+
}): Monitor => {
|
|
116
|
+
const parent: Monitor = new Monitor();
|
|
117
|
+
parent.id = new ObjectID(input.id);
|
|
118
|
+
if (input.name !== undefined) {
|
|
119
|
+
parent.name = input.name;
|
|
120
|
+
}
|
|
121
|
+
if (input.currentMonitorStatus !== undefined) {
|
|
122
|
+
parent.currentMonitorStatus = input.currentMonitorStatus;
|
|
123
|
+
}
|
|
124
|
+
if (input.dependsOnMonitorIds !== undefined) {
|
|
125
|
+
parent.dependsOnMonitors = input.dependsOnMonitorIds.map(
|
|
126
|
+
(grandParentId: string) => {
|
|
127
|
+
const stub: Monitor = new Monitor();
|
|
128
|
+
stub.id = new ObjectID(grandParentId);
|
|
129
|
+
return stub;
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return parent;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// A bare id-only reference, the shape dependsOnMonitors rows arrive in.
|
|
137
|
+
type MakeParentStub = (id: string) => Monitor;
|
|
138
|
+
|
|
139
|
+
const makeParentStub: MakeParentStub = (id: string): Monitor => {
|
|
140
|
+
const stub: Monitor = new Monitor();
|
|
141
|
+
stub.id = new ObjectID(id);
|
|
142
|
+
return stub;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
describe("MonitorDependencySuppression.getSuppressingParents", () => {
|
|
146
|
+
describe("default rule (no configured statuses): offline parents suppress", () => {
|
|
147
|
+
test("a parent whose current status is flagged offline suppresses", () => {
|
|
148
|
+
const result: Array<SuppressingParent> =
|
|
149
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
150
|
+
parents: [
|
|
151
|
+
makeParentRef({
|
|
152
|
+
monitorId: PARENT_A_ID,
|
|
153
|
+
monitorName: "Router",
|
|
154
|
+
statusId: STATUS_OFFLINE_ID,
|
|
155
|
+
statusName: "Offline",
|
|
156
|
+
isOfflineState: true,
|
|
157
|
+
}),
|
|
158
|
+
],
|
|
159
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
expect(result).toEqual([
|
|
163
|
+
{
|
|
164
|
+
monitorId: PARENT_A_ID,
|
|
165
|
+
monitorName: "Router",
|
|
166
|
+
statusName: "Offline",
|
|
167
|
+
},
|
|
168
|
+
]);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
test("a parent in a non-offline status does not suppress", () => {
|
|
172
|
+
const result: Array<SuppressingParent> =
|
|
173
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
174
|
+
parents: [
|
|
175
|
+
makeParentRef({
|
|
176
|
+
statusId: STATUS_OPERATIONAL_ID,
|
|
177
|
+
statusName: "Operational",
|
|
178
|
+
isOfflineState: false,
|
|
179
|
+
}),
|
|
180
|
+
],
|
|
181
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
expect(result).toEqual([]);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
test("a parent with NO current status never suppresses (a never-evaluated parent must not silence its children)", () => {
|
|
188
|
+
const result: Array<SuppressingParent> =
|
|
189
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
190
|
+
parents: [
|
|
191
|
+
makeParentRef({
|
|
192
|
+
statusId: undefined,
|
|
193
|
+
statusName: undefined,
|
|
194
|
+
isOfflineState: false,
|
|
195
|
+
}),
|
|
196
|
+
],
|
|
197
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
expect(result).toEqual([]);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("a suppressing parent with no status name falls back to 'Offline'", () => {
|
|
204
|
+
const result: Array<SuppressingParent> =
|
|
205
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
206
|
+
parents: [
|
|
207
|
+
makeParentRef({
|
|
208
|
+
statusId: STATUS_OFFLINE_ID,
|
|
209
|
+
statusName: undefined,
|
|
210
|
+
isOfflineState: true,
|
|
211
|
+
}),
|
|
212
|
+
],
|
|
213
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
expect(result[0]?.statusName).toBe("Offline");
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("configured-status rule takes full precedence over the offline flag", () => {
|
|
221
|
+
test("a parent in a configured status suppresses even when the status is not offline (degraded-state use case)", () => {
|
|
222
|
+
const result: Array<SuppressingParent> =
|
|
223
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
224
|
+
parents: [
|
|
225
|
+
makeParentRef({
|
|
226
|
+
monitorId: PARENT_A_ID,
|
|
227
|
+
monitorName: "Upstream API",
|
|
228
|
+
statusId: STATUS_DEGRADED_ID,
|
|
229
|
+
statusName: "Degraded",
|
|
230
|
+
isOfflineState: false,
|
|
231
|
+
}),
|
|
232
|
+
],
|
|
233
|
+
configuredSuppressionStatusIds: new Set<string>([STATUS_DEGRADED_ID]),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(result).toEqual([
|
|
237
|
+
{
|
|
238
|
+
monitorId: PARENT_A_ID,
|
|
239
|
+
monitorName: "Upstream API",
|
|
240
|
+
statusName: "Degraded",
|
|
241
|
+
},
|
|
242
|
+
]);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("an OFFLINE parent whose status is NOT in the configured set does not suppress", () => {
|
|
246
|
+
const result: Array<SuppressingParent> =
|
|
247
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
248
|
+
parents: [
|
|
249
|
+
makeParentRef({
|
|
250
|
+
statusId: STATUS_OFFLINE_ID,
|
|
251
|
+
statusName: "Offline",
|
|
252
|
+
isOfflineState: true,
|
|
253
|
+
}),
|
|
254
|
+
],
|
|
255
|
+
configuredSuppressionStatusIds: new Set<string>([STATUS_DEGRADED_ID]),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(result).toEqual([]);
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
test("a parent with no current status does not suppress under a configured list either", () => {
|
|
262
|
+
const result: Array<SuppressingParent> =
|
|
263
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
264
|
+
parents: [
|
|
265
|
+
makeParentRef({
|
|
266
|
+
statusId: undefined,
|
|
267
|
+
statusName: undefined,
|
|
268
|
+
isOfflineState: false,
|
|
269
|
+
}),
|
|
270
|
+
],
|
|
271
|
+
configuredSuppressionStatusIds: new Set<string>([STATUS_DEGRADED_ID]),
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
expect(result).toEqual([]);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
test("multiple parents: every matching parent is returned, in input order", () => {
|
|
279
|
+
const result: Array<SuppressingParent> =
|
|
280
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
281
|
+
parents: [
|
|
282
|
+
makeParentRef({
|
|
283
|
+
monitorId: PARENT_A_ID,
|
|
284
|
+
monitorName: "Router",
|
|
285
|
+
statusId: STATUS_OFFLINE_ID,
|
|
286
|
+
statusName: "Offline",
|
|
287
|
+
isOfflineState: true,
|
|
288
|
+
}),
|
|
289
|
+
makeParentRef({
|
|
290
|
+
monitorId: PARENT_B_ID,
|
|
291
|
+
monitorName: "Load Balancer",
|
|
292
|
+
statusId: STATUS_OPERATIONAL_ID,
|
|
293
|
+
statusName: "Operational",
|
|
294
|
+
isOfflineState: false,
|
|
295
|
+
}),
|
|
296
|
+
makeParentRef({
|
|
297
|
+
monitorId: PARENT_C_ID,
|
|
298
|
+
monitorName: "Database",
|
|
299
|
+
statusId: STATUS_OFFLINE_ID,
|
|
300
|
+
statusName: "Offline",
|
|
301
|
+
isOfflineState: true,
|
|
302
|
+
}),
|
|
303
|
+
],
|
|
304
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(result).toEqual([
|
|
308
|
+
{
|
|
309
|
+
monitorId: PARENT_A_ID,
|
|
310
|
+
monitorName: "Router",
|
|
311
|
+
statusName: "Offline",
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
monitorId: PARENT_C_ID,
|
|
315
|
+
monitorName: "Database",
|
|
316
|
+
statusName: "Offline",
|
|
317
|
+
},
|
|
318
|
+
]);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test("no parents yields no suppression", () => {
|
|
322
|
+
expect(
|
|
323
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
324
|
+
parents: [],
|
|
325
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
326
|
+
}),
|
|
327
|
+
).toEqual([]);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
describe("MonitorDependencySuppression.buildSuppressionReason", () => {
|
|
332
|
+
test("single parent: singular phrasing with quoted name and status", () => {
|
|
333
|
+
expect(
|
|
334
|
+
MonitorDependencySuppression.buildSuppressionReason([
|
|
335
|
+
{
|
|
336
|
+
monitorId: PARENT_A_ID,
|
|
337
|
+
monitorName: "Router",
|
|
338
|
+
statusName: "Offline",
|
|
339
|
+
},
|
|
340
|
+
]),
|
|
341
|
+
).toBe('parent monitor "Router" is Offline');
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("multiple parents: plural phrasing, comma-joined, in order", () => {
|
|
345
|
+
expect(
|
|
346
|
+
MonitorDependencySuppression.buildSuppressionReason([
|
|
347
|
+
{
|
|
348
|
+
monitorId: PARENT_A_ID,
|
|
349
|
+
monitorName: "Router",
|
|
350
|
+
statusName: "Offline",
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
monitorId: PARENT_B_ID,
|
|
354
|
+
monitorName: "Upstream API",
|
|
355
|
+
statusName: "Degraded",
|
|
356
|
+
},
|
|
357
|
+
]),
|
|
358
|
+
).toBe('parent monitors "Router" is Offline, "Upstream API" is Degraded');
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
describe("MonitorDependencySuppression.getDependencySuppression", () => {
|
|
363
|
+
afterEach(() => {
|
|
364
|
+
jest.restoreAllMocks();
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
function spyOnFindBy(rows: Array<Monitor>): SpyLike {
|
|
368
|
+
return jest
|
|
369
|
+
.spyOn(MonitorService, "findBy")
|
|
370
|
+
.mockResolvedValue(rows as never) as unknown as SpyLike;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
describe("zero-query contract for monitors without dependencies", () => {
|
|
374
|
+
test("dependsOnMonitors undefined: not suppressed and findBy is NEVER called", async () => {
|
|
375
|
+
const findBySpy: SpyLike = spyOnFindBy([]);
|
|
376
|
+
|
|
377
|
+
const monitor: Monitor = new Monitor();
|
|
378
|
+
monitor.id = ObjectID.generate();
|
|
379
|
+
|
|
380
|
+
const result: DependencySuppressionResult =
|
|
381
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
382
|
+
monitor,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
386
|
+
expect(findBySpy.mock.calls.length).toBe(0);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test("dependsOnMonitors empty array: not suppressed and findBy is NEVER called", async () => {
|
|
390
|
+
const findBySpy: SpyLike = spyOnFindBy([]);
|
|
391
|
+
|
|
392
|
+
const monitor: Monitor = new Monitor();
|
|
393
|
+
monitor.id = ObjectID.generate();
|
|
394
|
+
monitor.dependsOnMonitors = [];
|
|
395
|
+
|
|
396
|
+
const result: DependencySuppressionResult =
|
|
397
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
398
|
+
monitor,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
402
|
+
expect(findBySpy.mock.calls.length).toBe(0);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
test("dependency entries without any id are dropped and cause no query", async () => {
|
|
406
|
+
const findBySpy: SpyLike = spyOnFindBy([]);
|
|
407
|
+
|
|
408
|
+
const monitor: Monitor = new Monitor();
|
|
409
|
+
monitor.id = ObjectID.generate();
|
|
410
|
+
monitor.dependsOnMonitors = [new Monitor()];
|
|
411
|
+
|
|
412
|
+
const result: DependencySuppressionResult =
|
|
413
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
414
|
+
monitor,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
418
|
+
expect(findBySpy.mock.calls.length).toBe(0);
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test("monitor with parents: exactly one findBy, selecting the parents' current status", async () => {
|
|
423
|
+
const findBySpy: SpyLike = spyOnFindBy([
|
|
424
|
+
makeParentRow({
|
|
425
|
+
id: PARENT_A_ID,
|
|
426
|
+
name: "Router",
|
|
427
|
+
currentMonitorStatus: makeStatus({
|
|
428
|
+
id: STATUS_OPERATIONAL_ID,
|
|
429
|
+
name: "Operational",
|
|
430
|
+
isOfflineState: false,
|
|
431
|
+
}),
|
|
432
|
+
}),
|
|
433
|
+
]);
|
|
434
|
+
|
|
435
|
+
const monitor: Monitor = new Monitor();
|
|
436
|
+
monitor.id = ObjectID.generate();
|
|
437
|
+
monitor.dependsOnMonitors = [makeParentStub(PARENT_A_ID)];
|
|
438
|
+
|
|
439
|
+
const result: DependencySuppressionResult =
|
|
440
|
+
await MonitorDependencySuppression.getDependencySuppression({ monitor });
|
|
441
|
+
|
|
442
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
443
|
+
expect(findBySpy.mock.calls.length).toBe(1);
|
|
444
|
+
|
|
445
|
+
/*
|
|
446
|
+
* The query arg is asserted loosely (QueryHelper.any wraps the ids) but
|
|
447
|
+
* the select is the exact per-parent status shape the pure step needs.
|
|
448
|
+
*/
|
|
449
|
+
const callArg: {
|
|
450
|
+
select: Record<string, unknown>;
|
|
451
|
+
limit: number;
|
|
452
|
+
skip: number;
|
|
453
|
+
props: { isRoot: boolean };
|
|
454
|
+
} = findBySpy.mock.calls[0]![0] as {
|
|
455
|
+
select: Record<string, unknown>;
|
|
456
|
+
limit: number;
|
|
457
|
+
skip: number;
|
|
458
|
+
props: { isRoot: boolean };
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
expect(callArg.select).toEqual({
|
|
462
|
+
_id: true,
|
|
463
|
+
name: true,
|
|
464
|
+
currentMonitorStatus: {
|
|
465
|
+
_id: true,
|
|
466
|
+
name: true,
|
|
467
|
+
isOfflineState: true,
|
|
468
|
+
},
|
|
469
|
+
/*
|
|
470
|
+
* The parents' own parent ids ride along for the runtime
|
|
471
|
+
* mutual-cycle guard, so the guard costs no extra query.
|
|
472
|
+
*/
|
|
473
|
+
dependsOnMonitors: {
|
|
474
|
+
_id: true,
|
|
475
|
+
},
|
|
476
|
+
});
|
|
477
|
+
expect(callArg.limit).toBe(LIMIT_PER_PROJECT);
|
|
478
|
+
expect(callArg.skip).toBe(0);
|
|
479
|
+
expect(callArg.props).toEqual({ isRoot: true });
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
test("an offline parent suppresses; siblings in healthy or unknown status do not", async () => {
|
|
483
|
+
spyOnFindBy([
|
|
484
|
+
makeParentRow({
|
|
485
|
+
id: PARENT_A_ID,
|
|
486
|
+
name: "Router",
|
|
487
|
+
currentMonitorStatus: makeStatus({
|
|
488
|
+
id: STATUS_OFFLINE_ID,
|
|
489
|
+
name: "Offline",
|
|
490
|
+
isOfflineState: true,
|
|
491
|
+
}),
|
|
492
|
+
}),
|
|
493
|
+
makeParentRow({
|
|
494
|
+
id: PARENT_B_ID,
|
|
495
|
+
name: "Load Balancer",
|
|
496
|
+
currentMonitorStatus: makeStatus({
|
|
497
|
+
id: STATUS_OPERATIONAL_ID,
|
|
498
|
+
name: "Operational",
|
|
499
|
+
isOfflineState: false,
|
|
500
|
+
}),
|
|
501
|
+
}),
|
|
502
|
+
// Never evaluated: no current status at all.
|
|
503
|
+
makeParentRow({ id: PARENT_C_ID, name: "Database" }),
|
|
504
|
+
]);
|
|
505
|
+
|
|
506
|
+
const monitor: Monitor = new Monitor();
|
|
507
|
+
monitor.id = ObjectID.generate();
|
|
508
|
+
monitor.dependsOnMonitors = [
|
|
509
|
+
makeParentStub(PARENT_A_ID),
|
|
510
|
+
makeParentStub(PARENT_B_ID),
|
|
511
|
+
makeParentStub(PARENT_C_ID),
|
|
512
|
+
];
|
|
513
|
+
|
|
514
|
+
const result: DependencySuppressionResult =
|
|
515
|
+
await MonitorDependencySuppression.getDependencySuppression({ monitor });
|
|
516
|
+
|
|
517
|
+
expect(result.isSuppressed).toBe(true);
|
|
518
|
+
expect(result.suppressingParents).toEqual([
|
|
519
|
+
{
|
|
520
|
+
monitorId: PARENT_A_ID,
|
|
521
|
+
monitorName: "Router",
|
|
522
|
+
statusName: "Offline",
|
|
523
|
+
},
|
|
524
|
+
]);
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
test("configured suppression statuses are respected end-to-end: degraded (configured) suppresses, offline (unconfigured) does not", async () => {
|
|
528
|
+
spyOnFindBy([
|
|
529
|
+
makeParentRow({
|
|
530
|
+
id: PARENT_A_ID,
|
|
531
|
+
name: "Upstream API",
|
|
532
|
+
currentMonitorStatus: makeStatus({
|
|
533
|
+
id: STATUS_DEGRADED_ID,
|
|
534
|
+
name: "Degraded",
|
|
535
|
+
isOfflineState: false,
|
|
536
|
+
}),
|
|
537
|
+
}),
|
|
538
|
+
makeParentRow({
|
|
539
|
+
id: PARENT_B_ID,
|
|
540
|
+
name: "Router",
|
|
541
|
+
currentMonitorStatus: makeStatus({
|
|
542
|
+
id: STATUS_OFFLINE_ID,
|
|
543
|
+
name: "Offline",
|
|
544
|
+
isOfflineState: true,
|
|
545
|
+
}),
|
|
546
|
+
}),
|
|
547
|
+
]);
|
|
548
|
+
|
|
549
|
+
const monitor: Monitor = new Monitor();
|
|
550
|
+
monitor.id = ObjectID.generate();
|
|
551
|
+
monitor.dependsOnMonitors = [
|
|
552
|
+
makeParentStub(PARENT_A_ID),
|
|
553
|
+
makeParentStub(PARENT_B_ID),
|
|
554
|
+
];
|
|
555
|
+
monitor.suppressAlertsWhenParentMonitorStatuses = [
|
|
556
|
+
makeStatus({
|
|
557
|
+
id: STATUS_DEGRADED_ID,
|
|
558
|
+
name: "Degraded",
|
|
559
|
+
isOfflineState: false,
|
|
560
|
+
}),
|
|
561
|
+
];
|
|
562
|
+
|
|
563
|
+
const result: DependencySuppressionResult =
|
|
564
|
+
await MonitorDependencySuppression.getDependencySuppression({ monitor });
|
|
565
|
+
|
|
566
|
+
expect(result.isSuppressed).toBe(true);
|
|
567
|
+
expect(result.suppressingParents).toEqual([
|
|
568
|
+
{
|
|
569
|
+
monitorId: PARENT_A_ID,
|
|
570
|
+
monitorName: "Upstream API",
|
|
571
|
+
statusName: "Degraded",
|
|
572
|
+
},
|
|
573
|
+
]);
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
test("a nameless suppressing parent is reported as 'Unnamed monitor'", async () => {
|
|
577
|
+
spyOnFindBy([
|
|
578
|
+
makeParentRow({
|
|
579
|
+
id: PARENT_A_ID,
|
|
580
|
+
currentMonitorStatus: makeStatus({
|
|
581
|
+
id: STATUS_OFFLINE_ID,
|
|
582
|
+
name: "Offline",
|
|
583
|
+
isOfflineState: true,
|
|
584
|
+
}),
|
|
585
|
+
}),
|
|
586
|
+
]);
|
|
587
|
+
|
|
588
|
+
const monitor: Monitor = new Monitor();
|
|
589
|
+
monitor.id = ObjectID.generate();
|
|
590
|
+
monitor.dependsOnMonitors = [makeParentStub(PARENT_A_ID)];
|
|
591
|
+
|
|
592
|
+
const result: DependencySuppressionResult =
|
|
593
|
+
await MonitorDependencySuppression.getDependencySuppression({ monitor });
|
|
594
|
+
|
|
595
|
+
expect(result.suppressingParents).toEqual([
|
|
596
|
+
{
|
|
597
|
+
monitorId: PARENT_A_ID,
|
|
598
|
+
monitorName: "Unnamed monitor",
|
|
599
|
+
statusName: "Offline",
|
|
600
|
+
},
|
|
601
|
+
]);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
describe("self-parent guard: a persisted self-edge must never suppress the monitor's own alerts", () => {
|
|
605
|
+
test("a monitor whose only dependency entry is ITSELF causes no query and no suppression", async () => {
|
|
606
|
+
const findBySpy: SpyLike = spyOnFindBy([]);
|
|
607
|
+
|
|
608
|
+
const monitor: Monitor = new Monitor();
|
|
609
|
+
monitor.id = new ObjectID(CHILD_ID);
|
|
610
|
+
monitor.dependsOnMonitors = [makeParentStub(CHILD_ID)];
|
|
611
|
+
|
|
612
|
+
const result: DependencySuppressionResult =
|
|
613
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
614
|
+
monitor,
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
618
|
+
expect(findBySpy.mock.calls.length).toBe(0);
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
test("an UPPERCASE self-edge is dropped too (uuids compare case-insensitively)", async () => {
|
|
622
|
+
const findBySpy: SpyLike = spyOnFindBy([]);
|
|
623
|
+
|
|
624
|
+
const monitor: Monitor = new Monitor();
|
|
625
|
+
monitor.id = new ObjectID(CHILD_ID);
|
|
626
|
+
monitor.dependsOnMonitors = [makeParentStub(CHILD_ID.toUpperCase())];
|
|
627
|
+
|
|
628
|
+
const result: DependencySuppressionResult =
|
|
629
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
630
|
+
monitor,
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
634
|
+
expect(findBySpy.mock.calls.length).toBe(0);
|
|
635
|
+
});
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
describe("runtime mutual-cycle guard: a raced-in cycle fails open (pages) rather than silently suppressing", () => {
|
|
639
|
+
function spyOnLoggerWarn(): SpyLike {
|
|
640
|
+
return jest
|
|
641
|
+
.spyOn(logger, "warn")
|
|
642
|
+
.mockImplementation((): void => {}) as unknown as SpyLike;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
test("an offline parent that itself depends on this monitor is ignored and a warning is logged", async () => {
|
|
646
|
+
const warnSpy: SpyLike = spyOnLoggerWarn();
|
|
647
|
+
|
|
648
|
+
spyOnFindBy([
|
|
649
|
+
makeParentRow({
|
|
650
|
+
id: PARENT_A_ID,
|
|
651
|
+
name: "Router",
|
|
652
|
+
currentMonitorStatus: makeStatus({
|
|
653
|
+
id: STATUS_OFFLINE_ID,
|
|
654
|
+
name: "Offline",
|
|
655
|
+
isOfflineState: true,
|
|
656
|
+
}),
|
|
657
|
+
// The parent points back at the monitor: a committed cycle.
|
|
658
|
+
dependsOnMonitorIds: [CHILD_ID],
|
|
659
|
+
}),
|
|
660
|
+
]);
|
|
661
|
+
|
|
662
|
+
const monitor: Monitor = new Monitor();
|
|
663
|
+
monitor.id = new ObjectID(CHILD_ID);
|
|
664
|
+
monitor.dependsOnMonitors = [makeParentStub(PARENT_A_ID)];
|
|
665
|
+
|
|
666
|
+
const result: DependencySuppressionResult =
|
|
667
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
668
|
+
monitor,
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
672
|
+
expect(warnSpy.mock.calls.length).toBe(1);
|
|
673
|
+
expect(String(warnSpy.mock.calls[0]![0])).toContain("cycle");
|
|
674
|
+
expect(String(warnSpy.mock.calls[0]![0])).toContain(PARENT_A_ID);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
test("the guard is case-insensitive: the parent's back-edge may carry an UPPERCASE id", async () => {
|
|
678
|
+
const warnSpy: SpyLike = spyOnLoggerWarn();
|
|
679
|
+
|
|
680
|
+
spyOnFindBy([
|
|
681
|
+
makeParentRow({
|
|
682
|
+
id: PARENT_A_ID,
|
|
683
|
+
name: "Router",
|
|
684
|
+
currentMonitorStatus: makeStatus({
|
|
685
|
+
id: STATUS_OFFLINE_ID,
|
|
686
|
+
name: "Offline",
|
|
687
|
+
isOfflineState: true,
|
|
688
|
+
}),
|
|
689
|
+
dependsOnMonitorIds: [CHILD_ID.toUpperCase()],
|
|
690
|
+
}),
|
|
691
|
+
]);
|
|
692
|
+
|
|
693
|
+
const monitor: Monitor = new Monitor();
|
|
694
|
+
monitor.id = new ObjectID(CHILD_ID);
|
|
695
|
+
monitor.dependsOnMonitors = [makeParentStub(PARENT_A_ID)];
|
|
696
|
+
|
|
697
|
+
const result: DependencySuppressionResult =
|
|
698
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
699
|
+
monitor,
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
expect(result).toEqual({ isSuppressed: false, suppressingParents: [] });
|
|
703
|
+
expect(warnSpy.mock.calls.length).toBe(1);
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
test("only the cycling parent is ignored: a second, non-cycling offline parent still suppresses", async () => {
|
|
707
|
+
const warnSpy: SpyLike = spyOnLoggerWarn();
|
|
708
|
+
|
|
709
|
+
spyOnFindBy([
|
|
710
|
+
// P: offline but in a mutual cycle with the monitor — ignored.
|
|
711
|
+
makeParentRow({
|
|
712
|
+
id: PARENT_A_ID,
|
|
713
|
+
name: "Router",
|
|
714
|
+
currentMonitorStatus: makeStatus({
|
|
715
|
+
id: STATUS_OFFLINE_ID,
|
|
716
|
+
name: "Offline",
|
|
717
|
+
isOfflineState: true,
|
|
718
|
+
}),
|
|
719
|
+
dependsOnMonitorIds: [CHILD_ID],
|
|
720
|
+
}),
|
|
721
|
+
// Q: offline with no back-edge — suppresses as usual.
|
|
722
|
+
makeParentRow({
|
|
723
|
+
id: PARENT_B_ID,
|
|
724
|
+
name: "Load Balancer",
|
|
725
|
+
currentMonitorStatus: makeStatus({
|
|
726
|
+
id: STATUS_OFFLINE_ID,
|
|
727
|
+
name: "Offline",
|
|
728
|
+
isOfflineState: true,
|
|
729
|
+
}),
|
|
730
|
+
dependsOnMonitorIds: [],
|
|
731
|
+
}),
|
|
732
|
+
]);
|
|
733
|
+
|
|
734
|
+
const monitor: Monitor = new Monitor();
|
|
735
|
+
monitor.id = new ObjectID(CHILD_ID);
|
|
736
|
+
monitor.dependsOnMonitors = [
|
|
737
|
+
makeParentStub(PARENT_A_ID),
|
|
738
|
+
makeParentStub(PARENT_B_ID),
|
|
739
|
+
];
|
|
740
|
+
|
|
741
|
+
const result: DependencySuppressionResult =
|
|
742
|
+
await MonitorDependencySuppression.getDependencySuppression({
|
|
743
|
+
monitor,
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
expect(result.isSuppressed).toBe(true);
|
|
747
|
+
expect(result.suppressingParents).toEqual([
|
|
748
|
+
{
|
|
749
|
+
monitorId: PARENT_B_ID,
|
|
750
|
+
monitorName: "Load Balancer",
|
|
751
|
+
statusName: "Offline",
|
|
752
|
+
},
|
|
753
|
+
]);
|
|
754
|
+
expect(warnSpy.mock.calls.length).toBe(1);
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
|
|
759
|
+
/*
|
|
760
|
+
* The decision now lives in Common/Utils/Monitor/MonitorDependencyRule so
|
|
761
|
+
* the dashboard can import it without the server module graph; the server
|
|
762
|
+
* statics exercised above are thin delegates. One smoke check pins that
|
|
763
|
+
* the shared module itself exports the same behavior.
|
|
764
|
+
*/
|
|
765
|
+
describe("MonitorDependencyRule (shared pure module)", () => {
|
|
766
|
+
test("getSuppressingParents and buildSuppressionReason match the server-side delegates", () => {
|
|
767
|
+
const parents: Array<ParentMonitorStatusRef> = [
|
|
768
|
+
makeParentRef({
|
|
769
|
+
monitorId: PARENT_A_ID,
|
|
770
|
+
monitorName: "Router",
|
|
771
|
+
statusId: STATUS_OFFLINE_ID,
|
|
772
|
+
statusName: "Offline",
|
|
773
|
+
isOfflineState: true,
|
|
774
|
+
}),
|
|
775
|
+
makeParentRef({
|
|
776
|
+
monitorId: PARENT_B_ID,
|
|
777
|
+
monitorName: "Load Balancer",
|
|
778
|
+
statusId: STATUS_OPERATIONAL_ID,
|
|
779
|
+
statusName: "Operational",
|
|
780
|
+
isOfflineState: false,
|
|
781
|
+
}),
|
|
782
|
+
];
|
|
783
|
+
|
|
784
|
+
const fromRule: Array<SuppressingParent> =
|
|
785
|
+
MonitorDependencyRule.getSuppressingParents({
|
|
786
|
+
parents,
|
|
787
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
expect(fromRule).toEqual(
|
|
791
|
+
MonitorDependencySuppression.getSuppressingParents({
|
|
792
|
+
parents,
|
|
793
|
+
configuredSuppressionStatusIds: new Set<string>(),
|
|
794
|
+
}),
|
|
795
|
+
);
|
|
796
|
+
expect(fromRule).toEqual([
|
|
797
|
+
{
|
|
798
|
+
monitorId: PARENT_A_ID,
|
|
799
|
+
monitorName: "Router",
|
|
800
|
+
statusName: "Offline",
|
|
801
|
+
},
|
|
802
|
+
]);
|
|
803
|
+
|
|
804
|
+
expect(MonitorDependencyRule.buildSuppressionReason(fromRule)).toBe(
|
|
805
|
+
MonitorDependencySuppression.buildSuppressionReason(fromRule),
|
|
806
|
+
);
|
|
807
|
+
expect(MonitorDependencyRule.buildSuppressionReason(fromRule)).toBe(
|
|
808
|
+
'parent monitor "Router" is Offline',
|
|
809
|
+
);
|
|
810
|
+
});
|
|
811
|
+
});
|