@oneuptime/common 12.0.9 → 12.0.11

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 (262) hide show
  1. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  2. package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
  3. package/Models/DatabaseModels/RunnerJob.ts +17 -2
  4. package/Server/API/LlmProviderAPI.ts +8 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
  8. package/Server/Services/NetworkDeviceLinkService.ts +338 -2
  9. package/Server/Services/NetworkDeviceService.ts +265 -12
  10. package/Server/Services/RunnerJobService.ts +24 -1
  11. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
  12. package/Server/Types/Database/JSONColumnQuery.ts +42 -4
  13. package/Server/Utils/LLM/LLMService.ts +108 -19
  14. package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
  15. package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
  16. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
  17. package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
  18. package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
  19. package/Server/Utils/SSRFProtection.ts +5 -4
  20. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
  21. package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
  22. package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
  23. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
  24. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
  25. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
  26. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
  27. package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
  28. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
  29. package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
  30. package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
  31. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
  32. package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
  33. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
  34. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
  35. package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
  36. package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
  37. package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
  38. package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
  39. package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
  40. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
  41. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
  42. package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
  43. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
  44. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
  45. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
  46. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
  47. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
  48. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
  49. package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
  50. package/Tests/Types/API/URLTelScheme.test.ts +261 -0
  51. package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
  52. package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
  53. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
  54. package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
  55. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
  56. package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
  57. package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
  58. package/Tests/UI/Components/Button.test.tsx +279 -0
  59. package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
  60. package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
  61. package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
  62. package/Tests/UI/Components/Icon.test.tsx +57 -0
  63. package/Tests/UI/Components/List.test.tsx +20 -3
  64. package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
  65. package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
  66. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
  67. package/Tests/UI/Components/Pagination.test.tsx +721 -146
  68. package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
  69. package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
  70. package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
  71. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
  72. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
  73. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
  74. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
  75. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
  76. package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
  77. package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
  78. package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
  79. package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
  80. package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
  81. package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
  82. package/Types/API/Protocol.ts +9 -0
  83. package/Types/API/URL.ts +286 -20
  84. package/Types/Billing/PayAsYouGoPricing.ts +47 -0
  85. package/Types/CustomField/CustomFieldType.ts +28 -0
  86. package/Types/Monitor/MonitorType.ts +11 -0
  87. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  88. package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
  89. package/Types/Runbook/RunbookStepType.ts +23 -0
  90. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
  91. package/UI/Components/Button/Button.tsx +14 -22
  92. package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
  93. package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
  94. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
  95. package/UI/Components/Charts/Line/LineChart.tsx +4 -2
  96. package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
  97. package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
  98. package/UI/Components/Dictionary/Dictionary.tsx +4 -39
  99. package/UI/Components/Icon/Icon.tsx +1 -1
  100. package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
  101. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
  102. package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
  103. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
  104. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
  105. package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
  106. package/UI/Components/Pagination/Pagination.tsx +373 -328
  107. package/UI/Components/Pagination/PaginationUtil.ts +263 -0
  108. package/UI/Components/Pagination/Screenshots/README.md +15 -0
  109. package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
  110. package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
  111. package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
  112. package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
  113. package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
  114. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
  115. package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
  116. package/UI/Components/TextArea/TextArea.tsx +3 -0
  117. package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
  118. package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
  119. package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
  120. package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
  121. package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
  122. package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
  123. package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
  124. package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
  125. package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
  126. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
  127. package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
  128. package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
  129. package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
  130. package/Utils/API.ts +243 -36
  131. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
  132. package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
  133. package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
  139. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  140. package/build/dist/Server/API/LlmProviderAPI.js +9 -1
  141. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  146. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
  147. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  148. package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
  149. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
  150. package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
  151. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  152. package/build/dist/Server/Services/RunnerJobService.js +20 -2
  153. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  154. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
  155. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  156. package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
  157. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
  158. package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
  159. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  160. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
  161. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  162. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
  163. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  164. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
  165. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  166. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
  167. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  168. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
  169. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
  170. package/build/dist/Server/Utils/SSRFProtection.js +5 -4
  171. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  172. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
  173. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  174. package/build/dist/Types/API/Protocol.js +9 -0
  175. package/build/dist/Types/API/Protocol.js.map +1 -1
  176. package/build/dist/Types/API/URL.js +241 -18
  177. package/build/dist/Types/API/URL.js.map +1 -1
  178. package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
  179. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
  180. package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
  181. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  182. package/build/dist/Types/Monitor/MonitorType.js +10 -0
  183. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  184. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
  185. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
  186. package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
  187. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  188. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  189. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  190. package/build/dist/UI/Components/Button/Button.js +10 -16
  191. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
  193. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  194. package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
  195. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  196. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
  197. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  198. package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
  199. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  200. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
  201. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  202. package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
  203. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  204. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  205. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  206. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
  207. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  208. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
  209. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  210. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
  211. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
  212. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  213. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  214. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
  215. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  216. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
  217. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  218. package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
  219. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  220. package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
  221. package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
  222. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
  223. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  224. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
  225. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
  226. package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
  227. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  228. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
  229. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  230. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
  231. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
  232. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
  233. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
  234. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
  235. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
  236. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
  237. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
  238. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
  239. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
  240. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
  241. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
  242. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
  243. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
  244. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
  245. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
  246. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
  247. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
  248. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
  249. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
  250. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
  251. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
  252. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
  253. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
  254. package/build/dist/Utils/API.js +175 -34
  255. package/build/dist/Utils/API.js.map +1 -1
  256. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
  257. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  258. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
  259. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  260. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
  261. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
  262. package/package.json +1 -1
@@ -0,0 +1,556 @@
1
+ /*
2
+ * The alert creation path pulls the native isolated-vm addon through its
3
+ * template renderer (MonitorAlert → MonitorTemplateUtil → VMAPI →
4
+ * VMRunner). Nothing under test here touches the sandbox, and the
5
+ * prebuilt binary cannot always dlopen in the test environment — so stub
6
+ * the module out before anything imports it.
7
+ */
8
+ jest.mock("isolated-vm", () => {
9
+ return {};
10
+ });
11
+
12
+ import Alert from "../../../../Models/DatabaseModels/Alert";
13
+ import Incident from "../../../../Models/DatabaseModels/Incident";
14
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
15
+ import AlertService from "../../../../Server/Services/AlertService";
16
+ import CephClusterService from "../../../../Server/Services/CephClusterService";
17
+ import DockerHostService from "../../../../Server/Services/DockerHostService";
18
+ import DockerSwarmClusterService from "../../../../Server/Services/DockerSwarmClusterService";
19
+ import HostService from "../../../../Server/Services/HostService";
20
+ import IncidentService from "../../../../Server/Services/IncidentService";
21
+ import IoTFleetService from "../../../../Server/Services/IoTFleetService";
22
+ import KubernetesClusterService from "../../../../Server/Services/KubernetesClusterService";
23
+ import NetworkDeviceOwnerUserService from "../../../../Server/Services/NetworkDeviceOwnerUserService";
24
+ import PodmanHostService from "../../../../Server/Services/PodmanHostService";
25
+ import ProxmoxClusterService from "../../../../Server/Services/ProxmoxClusterService";
26
+ import ServiceService from "../../../../Server/Services/ServiceService";
27
+ import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
28
+ import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
29
+ import MonitorClusterContextUtil from "../../../../Server/Utils/Monitor/MonitorClusterContext";
30
+ import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
31
+ import Dictionary from "../../../../Types/Dictionary";
32
+ import { JSONObject } from "../../../../Types/JSON";
33
+ import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
34
+ import MonitorType from "../../../../Types/Monitor/MonitorType";
35
+ import ObjectID from "../../../../Types/ObjectID";
36
+ import { PerSeriesCriteriaMatch } from "../../../../Types/Probe/ProbeApiIngestResponse";
37
+ import ProbeMonitorResponse from "../../../../Types/Probe/ProbeMonitorResponse";
38
+ import {
39
+ afterEach,
40
+ beforeEach,
41
+ describe,
42
+ expect,
43
+ it,
44
+ jest,
45
+ } from "@jest/globals";
46
+
47
+ /*
48
+ * End-to-end cover for the reported bug, driven through the real alert
49
+ * creation path.
50
+ *
51
+ * A metric monitor grouped by `oneuptime.host.name` opened alerts titled
52
+ * after the host — "StarShip Green node prodgreen000002 CPU utilization >
53
+ * 90%" — whose Affected Resources card read "No resources affected",
54
+ * because the alert path recognised only `resource.host.name` and
55
+ * `host.name`. The host was in the inventory the whole time.
56
+ *
57
+ * These tests assert on what is handed to AlertService.create, with every
58
+ * surrounding service stubbed, and pin alert/incident parity so the two
59
+ * paths cannot drift apart again.
60
+ */
61
+
62
+ const PROJECT_ID: ObjectID = new ObjectID(
63
+ "11111111-1111-4111-8111-111111111111",
64
+ );
65
+ const MONITOR_ID: ObjectID = new ObjectID(
66
+ "22222222-2222-4222-8222-222222222222",
67
+ );
68
+ const SEVERITY_ID: ObjectID = new ObjectID(
69
+ "55555555-5555-4555-8555-555555555555",
70
+ );
71
+
72
+ function monitor(): Monitor {
73
+ const model: Monitor = new Monitor();
74
+ model._id = MONITOR_ID.toString();
75
+ model.projectId = PROJECT_ID;
76
+ model.monitorType = MonitorType.Metrics;
77
+ model.name = "StarShip Green node performance CPU";
78
+ return model;
79
+ }
80
+
81
+ function criteriaInstance(): MonitorCriteriaInstance {
82
+ const instance: MonitorCriteriaInstance = new MonitorCriteriaInstance();
83
+ instance.data!.id = "criteria-1";
84
+ instance.data!.name = "CPU utilization > 90%";
85
+ instance.data!.createIncidents = true;
86
+ instance.data!.createAlerts = true;
87
+ instance.data!.alerts = [
88
+ {
89
+ id: "alert-template-1",
90
+ title: "CPU utilization > 90%",
91
+ description: "A node breached the CPU threshold.",
92
+ alertSeverityId: SEVERITY_ID,
93
+ autoResolveAlert: false,
94
+ },
95
+ ];
96
+ instance.data!.incidents = [
97
+ {
98
+ id: "incident-template-1",
99
+ title: "CPU utilization > 90%",
100
+ description: "A node breached the CPU threshold.",
101
+ incidentSeverityId: SEVERITY_ID,
102
+ autoResolveIncident: false,
103
+ },
104
+ ];
105
+ return instance;
106
+ }
107
+
108
+ const dataToProcess: ProbeMonitorResponse = {
109
+ projectId: PROJECT_ID,
110
+ monitorId: MONITOR_ID,
111
+ monitoredAt: new Date("2026-08-13T03:33:00.000Z"),
112
+ } as unknown as ProbeMonitorResponse;
113
+
114
+ const NO_AUTO_RESOLVE: Dictionary<Array<string>> = {};
115
+
116
+ function series(
117
+ labels: JSONObject,
118
+ fingerprint: string,
119
+ ): PerSeriesCriteriaMatch {
120
+ return {
121
+ criteriaMetId: "criteria-1",
122
+ fingerprint: fingerprint,
123
+ labels: labels,
124
+ rootCause: "CPU is above 90%",
125
+ };
126
+ }
127
+
128
+ function idsOn(
129
+ relation: Array<{ _id?: string | undefined }> | undefined,
130
+ ): Array<string> {
131
+ return (relation || []).map((item: { _id?: string | undefined }): string => {
132
+ return String(item._id);
133
+ });
134
+ }
135
+
136
+ describe("Alerts link the resources their series identifies", () => {
137
+ let createdAlerts: Array<Alert> = [];
138
+ let createdIncidents: Array<Incident> = [];
139
+
140
+ /*
141
+ * Rows each resource lookup should return. Defaults to "nothing in the
142
+ * project"; a test opts a type in by setting its entry.
143
+ */
144
+ let hostRows: Array<{ _id: string }> = [];
145
+ let serviceRows: Array<{ _id: string }> = [];
146
+ let kubernetesClusterRows: Array<{ _id: string }> = [];
147
+ let dockerHostRows: Array<{ _id: string }> = [];
148
+ let podmanHostRows: Array<{ _id: string }> = [];
149
+ let proxmoxClusterRows: Array<{ _id: string }> = [];
150
+ let cephClusterRows: Array<{ _id: string }> = [];
151
+ let dockerSwarmClusterRows: Array<{ _id: string }> = [];
152
+ let iotFleetRows: Array<{ _id: string }> = [];
153
+
154
+ let clusterContext: {
155
+ proxmoxClusterIds: Array<string>;
156
+ cephClusterIds: Array<string>;
157
+ dockerSwarmClusterIds: Array<string>;
158
+ iotFleetIds: Array<string>;
159
+ };
160
+
161
+ beforeEach(() => {
162
+ createdAlerts = [];
163
+ createdIncidents = [];
164
+
165
+ hostRows = [];
166
+ serviceRows = [];
167
+ kubernetesClusterRows = [];
168
+ dockerHostRows = [];
169
+ podmanHostRows = [];
170
+ proxmoxClusterRows = [];
171
+ cephClusterRows = [];
172
+ dockerSwarmClusterRows = [];
173
+ iotFleetRows = [];
174
+
175
+ clusterContext = {
176
+ proxmoxClusterIds: [],
177
+ cephClusterIds: [],
178
+ dockerSwarmClusterIds: [],
179
+ iotFleetIds: [],
180
+ };
181
+
182
+ // No alert / incident is already open for this monitor.
183
+ jest.spyOn(AlertService, "findBy").mockResolvedValue([]);
184
+ jest.spyOn(IncidentService, "findBy").mockResolvedValue([]);
185
+
186
+ jest
187
+ .spyOn(ProjectScopedReferenceValidator, "isUsableInProject")
188
+ .mockResolvedValue(true);
189
+
190
+ jest
191
+ .spyOn(MonitorClusterContextUtil, "resolveClusterContextForMonitor")
192
+ .mockImplementation(async () => {
193
+ return clusterContext;
194
+ });
195
+
196
+ jest
197
+ .spyOn(NetworkDeviceOwnerUserService, "getDeviceOwnersForMonitor")
198
+ .mockResolvedValue({ ownerUserIds: [], ownerTeamIds: [] });
199
+
200
+ /*
201
+ * The inventory lookups the linker runs. Each returns whatever the
202
+ * test staged, so the assertions are about which relation the ids
203
+ * land on — not about the database.
204
+ */
205
+ jest.spyOn(HostService, "findBy").mockImplementation(async () => {
206
+ return hostRows as never;
207
+ });
208
+ jest.spyOn(ServiceService, "findBy").mockImplementation(async () => {
209
+ return serviceRows as never;
210
+ });
211
+ jest
212
+ .spyOn(KubernetesClusterService, "findBy")
213
+ .mockImplementation(async () => {
214
+ return kubernetesClusterRows as never;
215
+ });
216
+ jest.spyOn(DockerHostService, "findBy").mockImplementation(async () => {
217
+ return dockerHostRows as never;
218
+ });
219
+ jest.spyOn(PodmanHostService, "findBy").mockImplementation(async () => {
220
+ return podmanHostRows as never;
221
+ });
222
+ jest.spyOn(ProxmoxClusterService, "findBy").mockImplementation(async () => {
223
+ return proxmoxClusterRows as never;
224
+ });
225
+ jest.spyOn(CephClusterService, "findBy").mockImplementation(async () => {
226
+ return cephClusterRows as never;
227
+ });
228
+ jest
229
+ .spyOn(DockerSwarmClusterService, "findBy")
230
+ .mockImplementation(async () => {
231
+ return dockerSwarmClusterRows as never;
232
+ });
233
+ jest.spyOn(IoTFleetService, "findBy").mockImplementation(async () => {
234
+ return iotFleetRows as never;
235
+ });
236
+
237
+ jest
238
+ .spyOn(AlertService, "create")
239
+ .mockImplementation(async (createBy: unknown): Promise<Alert> => {
240
+ const alert: Alert = (createBy as { data: Alert }).data;
241
+ createdAlerts.push(alert);
242
+ alert._id = new ObjectID(
243
+ "77777777-7777-4777-8777-777777777777",
244
+ ).toString();
245
+ return alert;
246
+ });
247
+
248
+ jest
249
+ .spyOn(IncidentService, "create")
250
+ .mockImplementation(async (createBy: unknown): Promise<Incident> => {
251
+ const incident: Incident = (createBy as { data: Incident }).data;
252
+ createdIncidents.push(incident);
253
+ incident._id = new ObjectID(
254
+ "66666666-6666-4666-8666-666666666666",
255
+ ).toString();
256
+ return incident;
257
+ });
258
+
259
+ jest.spyOn(AlertService, "addOwners").mockResolvedValue(undefined);
260
+ jest.spyOn(IncidentService, "addOwners").mockResolvedValue(undefined);
261
+ });
262
+
263
+ afterEach(() => {
264
+ jest.restoreAllMocks();
265
+ });
266
+
267
+ it("links the host when the series is grouped by oneuptime.host.name", async () => {
268
+ // The exact shape of the reported alert.
269
+ hostRows = [{ _id: "host-prodgreen000002" }];
270
+
271
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
272
+ criteriaInstance: criteriaInstance(),
273
+ monitor: monitor(),
274
+ dataToProcess: dataToProcess,
275
+ rootCause: "CPU is above 90%",
276
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
277
+ matchesPerSeries: [
278
+ series({ "oneuptime.host.name": "prodgreen000002" }, "fp-1"),
279
+ ],
280
+ props: {},
281
+ });
282
+
283
+ expect(createdAlerts).toHaveLength(1);
284
+ expect(idsOn(createdAlerts[0]!.hosts)).toEqual(["host-prodgreen000002"]);
285
+ });
286
+
287
+ it("keeps the raw series labels on the alert", async () => {
288
+ /*
289
+ * The "Affected Resource" key/value card reads seriesLabels straight
290
+ * off the alert; linking must not disturb it.
291
+ */
292
+ hostRows = [{ _id: "host-1" }];
293
+
294
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
295
+ criteriaInstance: criteriaInstance(),
296
+ monitor: monitor(),
297
+ dataToProcess: dataToProcess,
298
+ rootCause: "CPU is above 90%",
299
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
300
+ matchesPerSeries: [
301
+ series({ "oneuptime.host.name": "prodgreen000002" }, "fp-1"),
302
+ ],
303
+ props: {},
304
+ });
305
+
306
+ expect(createdAlerts[0]!.seriesLabels).toEqual({
307
+ "oneuptime.host.name": "prodgreen000002",
308
+ });
309
+ });
310
+
311
+ it("links every resource type one series names", async () => {
312
+ hostRows = [{ _id: "host-1" }];
313
+ serviceRows = [{ _id: "service-1" }];
314
+ kubernetesClusterRows = [{ _id: "cluster-1" }];
315
+ dockerHostRows = [{ _id: "docker-1" }];
316
+ podmanHostRows = [{ _id: "podman-1" }];
317
+ proxmoxClusterRows = [{ _id: "pve-1" }];
318
+ cephClusterRows = [{ _id: "ceph-1" }];
319
+ dockerSwarmClusterRows = [{ _id: "swarm-1" }];
320
+ iotFleetRows = [{ _id: "fleet-1" }];
321
+
322
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
323
+ criteriaInstance: criteriaInstance(),
324
+ monitor: monitor(),
325
+ dataToProcess: dataToProcess,
326
+ rootCause: "CPU is above 90%",
327
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
328
+ matchesPerSeries: [
329
+ series(
330
+ {
331
+ "oneuptime.host.name": "web-1",
332
+ "oneuptime.service.name": "checkout",
333
+ "k8s.cluster.name": "prod",
334
+ "oneuptime.docker.host.name": "docker-box",
335
+ "oneuptime.podman.host.name": "podman-box",
336
+ "proxmox.cluster.name": "pve",
337
+ "ceph.cluster.name": "ceph",
338
+ "docker.swarm.cluster.name": "swarm",
339
+ "iot.fleet.name": "fleet",
340
+ },
341
+ "fp-1",
342
+ ),
343
+ ],
344
+ props: {},
345
+ });
346
+
347
+ const alert: Alert = createdAlerts[0]!;
348
+
349
+ expect(idsOn(alert.hosts)).toEqual(["host-1"]);
350
+ expect(idsOn(alert.services)).toEqual(["service-1"]);
351
+ expect(idsOn(alert.kubernetesClusters)).toEqual(["cluster-1"]);
352
+ expect(idsOn(alert.dockerHosts)).toEqual(["docker-1"]);
353
+ expect(idsOn(alert.podmanHosts)).toEqual(["podman-1"]);
354
+ expect(idsOn(alert.proxmoxClusters)).toEqual(["pve-1"]);
355
+ expect(idsOn(alert.cephClusters)).toEqual(["ceph-1"]);
356
+ expect(idsOn(alert.dockerSwarmClusters)).toEqual(["swarm-1"]);
357
+ expect(idsOn(alert.iotFleets)).toEqual(["fleet-1"]);
358
+ });
359
+
360
+ it("gives each series its own resource, with no cross-contamination", async () => {
361
+ /*
362
+ * One evaluation, two breaching hosts, two alerts. Each must carry
363
+ * only its own host — the loop reuses nothing between iterations.
364
+ */
365
+ const hostByName: Record<string, string> = {
366
+ prodgreen000002: "host-2",
367
+ prodgreen000007: "host-7",
368
+ };
369
+
370
+ jest.spyOn(HostService, "findBy").mockImplementation((async (
371
+ args: unknown,
372
+ ): Promise<Array<{ _id: string | undefined }>> => {
373
+ const query: JSONObject = (args as { query: JSONObject }).query;
374
+ const includes: { values?: Array<string> } = query["hostIdentifier"] as {
375
+ values?: Array<string>;
376
+ };
377
+ const name: string = String((includes.values || [])[0]);
378
+ return [{ _id: hostByName[name] }];
379
+ }) as never);
380
+
381
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
382
+ criteriaInstance: criteriaInstance(),
383
+ monitor: monitor(),
384
+ dataToProcess: dataToProcess,
385
+ rootCause: "CPU is above 90%",
386
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
387
+ matchesPerSeries: [
388
+ series({ "oneuptime.host.name": "prodgreen000002" }, "fp-1"),
389
+ series({ "oneuptime.host.name": "prodgreen000007" }, "fp-2"),
390
+ ],
391
+ props: {},
392
+ });
393
+
394
+ expect(createdAlerts).toHaveLength(2);
395
+ expect(idsOn(createdAlerts[0]!.hosts)).toEqual(["host-2"]);
396
+ expect(idsOn(createdAlerts[1]!.hosts)).toEqual(["host-7"]);
397
+ });
398
+
399
+ it("links nothing, and still opens the alert, for an ungrouped monitor", async () => {
400
+ /*
401
+ * A whole-monitor alert has no series and therefore no resource
402
+ * identity. It must not inherit one, and it must still be created.
403
+ */
404
+ hostRows = [{ _id: "host-1" }];
405
+
406
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
407
+ criteriaInstance: criteriaInstance(),
408
+ monitor: monitor(),
409
+ dataToProcess: dataToProcess,
410
+ rootCause: "CPU is above 90%",
411
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
412
+ props: {},
413
+ });
414
+
415
+ expect(createdAlerts).toHaveLength(1);
416
+ expect(createdAlerts[0]!.hosts).toBeUndefined();
417
+ expect(HostService.findBy).not.toHaveBeenCalled();
418
+ });
419
+
420
+ it("merges the monitor's step-config cluster with the one the series names", async () => {
421
+ /*
422
+ * The alert path used to ASSIGN the step-config clusters over
423
+ * whatever was already there. With both paths now able to resolve a
424
+ * Proxmox cluster, an assignment would drop one of them.
425
+ */
426
+ proxmoxClusterRows = [{ _id: "pve-from-label" }];
427
+ clusterContext = {
428
+ proxmoxClusterIds: ["pve-from-step-config"],
429
+ cephClusterIds: [],
430
+ dockerSwarmClusterIds: [],
431
+ iotFleetIds: [],
432
+ };
433
+
434
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
435
+ criteriaInstance: criteriaInstance(),
436
+ monitor: monitor(),
437
+ dataToProcess: dataToProcess,
438
+ rootCause: "CPU is above 90%",
439
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
440
+ matchesPerSeries: [series({ "proxmox.cluster.name": "pve" }, "fp-1")],
441
+ props: {},
442
+ });
443
+
444
+ expect(idsOn(createdAlerts[0]!.proxmoxClusters).sort()).toEqual([
445
+ "pve-from-label",
446
+ "pve-from-step-config",
447
+ ]);
448
+ });
449
+
450
+ it("still attaches the step-config cluster to an ungrouped alert", async () => {
451
+ clusterContext = {
452
+ proxmoxClusterIds: [],
453
+ cephClusterIds: ["ceph-1"],
454
+ dockerSwarmClusterIds: [],
455
+ iotFleetIds: [],
456
+ };
457
+
458
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
459
+ criteriaInstance: criteriaInstance(),
460
+ monitor: monitor(),
461
+ dataToProcess: dataToProcess,
462
+ rootCause: "Ceph health is in error",
463
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
464
+ props: {},
465
+ });
466
+
467
+ expect(idsOn(createdAlerts[0]!.cephClusters)).toEqual(["ceph-1"]);
468
+ });
469
+
470
+ it("leaves the alert unlinked when the resource is not in this project", async () => {
471
+ // The lookup is project-scoped, so an unknown host resolves to nothing.
472
+ hostRows = [];
473
+
474
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
475
+ criteriaInstance: criteriaInstance(),
476
+ monitor: monitor(),
477
+ dataToProcess: dataToProcess,
478
+ rootCause: "CPU is above 90%",
479
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
480
+ matchesPerSeries: [
481
+ series({ "oneuptime.host.name": "elsewhere" }, "fp-1"),
482
+ ],
483
+ props: {},
484
+ });
485
+
486
+ expect(createdAlerts).toHaveLength(1);
487
+ expect(createdAlerts[0]!.hosts).toBeUndefined();
488
+ });
489
+
490
+ it("scopes the inventory lookup to the monitor's project", async () => {
491
+ hostRows = [{ _id: "host-1" }];
492
+
493
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
494
+ criteriaInstance: criteriaInstance(),
495
+ monitor: monitor(),
496
+ dataToProcess: dataToProcess,
497
+ rootCause: "CPU is above 90%",
498
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
499
+ matchesPerSeries: [series({ "oneuptime.host.name": "web-1" }, "fp-1")],
500
+ props: {},
501
+ });
502
+
503
+ const call: { query: JSONObject } = (
504
+ HostService.findBy as unknown as {
505
+ mock: { calls: Array<Array<{ query: JSONObject }>> };
506
+ }
507
+ ).mock.calls[0]![0]!;
508
+
509
+ expect(call.query["projectId"]).toBe(PROJECT_ID);
510
+ });
511
+
512
+ it("links an incident and an alert from the same series identically", async () => {
513
+ /*
514
+ * The parity that keeps the two creation paths honest. Before the
515
+ * shared linker, the incident here linked the host and the alert did
516
+ * not.
517
+ */
518
+ hostRows = [{ _id: "host-1" }];
519
+ serviceRows = [{ _id: "service-1" }];
520
+
521
+ const labels: JSONObject = {
522
+ "oneuptime.host.name": "prodgreen000002",
523
+ "oneuptime.service.name": "checkout",
524
+ };
525
+
526
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
527
+ criteriaInstance: criteriaInstance(),
528
+ monitor: monitor(),
529
+ dataToProcess: dataToProcess,
530
+ rootCause: "CPU is above 90%",
531
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
532
+ matchesPerSeries: [series(labels, "fp-1")],
533
+ props: {},
534
+ });
535
+
536
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
537
+ criteriaInstance: criteriaInstance(),
538
+ monitor: monitor(),
539
+ dataToProcess: dataToProcess,
540
+ rootCause: "CPU is above 90%",
541
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
542
+ matchesPerSeries: [series(labels, "fp-1")],
543
+ props: {},
544
+ });
545
+
546
+ expect(createdAlerts).toHaveLength(1);
547
+ expect(createdIncidents).toHaveLength(1);
548
+
549
+ expect(idsOn(createdAlerts[0]!.hosts)).toEqual(
550
+ idsOn(createdIncidents[0]!.hosts),
551
+ );
552
+ expect(idsOn(createdAlerts[0]!.services)).toEqual(
553
+ idsOn(createdIncidents[0]!.services),
554
+ );
555
+ });
556
+ });