@oneuptime/common 12.0.29 → 12.0.30
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/Index.ts +11 -0
- package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
- package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
- package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
- package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
- package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
- package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
- package/Server/API/OnCallCalendarAPI.ts +2194 -0
- package/Server/EnvironmentConfig.ts +138 -0
- package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
- package/Server/Services/Index.ts +12 -0
- package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
- package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
- package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
- package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
- package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
- package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
- package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
- package/Server/Services/TeamMemberService.ts +489 -1
- package/Server/Services/TeamService.ts +50 -0
- package/Server/Services/UserNotificationSettingService.ts +44 -1
- package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
- package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
- package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
- package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
- package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
- package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
- package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
- package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
- package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
- package/Server/Utils/Response.ts +134 -0
- package/Server/Utils/StartServer.ts +10 -0
- package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
- package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
- package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
- package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
- package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
- package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
- package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
- package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
- package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
- package/Tests/Server/API/Helpers.ts +8 -0
- package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
- package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
- package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
- package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +369 -0
- package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
- package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
- package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
- package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
- package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
- package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
- package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
- package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
- package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
- package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
- package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
- package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
- package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
- package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
- package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
- package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
- package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
- package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
- package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
- package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
- package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
- package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
- package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
- package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
- package/Types/Calendar/ICalendar.ts +442 -0
- package/Types/Email/EmailTemplateType.ts +2 -0
- package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
- package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
- package/Types/OnCallDutyPolicy/Layer.ts +190 -35
- package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
- package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
- package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
- package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
- package/build/dist/Models/DatabaseModels/Index.js +11 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
- package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
- package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
- package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
- package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
- package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +102 -0
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
- package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.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/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
- package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
- package/build/dist/Server/Services/Index.js +12 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
- package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
- package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
- package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
- package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/TeamMemberService.js +396 -1
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +43 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
- package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
- package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
- package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
- package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
- package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
- package/build/dist/Server/Utils/Response.js +97 -0
- package/build/dist/Server/Utils/Response.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +9 -1
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
- package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
- package/build/dist/Types/Calendar/ICalendar.js +290 -0
- package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +2 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
- package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
- package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
- package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
- package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
- package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
- package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
- package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { AddOnCallCalendarFeeds1790400000000 } from "../../../../Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds";
|
|
2
|
+
import SchemaMigrations from "../../../../Server/Infrastructure/Postgres/SchemaMigrations/Index";
|
|
3
|
+
import { MigrationInterface, QueryRunner } from "typeorm";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { beforeAll, describe, expect, test } from "@jest/globals";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* The migration was generated by TypeORM against a fully migrated throwaway
|
|
10
|
+
* database, so the SQL itself is not hand-written - but what it contains is
|
|
11
|
+
* still worth pinning: that it creates exactly the five tables and the one
|
|
12
|
+
* column this feature adds and nothing else (a generator pointed at a
|
|
13
|
+
* drifted database happily emits DROP TABLE for half the schema), that the
|
|
14
|
+
* uniqueness rules the services rely on exist at the database, that rows
|
|
15
|
+
* cascade away with the things they belong to, and that down() undoes all of
|
|
16
|
+
* it.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const MIGRATION_NAME: string = "AddOnCallCalendarFeeds1790400000000";
|
|
20
|
+
|
|
21
|
+
const NEW_TABLES: Array<string> = [
|
|
22
|
+
"UserOnCallCalendarFeed",
|
|
23
|
+
"OnCallDutyPolicyScheduleCalendarFeed",
|
|
24
|
+
"ProjectOnCallCalendarFeed",
|
|
25
|
+
"UserOnCallShiftReminder",
|
|
26
|
+
"UserOnCallShiftReminderLog",
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const FEED_TABLES: Array<string> = [
|
|
30
|
+
"UserOnCallCalendarFeed",
|
|
31
|
+
"OnCallDutyPolicyScheduleCalendarFeed",
|
|
32
|
+
"ProjectOnCallCalendarFeed",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
type MigrationClass = new () => MigrationInterface;
|
|
36
|
+
|
|
37
|
+
async function run(direction: "up" | "down"): Promise<Array<string>> {
|
|
38
|
+
const queries: Array<string> = [];
|
|
39
|
+
|
|
40
|
+
const runner: QueryRunner = {
|
|
41
|
+
query: async (sql: string): Promise<void> => {
|
|
42
|
+
queries.push(sql);
|
|
43
|
+
},
|
|
44
|
+
} as unknown as QueryRunner;
|
|
45
|
+
|
|
46
|
+
const migration: AddOnCallCalendarFeeds1790400000000 =
|
|
47
|
+
new AddOnCallCalendarFeeds1790400000000();
|
|
48
|
+
|
|
49
|
+
if (direction === "up") {
|
|
50
|
+
await migration.up(runner);
|
|
51
|
+
} else {
|
|
52
|
+
await migration.down(runner);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return queries;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function createTableStatement(queries: Array<string>, table: string): string {
|
|
59
|
+
const statement: string | undefined = queries.find((sql: string) => {
|
|
60
|
+
return sql.startsWith(`CREATE TABLE "${table}" (`);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (!statement) {
|
|
64
|
+
throw new Error(`No CREATE TABLE for ${table}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return statement;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// "IDX_..." index names created in up(); the same names must be dropped in down().
|
|
71
|
+
function indexNames(queries: Array<string>): Array<string> {
|
|
72
|
+
return queries
|
|
73
|
+
.map((sql: string) => {
|
|
74
|
+
const match: RegExpMatchArray | null = sql.match(
|
|
75
|
+
/CREATE (?:UNIQUE )?INDEX "([^"]+)"/,
|
|
76
|
+
);
|
|
77
|
+
return match ? match[1]! : null;
|
|
78
|
+
})
|
|
79
|
+
.filter((name: string | null): name is string => {
|
|
80
|
+
return name !== null;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Every table name a statement touches, in any position.
|
|
85
|
+
function tablesMentioned(sql: string): Array<string> {
|
|
86
|
+
return [
|
|
87
|
+
...new Set(
|
|
88
|
+
[...sql.matchAll(/(?:TABLE|ON|REFERENCES) "([A-Za-z]+)"/g)].map(
|
|
89
|
+
(match: RegExpMatchArray) => {
|
|
90
|
+
return match[1]!;
|
|
91
|
+
},
|
|
92
|
+
),
|
|
93
|
+
),
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let up: Array<string> = [];
|
|
98
|
+
let down: Array<string> = [];
|
|
99
|
+
|
|
100
|
+
beforeAll(async () => {
|
|
101
|
+
up = await run("up");
|
|
102
|
+
down = await run("down");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("AddOnCallCalendarFeeds migration", () => {
|
|
106
|
+
test("names itself after its timestamp, in the class and the recorded name", () => {
|
|
107
|
+
const migration: AddOnCallCalendarFeeds1790400000000 =
|
|
108
|
+
new AddOnCallCalendarFeeds1790400000000();
|
|
109
|
+
|
|
110
|
+
expect(AddOnCallCalendarFeeds1790400000000.name).toBe(MIGRATION_NAME);
|
|
111
|
+
expect(migration.name).toBe(MIGRATION_NAME);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("is registered LAST, above every timestamp already registered", () => {
|
|
115
|
+
const registered: Array<MigrationClass> =
|
|
116
|
+
SchemaMigrations as Array<MigrationClass>;
|
|
117
|
+
|
|
118
|
+
expect(registered[registered.length - 1]).toBe(
|
|
119
|
+
AddOnCallCalendarFeeds1790400000000,
|
|
120
|
+
);
|
|
121
|
+
expect(
|
|
122
|
+
registered.filter((migration: MigrationClass) => {
|
|
123
|
+
return migration === AddOnCallCalendarFeeds1790400000000;
|
|
124
|
+
}),
|
|
125
|
+
).toHaveLength(1);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("is backed by exactly one file carrying the same timestamp", () => {
|
|
129
|
+
const directory: string = path.join(
|
|
130
|
+
__dirname,
|
|
131
|
+
"../../../../Server/Infrastructure/Postgres/SchemaMigrations",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const files: Array<string> = fs
|
|
135
|
+
.readdirSync(directory)
|
|
136
|
+
.filter((file: string) => {
|
|
137
|
+
return file.startsWith("1790400000000-");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(files).toEqual(["1790400000000-AddOnCallCalendarFeeds.ts"]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
test("creates exactly the five new tables", () => {
|
|
144
|
+
const created: Array<string> = up
|
|
145
|
+
.map((sql: string) => {
|
|
146
|
+
const match: RegExpMatchArray | null = sql.match(
|
|
147
|
+
/^CREATE TABLE "([A-Za-z]+)"/,
|
|
148
|
+
);
|
|
149
|
+
return match ? match[1]! : null;
|
|
150
|
+
})
|
|
151
|
+
.filter((name: string | null): name is string => {
|
|
152
|
+
return name !== null;
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(created.sort()).toEqual([...NEW_TABLES].sort());
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("adds shiftConfigVersion to OnCallDutyPolicySchedule as NOT NULL DEFAULT 0", () => {
|
|
159
|
+
const statements: Array<string> = up.filter((sql: string) => {
|
|
160
|
+
return sql.startsWith('ALTER TABLE "OnCallDutyPolicySchedule"');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
expect(statements).toHaveLength(1);
|
|
164
|
+
expect(statements[0]).toMatch(
|
|
165
|
+
/^ALTER TABLE "OnCallDutyPolicySchedule" ADD "shiftConfigVersion" integer NOT NULL DEFAULT '?0'?$/,
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("touches nothing outside the feature (no pre-existing drift smuggled in)", () => {
|
|
170
|
+
const allowed: Set<string> = new Set<string>([
|
|
171
|
+
...NEW_TABLES,
|
|
172
|
+
"OnCallDutyPolicySchedule",
|
|
173
|
+
"Project",
|
|
174
|
+
"User",
|
|
175
|
+
]);
|
|
176
|
+
|
|
177
|
+
for (const sql of [...up, ...down]) {
|
|
178
|
+
for (const table of tablesMentioned(sql)) {
|
|
179
|
+
expect({
|
|
180
|
+
sql: sql.slice(0, 80),
|
|
181
|
+
table,
|
|
182
|
+
allowed: allowed.has(table),
|
|
183
|
+
}).toEqual({ sql: sql.slice(0, 80), table, allowed: true });
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/*
|
|
187
|
+
* Project / User / the schedule only ever appear as FK targets or
|
|
188
|
+
* as the one ALTER above - never as a table being created/dropped.
|
|
189
|
+
*/
|
|
190
|
+
expect(sql).not.toMatch(/^(CREATE|DROP) TABLE "(Project|User)"/);
|
|
191
|
+
expect(sql).not.toMatch(/^DROP TABLE "OnCallDutyPolicySchedule"/);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test.each(FEED_TABLES)(
|
|
196
|
+
"%s stores a NOT NULL, UNIQUE token hash and a nullable encrypted token",
|
|
197
|
+
(table: string) => {
|
|
198
|
+
const statement: string = createTableStatement(up, table);
|
|
199
|
+
|
|
200
|
+
expect(statement).toMatch(
|
|
201
|
+
/"tokenHash" character varying\(100\) NOT NULL/,
|
|
202
|
+
);
|
|
203
|
+
expect(statement).toMatch(/UNIQUE \("tokenHash"\)/);
|
|
204
|
+
expect(statement).toMatch(/"token" text,/);
|
|
205
|
+
expect(statement).toMatch(
|
|
206
|
+
/"previousTokenHash" character varying\(100\),/,
|
|
207
|
+
);
|
|
208
|
+
expect(statement).toMatch(
|
|
209
|
+
/"previousTokenExpiresAt" TIMESTAMP WITH TIME ZONE,/,
|
|
210
|
+
);
|
|
211
|
+
expect(statement).toMatch(/"isEnabled" boolean NOT NULL DEFAULT true/);
|
|
212
|
+
expect(statement).toMatch(/"pastDays" integer NOT NULL DEFAULT '?2'?/);
|
|
213
|
+
expect(statement).toMatch(/"futureDays" integer NOT NULL DEFAULT '?90'?/);
|
|
214
|
+
expect(statement).toMatch(/"fetchCount" integer NOT NULL DEFAULT '?0'?/);
|
|
215
|
+
expect(statement).toMatch(
|
|
216
|
+
/"lastRenderTruncated" boolean NOT NULL DEFAULT false/,
|
|
217
|
+
);
|
|
218
|
+
},
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
test("indexes previousTokenHash on every feed table (the grace-period lookup)", () => {
|
|
222
|
+
for (const table of FEED_TABLES) {
|
|
223
|
+
expect(
|
|
224
|
+
up.some((sql: string) => {
|
|
225
|
+
return new RegExp(
|
|
226
|
+
`^CREATE INDEX "IDX_[0-9a-f]+" ON "${table}" \\("previousTokenHash"\\) $`,
|
|
227
|
+
).test(sql);
|
|
228
|
+
}),
|
|
229
|
+
).toBe(true);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("creates the uniqueness rules the services rely on", () => {
|
|
234
|
+
const uniqueIndexes: Array<string> = up.filter((sql: string) => {
|
|
235
|
+
return sql.startsWith("CREATE UNIQUE INDEX");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const expected: Array<[string, string]> = [
|
|
239
|
+
["UserOnCallCalendarFeed", '("projectId", "userId")'],
|
|
240
|
+
[
|
|
241
|
+
"OnCallDutyPolicyScheduleCalendarFeed",
|
|
242
|
+
'("onCallDutyPolicyScheduleId")',
|
|
243
|
+
],
|
|
244
|
+
["ProjectOnCallCalendarFeed", '("projectId")'],
|
|
245
|
+
[
|
|
246
|
+
"UserOnCallShiftReminder",
|
|
247
|
+
'("projectId", "userId", "minutesBeforeShift")',
|
|
248
|
+
],
|
|
249
|
+
[
|
|
250
|
+
"UserOnCallShiftReminderLog",
|
|
251
|
+
'("userId", "onCallDutyPolicyScheduleId", "shiftStartsAt", "minutesBeforeShift", "kind")',
|
|
252
|
+
],
|
|
253
|
+
];
|
|
254
|
+
|
|
255
|
+
for (const [table, columns] of expected) {
|
|
256
|
+
expect(
|
|
257
|
+
uniqueIndexes.some((sql: string) => {
|
|
258
|
+
return sql.includes(`ON "${table}" ${columns}`);
|
|
259
|
+
}),
|
|
260
|
+
).toBe(true);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
expect(uniqueIndexes).toHaveLength(expected.length);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
test("rows cascade away with their project, user and schedule; creators are kept informationally", () => {
|
|
267
|
+
const cascades: Array<[string, string, string]> = [
|
|
268
|
+
["UserOnCallCalendarFeed", "projectId", "Project"],
|
|
269
|
+
["UserOnCallCalendarFeed", "userId", "User"],
|
|
270
|
+
["OnCallDutyPolicyScheduleCalendarFeed", "projectId", "Project"],
|
|
271
|
+
[
|
|
272
|
+
"OnCallDutyPolicyScheduleCalendarFeed",
|
|
273
|
+
"onCallDutyPolicyScheduleId",
|
|
274
|
+
"OnCallDutyPolicySchedule",
|
|
275
|
+
],
|
|
276
|
+
["ProjectOnCallCalendarFeed", "projectId", "Project"],
|
|
277
|
+
["UserOnCallShiftReminder", "projectId", "Project"],
|
|
278
|
+
["UserOnCallShiftReminder", "userId", "User"],
|
|
279
|
+
["UserOnCallShiftReminderLog", "projectId", "Project"],
|
|
280
|
+
["UserOnCallShiftReminderLog", "userId", "User"],
|
|
281
|
+
[
|
|
282
|
+
"UserOnCallShiftReminderLog",
|
|
283
|
+
"onCallDutyPolicyScheduleId",
|
|
284
|
+
"OnCallDutyPolicySchedule",
|
|
285
|
+
],
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
for (const [table, column, target] of cascades) {
|
|
289
|
+
expect(
|
|
290
|
+
up.some((sql: string) => {
|
|
291
|
+
return (
|
|
292
|
+
sql.startsWith(`ALTER TABLE "${table}" ADD CONSTRAINT`) &&
|
|
293
|
+
sql.includes(
|
|
294
|
+
`FOREIGN KEY ("${column}") REFERENCES "${target}"("_id") ON DELETE CASCADE`,
|
|
295
|
+
)
|
|
296
|
+
);
|
|
297
|
+
}),
|
|
298
|
+
).toBe(true);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
for (const table of [
|
|
302
|
+
"OnCallDutyPolicyScheduleCalendarFeed",
|
|
303
|
+
"ProjectOnCallCalendarFeed",
|
|
304
|
+
]) {
|
|
305
|
+
expect(
|
|
306
|
+
up.some((sql: string) => {
|
|
307
|
+
return (
|
|
308
|
+
sql.startsWith(`ALTER TABLE "${table}" ADD CONSTRAINT`) &&
|
|
309
|
+
sql.includes(
|
|
310
|
+
'FOREIGN KEY ("createdByUserId") REFERENCES "User"("_id") ON DELETE SET NULL',
|
|
311
|
+
)
|
|
312
|
+
);
|
|
313
|
+
}),
|
|
314
|
+
).toBe(true);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("the reminder log's key columns are NOT NULL and its lead defaults to 0", () => {
|
|
319
|
+
const statement: string = createTableStatement(
|
|
320
|
+
up,
|
|
321
|
+
"UserOnCallShiftReminderLog",
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
expect(statement).toMatch(
|
|
325
|
+
/"shiftStartsAt" TIMESTAMP WITH TIME ZONE NOT NULL/,
|
|
326
|
+
);
|
|
327
|
+
expect(statement).toMatch(
|
|
328
|
+
/"minutesBeforeShift" integer NOT NULL DEFAULT '?0'?/,
|
|
329
|
+
);
|
|
330
|
+
expect(statement).toMatch(/"kind" character varying\(100\) NOT NULL/);
|
|
331
|
+
expect(statement).toMatch(/"claimedAt" TIMESTAMP WITH TIME ZONE NOT NULL/);
|
|
332
|
+
expect(statement).toMatch(/"sentAt" TIMESTAMP WITH TIME ZONE,/);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("down() drops every table, every index and the column that up() created", () => {
|
|
336
|
+
for (const table of NEW_TABLES) {
|
|
337
|
+
expect(down).toContain(`DROP TABLE "${table}"`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
expect(down).toContain(
|
|
341
|
+
'ALTER TABLE "OnCallDutyPolicySchedule" DROP COLUMN "shiftConfigVersion"',
|
|
342
|
+
);
|
|
343
|
+
|
|
344
|
+
const created: Array<string> = indexNames(up);
|
|
345
|
+
expect(created.length).toBeGreaterThan(0);
|
|
346
|
+
|
|
347
|
+
for (const name of created) {
|
|
348
|
+
expect(down).toContain(`DROP INDEX "public"."${name}"`);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// And nothing in down() creates anything.
|
|
352
|
+
expect(
|
|
353
|
+
down.filter((sql: string) => {
|
|
354
|
+
return sql.startsWith("CREATE");
|
|
355
|
+
}),
|
|
356
|
+
).toEqual([]);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test("the file carries no hand-written SQL names (every constraint id is a TypeORM hash)", () => {
|
|
360
|
+
for (const sql of up) {
|
|
361
|
+
for (const match of sql.matchAll(/CONSTRAINT "([^"]+)"/g)) {
|
|
362
|
+
expect(match[1]).toMatch(/^(PK|UQ|FK)_[0-9a-f]{27,}$/);
|
|
363
|
+
}
|
|
364
|
+
for (const match of sql.matchAll(/INDEX "([^"]+)"/g)) {
|
|
365
|
+
expect(match[1]).toMatch(/^IDX_[0-9a-f]{26,}$/);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
});
|