@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.
- package/Models/DatabaseModels/NetworkDevice.ts +44 -0
- package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
- package/Models/DatabaseModels/RunnerJob.ts +17 -2
- package/Server/API/LlmProviderAPI.ts +8 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
- package/Server/Services/NetworkDeviceLinkService.ts +338 -2
- package/Server/Services/NetworkDeviceService.ts +265 -12
- package/Server/Services/RunnerJobService.ts +24 -1
- package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
- package/Server/Types/Database/JSONColumnQuery.ts +42 -4
- package/Server/Utils/LLM/LLMService.ts +108 -19
- package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
- package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
- package/Server/Utils/SSRFProtection.ts +5 -4
- package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
- package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
- package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
- package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
- package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
- package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
- package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
- package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
- package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
- package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
- package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
- package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
- package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
- package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
- package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
- package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
- package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
- package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
- package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
- package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
- package/Tests/Types/API/URLTelScheme.test.ts +261 -0
- package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
- package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
- package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
- package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
- package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
- package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
- package/Tests/UI/Components/Button.test.tsx +279 -0
- package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
- package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
- package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
- package/Tests/UI/Components/Icon.test.tsx +57 -0
- package/Tests/UI/Components/List.test.tsx +20 -3
- package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
- package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
- package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
- package/Tests/UI/Components/Pagination.test.tsx +721 -146
- package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
- package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
- package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
- package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
- package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
- package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
- package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
- package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
- package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
- package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
- package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
- package/Types/API/Protocol.ts +9 -0
- package/Types/API/URL.ts +286 -20
- package/Types/Billing/PayAsYouGoPricing.ts +47 -0
- package/Types/CustomField/CustomFieldType.ts +28 -0
- package/Types/Monitor/MonitorType.ts +11 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
- package/Types/Runbook/RunbookStepType.ts +23 -0
- package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
- package/UI/Components/Button/Button.tsx +14 -22
- package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
- package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
- package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
- package/UI/Components/Charts/Line/LineChart.tsx +4 -2
- package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
- package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
- package/UI/Components/Dictionary/Dictionary.tsx +4 -39
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
- package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
- package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
- package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
- package/UI/Components/Pagination/Pagination.tsx +373 -328
- package/UI/Components/Pagination/PaginationUtil.ts +263 -0
- package/UI/Components/Pagination/Screenshots/README.md +15 -0
- package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
- package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
- package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
- package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
- package/UI/Components/TextArea/TextArea.tsx +3 -0
- package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
- package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
- package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
- package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
- package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
- package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
- package/Utils/API.ts +243 -36
- package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
- package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
- package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
- package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
- package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
- package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
- package/build/dist/Server/API/LlmProviderAPI.js +9 -1
- package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.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/NetworkDeviceLabelRuleEngineService.js +202 -0
- package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
- package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/RunnerJobService.js +20 -2
- package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
- package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
- package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
- package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
- package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
- package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
- package/build/dist/Server/Utils/SSRFProtection.js +5 -4
- package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
- package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
- package/build/dist/Types/API/Protocol.js +9 -0
- package/build/dist/Types/API/Protocol.js.map +1 -1
- package/build/dist/Types/API/URL.js +241 -18
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
- package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
- package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
- package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +10 -0
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
- package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
- package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
- package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
- package/build/dist/UI/Components/Button/Button.js +10 -16
- package/build/dist/UI/Components/Button/Button.js.map +1 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
- package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
- package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
- package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
- package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
- package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
- package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
- package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
- package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
- package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
- package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
- package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
- package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
- package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
- package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
- package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
- package/build/dist/Utils/API.js +175 -34
- package/build/dist/Utils/API.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
- package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
- package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { describe, expect, test } from "@jest/globals";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import SchemaMigrations from "../../../../Server/Infrastructure/Postgres/SchemaMigrations/Index";
|
|
5
|
+
import { AddDeviceRoleAndDeclaredLinkParent1787400000000 } from "../../../../Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* The migration behind #3192: NetworkDevice.deviceRole and
|
|
9
|
+
* NetworkDeviceLink.parentDeviceId.
|
|
10
|
+
*
|
|
11
|
+
* Two things are worth pinning about it, and neither is the SQL — the
|
|
12
|
+
* statements were generated rather than written, and the schema-drift job
|
|
13
|
+
* already proves they match the entities.
|
|
14
|
+
*
|
|
15
|
+
* The first is NULLABILITY, because it carries meaning here rather than
|
|
16
|
+
* just permissiveness. NULL is not "unset pending a backfill": on
|
|
17
|
+
* deviceRole it means "no override, let the classifier decide", and on
|
|
18
|
+
* parentDeviceId it means "peers, infer the direction". They are the
|
|
19
|
+
* values every existing row should hold, and a DEFAULT or a NOT NULL on
|
|
20
|
+
* either would silently restate every device and every link in every
|
|
21
|
+
* project as something an operator had chosen.
|
|
22
|
+
*
|
|
23
|
+
* The second is ORDERING. This is the newest registered migration, so it
|
|
24
|
+
* inherits the guard that used to live in
|
|
25
|
+
* EpisodeMemberNotifyIndexesMigration.test.ts: its timestamp must sort
|
|
26
|
+
* above every other. A migration generated with `generate-postgres-
|
|
27
|
+
* migration` carries a WALL-CLOCK timestamp, and the recent migrations in
|
|
28
|
+
* this repo use hand-picked round numbers that run ahead of it — so the
|
|
29
|
+
* generated file lands below several already-registered migrations unless
|
|
30
|
+
* somebody renumbers it. That is exactly what happened to this one.
|
|
31
|
+
* Whoever adds the next migration should move this test's ordering block
|
|
32
|
+
* to theirs.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
const MIGRATION_PATH: string = path.join(
|
|
36
|
+
__dirname,
|
|
37
|
+
"../../../../Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts",
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const SOURCE: string = fs.readFileSync(MIGRATION_PATH, "utf8");
|
|
41
|
+
|
|
42
|
+
interface MigrationClass {
|
|
43
|
+
name: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function timestampOf(migrationClass: MigrationClass): number | null {
|
|
47
|
+
const match: RegExpMatchArray | null = migrationClass.name.match(/(\d+)$/);
|
|
48
|
+
return match ? Number(match[1]) : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
describe("the columns it adds", () => {
|
|
52
|
+
test("NetworkDevice gains deviceRole", () => {
|
|
53
|
+
expect(SOURCE).toContain(
|
|
54
|
+
`ALTER TABLE "NetworkDevice" ADD "deviceRole" character varying(100)`,
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("NetworkDeviceLink gains parentDeviceId", () => {
|
|
59
|
+
expect(SOURCE).toContain(
|
|
60
|
+
`ALTER TABLE "NetworkDeviceLink" ADD "parentDeviceId" uuid`,
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/*
|
|
65
|
+
* See the header: NULL is a meaningful value on both, so neither may
|
|
66
|
+
* arrive with a DEFAULT or a NOT NULL.
|
|
67
|
+
*/
|
|
68
|
+
test("neither column is given a default", () => {
|
|
69
|
+
const addStatements: Array<string> = [
|
|
70
|
+
...SOURCE.matchAll(/`(ALTER TABLE [^`]*ADD "[^"]+"[^`]*)`/g),
|
|
71
|
+
].map((match: RegExpMatchArray): string => {
|
|
72
|
+
return match[1] as string;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
expect(addStatements.length).toBe(2);
|
|
76
|
+
for (const statement of addStatements) {
|
|
77
|
+
expect(statement).not.toContain("DEFAULT");
|
|
78
|
+
expect(statement).not.toContain("NOT NULL");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("the parent is indexed and cascades with the device it names", () => {
|
|
83
|
+
expect(SOURCE).toContain(
|
|
84
|
+
`CREATE INDEX "IDX_01752cd47b773df38b4a54ae53" ON "NetworkDeviceLink" ("parentDeviceId")`,
|
|
85
|
+
);
|
|
86
|
+
expect(SOURCE).toContain(
|
|
87
|
+
`FOREIGN KEY ("parentDeviceId") REFERENCES "NetworkDevice"("_id") ON DELETE CASCADE`,
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* The parent is always one of the link's own two ends, and both of those
|
|
93
|
+
* already cascade — so this cascade only ever fires alongside one of
|
|
94
|
+
* them. Anything weaker would leave a link pointing at a deleted device.
|
|
95
|
+
*/
|
|
96
|
+
test("it touches nothing beyond those two tables", () => {
|
|
97
|
+
const touchedTables: Set<string> = new Set<string>(
|
|
98
|
+
[...SOURCE.matchAll(/ALTER TABLE "(\w+)"/g)].map(
|
|
99
|
+
(match: RegExpMatchArray): string => {
|
|
100
|
+
return match[1] as string;
|
|
101
|
+
},
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
expect([...touchedTables].sort()).toEqual([
|
|
106
|
+
"NetworkDevice",
|
|
107
|
+
"NetworkDeviceLink",
|
|
108
|
+
]);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("up and down are symmetric", () => {
|
|
113
|
+
test("down drops everything up adds, and nothing else", () => {
|
|
114
|
+
const added: Array<string> = [...SOURCE.matchAll(/ADD "(\w+)"/g)].map(
|
|
115
|
+
(match: RegExpMatchArray): string => {
|
|
116
|
+
return match[1] as string;
|
|
117
|
+
},
|
|
118
|
+
);
|
|
119
|
+
const dropped: Array<string> = [
|
|
120
|
+
...SOURCE.matchAll(/DROP COLUMN "(\w+)"/g),
|
|
121
|
+
].map((match: RegExpMatchArray): string => {
|
|
122
|
+
return match[1] as string;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(added.sort()).toEqual(dropped.sort());
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("the index and the constraint are dropped too", () => {
|
|
129
|
+
expect(SOURCE).toContain(
|
|
130
|
+
`DROP INDEX "public"."IDX_01752cd47b773df38b4a54ae53"`,
|
|
131
|
+
);
|
|
132
|
+
expect(SOURCE).toContain(
|
|
133
|
+
`DROP CONSTRAINT "FK_01752cd47b773df38b4a54ae539"`,
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
/*
|
|
138
|
+
* A stray semicolon would split one queryRunner.query() into two.
|
|
139
|
+
*
|
|
140
|
+
* Trailing whitespace is tolerated on purpose: TypeORM's generator ends
|
|
141
|
+
* a CREATE INDEX with no WHERE clause in a single space, and this file
|
|
142
|
+
* is generated. Normalising it here would mean the checked-in SQL no
|
|
143
|
+
* longer matched what `npm run generate-postgres-migration` produces,
|
|
144
|
+
* and the next person to regenerate would see a spurious diff. Newlines
|
|
145
|
+
* are a different matter — one inside a statement means the template
|
|
146
|
+
* literal wrapped, and that is worth catching.
|
|
147
|
+
*/
|
|
148
|
+
test("every statement is a complete, single statement", () => {
|
|
149
|
+
for (const statement of [
|
|
150
|
+
...SOURCE.matchAll(/`((?:ALTER TABLE|CREATE INDEX|DROP INDEX)[^`]+)`/g),
|
|
151
|
+
]) {
|
|
152
|
+
expect(statement[1]).not.toContain(";");
|
|
153
|
+
expect(statement[1]).not.toContain("\n");
|
|
154
|
+
expect(statement[1]!.trimStart()).toBe(statement[1]);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("the migration runs", () => {
|
|
160
|
+
test("it is registered", () => {
|
|
161
|
+
const index: string = fs.readFileSync(
|
|
162
|
+
path.join(path.dirname(MIGRATION_PATH), "Index.ts"),
|
|
163
|
+
"utf8",
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
expect(index).toContain(
|
|
167
|
+
'from "./1787400000000-AddDeviceRoleAndDeclaredLinkParent"',
|
|
168
|
+
);
|
|
169
|
+
expect(index).toContain("AddDeviceRoleAndDeclaredLinkParent1787400000000,");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
* ...and registered for real, not just mentioned in the file: an import
|
|
174
|
+
* that never reaches the default-export array leaves the migration
|
|
175
|
+
* unregistered, and it silently never runs.
|
|
176
|
+
*/
|
|
177
|
+
test("it is in the exported migration list", () => {
|
|
178
|
+
expect(SchemaMigrations).toContain(
|
|
179
|
+
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* TypeORM records applied migrations by the `name` property, not the file
|
|
185
|
+
* name. A mismatch re-runs the migration on every boot.
|
|
186
|
+
*/
|
|
187
|
+
test("its declared name matches its class name", () => {
|
|
188
|
+
expect(new AddDeviceRoleAndDeclaredLinkParent1787400000000().name).toBe(
|
|
189
|
+
"AddDeviceRoleAndDeclaredLinkParent1787400000000",
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// The guard described in the header. Hand it to the next migration.
|
|
194
|
+
test("its timestamp sorts after every other registered migration", () => {
|
|
195
|
+
const ourTimestamp: number | null = timestampOf(
|
|
196
|
+
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(ourTimestamp).not.toBeNull();
|
|
200
|
+
|
|
201
|
+
const otherTimestamps: Array<number> = [];
|
|
202
|
+
|
|
203
|
+
for (const migrationClass of SchemaMigrations) {
|
|
204
|
+
if (migrationClass === AddDeviceRoleAndDeclaredLinkParent1787400000000) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const timestamp: number | null = timestampOf(
|
|
209
|
+
migrationClass as MigrationClass,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
if (timestamp !== null) {
|
|
213
|
+
otherTimestamps.push(timestamp);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/*
|
|
218
|
+
* Math.max() of an empty list is -Infinity, which every timestamp beats.
|
|
219
|
+
* Prove the list was actually enumerated before leaning on the maximum.
|
|
220
|
+
*/
|
|
221
|
+
expect(otherTimestamps.length).toBeGreaterThan(100);
|
|
222
|
+
|
|
223
|
+
expect(ourTimestamp).toBeGreaterThan(Math.max(...otherTimestamps));
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("it is registered last, matching that timestamp", () => {
|
|
227
|
+
expect(SchemaMigrations[SchemaMigrations.length - 1]).toBe(
|
|
228
|
+
AddDeviceRoleAndDeclaredLinkParent1787400000000,
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
/*
|
|
233
|
+
* ...and the timestamp in the class name is the one on disk. A class
|
|
234
|
+
* renamed without renaming its file (or two migrations landing on the
|
|
235
|
+
* same timestamp) leaves the ordering above asserting something that is
|
|
236
|
+
* not what actually runs.
|
|
237
|
+
*/
|
|
238
|
+
test("exactly one file on disk carries its timestamp, and it is this one", () => {
|
|
239
|
+
const directory: string = path.dirname(MIGRATION_PATH);
|
|
240
|
+
const matching: Array<string> = fs
|
|
241
|
+
.readdirSync(directory)
|
|
242
|
+
.filter((file: string): boolean => {
|
|
243
|
+
return file.startsWith("1787400000000-");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expect(matching).toEqual([
|
|
247
|
+
"1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts",
|
|
248
|
+
]);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
@@ -444,10 +444,31 @@ describe("the migration runs", () => {
|
|
|
444
444
|
);
|
|
445
445
|
});
|
|
446
446
|
|
|
447
|
-
|
|
448
|
-
|
|
447
|
+
/*
|
|
448
|
+
* Registered in timestamp order relative to whatever follows it.
|
|
449
|
+
*
|
|
450
|
+
* This asserted "it is last in the array" until a second migration was
|
|
451
|
+
* added behind it, which is a thing that happens to every migration
|
|
452
|
+
* exactly once and is not what the test was ever about. The invariant
|
|
453
|
+
* worth holding is the one the "matching its timestamp" half named:
|
|
454
|
+
* nothing registered AFTER this may carry an earlier timestamp, because
|
|
455
|
+
* the array is how a reader works out what runs when. A newly generated
|
|
456
|
+
* migration carries a wall-clock timestamp, which can easily fall below
|
|
457
|
+
* the hand-picked round numbers the recent ones use — appending it
|
|
458
|
+
* without renumbering is how the two orders drift apart.
|
|
459
|
+
*/
|
|
460
|
+
test("nothing registered after it carries an earlier timestamp", () => {
|
|
461
|
+
const position: number = SchemaMigrations.indexOf(
|
|
449
462
|
AddEpisodeMemberNotifyIndexes1787300000000,
|
|
450
463
|
);
|
|
464
|
+
expect(position).toBeGreaterThan(-1);
|
|
465
|
+
|
|
466
|
+
for (const migration of SchemaMigrations.slice(position + 1)) {
|
|
467
|
+
const timestamp: number = Number(
|
|
468
|
+
(migration.name.match(/(\d+)$/) || [])[1],
|
|
469
|
+
);
|
|
470
|
+
expect(timestamp).toBeGreaterThan(1787300000000);
|
|
471
|
+
}
|
|
451
472
|
});
|
|
452
473
|
|
|
453
474
|
/*
|
|
@@ -461,34 +482,41 @@ describe("the migration runs", () => {
|
|
|
461
482
|
});
|
|
462
483
|
|
|
463
484
|
/*
|
|
464
|
-
* Migrations execute in timestamp order,
|
|
465
|
-
* already
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
*
|
|
485
|
+
* Migrations execute in timestamp order, so one landing BELOW a migration
|
|
486
|
+
* that has already run applies out of order — and on a fresh install runs
|
|
487
|
+
* in a different order than it did in production, which is how a schema
|
|
488
|
+
* that passes drift locally still diverges between deployments.
|
|
489
|
+
*
|
|
490
|
+
* This used to read "above every OTHER registered migration", i.e. that
|
|
491
|
+
* this was the newest. That guard belongs to whichever migration is
|
|
492
|
+
* currently newest — see
|
|
493
|
+
* DeviceRoleAndDeclaredLinkParentMigration.test.ts, which now carries it
|
|
494
|
+
* — and it cannot live here, because it fails by design the moment
|
|
495
|
+
* anything lands above it. What is permanently true of this migration,
|
|
496
|
+
* and is the half that protects an existing deployment, is that nothing
|
|
497
|
+
* registered BEFORE it carries a later timestamp.
|
|
471
498
|
*/
|
|
472
|
-
test("its timestamp sorts after every
|
|
499
|
+
test("its timestamp sorts after every migration registered before it", () => {
|
|
473
500
|
const ourTimestamp: number | null = timestampOf(
|
|
474
501
|
AddEpisodeMemberNotifyIndexes1787300000000,
|
|
475
502
|
);
|
|
476
503
|
|
|
477
504
|
expect(ourTimestamp).not.toBeNull();
|
|
478
505
|
|
|
479
|
-
const
|
|
506
|
+
const position: number = SchemaMigrations.indexOf(
|
|
507
|
+
AddEpisodeMemberNotifyIndexes1787300000000,
|
|
508
|
+
);
|
|
509
|
+
expect(position).toBeGreaterThan(-1);
|
|
480
510
|
|
|
481
|
-
|
|
482
|
-
if (migrationClass === AddEpisodeMemberNotifyIndexes1787300000000) {
|
|
483
|
-
continue;
|
|
484
|
-
}
|
|
511
|
+
const earlierTimestamps: Array<number> = [];
|
|
485
512
|
|
|
513
|
+
for (const migrationClass of SchemaMigrations.slice(0, position)) {
|
|
486
514
|
const timestamp: number | null = timestampOf(
|
|
487
515
|
migrationClass as MigrationClass,
|
|
488
516
|
);
|
|
489
517
|
|
|
490
518
|
if (timestamp !== null) {
|
|
491
|
-
|
|
519
|
+
earlierTimestamps.push(timestamp);
|
|
492
520
|
}
|
|
493
521
|
}
|
|
494
522
|
|
|
@@ -497,9 +525,9 @@ describe("the migration runs", () => {
|
|
|
497
525
|
* Prove the list was actually enumerated before leaning on the maximum,
|
|
498
526
|
* or the assertion below is vacuous again.
|
|
499
527
|
*/
|
|
500
|
-
expect(
|
|
528
|
+
expect(earlierTimestamps.length).toBeGreaterThan(100);
|
|
501
529
|
|
|
502
|
-
expect(ourTimestamp).toBeGreaterThan(Math.max(...
|
|
530
|
+
expect(ourTimestamp).toBeGreaterThan(Math.max(...earlierTimestamps));
|
|
503
531
|
});
|
|
504
532
|
|
|
505
533
|
/*
|