@oneuptime/common 13.0.8 → 14.0.1
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/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/BaseAPI.ts +26 -5
- package/Server/API/GlobalConfigAPI.ts +228 -462
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/StatusPageAPI.ts +100 -42
- package/Server/API/TeamMemberAPI.ts +10 -1
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +59 -6
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/ProjectService.ts +284 -0
- package/Server/Services/RumSessionPinService.ts +25 -6
- package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +183 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- package/build/dist/Server/API/BaseAPI.js +26 -5
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +93 -43
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +8 -1
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +48 -6
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +214 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +24 -6
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -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/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
|
@@ -14,6 +14,7 @@ import UpdateBy from "../../../Server/Types/Database/UpdateBy";
|
|
|
14
14
|
import logger from "../../../Server/Utils/Logger";
|
|
15
15
|
import URL from "../../../Types/API/URL";
|
|
16
16
|
import ObjectID from "../../../Types/ObjectID";
|
|
17
|
+
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
17
18
|
import { describe, expect, it, beforeEach, afterEach } from "@jest/globals";
|
|
18
19
|
|
|
19
20
|
/*
|
|
@@ -21,8 +22,8 @@ import { describe, expect, it, beforeEach, afterEach } from "@jest/globals";
|
|
|
21
22
|
* to notice an SLO's monitor rules went stale. The engine is covered
|
|
22
23
|
* separately; what matters here is that something actually calls it.
|
|
23
24
|
*
|
|
24
|
-
* - MonitorService, when a monitor's labels, name or description change.
|
|
25
|
-
* SLO monitor rules match on all
|
|
25
|
+
* - MonitorService, when a monitor's labels, type, name or description change.
|
|
26
|
+
* SLO monitor rules match on all four, so a rename can pull a monitor
|
|
26
27
|
* into an SLO or push it out. Keyed on the field being present rather
|
|
27
28
|
* than non-empty, because clearing every label arrives as `[]` and is
|
|
28
29
|
* exactly the edit that should detach the monitor.
|
|
@@ -129,6 +130,24 @@ describe("MonitorService.onUpdateSuccess - keeping SLO monitor rules honest", ()
|
|
|
129
130
|
jest.restoreAllMocks();
|
|
130
131
|
});
|
|
131
132
|
|
|
133
|
+
it("re-runs SLO rules for every affected monitor when its type changes", async () => {
|
|
134
|
+
await callHook(
|
|
135
|
+
MonitorService,
|
|
136
|
+
"onUpdateSuccess",
|
|
137
|
+
monitorUpdate({ monitorType: MonitorType.API }),
|
|
138
|
+
[MONITOR_ID, OTHER_MONITOR_ID],
|
|
139
|
+
);
|
|
140
|
+
expect(syncSlosForMonitorSpy).toHaveBeenCalledTimes(2);
|
|
141
|
+
expect(syncSlosForMonitorSpy).toHaveBeenCalledWith({
|
|
142
|
+
monitorId: MONITOR_ID,
|
|
143
|
+
projectId: PROJECT_ID,
|
|
144
|
+
});
|
|
145
|
+
expect(syncSlosForMonitorSpy).toHaveBeenCalledWith({
|
|
146
|
+
monitorId: OTHER_MONITOR_ID,
|
|
147
|
+
projectId: PROJECT_ID,
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
132
151
|
it("re-runs the SLO monitor rules when a monitor gains a label", async () => {
|
|
133
152
|
await callHook(
|
|
134
153
|
MonitorService,
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
import Entities from "../../../Models/DatabaseModels/Index";
|
|
2
|
+
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
3
|
+
import ServiceLevelObjective from "../../../Models/DatabaseModels/ServiceLevelObjective";
|
|
4
|
+
import ServiceLevelObjectiveMonitorRule from "../../../Models/DatabaseModels/ServiceLevelObjectiveMonitorRule";
|
|
5
|
+
import PostgresAppInstance from "../../../Server/Infrastructure/PostgresDatabase";
|
|
6
|
+
import AuditLogService from "../../../Server/Services/AuditLogService";
|
|
7
|
+
import MonitorService from "../../../Server/Services/MonitorService";
|
|
8
|
+
import ServiceLevelObjectiveFeedService from "../../../Server/Services/ServiceLevelObjectiveFeedService";
|
|
9
|
+
import ServiceLevelObjectiveMonitorRuleEngineService from "../../../Server/Services/ServiceLevelObjectiveMonitorRuleEngineService";
|
|
10
|
+
import ServiceLevelObjectiveMonitorRuleService from "../../../Server/Services/ServiceLevelObjectiveMonitorRuleService";
|
|
11
|
+
import ServiceLevelObjectiveService from "../../../Server/Services/ServiceLevelObjectiveService";
|
|
12
|
+
import FilterCondition from "../../../Types/Filter/FilterCondition";
|
|
13
|
+
import MonitorType from "../../../Types/Monitor/MonitorType";
|
|
14
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
15
|
+
import RuleCriteria, {
|
|
16
|
+
RULE_CRITERIA_SCHEMA_VERSION,
|
|
17
|
+
RuleCriteriaFilter,
|
|
18
|
+
RuleCriteriaOperator,
|
|
19
|
+
} from "../../../Types/Rules/RuleCriteria";
|
|
20
|
+
import { DataSource } from "typeorm";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Opt in with RUN_POSTGRES_SLO_MONITOR_TYPE_TESTS=true and config.env.
|
|
24
|
+
* The database must already be migrated. Only table structures are copied
|
|
25
|
+
* into a unique schema; every fixture and membership write stays there.
|
|
26
|
+
* Persistence, validation, rule hooks and the engine use production services.
|
|
27
|
+
* Only unrelated feed, audit and workflow delivery is replaced.
|
|
28
|
+
*/
|
|
29
|
+
const describePostgres: typeof describe =
|
|
30
|
+
process.env["RUN_POSTGRES_SLO_MONITOR_TYPE_TESTS"] === "true"
|
|
31
|
+
? describe
|
|
32
|
+
: describe.skip;
|
|
33
|
+
|
|
34
|
+
function criteria(
|
|
35
|
+
filters: Array<RuleCriteriaFilter>,
|
|
36
|
+
filterCondition: FilterCondition = FilterCondition.All,
|
|
37
|
+
): RuleCriteria {
|
|
38
|
+
return {
|
|
39
|
+
schemaVersion: RULE_CRITERIA_SCHEMA_VERSION,
|
|
40
|
+
filterCondition,
|
|
41
|
+
filters,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function typeFilter(
|
|
46
|
+
monitorType: MonitorType,
|
|
47
|
+
operator: RuleCriteriaOperator = RuleCriteriaOperator.Equals,
|
|
48
|
+
): RuleCriteriaFilter {
|
|
49
|
+
return { field: "monitorType", operator, value: monitorType };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
describePostgres("SLO monitor type rules against Postgres", () => {
|
|
53
|
+
const schema: string = `slo_monitor_type_${ObjectID.generate().toString().replace(/-/g, "")}`;
|
|
54
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
55
|
+
const otherProjectId: ObjectID = ObjectID.generate();
|
|
56
|
+
const tables: Array<string> = [
|
|
57
|
+
"Monitor",
|
|
58
|
+
"Label",
|
|
59
|
+
"MonitorLabel",
|
|
60
|
+
"ServiceLevelObjective",
|
|
61
|
+
"ServiceLevelObjectiveMonitor",
|
|
62
|
+
"ServiceLevelObjectiveAutoAddedMonitor",
|
|
63
|
+
"ServiceLevelObjectiveMonitorLabel",
|
|
64
|
+
"ServiceLevelObjectiveMonitorRule",
|
|
65
|
+
"ServiceLevelObjectiveMonitorRuleMonitorLabel",
|
|
66
|
+
];
|
|
67
|
+
let database: DataSource;
|
|
68
|
+
let sloId: ObjectID;
|
|
69
|
+
let apiId: ObjectID;
|
|
70
|
+
let websiteId: ObjectID;
|
|
71
|
+
let otherProjectApiId: ObjectID;
|
|
72
|
+
|
|
73
|
+
beforeAll(async () => {
|
|
74
|
+
database = new DataSource({
|
|
75
|
+
type: "postgres",
|
|
76
|
+
host: process.env["SLO_MONITOR_TYPE_TEST_DATABASE_HOST"] || "localhost",
|
|
77
|
+
port: Number(
|
|
78
|
+
process.env["SLO_MONITOR_TYPE_TEST_DATABASE_PORT"] || "5400",
|
|
79
|
+
),
|
|
80
|
+
username: process.env["DATABASE_USERNAME"] || "postgres",
|
|
81
|
+
password: process.env["DATABASE_PASSWORD"] || "password",
|
|
82
|
+
database:
|
|
83
|
+
process.env["SLO_MONITOR_TYPE_TEST_DATABASE_NAME"] ||
|
|
84
|
+
process.env["DATABASE_NAME"] ||
|
|
85
|
+
"oneuptimedb",
|
|
86
|
+
entities: Entities,
|
|
87
|
+
schema,
|
|
88
|
+
synchronize: false,
|
|
89
|
+
extra: { options: `-c search_path=${schema},public` },
|
|
90
|
+
});
|
|
91
|
+
await database.initialize();
|
|
92
|
+
await database.query(`CREATE SCHEMA "${schema}"`);
|
|
93
|
+
for (const table of tables) {
|
|
94
|
+
await database.query(
|
|
95
|
+
`CREATE TABLE "${schema}"."${table}" (LIKE public."${table}" INCLUDING ALL)`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
jest.spyOn(PostgresAppInstance, "isConnected").mockReturnValue(true);
|
|
100
|
+
jest.spyOn(PostgresAppInstance, "getDataSource").mockReturnValue(database);
|
|
101
|
+
jest.spyOn(AuditLogService, "recordCreate").mockResolvedValue();
|
|
102
|
+
jest.spyOn(AuditLogService, "recordUpdate").mockResolvedValue();
|
|
103
|
+
jest
|
|
104
|
+
.spyOn(
|
|
105
|
+
ServiceLevelObjectiveFeedService,
|
|
106
|
+
"createServiceLevelObjectiveFeedItem",
|
|
107
|
+
)
|
|
108
|
+
.mockResolvedValue();
|
|
109
|
+
jest
|
|
110
|
+
.spyOn(ServiceLevelObjectiveMonitorRuleService, "onTriggerWorkflow")
|
|
111
|
+
.mockResolvedValue();
|
|
112
|
+
jest
|
|
113
|
+
.spyOn(ServiceLevelObjectiveService, "onTriggerWorkflow")
|
|
114
|
+
.mockResolvedValue();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
beforeEach(async () => {
|
|
118
|
+
await database.query(
|
|
119
|
+
`TRUNCATE ${tables
|
|
120
|
+
.map((table: string): string => {
|
|
121
|
+
return `"${schema}"."${table}"`;
|
|
122
|
+
})
|
|
123
|
+
.join(", ")}`,
|
|
124
|
+
);
|
|
125
|
+
sloId = await seedSlo(projectId);
|
|
126
|
+
apiId = await seedMonitor(MonitorType.API, "api-production", projectId);
|
|
127
|
+
websiteId = await seedMonitor(
|
|
128
|
+
MonitorType.Website,
|
|
129
|
+
"website-production",
|
|
130
|
+
projectId,
|
|
131
|
+
);
|
|
132
|
+
otherProjectApiId = await seedMonitor(
|
|
133
|
+
MonitorType.API,
|
|
134
|
+
"api-production",
|
|
135
|
+
otherProjectId,
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
afterAll(async () => {
|
|
140
|
+
jest.restoreAllMocks();
|
|
141
|
+
if (database?.isInitialized) {
|
|
142
|
+
await database.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
|
|
143
|
+
await database.destroy();
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
async function seedSlo(ownerProjectId: ObjectID): Promise<ObjectID> {
|
|
148
|
+
const id: ObjectID = ObjectID.generate();
|
|
149
|
+
await database.query(
|
|
150
|
+
`INSERT INTO "${schema}"."ServiceLevelObjective"
|
|
151
|
+
("_id", "projectId", "name", "slug", "targetPercentage", "version")
|
|
152
|
+
VALUES ($1, $2, 'Synthetic SLO', $3, 99.9, 1)`,
|
|
153
|
+
[id.toString(), ownerProjectId.toString(), `slo-type-${id.toString()}`],
|
|
154
|
+
);
|
|
155
|
+
return id;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async function seedMonitor(
|
|
159
|
+
monitorType: MonitorType,
|
|
160
|
+
name: string,
|
|
161
|
+
ownerProjectId: ObjectID,
|
|
162
|
+
): Promise<ObjectID> {
|
|
163
|
+
const id: ObjectID = ObjectID.generate();
|
|
164
|
+
await database.query(
|
|
165
|
+
`INSERT INTO "${schema}"."Monitor"
|
|
166
|
+
("_id", "projectId", "name", "description", "slug", "monitorType", "currentMonitorStatusId", "version")
|
|
167
|
+
VALUES ($1, $2, $3, 'Customer facing production service', $4, $5, $6, 1)`,
|
|
168
|
+
[
|
|
169
|
+
id.toString(),
|
|
170
|
+
ownerProjectId.toString(),
|
|
171
|
+
name,
|
|
172
|
+
`monitor-type-${id.toString()}`,
|
|
173
|
+
monitorType,
|
|
174
|
+
ObjectID.generate().toString(),
|
|
175
|
+
],
|
|
176
|
+
);
|
|
177
|
+
return id;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function createRule(
|
|
181
|
+
ruleCriteria: RuleCriteria,
|
|
182
|
+
targetSloId: ObjectID = sloId,
|
|
183
|
+
ownerProjectId: ObjectID = projectId,
|
|
184
|
+
): Promise<ServiceLevelObjectiveMonitorRule> {
|
|
185
|
+
const rule: ServiceLevelObjectiveMonitorRule =
|
|
186
|
+
new ServiceLevelObjectiveMonitorRule();
|
|
187
|
+
rule.projectId = ownerProjectId;
|
|
188
|
+
rule.serviceLevelObjectiveId = targetSloId;
|
|
189
|
+
rule.name = "Synthetic type rule";
|
|
190
|
+
rule.isEnabled = true;
|
|
191
|
+
rule.criteria = ruleCriteria;
|
|
192
|
+
return ServiceLevelObjectiveMonitorRuleService.create({
|
|
193
|
+
data: rule,
|
|
194
|
+
props: { isRoot: true },
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async function expectMembership(
|
|
199
|
+
attachedIds: Array<ObjectID>,
|
|
200
|
+
autoAddedIds: Array<ObjectID> = attachedIds,
|
|
201
|
+
targetSloId: ObjectID = sloId,
|
|
202
|
+
): Promise<void> {
|
|
203
|
+
const slo: ServiceLevelObjective | null =
|
|
204
|
+
await ServiceLevelObjectiveService.findOneById({
|
|
205
|
+
id: targetSloId,
|
|
206
|
+
select: { monitors: { _id: true }, autoAddedMonitors: { _id: true } },
|
|
207
|
+
props: { isRoot: true },
|
|
208
|
+
});
|
|
209
|
+
expect(slo).not.toBeNull();
|
|
210
|
+
const ids: (monitors: Array<Monitor> | undefined) => Array<string> = (
|
|
211
|
+
monitors: Array<Monitor> | undefined,
|
|
212
|
+
): Array<string> => {
|
|
213
|
+
return (monitors || [])
|
|
214
|
+
.map((monitor: Monitor): string => {
|
|
215
|
+
return monitor.id!.toString();
|
|
216
|
+
})
|
|
217
|
+
.sort();
|
|
218
|
+
};
|
|
219
|
+
expect(ids(slo!.monitors)).toEqual(attachedIds.map(String).sort());
|
|
220
|
+
expect(ids(slo!.autoAddedMonitors)).toEqual(
|
|
221
|
+
autoAddedIds.map(String).sort(),
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
test("round-trips a type criterion and backfills only matching monitors in the SLO's project", async () => {
|
|
226
|
+
const savedCriteria: RuleCriteria = criteria([typeFilter(MonitorType.API)]);
|
|
227
|
+
const rule: ServiceLevelObjectiveMonitorRule =
|
|
228
|
+
await createRule(savedCriteria);
|
|
229
|
+
const stored: ServiceLevelObjectiveMonitorRule | null =
|
|
230
|
+
await ServiceLevelObjectiveMonitorRuleService.findOneById({
|
|
231
|
+
id: rule.id!,
|
|
232
|
+
select: { criteria: true, monitorType: true },
|
|
233
|
+
props: { isRoot: true },
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(stored?.criteria).toEqual(savedCriteria);
|
|
237
|
+
await expectMembership([apiId]);
|
|
238
|
+
await expect(
|
|
239
|
+
ServiceLevelObjectiveMonitorRuleEngineService.syncMonitorsForSlo({
|
|
240
|
+
serviceLevelObjectiveId: sloId,
|
|
241
|
+
}),
|
|
242
|
+
).resolves.toEqual({ monitorIdsAdded: [], monitorIdsRemoved: [] });
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("editing Equals to NotEquals persists the new operator and replaces automatic membership", async () => {
|
|
246
|
+
const rule: ServiceLevelObjectiveMonitorRule = await createRule(
|
|
247
|
+
criteria([typeFilter(MonitorType.API)]),
|
|
248
|
+
);
|
|
249
|
+
const updatedCriteria: RuleCriteria = criteria([
|
|
250
|
+
typeFilter(MonitorType.API, RuleCriteriaOperator.NotEquals),
|
|
251
|
+
]);
|
|
252
|
+
await ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
253
|
+
id: rule.id!,
|
|
254
|
+
data: { criteria: updatedCriteria },
|
|
255
|
+
props: { isRoot: true },
|
|
256
|
+
});
|
|
257
|
+
const rows: Array<{ criteria: RuleCriteria }> = await database.query(
|
|
258
|
+
`SELECT "criteria" FROM "${schema}"."ServiceLevelObjectiveMonitorRule" WHERE "_id" = $1`,
|
|
259
|
+
[rule.id!.toString()],
|
|
260
|
+
);
|
|
261
|
+
expect(rows[0]?.criteria).toEqual(updatedCriteria);
|
|
262
|
+
await expectMembership([websiteId]);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test("the nullable type column supports legacy type-only rules and existing rules without a type", async () => {
|
|
266
|
+
const rule: ServiceLevelObjectiveMonitorRule =
|
|
267
|
+
new ServiceLevelObjectiveMonitorRule();
|
|
268
|
+
rule.projectId = projectId;
|
|
269
|
+
rule.serviceLevelObjectiveId = sloId;
|
|
270
|
+
rule.name = "Legacy type rule";
|
|
271
|
+
rule.isEnabled = true;
|
|
272
|
+
rule.monitorType = MonitorType.API;
|
|
273
|
+
const created: ServiceLevelObjectiveMonitorRule =
|
|
274
|
+
await ServiceLevelObjectiveMonitorRuleService.create({
|
|
275
|
+
data: rule,
|
|
276
|
+
props: { isRoot: true },
|
|
277
|
+
});
|
|
278
|
+
const stored: ServiceLevelObjectiveMonitorRule | null =
|
|
279
|
+
await ServiceLevelObjectiveMonitorRuleService.findOneById({
|
|
280
|
+
id: created.id!,
|
|
281
|
+
select: { monitorType: true, criteria: true },
|
|
282
|
+
props: { isRoot: true },
|
|
283
|
+
});
|
|
284
|
+
expect(stored?.monitorType).toBe(MonitorType.API);
|
|
285
|
+
expect(stored?.criteria).toBeNull();
|
|
286
|
+
await expectMembership([apiId]);
|
|
287
|
+
|
|
288
|
+
const columns: Array<{
|
|
289
|
+
is_nullable: string;
|
|
290
|
+
column_default: string | null;
|
|
291
|
+
}> = await database.query(
|
|
292
|
+
`SELECT is_nullable, column_default FROM information_schema.columns
|
|
293
|
+
WHERE table_schema = $1 AND table_name = 'ServiceLevelObjectiveMonitorRule' AND column_name = 'monitorType'`,
|
|
294
|
+
[schema],
|
|
295
|
+
);
|
|
296
|
+
expect(columns).toEqual([{ is_nullable: "YES", column_default: null }]);
|
|
297
|
+
|
|
298
|
+
await ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
299
|
+
id: created.id!,
|
|
300
|
+
data: {
|
|
301
|
+
criteria: criteria([
|
|
302
|
+
{
|
|
303
|
+
field: "monitorNamePattern",
|
|
304
|
+
operator: RuleCriteriaOperator.MatchesPattern,
|
|
305
|
+
value: "^website-",
|
|
306
|
+
},
|
|
307
|
+
]),
|
|
308
|
+
},
|
|
309
|
+
props: { isRoot: true },
|
|
310
|
+
});
|
|
311
|
+
await expectMembership([websiteId]);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
test("Match all and Match any combine a persisted type with positive and negative text patterns", async () => {
|
|
315
|
+
const filters: Array<RuleCriteriaFilter> = [
|
|
316
|
+
typeFilter(MonitorType.API),
|
|
317
|
+
{
|
|
318
|
+
field: "monitorNamePattern",
|
|
319
|
+
operator: RuleCriteriaOperator.MatchesPattern,
|
|
320
|
+
value: "^website-",
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
field: "monitorDescriptionPattern",
|
|
324
|
+
operator: RuleCriteriaOperator.DoesNotMatchPattern,
|
|
325
|
+
value: "production",
|
|
326
|
+
},
|
|
327
|
+
];
|
|
328
|
+
const rule: ServiceLevelObjectiveMonitorRule = await createRule(
|
|
329
|
+
criteria(filters),
|
|
330
|
+
);
|
|
331
|
+
await expectMembership([]);
|
|
332
|
+
|
|
333
|
+
await ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
334
|
+
id: rule.id!,
|
|
335
|
+
data: { criteria: criteria(filters, FilterCondition.Any) },
|
|
336
|
+
props: { isRoot: true },
|
|
337
|
+
});
|
|
338
|
+
await expectMembership([apiId, websiteId]);
|
|
339
|
+
|
|
340
|
+
await ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
341
|
+
id: rule.id!,
|
|
342
|
+
data: {
|
|
343
|
+
criteria: criteria([
|
|
344
|
+
typeFilter(MonitorType.API),
|
|
345
|
+
{
|
|
346
|
+
field: "monitorNamePattern",
|
|
347
|
+
operator: RuleCriteriaOperator.MatchesPattern,
|
|
348
|
+
value: "^api-",
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
field: "monitorDescriptionPattern",
|
|
352
|
+
operator: RuleCriteriaOperator.DoesNotMatchPattern,
|
|
353
|
+
value: "staging",
|
|
354
|
+
},
|
|
355
|
+
]),
|
|
356
|
+
},
|
|
357
|
+
props: { isRoot: true },
|
|
358
|
+
});
|
|
359
|
+
await expectMembership([apiId]);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
test("monitor-side type changes attach and detach automatic members while preserving manual membership", async () => {
|
|
363
|
+
await database.query(
|
|
364
|
+
`INSERT INTO "${schema}"."ServiceLevelObjectiveMonitor" ("serviceLevelObjectiveId", "monitorId") VALUES ($1, $2)`,
|
|
365
|
+
[sloId.toString(), websiteId.toString()],
|
|
366
|
+
);
|
|
367
|
+
await createRule(criteria([typeFilter(MonitorType.API)]));
|
|
368
|
+
await expectMembership([apiId, websiteId], [apiId]);
|
|
369
|
+
|
|
370
|
+
await MonitorService.updateColumnsByIdWithoutHooks({
|
|
371
|
+
id: apiId,
|
|
372
|
+
data: { monitorType: MonitorType.Website },
|
|
373
|
+
});
|
|
374
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncSlosForMonitor({
|
|
375
|
+
monitorId: apiId,
|
|
376
|
+
});
|
|
377
|
+
await expectMembership([websiteId], []);
|
|
378
|
+
|
|
379
|
+
await MonitorService.updateColumnsByIdWithoutHooks({
|
|
380
|
+
id: websiteId,
|
|
381
|
+
data: { monitorType: MonitorType.API },
|
|
382
|
+
});
|
|
383
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncSlosForMonitor({
|
|
384
|
+
monitorId: websiteId,
|
|
385
|
+
});
|
|
386
|
+
await expectMembership([websiteId], []);
|
|
387
|
+
|
|
388
|
+
await MonitorService.updateColumnsByIdWithoutHooks({
|
|
389
|
+
id: websiteId,
|
|
390
|
+
data: { monitorType: MonitorType.Website },
|
|
391
|
+
});
|
|
392
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncSlosForMonitor({
|
|
393
|
+
monitorId: websiteId,
|
|
394
|
+
});
|
|
395
|
+
await expectMembership([websiteId], []);
|
|
396
|
+
|
|
397
|
+
await MonitorService.updateColumnsByIdWithoutHooks({
|
|
398
|
+
id: apiId,
|
|
399
|
+
data: { monitorType: MonitorType.API },
|
|
400
|
+
});
|
|
401
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncSlosForMonitor({
|
|
402
|
+
monitorId: apiId,
|
|
403
|
+
});
|
|
404
|
+
await expectMembership([apiId, websiteId], [apiId]);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
test("a type change in another project cannot attach its monitor to this SLO", async () => {
|
|
408
|
+
const otherSloId: ObjectID = await seedSlo(otherProjectId);
|
|
409
|
+
await createRule(criteria([typeFilter(MonitorType.API)]));
|
|
410
|
+
await createRule(
|
|
411
|
+
criteria([typeFilter(MonitorType.Website)]),
|
|
412
|
+
otherSloId,
|
|
413
|
+
otherProjectId,
|
|
414
|
+
);
|
|
415
|
+
await expectMembership([], [], otherSloId);
|
|
416
|
+
|
|
417
|
+
await MonitorService.updateColumnsByIdWithoutHooks({
|
|
418
|
+
id: otherProjectApiId,
|
|
419
|
+
data: { monitorType: MonitorType.Website },
|
|
420
|
+
});
|
|
421
|
+
await ServiceLevelObjectiveMonitorRuleEngineService.syncSlosForMonitor({
|
|
422
|
+
monitorId: otherProjectApiId,
|
|
423
|
+
});
|
|
424
|
+
await expectMembership(
|
|
425
|
+
[otherProjectApiId],
|
|
426
|
+
[otherProjectApiId],
|
|
427
|
+
otherSloId,
|
|
428
|
+
);
|
|
429
|
+
await expectMembership([apiId]);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
test("disabling the type rule removes its persisted automatic membership", async () => {
|
|
433
|
+
const rule: ServiceLevelObjectiveMonitorRule = await createRule(
|
|
434
|
+
criteria([typeFilter(MonitorType.API)]),
|
|
435
|
+
);
|
|
436
|
+
await expectMembership([apiId]);
|
|
437
|
+
await ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
438
|
+
id: rule.id!,
|
|
439
|
+
data: { isEnabled: false },
|
|
440
|
+
props: { isRoot: true },
|
|
441
|
+
});
|
|
442
|
+
await expectMembership([]);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test.each([
|
|
446
|
+
{
|
|
447
|
+
field: "monitorType",
|
|
448
|
+
operator: RuleCriteriaOperator.Equals,
|
|
449
|
+
value: "not-a-monitor-type",
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
field: "monitorType",
|
|
453
|
+
operator: RuleCriteriaOperator.Contains,
|
|
454
|
+
value: MonitorType.API,
|
|
455
|
+
},
|
|
456
|
+
])(
|
|
457
|
+
"rejects invalid type criteria before changing stored rules or membership: %j",
|
|
458
|
+
async (filter: RuleCriteriaFilter) => {
|
|
459
|
+
const rule: ServiceLevelObjectiveMonitorRule = await createRule(
|
|
460
|
+
criteria([typeFilter(MonitorType.API)]),
|
|
461
|
+
);
|
|
462
|
+
await expect(createRule(criteria([filter]))).rejects.toThrow();
|
|
463
|
+
await expect(
|
|
464
|
+
ServiceLevelObjectiveMonitorRuleService.updateOneById({
|
|
465
|
+
id: rule.id!,
|
|
466
|
+
data: { criteria: criteria([filter]) },
|
|
467
|
+
props: { isRoot: true },
|
|
468
|
+
}),
|
|
469
|
+
).rejects.toThrow();
|
|
470
|
+
const rows: Array<{ criteria: RuleCriteria }> = await database.query(
|
|
471
|
+
`SELECT "criteria" FROM "${schema}"."ServiceLevelObjectiveMonitorRule"`,
|
|
472
|
+
);
|
|
473
|
+
expect(rows).toHaveLength(1);
|
|
474
|
+
expect(rows[0]?.criteria).toEqual(
|
|
475
|
+
criteria([typeFilter(MonitorType.API)]),
|
|
476
|
+
);
|
|
477
|
+
await expectMembership([apiId]);
|
|
478
|
+
},
|
|
479
|
+
);
|
|
480
|
+
});
|
|
@@ -17,7 +17,9 @@ import IncidentStateTimelineService from "../../../Server/Services/IncidentState
|
|
|
17
17
|
import MonitorStatusService from "../../../Server/Services/MonitorStatusService";
|
|
18
18
|
import ServiceLevelObjectiveService from "../../../Server/Services/ServiceLevelObjectiveService";
|
|
19
19
|
import ServiceLevelObjectiveBurnRateRuleService from "../../../Server/Services/ServiceLevelObjectiveBurnRateRuleService";
|
|
20
|
+
import ServiceLevelObjectiveLabelRuleEngineService from "../../../Server/Services/ServiceLevelObjectiveLabelRuleEngineService";
|
|
20
21
|
import ServiceLevelObjectiveMonitorRuleEngineService from "../../../Server/Services/ServiceLevelObjectiveMonitorRuleEngineService";
|
|
22
|
+
import ServiceLevelObjectiveOwnerRuleEngineService from "../../../Server/Services/ServiceLevelObjectiveOwnerRuleEngineService";
|
|
21
23
|
import ServiceLevelObjectiveOwnerTeamService from "../../../Server/Services/ServiceLevelObjectiveOwnerTeamService";
|
|
22
24
|
import ServiceLevelObjectiveOwnerUserService from "../../../Server/Services/ServiceLevelObjectiveOwnerUserService";
|
|
23
25
|
import TeamMemberService from "../../../Server/Services/TeamMemberService";
|
|
@@ -2554,3 +2556,163 @@ describe("ServiceLevelObjectiveService - applying the monitor rules", () => {
|
|
|
2554
2556
|
expect(syncMonitorsForSloSpy).not.toHaveBeenCalled();
|
|
2555
2557
|
});
|
|
2556
2558
|
});
|
|
2559
|
+
|
|
2560
|
+
/*
|
|
2561
|
+
* SLO label and owner rules fire when an SLO is created, like every other
|
|
2562
|
+
* resource's: label rules first, so an owner rule can key on a label a label
|
|
2563
|
+
* rule just attached, and without holding up - or ever failing - the create.
|
|
2564
|
+
*/
|
|
2565
|
+
describe("ServiceLevelObjectiveService - applying the label and owner rules", () => {
|
|
2566
|
+
let labelRulesSpy: jest.SpyInstance;
|
|
2567
|
+
let ownerRulesSpy: jest.SpyInstance;
|
|
2568
|
+
let errorSpy: jest.SpyInstance;
|
|
2569
|
+
|
|
2570
|
+
// The rules run off the request path; let them.
|
|
2571
|
+
async function settle(): Promise<void> {
|
|
2572
|
+
for (let i: number = 0; i < 10; i++) {
|
|
2573
|
+
await new Promise((resolve: (value: unknown) => void) => {
|
|
2574
|
+
setTimeout(resolve, 0);
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
function createdSlo(): ServiceLevelObjective {
|
|
2580
|
+
return makeSlo({
|
|
2581
|
+
_id: SLO_ID.toString(),
|
|
2582
|
+
id: SLO_ID,
|
|
2583
|
+
projectId: PROJECT_ID,
|
|
2584
|
+
targetPercentage: 99.9,
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
function onCreateSuccess(
|
|
2589
|
+
createdItem: ServiceLevelObjective,
|
|
2590
|
+
): Promise<unknown> {
|
|
2591
|
+
return callHook(
|
|
2592
|
+
"onCreateSuccess",
|
|
2593
|
+
{
|
|
2594
|
+
createBy: makeCreateBy({
|
|
2595
|
+
projectId: PROJECT_ID,
|
|
2596
|
+
targetPercentage: 99.9,
|
|
2597
|
+
}),
|
|
2598
|
+
carryForward: null,
|
|
2599
|
+
},
|
|
2600
|
+
createdItem,
|
|
2601
|
+
);
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
beforeEach(() => {
|
|
2605
|
+
labelRulesSpy = jest
|
|
2606
|
+
.spyOn(
|
|
2607
|
+
ServiceLevelObjectiveLabelRuleEngineService,
|
|
2608
|
+
"applyRulesToServiceLevelObjective",
|
|
2609
|
+
)
|
|
2610
|
+
.mockResolvedValue(undefined);
|
|
2611
|
+
ownerRulesSpy = jest
|
|
2612
|
+
.spyOn(
|
|
2613
|
+
ServiceLevelObjectiveOwnerRuleEngineService,
|
|
2614
|
+
"applyRulesToServiceLevelObjective",
|
|
2615
|
+
)
|
|
2616
|
+
.mockResolvedValue(undefined);
|
|
2617
|
+
errorSpy = jest.spyOn(logger, "error").mockImplementation(() => {});
|
|
2618
|
+
|
|
2619
|
+
jest
|
|
2620
|
+
.spyOn(
|
|
2621
|
+
ServiceLevelObjectiveMonitorRuleEngineService,
|
|
2622
|
+
"syncMonitorsForSlo",
|
|
2623
|
+
)
|
|
2624
|
+
.mockResolvedValue({ monitorIdsAdded: [], monitorIdsRemoved: [] });
|
|
2625
|
+
jest
|
|
2626
|
+
.spyOn(ServiceLevelObjectiveService, "updateOneById")
|
|
2627
|
+
.mockResolvedValue(1);
|
|
2628
|
+
jest
|
|
2629
|
+
.spyOn(ServiceLevelObjectiveService, "findOneById")
|
|
2630
|
+
.mockResolvedValue(makeSlo({ projectId: PROJECT_ID }));
|
|
2631
|
+
jest.spyOn(AlertSeverityService, "findOneBy").mockResolvedValue(null);
|
|
2632
|
+
jest
|
|
2633
|
+
.spyOn(ServiceLevelObjectiveBurnRateRuleService, "create")
|
|
2634
|
+
.mockResolvedValue(makeBurnRateRule(RULE_ID));
|
|
2635
|
+
});
|
|
2636
|
+
|
|
2637
|
+
afterEach(() => {
|
|
2638
|
+
jest.restoreAllMocks();
|
|
2639
|
+
});
|
|
2640
|
+
|
|
2641
|
+
it("applies the label rules, then the owner rules, to the SLO it created", async () => {
|
|
2642
|
+
const createdItem: ServiceLevelObjective = createdSlo();
|
|
2643
|
+
|
|
2644
|
+
await onCreateSuccess(createdItem);
|
|
2645
|
+
await settle();
|
|
2646
|
+
|
|
2647
|
+
expect(labelRulesSpy).toHaveBeenCalledTimes(1);
|
|
2648
|
+
expect(labelRulesSpy).toHaveBeenCalledWith(createdItem);
|
|
2649
|
+
expect(ownerRulesSpy).toHaveBeenCalledTimes(1);
|
|
2650
|
+
expect(ownerRulesSpy).toHaveBeenCalledWith(createdItem);
|
|
2651
|
+
expect(labelRulesSpy.mock.invocationCallOrder[0]!).toBeLessThan(
|
|
2652
|
+
ownerRulesSpy.mock.invocationCallOrder[0]!,
|
|
2653
|
+
);
|
|
2654
|
+
});
|
|
2655
|
+
|
|
2656
|
+
// So an owner rule sees the labels the label rules just attached.
|
|
2657
|
+
it("starts the owner rules only once the label rules have finished", async () => {
|
|
2658
|
+
let finishLabelRules: () => void = () => {};
|
|
2659
|
+
labelRulesSpy.mockReturnValue(
|
|
2660
|
+
new Promise<void>((resolve: () => void) => {
|
|
2661
|
+
finishLabelRules = resolve;
|
|
2662
|
+
}),
|
|
2663
|
+
);
|
|
2664
|
+
|
|
2665
|
+
await onCreateSuccess(createdSlo());
|
|
2666
|
+
await settle();
|
|
2667
|
+
|
|
2668
|
+
expect(labelRulesSpy).toHaveBeenCalledTimes(1);
|
|
2669
|
+
expect(ownerRulesSpy).not.toHaveBeenCalled();
|
|
2670
|
+
|
|
2671
|
+
finishLabelRules();
|
|
2672
|
+
await settle();
|
|
2673
|
+
|
|
2674
|
+
expect(ownerRulesSpy).toHaveBeenCalledTimes(1);
|
|
2675
|
+
});
|
|
2676
|
+
|
|
2677
|
+
it("does not hold up the create while the rules run", async () => {
|
|
2678
|
+
labelRulesSpy.mockReturnValue(
|
|
2679
|
+
new Promise<void>(() => {
|
|
2680
|
+
// Never settles.
|
|
2681
|
+
}),
|
|
2682
|
+
);
|
|
2683
|
+
const createdItem: ServiceLevelObjective = createdSlo();
|
|
2684
|
+
|
|
2685
|
+
await expect(onCreateSuccess(createdItem)).resolves.toBe(createdItem);
|
|
2686
|
+
});
|
|
2687
|
+
|
|
2688
|
+
it("never fails the create when the rules cannot be applied, and logs why", async () => {
|
|
2689
|
+
labelRulesSpy.mockRejectedValue(new Error("database is down"));
|
|
2690
|
+
const createdItem: ServiceLevelObjective = createdSlo();
|
|
2691
|
+
|
|
2692
|
+
await expect(onCreateSuccess(createdItem)).resolves.toBe(createdItem);
|
|
2693
|
+
await settle();
|
|
2694
|
+
|
|
2695
|
+
const messages: Array<string> = errorSpy.mock.calls.map(
|
|
2696
|
+
(call: Array<unknown>): string => {
|
|
2697
|
+
return String(call[0]);
|
|
2698
|
+
},
|
|
2699
|
+
);
|
|
2700
|
+
expect(
|
|
2701
|
+
messages.some((message: string): boolean => {
|
|
2702
|
+
return (
|
|
2703
|
+
message.includes("label and owner rules") &&
|
|
2704
|
+
message.includes(SLO_ID.toString()) &&
|
|
2705
|
+
message.includes("database is down")
|
|
2706
|
+
);
|
|
2707
|
+
}),
|
|
2708
|
+
).toBe(true);
|
|
2709
|
+
});
|
|
2710
|
+
|
|
2711
|
+
it("applies no rules to an SLO that has no id", async () => {
|
|
2712
|
+
await onCreateSuccess(makeSlo({ projectId: PROJECT_ID }));
|
|
2713
|
+
await settle();
|
|
2714
|
+
|
|
2715
|
+
expect(labelRulesSpy).not.toHaveBeenCalled();
|
|
2716
|
+
expect(ownerRulesSpy).not.toHaveBeenCalled();
|
|
2717
|
+
});
|
|
2718
|
+
});
|