Skip to content

Commit 9e2d164

Browse files
committed
fix: mark completed till validation for admin migrations
Signed-off-by: ferhat elmas <elmas.ferhat@gmail.com>
1 parent d2f47ef commit 9e2d164

3 files changed

Lines changed: 104 additions & 3 deletions

File tree

src/http/routes/admin/migrations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ export default async function routes(fastify: FastifyInstance) {
4141

4242
if (
4343
typeof markCompletedTillMigration === 'string' &&
44-
!DBMigration[untilMigration as keyof typeof DBMigration]
44+
!DBMigration[markCompletedTillMigration as keyof typeof DBMigration]
4545
) {
4646
return reply.status(400).send({ message: 'Invalid migration' })
4747
}
4848

4949
await resetMigrationsOnTenants({
5050
till: untilMigration as keyof typeof DBMigration,
5151
markCompletedTillMigration: markCompletedTillMigration
52-
? markCompletedTillMigration
52+
? (markCompletedTillMigration as keyof typeof DBMigration)
5353
: undefined,
5454
signal: req.signals.disconnect.signal,
5555
})

src/http/routes/admin/tenants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ export default async function routes(fastify: FastifyInstance) {
609609

610610
if (
611611
typeof markCompletedTillMigration === 'string' &&
612-
!DBMigration[untilMigration as keyof typeof DBMigration]
612+
!DBMigration[markCompletedTillMigration as keyof typeof DBMigration]
613613
) {
614614
return reply.status(400).send({ message: 'Invalid migration' })
615615
}

src/test/admin-migrations.test.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
jest.mock('@internal/database/migrations', () => {
2+
const actual = jest.requireActual('@internal/database/migrations')
3+
return {
4+
...actual,
5+
resetMigrationsOnTenants: jest.fn(),
6+
resetMigration: jest.fn(),
7+
runMigrationsOnAllTenants: jest.fn(),
8+
runMigrationsOnTenant: jest.fn(),
9+
}
10+
})
11+
12+
import * as migrations from '@internal/database/migrations'
13+
import { DBMigration } from '@internal/database/migrations'
14+
import { mergeConfig } from '../config'
15+
import { multitenantKnex } from '../internal/database/multitenant-db'
16+
17+
mergeConfig({
18+
pgQueueEnable: true,
19+
})
20+
21+
import { adminApp } from './common'
22+
23+
const tenantId = 'admin-migrations-test-tenant'
24+
25+
const tenantPayload = {
26+
anonKey: 'anon-key',
27+
databaseUrl: 'postgres://tenant-db',
28+
jwtSecret: 'jwt-secret',
29+
serviceKey: 'service-key',
30+
}
31+
32+
describe('Admin migrations routes', () => {
33+
beforeAll(async () => {
34+
await migrations.runMultitenantMigrations()
35+
})
36+
37+
afterEach(async () => {
38+
jest.clearAllMocks()
39+
40+
await adminApp.inject({
41+
method: 'DELETE',
42+
url: `/tenants/${tenantId}`,
43+
headers: {
44+
apikey: process.env.ADMIN_API_KEYS,
45+
},
46+
})
47+
})
48+
49+
afterAll(async () => {
50+
await multitenantKnex.destroy()
51+
})
52+
53+
test('rejects invalid markCompletedTillMigration for fleet reset', async () => {
54+
const resetSpy = jest.mocked(migrations.resetMigrationsOnTenants).mockResolvedValue(undefined)
55+
56+
const response = await adminApp.inject({
57+
method: 'POST',
58+
url: '/migrations/reset/fleet',
59+
payload: {
60+
untilMigration: 'storage-schema' satisfies keyof typeof DBMigration,
61+
markCompletedTillMigration: 'not-a-real-migration',
62+
},
63+
headers: {
64+
apikey: process.env.ADMIN_API_KEYS,
65+
},
66+
})
67+
68+
expect(response.statusCode).toBe(400)
69+
expect(JSON.parse(response.body)).toEqual({ message: 'Invalid migration' })
70+
expect(resetSpy).not.toHaveBeenCalled()
71+
})
72+
73+
test('rejects invalid markCompletedTillMigration for tenant reset', async () => {
74+
await adminApp.inject({
75+
method: 'POST',
76+
url: `/tenants/${tenantId}`,
77+
payload: tenantPayload,
78+
headers: {
79+
apikey: process.env.ADMIN_API_KEYS,
80+
},
81+
})
82+
83+
const resetSpy = jest.mocked(migrations.resetMigration).mockResolvedValue(false)
84+
85+
const response = await adminApp.inject({
86+
method: 'POST',
87+
url: `/tenants/${tenantId}/migrations/reset`,
88+
payload: {
89+
untilMigration: 'storage-schema' satisfies keyof typeof DBMigration,
90+
markCompletedTillMigration: 'not-a-real-migration',
91+
},
92+
headers: {
93+
apikey: process.env.ADMIN_API_KEYS,
94+
},
95+
})
96+
97+
expect(response.statusCode).toBe(400)
98+
expect(JSON.parse(response.body)).toEqual({ message: 'Invalid migration' })
99+
expect(resetSpy).not.toHaveBeenCalled()
100+
})
101+
})

0 commit comments

Comments
 (0)