first commit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
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()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,30 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createStorageProvider } from '@/lib/storage/factory'
|
||||
import { StorageConfigError, StorageProviderNotImplementedError } from '@/lib/storage/errors'
|
||||
|
||||
describe('storage factory', () => {
|
||||
it('creates local provider when STORAGE_TYPE=local', () => {
|
||||
const provider = createStorageProvider({ storageType: 'local' })
|
||||
expect(provider.kind).toBe('local')
|
||||
})
|
||||
|
||||
it('creates minio provider when STORAGE_TYPE=minio', () => {
|
||||
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'
|
||||
|
||||
const provider = createStorageProvider({ storageType: 'minio' })
|
||||
expect(provider.kind).toBe('minio')
|
||||
})
|
||||
|
||||
it('throws explicit not-implemented error when STORAGE_TYPE=cos', () => {
|
||||
expect(() => createStorageProvider({ storageType: 'cos' })).toThrow(StorageProviderNotImplementedError)
|
||||
})
|
||||
|
||||
it('throws config error on unknown storage type', () => {
|
||||
expect(() => createStorageProvider({ storageType: 'unknown' })).toThrow(StorageConfigError)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user