@oneuptime/common 12.0.2 → 12.0.3
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/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +39 -0
- package/Server/EnvironmentConfig.ts +31 -1
- package/Server/Infrastructure/GlobalCache.ts +115 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/CephClusterService.ts +26 -86
- package/Server/Services/CloudResourceService.ts +23 -83
- package/Server/Services/DatabaseService.ts +111 -0
- package/Server/Services/DockerHostService.ts +19 -79
- package/Server/Services/DockerSwarmClusterService.ts +27 -88
- package/Server/Services/HostService.ts +46 -99
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetService.ts +19 -79
- package/Server/Services/KubernetesClusterService.ts +17 -78
- package/Server/Services/LabelService.ts +57 -10
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +89 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/PodmanHostService.ts +19 -79
- package/Server/Services/ProxmoxClusterService.ts +23 -83
- package/Server/Services/RumApplicationService.ts +19 -80
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +24 -85
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Decimal.ts +16 -4
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +39 -0
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +27 -1
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -76
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -73
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +86 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -69
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -102
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.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/IoTFleetService.js +19 -69
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +42 -7
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +81 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -69
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -70
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
import MonitorStepsReferenceExtractor, {
|
|
2
|
+
MonitorStepsReference,
|
|
3
|
+
MonitorStepsReferenceModel,
|
|
4
|
+
toReferenceId,
|
|
5
|
+
} from "../../../../Server/Utils/Monitor/MonitorStepsReferenceExtractor";
|
|
6
|
+
import { JSONObject, JSONValue, ObjectType } from "../../../../Types/JSON";
|
|
7
|
+
import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
|
|
8
|
+
import ObjectID from "../../../../Types/ObjectID";
|
|
9
|
+
import { describe, expect, it } from "@jest/globals";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Contract under test: tell a real reference inside monitorSteps apart from the
|
|
13
|
+
* many uuids in there that are NOT references.
|
|
14
|
+
*
|
|
15
|
+
* This is the whole reason issue #3039 could not be fixed before. The old guard
|
|
16
|
+
* scraped every uuid out of the serialized blob with a regex, so it could only
|
|
17
|
+
* ever ask "does this happen to be another project's record?" — asking "does
|
|
18
|
+
* this exist?" would have rejected every step id, criteria id and
|
|
19
|
+
* incident/alert template id, none of which match a row anywhere.
|
|
20
|
+
*
|
|
21
|
+
* Reading the structure instead means every id that comes back is known to
|
|
22
|
+
* point at a specific model, so it can be required to exist.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const STATUS_ID: string = "0a3f7e0e-0a4a-4f3f-8b46-0f4f1e2d5c60";
|
|
26
|
+
const DEFAULT_STATUS_ID: string = "5e8b6bd1-3a09-4b0b-9a4e-2a76b0a1c111";
|
|
27
|
+
const INCIDENT_SEVERITY_ID: string = "9b1c1c1e-8a11-4a6f-9c31-6d2f0b6d4a22";
|
|
28
|
+
const ALERT_SEVERITY_ID: string = "c31b3a44-1f60-4a1d-95bb-3e0e6f9a7d33";
|
|
29
|
+
const ON_CALL_POLICY_ID: string = "d40e5c55-2b71-4b2e-86cc-4f1f7a0b8e44";
|
|
30
|
+
const LABEL_ID: string = "e51f6d66-3c82-4c3f-97dd-501a8b1c9f55";
|
|
31
|
+
const TEAM_ID: string = "f6207e77-4d93-4d40-a8ee-612b9c2daa66";
|
|
32
|
+
const USER_ID: string = "07318f88-5ea4-4e51-b9ff-723cad3ebb77";
|
|
33
|
+
const ROLE_ID: string = "1842909a-6fb5-4f62-8a00-834dbe4fcc88";
|
|
34
|
+
const TELEMETRY_SERVICE_ID: string = "29530aab-70c6-4073-9b11-945ecf50dd99";
|
|
35
|
+
const NETWORK_DEVICE_ID: string = "3a641bbc-81d7-4184-8c22-a56fd0610eaa";
|
|
36
|
+
|
|
37
|
+
// Local identity, not a pointer at another row. None of these may be returned.
|
|
38
|
+
const STEP_ID: string = "4b752ccd-92e8-4295-9d33-b670e1721fbb";
|
|
39
|
+
const CRITERIA_ID: string = "5c863dde-a3f9-43a6-8e44-c781f2832acc";
|
|
40
|
+
const INCIDENT_TEMPLATE_ID: string = "6d974eef-b40a-44b7-9f55-d892031943dd";
|
|
41
|
+
const ALERT_TEMPLATE_ID: string = "7ea85ff0-c51b-45c8-a066-e9a3142a54ee";
|
|
42
|
+
|
|
43
|
+
/*
|
|
44
|
+
* `{"_type":"ObjectID","value":"…"}` — how JSONFunctions.serialize writes the
|
|
45
|
+
* ObjectIDs nested inside the incidents and alerts arrays.
|
|
46
|
+
*/
|
|
47
|
+
const objectIdJSON: (id: string) => JSONObject = (id: string): JSONObject => {
|
|
48
|
+
return { _type: ObjectType.ObjectID, value: id };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const criteriaInstance: (overrides: JSONObject) => JSONObject = (
|
|
52
|
+
overrides: JSONObject,
|
|
53
|
+
): JSONObject => {
|
|
54
|
+
return {
|
|
55
|
+
_type: ObjectType.MonitorCriteriaInstance,
|
|
56
|
+
value: {
|
|
57
|
+
id: CRITERIA_ID,
|
|
58
|
+
name: "Monitor is offline",
|
|
59
|
+
description: "",
|
|
60
|
+
filterCondition: "all",
|
|
61
|
+
filters: [],
|
|
62
|
+
incidents: [],
|
|
63
|
+
alerts: [],
|
|
64
|
+
...overrides,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const stepsWithCriteria: (
|
|
70
|
+
instances: Array<JSONObject>,
|
|
71
|
+
stepOverrides?: JSONObject,
|
|
72
|
+
) => JSONObject = (
|
|
73
|
+
instances: Array<JSONObject>,
|
|
74
|
+
stepOverrides?: JSONObject,
|
|
75
|
+
): JSONObject => {
|
|
76
|
+
return {
|
|
77
|
+
_type: ObjectType.MonitorSteps,
|
|
78
|
+
value: {
|
|
79
|
+
defaultMonitorStatusId: DEFAULT_STATUS_ID,
|
|
80
|
+
monitorStepsInstanceArray: [
|
|
81
|
+
{
|
|
82
|
+
_type: ObjectType.MonitorStep,
|
|
83
|
+
value: {
|
|
84
|
+
id: STEP_ID,
|
|
85
|
+
...(stepOverrides || {}),
|
|
86
|
+
monitorCriteria: {
|
|
87
|
+
_type: ObjectType.MonitorCriteria,
|
|
88
|
+
value: {
|
|
89
|
+
monitorCriteriaInstanceArray: instances,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const idsFor: (
|
|
100
|
+
references: Array<MonitorStepsReference>,
|
|
101
|
+
model: MonitorStepsReferenceModel,
|
|
102
|
+
) => Array<string> = (
|
|
103
|
+
references: Array<MonitorStepsReference>,
|
|
104
|
+
model: MonitorStepsReferenceModel,
|
|
105
|
+
): Array<string> => {
|
|
106
|
+
return references
|
|
107
|
+
.filter((reference: MonitorStepsReference) => {
|
|
108
|
+
return reference.model === model;
|
|
109
|
+
})
|
|
110
|
+
.map((reference: MonitorStepsReference) => {
|
|
111
|
+
return reference.id;
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const findById: (
|
|
116
|
+
references: Array<MonitorStepsReference>,
|
|
117
|
+
id: string,
|
|
118
|
+
) => MonitorStepsReference | undefined = (
|
|
119
|
+
references: Array<MonitorStepsReference>,
|
|
120
|
+
id: string,
|
|
121
|
+
): MonitorStepsReference | undefined => {
|
|
122
|
+
return references.find((reference: MonitorStepsReference) => {
|
|
123
|
+
return reference.id === id;
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
describe("MonitorStepsReferenceExtractor", () => {
|
|
128
|
+
describe("what counts as a reference", () => {
|
|
129
|
+
it("returns the default monitor status", () => {
|
|
130
|
+
const references: Array<MonitorStepsReference> =
|
|
131
|
+
MonitorStepsReferenceExtractor.extract(stepsWithCriteria([]));
|
|
132
|
+
|
|
133
|
+
expect(
|
|
134
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
|
|
135
|
+
).toEqual([DEFAULT_STATUS_ID]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("returns the status a criteria switches the monitor to", () => {
|
|
139
|
+
const references: Array<MonitorStepsReference> =
|
|
140
|
+
MonitorStepsReferenceExtractor.extract(
|
|
141
|
+
stepsWithCriteria([
|
|
142
|
+
criteriaInstance({
|
|
143
|
+
monitorStatusId: STATUS_ID,
|
|
144
|
+
changeMonitorStatus: true,
|
|
145
|
+
}),
|
|
146
|
+
]),
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
expect(
|
|
150
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
|
|
151
|
+
).toContain(STATUS_ID);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("returns every id a criteria's incident template carries", () => {
|
|
155
|
+
const references: Array<MonitorStepsReference> =
|
|
156
|
+
MonitorStepsReferenceExtractor.extract(
|
|
157
|
+
stepsWithCriteria([
|
|
158
|
+
criteriaInstance({
|
|
159
|
+
createIncidents: true,
|
|
160
|
+
incidents: [
|
|
161
|
+
{
|
|
162
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
163
|
+
title: "Down",
|
|
164
|
+
description: "",
|
|
165
|
+
incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
|
|
166
|
+
onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
|
|
167
|
+
labelIds: [objectIdJSON(LABEL_ID)],
|
|
168
|
+
ownerTeamIds: [objectIdJSON(TEAM_ID)],
|
|
169
|
+
ownerUserIds: [objectIdJSON(USER_ID)],
|
|
170
|
+
incidentMemberRoles: [
|
|
171
|
+
{
|
|
172
|
+
roleId: objectIdJSON(ROLE_ID),
|
|
173
|
+
userId: objectIdJSON(USER_ID),
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
}),
|
|
179
|
+
]),
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
expect(
|
|
183
|
+
idsFor(references, MonitorStepsReferenceModel.IncidentSeverity),
|
|
184
|
+
).toEqual([INCIDENT_SEVERITY_ID]);
|
|
185
|
+
expect(
|
|
186
|
+
idsFor(references, MonitorStepsReferenceModel.OnCallDutyPolicy),
|
|
187
|
+
).toEqual([ON_CALL_POLICY_ID]);
|
|
188
|
+
expect(idsFor(references, MonitorStepsReferenceModel.Label)).toEqual([
|
|
189
|
+
LABEL_ID,
|
|
190
|
+
]);
|
|
191
|
+
expect(idsFor(references, MonitorStepsReferenceModel.Team)).toEqual([
|
|
192
|
+
TEAM_ID,
|
|
193
|
+
]);
|
|
194
|
+
expect(
|
|
195
|
+
idsFor(references, MonitorStepsReferenceModel.IncidentRole),
|
|
196
|
+
).toEqual([ROLE_ID]);
|
|
197
|
+
// Once as an owner and once as the member the role is assigned to.
|
|
198
|
+
expect(idsFor(references, MonitorStepsReferenceModel.User)).toEqual([
|
|
199
|
+
USER_ID,
|
|
200
|
+
USER_ID,
|
|
201
|
+
]);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("returns every id a criteria's alert template carries", () => {
|
|
205
|
+
const references: Array<MonitorStepsReference> =
|
|
206
|
+
MonitorStepsReferenceExtractor.extract(
|
|
207
|
+
stepsWithCriteria([
|
|
208
|
+
criteriaInstance({
|
|
209
|
+
createAlerts: true,
|
|
210
|
+
alerts: [
|
|
211
|
+
{
|
|
212
|
+
id: ALERT_TEMPLATE_ID,
|
|
213
|
+
title: "Down",
|
|
214
|
+
description: "",
|
|
215
|
+
alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
|
|
216
|
+
onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
|
|
217
|
+
labelIds: [objectIdJSON(LABEL_ID)],
|
|
218
|
+
ownerTeamIds: [objectIdJSON(TEAM_ID)],
|
|
219
|
+
ownerUserIds: [objectIdJSON(USER_ID)],
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
}),
|
|
223
|
+
]),
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
expect(
|
|
227
|
+
idsFor(references, MonitorStepsReferenceModel.AlertSeverity),
|
|
228
|
+
).toEqual([ALERT_SEVERITY_ID]);
|
|
229
|
+
expect(
|
|
230
|
+
idsFor(references, MonitorStepsReferenceModel.OnCallDutyPolicy),
|
|
231
|
+
).toEqual([ON_CALL_POLICY_ID]);
|
|
232
|
+
expect(idsFor(references, MonitorStepsReferenceModel.Label)).toEqual([
|
|
233
|
+
LABEL_ID,
|
|
234
|
+
]);
|
|
235
|
+
expect(idsFor(references, MonitorStepsReferenceModel.Team)).toEqual([
|
|
236
|
+
TEAM_ID,
|
|
237
|
+
]);
|
|
238
|
+
expect(idsFor(references, MonitorStepsReferenceModel.User)).toEqual([
|
|
239
|
+
USER_ID,
|
|
240
|
+
]);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("returns the telemetry services a step is scoped to, from every sub-config that carries them", () => {
|
|
244
|
+
for (const field of [
|
|
245
|
+
"logMonitor",
|
|
246
|
+
"traceMonitor",
|
|
247
|
+
"exceptionMonitor",
|
|
248
|
+
"profileMonitor",
|
|
249
|
+
"metricMonitor",
|
|
250
|
+
]) {
|
|
251
|
+
const references: Array<MonitorStepsReference> =
|
|
252
|
+
MonitorStepsReferenceExtractor.extract(
|
|
253
|
+
stepsWithCriteria([], {
|
|
254
|
+
[field]: {
|
|
255
|
+
telemetryServiceIds: [objectIdJSON(TELEMETRY_SERVICE_ID)],
|
|
256
|
+
},
|
|
257
|
+
}),
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
expect(
|
|
261
|
+
idsFor(references, MonitorStepsReferenceModel.TelemetryService),
|
|
262
|
+
).toEqual([TELEMETRY_SERVICE_ID]);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("returns the device a network device step walks", () => {
|
|
267
|
+
const references: Array<MonitorStepsReference> =
|
|
268
|
+
MonitorStepsReferenceExtractor.extract(
|
|
269
|
+
stepsWithCriteria([], {
|
|
270
|
+
networkDeviceMonitor: { networkDeviceId: NETWORK_DEVICE_ID },
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
expect(
|
|
275
|
+
idsFor(references, MonitorStepsReferenceModel.NetworkDevice),
|
|
276
|
+
).toEqual([NETWORK_DEVICE_ID]);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
describe("what is NOT a reference", () => {
|
|
281
|
+
it("never returns the step id, the criteria id, or an incident/alert template id", () => {
|
|
282
|
+
/*
|
|
283
|
+
* These are all `ObjectID.generate()` values minted client-side for local
|
|
284
|
+
* identity — Terraform never sends them, so they are minted again on
|
|
285
|
+
* every write. They match no row anywhere, and returning them is exactly
|
|
286
|
+
* what stopped the old regex-based guard from checking existence.
|
|
287
|
+
*/
|
|
288
|
+
const references: Array<MonitorStepsReference> =
|
|
289
|
+
MonitorStepsReferenceExtractor.extract(
|
|
290
|
+
stepsWithCriteria([
|
|
291
|
+
criteriaInstance({
|
|
292
|
+
createIncidents: true,
|
|
293
|
+
createAlerts: true,
|
|
294
|
+
incidents: [
|
|
295
|
+
{ id: INCIDENT_TEMPLATE_ID, title: "t", description: "" },
|
|
296
|
+
],
|
|
297
|
+
alerts: [{ id: ALERT_TEMPLATE_ID, title: "t", description: "" }],
|
|
298
|
+
}),
|
|
299
|
+
]),
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
const returned: Array<string> = references.map(
|
|
303
|
+
(reference: MonitorStepsReference) => {
|
|
304
|
+
return reference.id;
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
expect(returned).not.toContain(STEP_ID);
|
|
309
|
+
expect(returned).not.toContain(CRITERIA_ID);
|
|
310
|
+
expect(returned).not.toContain(INCIDENT_TEMPLATE_ID);
|
|
311
|
+
expect(returned).not.toContain(ALERT_TEMPLATE_ID);
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it("skips a blank id rather than reporting it as a missing reference", () => {
|
|
315
|
+
/*
|
|
316
|
+
* A stored `{"_type":"ObjectID","value":""}` rehydrates to
|
|
317
|
+
* `new ObjectID("")`, which is truthy. Reporting it as a missing
|
|
318
|
+
* *reference* would be misleading — it is an unset field, and the
|
|
319
|
+
* required-field checks own that case.
|
|
320
|
+
*/
|
|
321
|
+
const references: Array<MonitorStepsReference> =
|
|
322
|
+
MonitorStepsReferenceExtractor.extract(
|
|
323
|
+
stepsWithCriteria([
|
|
324
|
+
criteriaInstance({
|
|
325
|
+
monitorStatusId: "",
|
|
326
|
+
changeMonitorStatus: true,
|
|
327
|
+
createIncidents: true,
|
|
328
|
+
incidents: [
|
|
329
|
+
{
|
|
330
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
331
|
+
title: "t",
|
|
332
|
+
description: "",
|
|
333
|
+
incidentSeverityId: objectIdJSON(""),
|
|
334
|
+
},
|
|
335
|
+
],
|
|
336
|
+
}),
|
|
337
|
+
]),
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
expect(
|
|
341
|
+
idsFor(references, MonitorStepsReferenceModel.IncidentSeverity),
|
|
342
|
+
).toEqual([]);
|
|
343
|
+
expect(
|
|
344
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
|
|
345
|
+
).toEqual([DEFAULT_STATUS_ID]);
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
describe("isOperative — which references the monitor actually reads", () => {
|
|
350
|
+
it("marks the default monitor status operative, because the monitor is stamped with it", () => {
|
|
351
|
+
const references: Array<MonitorStepsReference> =
|
|
352
|
+
MonitorStepsReferenceExtractor.extract(stepsWithCriteria([]));
|
|
353
|
+
|
|
354
|
+
expect(findById(references, DEFAULT_STATUS_ID)?.isOperative).toBe(true);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("marks a criteria status operative only when the criteria changes the status", () => {
|
|
358
|
+
const on: Array<MonitorStepsReference> =
|
|
359
|
+
MonitorStepsReferenceExtractor.extract(
|
|
360
|
+
stepsWithCriteria([
|
|
361
|
+
criteriaInstance({
|
|
362
|
+
monitorStatusId: STATUS_ID,
|
|
363
|
+
changeMonitorStatus: true,
|
|
364
|
+
}),
|
|
365
|
+
]),
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
const off: Array<MonitorStepsReference> =
|
|
369
|
+
MonitorStepsReferenceExtractor.extract(
|
|
370
|
+
stepsWithCriteria([
|
|
371
|
+
criteriaInstance({
|
|
372
|
+
monitorStatusId: STATUS_ID,
|
|
373
|
+
changeMonitorStatus: false,
|
|
374
|
+
}),
|
|
375
|
+
]),
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
expect(findById(on, STATUS_ID)?.isOperative).toBe(true);
|
|
379
|
+
expect(findById(off, STATUS_ID)?.isOperative).toBe(false);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
it("marks incident template ids operative only when the criteria creates incidents", () => {
|
|
383
|
+
const incidents: Array<JSONValue> = [
|
|
384
|
+
{
|
|
385
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
386
|
+
title: "t",
|
|
387
|
+
description: "",
|
|
388
|
+
incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
|
|
389
|
+
onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
|
|
390
|
+
},
|
|
391
|
+
];
|
|
392
|
+
|
|
393
|
+
const on: Array<MonitorStepsReference> =
|
|
394
|
+
MonitorStepsReferenceExtractor.extract(
|
|
395
|
+
stepsWithCriteria([
|
|
396
|
+
criteriaInstance({ createIncidents: true, incidents: incidents }),
|
|
397
|
+
]),
|
|
398
|
+
);
|
|
399
|
+
|
|
400
|
+
const off: Array<MonitorStepsReference> =
|
|
401
|
+
MonitorStepsReferenceExtractor.extract(
|
|
402
|
+
stepsWithCriteria([
|
|
403
|
+
criteriaInstance({ createIncidents: false, incidents: incidents }),
|
|
404
|
+
]),
|
|
405
|
+
);
|
|
406
|
+
|
|
407
|
+
expect(findById(on, INCIDENT_SEVERITY_ID)?.isOperative).toBe(true);
|
|
408
|
+
expect(findById(on, ON_CALL_POLICY_ID)?.isOperative).toBe(true);
|
|
409
|
+
expect(findById(off, INCIDENT_SEVERITY_ID)?.isOperative).toBe(false);
|
|
410
|
+
expect(findById(off, ON_CALL_POLICY_ID)?.isOperative).toBe(false);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it("marks alert template ids operative only when the criteria creates alerts", () => {
|
|
414
|
+
const alerts: Array<JSONValue> = [
|
|
415
|
+
{
|
|
416
|
+
id: ALERT_TEMPLATE_ID,
|
|
417
|
+
title: "t",
|
|
418
|
+
description: "",
|
|
419
|
+
alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
|
|
420
|
+
},
|
|
421
|
+
];
|
|
422
|
+
|
|
423
|
+
const on: Array<MonitorStepsReference> =
|
|
424
|
+
MonitorStepsReferenceExtractor.extract(
|
|
425
|
+
stepsWithCriteria([
|
|
426
|
+
criteriaInstance({ createAlerts: true, alerts: alerts }),
|
|
427
|
+
]),
|
|
428
|
+
);
|
|
429
|
+
|
|
430
|
+
const off: Array<MonitorStepsReference> =
|
|
431
|
+
MonitorStepsReferenceExtractor.extract(
|
|
432
|
+
stepsWithCriteria([
|
|
433
|
+
criteriaInstance({ createAlerts: false, alerts: alerts }),
|
|
434
|
+
]),
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
expect(findById(on, ALERT_SEVERITY_ID)?.isOperative).toBe(true);
|
|
438
|
+
expect(findById(off, ALERT_SEVERITY_ID)?.isOperative).toBe(false);
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
it("never marks a telemetry service or network device operative", () => {
|
|
442
|
+
/*
|
|
443
|
+
* Neither can produce the foreign key violation this guard exists for,
|
|
444
|
+
* both already degrade on their own when the target is gone, and
|
|
445
|
+
* deleting a telemetry service is ordinary enough that requiring it would
|
|
446
|
+
* refuse every later edit of a monitor that once watched it.
|
|
447
|
+
*/
|
|
448
|
+
const references: Array<MonitorStepsReference> =
|
|
449
|
+
MonitorStepsReferenceExtractor.extract(
|
|
450
|
+
stepsWithCriteria([], {
|
|
451
|
+
logMonitor: {
|
|
452
|
+
telemetryServiceIds: [objectIdJSON(TELEMETRY_SERVICE_ID)],
|
|
453
|
+
},
|
|
454
|
+
networkDeviceMonitor: { networkDeviceId: NETWORK_DEVICE_ID },
|
|
455
|
+
}),
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
expect(findById(references, TELEMETRY_SERVICE_ID)?.isOperative).toBe(
|
|
459
|
+
false,
|
|
460
|
+
);
|
|
461
|
+
expect(findById(references, NETWORK_DEVICE_ID)?.isOperative).toBe(false);
|
|
462
|
+
});
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
describe("the shapes monitorSteps actually arrives in", () => {
|
|
466
|
+
it("walks a live MonitorSteps object, not just its serialized form", () => {
|
|
467
|
+
const monitorSteps: MonitorSteps = MonitorSteps.fromJSON(
|
|
468
|
+
stepsWithCriteria([
|
|
469
|
+
criteriaInstance({
|
|
470
|
+
monitorStatusId: STATUS_ID,
|
|
471
|
+
changeMonitorStatus: true,
|
|
472
|
+
}),
|
|
473
|
+
]),
|
|
474
|
+
);
|
|
475
|
+
|
|
476
|
+
const references: Array<MonitorStepsReference> =
|
|
477
|
+
MonitorStepsReferenceExtractor.extract(monitorSteps);
|
|
478
|
+
|
|
479
|
+
expect(
|
|
480
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus).sort(),
|
|
481
|
+
).toEqual([DEFAULT_STATUS_ID, STATUS_ID].sort());
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
it("accepts a payload with no _type/value envelope", () => {
|
|
485
|
+
/*
|
|
486
|
+
* A hand-written REST body does not have to carry the envelopes the
|
|
487
|
+
* dashboard emits, and it must be walked just as thoroughly.
|
|
488
|
+
*/
|
|
489
|
+
const references: Array<MonitorStepsReference> =
|
|
490
|
+
MonitorStepsReferenceExtractor.extract({
|
|
491
|
+
defaultMonitorStatusId: DEFAULT_STATUS_ID,
|
|
492
|
+
monitorStepsInstanceArray: [
|
|
493
|
+
{
|
|
494
|
+
id: STEP_ID,
|
|
495
|
+
monitorCriteria: {
|
|
496
|
+
monitorCriteriaInstanceArray: [
|
|
497
|
+
{
|
|
498
|
+
id: CRITERIA_ID,
|
|
499
|
+
monitorStatusId: STATUS_ID,
|
|
500
|
+
changeMonitorStatus: true,
|
|
501
|
+
incidents: [],
|
|
502
|
+
alerts: [],
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
],
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
expect(
|
|
511
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus).sort(),
|
|
512
|
+
).toEqual([DEFAULT_STATUS_ID, STATUS_ID].sort());
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
it("reads an id whether it is a bare uuid or an ObjectID envelope", () => {
|
|
516
|
+
const bare: Array<MonitorStepsReference> =
|
|
517
|
+
MonitorStepsReferenceExtractor.extract(
|
|
518
|
+
stepsWithCriteria([
|
|
519
|
+
criteriaInstance({
|
|
520
|
+
createIncidents: true,
|
|
521
|
+
incidents: [
|
|
522
|
+
{
|
|
523
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
524
|
+
title: "t",
|
|
525
|
+
description: "",
|
|
526
|
+
incidentSeverityId: INCIDENT_SEVERITY_ID,
|
|
527
|
+
},
|
|
528
|
+
],
|
|
529
|
+
}),
|
|
530
|
+
]),
|
|
531
|
+
);
|
|
532
|
+
|
|
533
|
+
const wrapped: Array<MonitorStepsReference> =
|
|
534
|
+
MonitorStepsReferenceExtractor.extract(
|
|
535
|
+
stepsWithCriteria([
|
|
536
|
+
criteriaInstance({
|
|
537
|
+
createIncidents: true,
|
|
538
|
+
incidents: [
|
|
539
|
+
{
|
|
540
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
541
|
+
title: "t",
|
|
542
|
+
description: "",
|
|
543
|
+
incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
}),
|
|
547
|
+
]),
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
expect(idsFor(bare, MonitorStepsReferenceModel.IncidentSeverity)).toEqual(
|
|
551
|
+
[INCIDENT_SEVERITY_ID],
|
|
552
|
+
);
|
|
553
|
+
expect(
|
|
554
|
+
idsFor(wrapped, MonitorStepsReferenceModel.IncidentSeverity),
|
|
555
|
+
).toEqual([INCIDENT_SEVERITY_ID]);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it("walks every step and every criteria, not just the first", () => {
|
|
559
|
+
const references: Array<MonitorStepsReference> =
|
|
560
|
+
MonitorStepsReferenceExtractor.extract({
|
|
561
|
+
_type: ObjectType.MonitorSteps,
|
|
562
|
+
value: {
|
|
563
|
+
defaultMonitorStatusId: DEFAULT_STATUS_ID,
|
|
564
|
+
monitorStepsInstanceArray: [
|
|
565
|
+
{
|
|
566
|
+
_type: ObjectType.MonitorStep,
|
|
567
|
+
value: {
|
|
568
|
+
id: STEP_ID,
|
|
569
|
+
monitorCriteria: {
|
|
570
|
+
_type: ObjectType.MonitorCriteria,
|
|
571
|
+
value: {
|
|
572
|
+
monitorCriteriaInstanceArray: [
|
|
573
|
+
criteriaInstance({
|
|
574
|
+
monitorStatusId: STATUS_ID,
|
|
575
|
+
changeMonitorStatus: true,
|
|
576
|
+
}),
|
|
577
|
+
],
|
|
578
|
+
},
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
_type: ObjectType.MonitorStep,
|
|
584
|
+
value: {
|
|
585
|
+
id: STEP_ID,
|
|
586
|
+
monitorCriteria: {
|
|
587
|
+
_type: ObjectType.MonitorCriteria,
|
|
588
|
+
value: {
|
|
589
|
+
monitorCriteriaInstanceArray: [
|
|
590
|
+
criteriaInstance({
|
|
591
|
+
createAlerts: true,
|
|
592
|
+
alerts: [
|
|
593
|
+
{
|
|
594
|
+
id: ALERT_TEMPLATE_ID,
|
|
595
|
+
title: "t",
|
|
596
|
+
description: "",
|
|
597
|
+
alertSeverityId: objectIdJSON(ALERT_SEVERITY_ID),
|
|
598
|
+
},
|
|
599
|
+
],
|
|
600
|
+
}),
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
expect(
|
|
611
|
+
idsFor(references, MonitorStepsReferenceModel.MonitorStatus),
|
|
612
|
+
).toContain(STATUS_ID);
|
|
613
|
+
expect(
|
|
614
|
+
idsFor(references, MonitorStepsReferenceModel.AlertSeverity),
|
|
615
|
+
).toEqual([ALERT_SEVERITY_ID]);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
it("returns nothing rather than throwing on absent or malformed input", () => {
|
|
619
|
+
/*
|
|
620
|
+
* monitorSteps is a free-form JSON column and older rows can be
|
|
621
|
+
* malformed — MonitorSteps.fromDatabase is deliberately lenient about
|
|
622
|
+
* that for the same reason. A guard that threw here would make such a row
|
|
623
|
+
* impossible to save OR delete.
|
|
624
|
+
*/
|
|
625
|
+
expect(MonitorStepsReferenceExtractor.extract(undefined)).toEqual([]);
|
|
626
|
+
expect(MonitorStepsReferenceExtractor.extract(null)).toEqual([]);
|
|
627
|
+
expect(MonitorStepsReferenceExtractor.extract({})).toEqual([]);
|
|
628
|
+
expect(
|
|
629
|
+
MonitorStepsReferenceExtractor.extract({
|
|
630
|
+
_type: ObjectType.MonitorSteps,
|
|
631
|
+
value: { monitorStepsInstanceArray: "not an array" },
|
|
632
|
+
}),
|
|
633
|
+
).toEqual([]);
|
|
634
|
+
expect(
|
|
635
|
+
MonitorStepsReferenceExtractor.extract({
|
|
636
|
+
_type: ObjectType.MonitorSteps,
|
|
637
|
+
value: {
|
|
638
|
+
monitorStepsInstanceArray: [null, 7, "nope", { value: null }],
|
|
639
|
+
},
|
|
640
|
+
}),
|
|
641
|
+
).toEqual([]);
|
|
642
|
+
expect(
|
|
643
|
+
MonitorStepsReferenceExtractor.extract(new MonitorSteps()),
|
|
644
|
+
).toEqual([]);
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
describe("path — where the message points the user", () => {
|
|
649
|
+
it("names the criteria and the field", () => {
|
|
650
|
+
const references: Array<MonitorStepsReference> =
|
|
651
|
+
MonitorStepsReferenceExtractor.extract(
|
|
652
|
+
stepsWithCriteria([
|
|
653
|
+
criteriaInstance({
|
|
654
|
+
monitorStatusId: STATUS_ID,
|
|
655
|
+
changeMonitorStatus: true,
|
|
656
|
+
createIncidents: true,
|
|
657
|
+
incidents: [
|
|
658
|
+
{
|
|
659
|
+
id: INCIDENT_TEMPLATE_ID,
|
|
660
|
+
title: "t",
|
|
661
|
+
description: "",
|
|
662
|
+
incidentSeverityId: objectIdJSON(INCIDENT_SEVERITY_ID),
|
|
663
|
+
onCallPolicyIds: [objectIdJSON(ON_CALL_POLICY_ID)],
|
|
664
|
+
},
|
|
665
|
+
],
|
|
666
|
+
}),
|
|
667
|
+
]),
|
|
668
|
+
);
|
|
669
|
+
|
|
670
|
+
expect(findById(references, DEFAULT_STATUS_ID)?.path).toBe(
|
|
671
|
+
"default monitor status",
|
|
672
|
+
);
|
|
673
|
+
expect(findById(references, STATUS_ID)?.path).toBe(
|
|
674
|
+
'criteria "Monitor is offline" monitor status',
|
|
675
|
+
);
|
|
676
|
+
expect(findById(references, INCIDENT_SEVERITY_ID)?.path).toBe(
|
|
677
|
+
'criteria "Monitor is offline" incident severity',
|
|
678
|
+
);
|
|
679
|
+
expect(findById(references, ON_CALL_POLICY_ID)?.path).toBe(
|
|
680
|
+
'criteria "Monitor is offline" incident on-call policy',
|
|
681
|
+
);
|
|
682
|
+
});
|
|
683
|
+
|
|
684
|
+
it("falls back to the criteria's position when it has no name", () => {
|
|
685
|
+
const references: Array<MonitorStepsReference> =
|
|
686
|
+
MonitorStepsReferenceExtractor.extract(
|
|
687
|
+
stepsWithCriteria([
|
|
688
|
+
criteriaInstance({
|
|
689
|
+
name: "",
|
|
690
|
+
monitorStatusId: STATUS_ID,
|
|
691
|
+
changeMonitorStatus: true,
|
|
692
|
+
}),
|
|
693
|
+
]),
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
expect(findById(references, STATUS_ID)?.path).toBe(
|
|
697
|
+
'criteria "#1" monitor status',
|
|
698
|
+
);
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
describe("toReferenceId", () => {
|
|
703
|
+
it("reads every shape an id arrives in", () => {
|
|
704
|
+
expect(toReferenceId(STATUS_ID)).toBe(STATUS_ID);
|
|
705
|
+
expect(toReferenceId(new ObjectID(STATUS_ID))).toBe(STATUS_ID);
|
|
706
|
+
expect(toReferenceId(objectIdJSON(STATUS_ID))).toBe(STATUS_ID);
|
|
707
|
+
// The marker-less `{ value }` shape MonitorCriteriaInstance.fromJSON accepts.
|
|
708
|
+
expect(toReferenceId({ value: STATUS_ID })).toBe(STATUS_ID);
|
|
709
|
+
expect(toReferenceId(` ${STATUS_ID} `)).toBe(STATUS_ID);
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
it("treats absent, blank and non-id values as no reference", () => {
|
|
713
|
+
expect(toReferenceId(undefined)).toBeNull();
|
|
714
|
+
expect(toReferenceId(null)).toBeNull();
|
|
715
|
+
expect(toReferenceId("")).toBeNull();
|
|
716
|
+
expect(toReferenceId(" ")).toBeNull();
|
|
717
|
+
expect(toReferenceId(objectIdJSON(""))).toBeNull();
|
|
718
|
+
expect(toReferenceId(new ObjectID(""))).toBeNull();
|
|
719
|
+
expect(toReferenceId(42)).toBeNull();
|
|
720
|
+
expect(toReferenceId([STATUS_ID] as unknown as JSONValue)).toBeNull();
|
|
721
|
+
expect(toReferenceId({ notAValue: STATUS_ID })).toBeNull();
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
});
|