@oneuptime/common 11.7.1 → 11.7.2

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.
Files changed (237) hide show
  1. package/Models/DatabaseModels/DashboardDomain.ts +1 -0
  2. package/Models/DatabaseModels/Incident.ts +2 -0
  3. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  4. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  5. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  6. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/Monitor.ts +1 -0
  9. package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
  10. package/Models/DatabaseModels/NetworkSite.ts +1 -0
  11. package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +1 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -0
  13. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +2 -0
  14. package/Models/DatabaseModels/Probe.ts +13 -13
  15. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  17. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  18. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
  19. package/Models/DatabaseModels/StatusPage.ts +1 -0
  20. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  21. package/Models/DatabaseModels/StatusPageDomain.ts +1 -0
  22. package/Models/DatabaseModels/WorkspaceNotificationSummary.ts +1 -0
  23. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +11 -0
  24. package/Server/API/BaseAPI.ts +17 -1
  25. package/Server/API/CommonAPI.ts +32 -0
  26. package/Server/API/MicrosoftTeamsAPI.ts +99 -2
  27. package/Server/API/ProbeAPI.ts +2 -0
  28. package/Server/API/SlackAPI.ts +62 -0
  29. package/Server/API/StatusPageAPI.ts +157 -192
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.ts +89 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.ts +61 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.ts +280 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  34. package/Server/Services/DatabaseService.ts +11 -3
  35. package/Server/Services/MonitorGroupService.ts +145 -0
  36. package/Server/Services/MonitorService.ts +231 -30
  37. package/Server/Services/ProbeService.ts +319 -16
  38. package/Server/Services/StatusPageService.ts +72 -42
  39. package/Server/Services/WorkspaceNotificationRuleService.ts +232 -2
  40. package/Server/Utils/Database/PostgresErrorTranslator.ts +131 -0
  41. package/Server/Utils/Monitor/MonitorResource.ts +88 -35
  42. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +21 -1
  43. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +158 -0
  44. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +706 -6
  45. package/Tests/Models/DatabaseModels/ProbeColumnAccessControl.test.ts +103 -0
  46. package/Tests/Server/API/BaseAPIUpdateNoOp.test.ts +135 -0
  47. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +317 -0
  48. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +228 -0
  49. package/Tests/Server/API/ProbeAPI.test.ts +6 -0
  50. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +167 -0
  51. package/Tests/Server/Services/AddHotQueryIndexesMigration.test.ts +255 -0
  52. package/Tests/Server/Services/AddHotQueryIndexesSecondPassMigration.test.ts +258 -0
  53. package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +1 -1
  54. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +121 -0
  55. package/Tests/Server/Services/HeartbeatWriteFastPathSafety.test.ts +200 -0
  56. package/Tests/Server/Services/HookFreeWriteSafetySecondPass.test.ts +181 -0
  57. package/Tests/Server/Services/MonitorGroupServiceBatchedStatuses.test.ts +513 -0
  58. package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +492 -0
  59. package/Tests/Server/Services/MonitorServiceProbeSelection.test.ts +401 -0
  60. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +453 -0
  61. package/Tests/Server/Services/ProbeAuthKeyCacheAndHeartbeat.test.ts +679 -0
  62. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +3 -3
  63. package/Tests/Server/Services/StatusPageDomainResolutionCache.test.ts +245 -0
  64. package/Tests/Server/Services/StatusPageOverviewTimelineWindow.test.ts +283 -0
  65. package/Tests/Server/Services/StatusPageServiceMcp.test.ts +17 -1
  66. package/Tests/Server/Services/StatusPageServiceMonitorGroupBatching.test.ts +331 -0
  67. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +12 -12
  68. package/Tests/Server/Services/WorkspaceNotificationRuleChats.test.ts +1390 -0
  69. package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +4 -4
  70. package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +2 -2
  71. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +1 -3
  72. package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +1 -3
  73. package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +1 -1
  74. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +5 -5
  75. package/Tests/Server/Utils/Alert/AlertPrivacyFilter.test.ts +187 -0
  76. package/Tests/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.test.ts +170 -0
  77. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +125 -0
  78. package/Tests/Server/Utils/Incident/IncidentPrivacyFilter.test.ts +264 -0
  79. package/Tests/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.test.ts +175 -0
  80. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +181 -0
  81. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +1 -1
  82. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +2 -2
  83. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +341 -0
  84. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +2175 -0
  85. package/Tests/Server/Utils/Workspace/SlackChannelsList.test.ts +585 -0
  86. package/Tests/Types/Billing/MeteredPlan.test.ts +46 -0
  87. package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +219 -1
  88. package/Tests/UI/Components/BulkUpdateForm.test.tsx +174 -0
  89. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +315 -0
  90. package/Tests/UI/Components/ModelDetailSelect.test.tsx +229 -0
  91. package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1258 -0
  92. package/Tests/UI/Components/ModelTableExportFromColumns.test.ts +153 -0
  93. package/Tests/UI/Components/MonacoLoader.test.ts +67 -0
  94. package/Tests/UI/Components/MonacoRuntime.test.ts +121 -0
  95. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +212 -3
  96. package/Tests/UI/Utils/Project.test.ts +809 -0
  97. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +360 -0
  98. package/Tests/Utils/Alerts/AlertMetricType.test.ts +143 -0
  99. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +219 -0
  100. package/Tests/Utils/Incident/IncidentMetricType.test.ts +174 -0
  101. package/Tests/Utils/Monitor/MonitorProbeSelectionUtil.test.ts +145 -0
  102. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +263 -0
  103. package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +4 -0
  104. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +25 -10
  105. package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
  106. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +63 -8
  107. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  108. package/UI/Components/CodeEditor/MonacoLoader.ts +36 -0
  109. package/UI/Components/Forms/ModelForm.tsx +41 -18
  110. package/UI/Components/ModelDetail/CardModelDetail.tsx +23 -1
  111. package/UI/Components/ModelDetail/ModelDetail.tsx +46 -1
  112. package/UI/Components/ModelTable/BaseModelTable.tsx +300 -30
  113. package/UI/Components/ModelTable/Column.ts +12 -0
  114. package/UI/Components/ModelTable/ExportFromColumns.ts +57 -0
  115. package/UI/Components/Navbar/NavBar.tsx +66 -1
  116. package/UI/Components/Table/Table.tsx +52 -13
  117. package/UI/Components/Table/Types/Column.ts +18 -0
  118. package/UI/Utils/Project.ts +214 -18
  119. package/UI/Utils/TableColumnsToCsv.ts +86 -6
  120. package/UI/esbuild-config.js +34 -0
  121. package/Utils/Monitor/MonitorProbeSelectionUtil.ts +72 -0
  122. package/build/dist/Models/DatabaseModels/DashboardDomain.js +1 -0
  123. package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
  124. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  125. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  127. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  129. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  131. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  133. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  134. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  135. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  136. package/build/dist/Models/DatabaseModels/Monitor.js +1 -0
  137. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
  139. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  140. package/build/dist/Models/DatabaseModels/NetworkSite.js +1 -0
  141. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  142. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +1 -0
  143. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -1
  144. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -0
  145. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  146. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +2 -0
  147. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  148. package/build/dist/Models/DatabaseModels/Probe.js +13 -13
  149. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  150. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  151. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  152. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  153. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  154. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  155. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  156. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
  157. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/StatusPage.js +1 -0
  159. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  161. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/StatusPageDomain.js +1 -0
  163. package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
  164. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js +1 -0
  165. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js.map +1 -1
  166. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  167. package/build/dist/Server/API/BaseAPI.js +12 -1
  168. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  169. package/build/dist/Server/API/CommonAPI.js +21 -0
  170. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  171. package/build/dist/Server/API/MicrosoftTeamsAPI.js +72 -2
  172. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  173. package/build/dist/Server/API/ProbeAPI.js +2 -0
  174. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  175. package/build/dist/Server/API/SlackAPI.js +44 -0
  176. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  177. package/build/dist/Server/API/StatusPageAPI.js +98 -152
  178. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  179. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js +36 -0
  180. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js.map +1 -0
  181. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js +26 -0
  182. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js.map +1 -0
  183. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js +254 -0
  184. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js.map +1 -0
  185. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  187. package/build/dist/Server/Services/DatabaseService.js +10 -2
  188. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  189. package/build/dist/Server/Services/MonitorGroupService.js +118 -0
  190. package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
  191. package/build/dist/Server/Services/MonitorService.js +198 -24
  192. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  193. package/build/dist/Server/Services/ProbeService.js +238 -9
  194. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  195. package/build/dist/Server/Services/StatusPageService.js +46 -39
  196. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  197. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +178 -3
  198. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  199. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +80 -0
  200. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -0
  201. package/build/dist/Server/Utils/Monitor/MonitorResource.js +67 -29
  202. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  203. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +31 -14
  204. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  205. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +117 -0
  206. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -0
  207. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +549 -7
  208. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  209. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +17 -7
  210. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  211. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +37 -11
  212. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  213. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +2 -0
  214. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  215. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +34 -0
  216. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +1 -0
  217. package/build/dist/UI/Components/Forms/ModelForm.js +37 -17
  218. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  219. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +22 -1
  220. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  221. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +31 -1
  222. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  223. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +234 -21
  224. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  225. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js +30 -0
  226. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js.map +1 -0
  227. package/build/dist/UI/Components/Navbar/NavBar.js +39 -1
  228. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  229. package/build/dist/UI/Components/Table/Table.js +31 -11
  230. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  231. package/build/dist/UI/Utils/Project.js +161 -15
  232. package/build/dist/UI/Utils/Project.js.map +1 -1
  233. package/build/dist/UI/Utils/TableColumnsToCsv.js +67 -6
  234. package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -1
  235. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js +52 -0
  236. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js.map +1 -0
  237. package/package.json +4 -3
@@ -0,0 +1,401 @@
1
+ import MonitorService from "../../../Server/Services/MonitorService";
2
+ import MonitorProbeService from "../../../Server/Services/MonitorProbeService";
3
+ import ProbeService from "../../../Server/Services/ProbeService";
4
+ import ProjectService from "../../../Server/Services/ProjectService";
5
+ import MonitorProbe from "../../../Models/DatabaseModels/MonitorProbe";
6
+ import Probe from "../../../Models/DatabaseModels/Probe";
7
+ import Project from "../../../Models/DatabaseModels/Project";
8
+ import ObjectID from "../../../Types/ObjectID";
9
+ import BadDataException from "../../../Types/Exception/BadDataException";
10
+ import { afterEach, beforeEach, describe, expect, it } from "@jest/globals";
11
+ import { getJestSpyOn } from "../../Spy";
12
+
13
+ /*
14
+ * Probe assignment at monitor-create time.
15
+ *
16
+ * Before this, every probe flagged "auto enable on new monitors" was attached
17
+ * and there was no way to say which probe should watch a given resource. The
18
+ * create form now sends the user's choice through miscDataProps; these tests
19
+ * pin the three things that matter:
20
+ *
21
+ * - no selection sent (API clients, monitor templates) still gets the old
22
+ * auto-enable defaults, unchanged,
23
+ * - a selection is honoured exactly - including an explicitly empty one,
24
+ * - ids from the browser cannot pull in another project's probes.
25
+ */
26
+
27
+ const PROJECT_ID: ObjectID = new ObjectID(
28
+ "11111111-1111-4111-8111-111111111111",
29
+ );
30
+ const MONITOR_ID: ObjectID = new ObjectID(
31
+ "22222222-2222-4222-8222-222222222222",
32
+ );
33
+ const GLOBAL_PROBE_ID: ObjectID = new ObjectID(
34
+ "33333333-3333-4333-8333-333333333333",
35
+ );
36
+ const PROJECT_PROBE_ID: ObjectID = new ObjectID(
37
+ "44444444-4444-4444-8444-444444444444",
38
+ );
39
+ const OTHER_PROJECT_PROBE_ID: ObjectID = new ObjectID(
40
+ "55555555-5555-4555-8555-555555555555",
41
+ );
42
+
43
+ type MakeProbeFunction = (id: ObjectID) => Probe;
44
+
45
+ const makeProbe: MakeProbeFunction = (id: ObjectID): Probe => {
46
+ const probe: Probe = new Probe();
47
+ probe.id = id;
48
+ return probe;
49
+ };
50
+
51
+ describe("MonitorService probe selection", () => {
52
+ let createdMonitorProbes: Array<MonitorProbe> = [];
53
+
54
+ beforeEach(() => {
55
+ createdMonitorProbes = [];
56
+
57
+ getJestSpyOn(MonitorProbeService, "create").mockImplementation(
58
+ async (createBy: any): Promise<MonitorProbe> => {
59
+ createdMonitorProbes.push(createBy.data as MonitorProbe);
60
+ return createBy.data as MonitorProbe;
61
+ },
62
+ );
63
+ });
64
+
65
+ afterEach(() => {
66
+ jest.restoreAllMocks();
67
+ });
68
+
69
+ describe("getSelectedProbeIdsFromMiscDataProps", () => {
70
+ it("returns undefined when no probes key was sent, so defaults still apply", () => {
71
+ expect(
72
+ MonitorService.getSelectedProbeIdsFromMiscDataProps(undefined),
73
+ ).toBeUndefined();
74
+
75
+ expect(
76
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({}),
77
+ ).toBeUndefined();
78
+ });
79
+
80
+ it("returns undefined when probes is not an array", () => {
81
+ expect(
82
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({
83
+ probes: GLOBAL_PROBE_ID.toString(),
84
+ }),
85
+ ).toBeUndefined();
86
+ });
87
+
88
+ it("returns an empty array for an explicitly empty selection", () => {
89
+ /*
90
+ * Distinct from undefined: the user cleared the picker, so no probes are
91
+ * wanted - falling back to defaults here would silently re-add them.
92
+ */
93
+ expect(
94
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({ probes: [] }),
95
+ ).toEqual([]);
96
+ });
97
+
98
+ it("coerces the plain strings that actually arrive on the wire into ObjectIDs", () => {
99
+ /*
100
+ * miscDataProps is not run through the model serializer, so ids reach
101
+ * the server as strings.
102
+ */
103
+ const probeIds: Array<ObjectID> | undefined =
104
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({
105
+ probes: [GLOBAL_PROBE_ID.toString(), PROJECT_PROBE_ID.toString()],
106
+ });
107
+
108
+ expect(probeIds).toHaveLength(2);
109
+ expect(probeIds![0]).toBeInstanceOf(ObjectID);
110
+ expect(
111
+ probeIds!.map((id: ObjectID) => {
112
+ return id.toString();
113
+ }),
114
+ ).toEqual([GLOBAL_PROBE_ID.toString(), PROJECT_PROBE_ID.toString()]);
115
+ });
116
+
117
+ it("deduplicates repeated ids so MonitorProbeService does not reject the second insert", () => {
118
+ const probeIds: Array<ObjectID> | undefined =
119
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({
120
+ probes: [
121
+ GLOBAL_PROBE_ID.toString(),
122
+ GLOBAL_PROBE_ID.toString(),
123
+ PROJECT_PROBE_ID.toString(),
124
+ ],
125
+ });
126
+
127
+ expect(
128
+ probeIds!.map((id: ObjectID) => {
129
+ return id.toString();
130
+ }),
131
+ ).toEqual([GLOBAL_PROBE_ID.toString(), PROJECT_PROBE_ID.toString()]);
132
+ });
133
+
134
+ it("skips empty entries", () => {
135
+ const probeIds: Array<ObjectID> | undefined =
136
+ MonitorService.getSelectedProbeIdsFromMiscDataProps({
137
+ probes: ["", null, PROJECT_PROBE_ID.toString()],
138
+ });
139
+
140
+ expect(
141
+ probeIds!.map((id: ObjectID) => {
142
+ return id.toString();
143
+ }),
144
+ ).toEqual([PROJECT_PROBE_ID.toString()]);
145
+ });
146
+ });
147
+
148
+ describe("addProbesToMonitor", () => {
149
+ it("falls back to the auto-enable defaults when nothing was selected", async () => {
150
+ const addDefaultSpy: jest.SpyInstance<any, any> = getJestSpyOn(
151
+ MonitorService,
152
+ "addDefaultProbesToMonitor",
153
+ ).mockResolvedValue(undefined);
154
+
155
+ await MonitorService.addProbesToMonitor({
156
+ projectId: PROJECT_ID,
157
+ monitorId: MONITOR_ID,
158
+ selectedProbeIds: undefined,
159
+ });
160
+
161
+ expect(addDefaultSpy).toHaveBeenCalledWith(PROJECT_ID, MONITOR_ID);
162
+ });
163
+
164
+ it("uses the explicit selection instead of the defaults when one was sent", async () => {
165
+ const addDefaultSpy: jest.SpyInstance<any, any> = getJestSpyOn(
166
+ MonitorService,
167
+ "addDefaultProbesToMonitor",
168
+ ).mockResolvedValue(undefined);
169
+
170
+ const addSelectedSpy: jest.SpyInstance<any, any> = getJestSpyOn(
171
+ MonitorService,
172
+ "addSelectedProbesToMonitor",
173
+ ).mockResolvedValue(undefined);
174
+
175
+ await MonitorService.addProbesToMonitor({
176
+ projectId: PROJECT_ID,
177
+ monitorId: MONITOR_ID,
178
+ selectedProbeIds: [PROJECT_PROBE_ID],
179
+ });
180
+
181
+ expect(addSelectedSpy).toHaveBeenCalledWith(PROJECT_ID, MONITOR_ID, [
182
+ PROJECT_PROBE_ID,
183
+ ]);
184
+ expect(addDefaultSpy).not.toHaveBeenCalled();
185
+ });
186
+
187
+ it("attaches nothing - not the defaults - for an explicitly empty selection", async () => {
188
+ const addDefaultSpy: jest.SpyInstance<any, any> = getJestSpyOn(
189
+ MonitorService,
190
+ "addDefaultProbesToMonitor",
191
+ ).mockResolvedValue(undefined);
192
+
193
+ await MonitorService.addProbesToMonitor({
194
+ projectId: PROJECT_ID,
195
+ monitorId: MONITOR_ID,
196
+ selectedProbeIds: [],
197
+ });
198
+
199
+ expect(addDefaultSpy).not.toHaveBeenCalled();
200
+ expect(createdMonitorProbes).toHaveLength(0);
201
+ });
202
+
203
+ it("rejects a missing projectId or monitorId", async () => {
204
+ await expect(
205
+ MonitorService.addProbesToMonitor({
206
+ projectId: undefined,
207
+ monitorId: MONITOR_ID,
208
+ selectedProbeIds: [],
209
+ }),
210
+ ).rejects.toThrow(BadDataException);
211
+
212
+ await expect(
213
+ MonitorService.addProbesToMonitor({
214
+ projectId: PROJECT_ID,
215
+ monitorId: null,
216
+ selectedProbeIds: [],
217
+ }),
218
+ ).rejects.toThrow(BadDataException);
219
+ });
220
+ });
221
+
222
+ describe("addSelectedProbesToMonitor", () => {
223
+ type MockProbeLookupFunction = (data: {
224
+ globalProbes: Array<Probe>;
225
+ projectProbes: Array<Probe>;
226
+ }) => void;
227
+
228
+ const mockProbeLookup: MockProbeLookupFunction = (data: {
229
+ globalProbes: Array<Probe>;
230
+ projectProbes: Array<Probe>;
231
+ }): void => {
232
+ getJestSpyOn(ProbeService, "findBy").mockImplementation(
233
+ async (findBy: any): Promise<Array<Probe>> => {
234
+ return findBy.query.isGlobalProbe === true
235
+ ? data.globalProbes
236
+ : data.projectProbes;
237
+ },
238
+ );
239
+ };
240
+
241
+ it("creates one enabled MonitorProbe per selected probe", async () => {
242
+ mockProbeLookup({
243
+ globalProbes: [makeProbe(GLOBAL_PROBE_ID)],
244
+ projectProbes: [makeProbe(PROJECT_PROBE_ID)],
245
+ });
246
+
247
+ await MonitorService.addSelectedProbesToMonitor(PROJECT_ID, MONITOR_ID, [
248
+ GLOBAL_PROBE_ID,
249
+ PROJECT_PROBE_ID,
250
+ ]);
251
+
252
+ expect(createdMonitorProbes).toHaveLength(2);
253
+
254
+ for (const monitorProbe of createdMonitorProbes) {
255
+ expect(monitorProbe.monitorId?.toString()).toEqual(
256
+ MONITOR_ID.toString(),
257
+ );
258
+ expect(monitorProbe.projectId?.toString()).toEqual(
259
+ PROJECT_ID.toString(),
260
+ );
261
+ expect(monitorProbe.isEnabled).toBe(true);
262
+ }
263
+
264
+ expect(
265
+ createdMonitorProbes.map((monitorProbe: MonitorProbe) => {
266
+ return monitorProbe.probeId?.toString();
267
+ }),
268
+ ).toEqual([GLOBAL_PROBE_ID.toString(), PROJECT_PROBE_ID.toString()]);
269
+ });
270
+
271
+ it("drops ids that are neither global nor owned by this project", async () => {
272
+ /*
273
+ * The id list comes from the browser. A probe belonging to someone
274
+ * else's project must not become a MonitorProbe row just because its id
275
+ * was posted.
276
+ */
277
+ mockProbeLookup({
278
+ globalProbes: [],
279
+ projectProbes: [makeProbe(PROJECT_PROBE_ID)],
280
+ });
281
+
282
+ await MonitorService.addSelectedProbesToMonitor(PROJECT_ID, MONITOR_ID, [
283
+ PROJECT_PROBE_ID,
284
+ OTHER_PROJECT_PROBE_ID,
285
+ ]);
286
+
287
+ expect(
288
+ createdMonitorProbes.map((monitorProbe: MonitorProbe) => {
289
+ return monitorProbe.probeId?.toString();
290
+ }),
291
+ ).toEqual([PROJECT_PROBE_ID.toString()]);
292
+ });
293
+
294
+ it("scopes the two lookups to global probes and to this project only", async () => {
295
+ const findBySpy: jest.SpyInstance<any, any> = getJestSpyOn(
296
+ ProbeService,
297
+ "findBy",
298
+ ).mockResolvedValue([]);
299
+
300
+ await MonitorService.addSelectedProbesToMonitor(PROJECT_ID, MONITOR_ID, [
301
+ PROJECT_PROBE_ID,
302
+ ]);
303
+
304
+ const queries: Array<any> = findBySpy.mock.calls.map(
305
+ (call: Array<any>) => {
306
+ return call[0].query;
307
+ },
308
+ );
309
+
310
+ expect(queries).toHaveLength(2);
311
+ expect(queries[0].isGlobalProbe).toBe(true);
312
+ expect(queries[0].projectId).toBeUndefined();
313
+ expect(queries[1].isGlobalProbe).toBe(false);
314
+ expect(queries[1].projectId).toEqual(PROJECT_ID);
315
+ });
316
+
317
+ it("does nothing at all for an empty id list", async () => {
318
+ const findBySpy: jest.SpyInstance<any, any> = getJestSpyOn(
319
+ ProbeService,
320
+ "findBy",
321
+ ).mockResolvedValue([]);
322
+
323
+ await MonitorService.addSelectedProbesToMonitor(
324
+ PROJECT_ID,
325
+ MONITOR_ID,
326
+ [],
327
+ );
328
+
329
+ expect(findBySpy).not.toHaveBeenCalled();
330
+ expect(createdMonitorProbes).toHaveLength(0);
331
+ });
332
+ });
333
+
334
+ describe("addDefaultProbesToMonitor", () => {
335
+ type MockProjectFunction = (skipGlobalProbes: boolean) => void;
336
+
337
+ const mockProject: MockProjectFunction = (
338
+ skipGlobalProbes: boolean,
339
+ ): void => {
340
+ const project: Project = new Project();
341
+ project.id = PROJECT_ID;
342
+ project.doNotAddGlobalProbesByDefaultOnNewMonitors = skipGlobalProbes;
343
+
344
+ getJestSpyOn(ProjectService, "findOneById").mockResolvedValue(project);
345
+ };
346
+
347
+ it("attaches every probe that opted in to new monitors", async () => {
348
+ mockProject(false);
349
+
350
+ getJestSpyOn(ProbeService, "findBy").mockImplementation(
351
+ async (findBy: any): Promise<Array<Probe>> => {
352
+ return findBy.query.isGlobalProbe === true
353
+ ? [makeProbe(GLOBAL_PROBE_ID)]
354
+ : [makeProbe(PROJECT_PROBE_ID)];
355
+ },
356
+ );
357
+
358
+ await MonitorService.addDefaultProbesToMonitor(PROJECT_ID, MONITOR_ID);
359
+
360
+ expect(
361
+ createdMonitorProbes.map((monitorProbe: MonitorProbe) => {
362
+ return monitorProbe.probeId?.toString();
363
+ }),
364
+ ).toEqual([GLOBAL_PROBE_ID.toString(), PROJECT_PROBE_ID.toString()]);
365
+ });
366
+
367
+ it("skips the global probe lookup entirely when the project opted out", async () => {
368
+ mockProject(true);
369
+
370
+ const findBySpy: jest.SpyInstance<any, any> = getJestSpyOn(
371
+ ProbeService,
372
+ "findBy",
373
+ ).mockResolvedValue([makeProbe(PROJECT_PROBE_ID)]);
374
+
375
+ await MonitorService.addDefaultProbesToMonitor(PROJECT_ID, MONITOR_ID);
376
+
377
+ expect(findBySpy).toHaveBeenCalledTimes(1);
378
+ expect(findBySpy.mock.calls[0]![0].query.isGlobalProbe).toBe(false);
379
+ expect(
380
+ createdMonitorProbes.map((monitorProbe: MonitorProbe) => {
381
+ return monitorProbe.probeId?.toString();
382
+ }),
383
+ ).toEqual([PROJECT_PROBE_ID.toString()]);
384
+ });
385
+
386
+ it("only asks for probes that opted in", async () => {
387
+ mockProject(false);
388
+
389
+ const findBySpy: jest.SpyInstance<any, any> = getJestSpyOn(
390
+ ProbeService,
391
+ "findBy",
392
+ ).mockResolvedValue([]);
393
+
394
+ await MonitorService.addDefaultProbesToMonitor(PROJECT_ID, MONITOR_ID);
395
+
396
+ for (const call of findBySpy.mock.calls) {
397
+ expect(call[0].query.shouldAutoEnableProbeOnNewMonitors).toBe(true);
398
+ }
399
+ });
400
+ });
401
+ });