- Add Husky pre-commit and pre-push hooks for linting, type checking, and build validation - Fix visual hierarchy bug in the provider onboarding tutorial - Remove feedback modal - Move MinIO bucket creation logic to before app startup - Wire MiniMax audio through voice generation pipeline - Fix scene insertion issues - Fix portal tutorial modal and harden panel variant task flow
98 lines
3.3 KiB
TypeScript
98 lines
3.3 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { ensureStorageReady } from '@/lib/storage/bootstrap'
|
|
|
|
type MockCommand = {
|
|
readonly type: 'HeadBucketCommand' | 'CreateBucketCommand'
|
|
readonly input: Record<string, unknown>
|
|
}
|
|
|
|
const {
|
|
sendMock,
|
|
s3ClientMock,
|
|
headBucketCommandMock,
|
|
createBucketCommandMock,
|
|
} = vi.hoisted(() => ({
|
|
sendMock: vi.fn<(command: MockCommand) => Promise<unknown>>(),
|
|
s3ClientMock: vi.fn(() => ({ send: undefined as unknown })),
|
|
headBucketCommandMock: vi.fn((input: Record<string, unknown>): MockCommand => ({
|
|
type: 'HeadBucketCommand',
|
|
input,
|
|
})),
|
|
createBucketCommandMock: vi.fn((input: Record<string, unknown>): MockCommand => ({
|
|
type: 'CreateBucketCommand',
|
|
input,
|
|
})),
|
|
}))
|
|
|
|
s3ClientMock.mockImplementation(() => ({ send: sendMock }))
|
|
|
|
vi.mock('@aws-sdk/client-s3', () => ({
|
|
S3Client: s3ClientMock,
|
|
HeadBucketCommand: headBucketCommandMock,
|
|
CreateBucketCommand: createBucketCommandMock,
|
|
}))
|
|
|
|
describe('storage bootstrap', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
process.env.MINIO_ENDPOINT = 'http://127.0.0.1:9000'
|
|
process.env.MINIO_REGION = 'us-east-1'
|
|
process.env.MINIO_BUCKET = 'waoowaoo'
|
|
process.env.MINIO_ACCESS_KEY = 'minioadmin'
|
|
process.env.MINIO_SECRET_KEY = 'minioadmin'
|
|
process.env.MINIO_FORCE_PATH_STYLE = 'true'
|
|
})
|
|
|
|
it('skips startup storage initialization when STORAGE_TYPE=local', async () => {
|
|
await expect(ensureStorageReady({ storageType: 'local' })).resolves.toBe('skipped')
|
|
expect(s3ClientMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('verifies the MinIO bucket during startup when it already exists', async () => {
|
|
sendMock.mockResolvedValueOnce({})
|
|
|
|
await expect(ensureStorageReady({ storageType: 'minio' })).resolves.toBe('existing')
|
|
|
|
expect(s3ClientMock).toHaveBeenCalledWith({
|
|
endpoint: 'http://127.0.0.1:9000',
|
|
region: 'us-east-1',
|
|
forcePathStyle: true,
|
|
credentials: {
|
|
accessKeyId: 'minioadmin',
|
|
secretAccessKey: 'minioadmin',
|
|
},
|
|
})
|
|
expect(headBucketCommandMock).toHaveBeenCalledWith({ Bucket: 'waoowaoo' })
|
|
expect(createBucketCommandMock).not.toHaveBeenCalled()
|
|
})
|
|
|
|
it('creates the MinIO bucket during startup when HeadBucket reports it missing', async () => {
|
|
sendMock
|
|
.mockRejectedValueOnce(Object.assign(new Error('missing bucket'), {
|
|
name: 'NotFound',
|
|
$metadata: { httpStatusCode: 404 },
|
|
}))
|
|
.mockResolvedValueOnce({})
|
|
|
|
await expect(ensureStorageReady({ storageType: 'minio' })).resolves.toBe('created')
|
|
|
|
expect(headBucketCommandMock).toHaveBeenCalledWith({ Bucket: 'waoowaoo' })
|
|
expect(createBucketCommandMock).toHaveBeenCalledWith({ Bucket: 'waoowaoo' })
|
|
expect(sendMock).toHaveBeenNthCalledWith(2, {
|
|
type: 'CreateBucketCommand',
|
|
input: { Bucket: 'waoowaoo' },
|
|
})
|
|
})
|
|
|
|
it('fails fast when MinIO returns a non-bucket-missing error at startup', async () => {
|
|
const startupError = Object.assign(new Error('MinIO unavailable'), {
|
|
name: 'TimeoutError',
|
|
$metadata: { httpStatusCode: 503 },
|
|
})
|
|
sendMock.mockRejectedValueOnce(startupError)
|
|
|
|
await expect(ensureStorageReady({ storageType: 'minio' })).rejects.toBe(startupError)
|
|
expect(createBucketCommandMock).not.toHaveBeenCalled()
|
|
})
|
|
})
|