import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { DatabaseRestore } from '@/utils/restore' import path from 'path' // Mock pg-dump-restore vi.mock('pg-dump-restore', () => ({ pgRestore: vi.fn().mockResolvedValue(undefined), })) // Mock fs with importOriginal for partial mocking vi.mock('fs', async (importOriginal) => { const actual = await importOriginal() as typeof import('fs') return { ...actual, promises: { ...actual.promises, readdir: vi.fn().mockResolvedValue([]), access: vi.fn().mockResolvedValue(undefined), stat: vi.fn().mockResolvedValue({ size: 1024, mtime: new Date() }), }, } }) // Mock logger vi.mock('@/utils/logger', () => ({ logger: { db: vi.fn(), error: vi.fn(), api: vi.fn(), middleware: vi.fn(), }, })) describe('DatabaseRestore', () => { let restore: DatabaseRestore beforeEach(() => { vi.clearAllMocks() restore = new DatabaseRestore() }) afterEach(() => { vi.restoreAllMocks() }) describe('getDbConfig', () => { it('应该返回正确的数据库配置', () => { process.env.DB_HOST = 'test-host' process.env.DB_PORT = '5433' process.env.DB_DATABASE = 'test-db' process.env.DB_USERNAME = 'test-user' process.env.DB_PASSWORD = 'test-password' const config = (restore as any).getDbConfig() expect(config).toEqual({ host: 'test-host', port: 5433, database: 'test-db', username: 'test-user', password: 'test-password', }) }) it('应该使用默认值当环境变量未设置时', () => { delete process.env.DB_HOST delete process.env.DB_PORT delete process.env.DB_DATABASE delete process.env.DB_USERNAME delete process.env.DB_PASSWORD const config = (restore as any).getDbConfig() expect(config).toEqual({ host: 'localhost', port: 5432, database: 'postgres', username: 'postgres', password: '', }) }) }) describe('findLatestBackup', () => { it('应该返回最新的备份文件', async () => { const fs = await import('fs') vi.mocked(fs.promises.readdir).mockResolvedValue([ 'backup-2024-01-01T00-00-00Z.dump', 'backup-2024-01-03T00-00-00Z.dump', 'backup-2024-01-02T00-00-00Z.dump', ] as any) const latest = await restore.findLatestBackup() expect(latest).toBe(path.join('./backups', 'backup-2024-01-03T00-00-00Z.dump')) }) it('应该返回null当没有备份文件时', async () => { const fs = await import('fs') vi.mocked(fs.promises.readdir).mockResolvedValue([ 'some-other-file.txt' ] as any) const latest = await restore.findLatestBackup() expect(latest).toBeNull() }) it('应该在读取目录失败时返回null', async () => { const fs = await import('fs') const { logger } = await import('@/utils/logger') vi.mocked(fs.promises.readdir).mockRejectedValueOnce(new Error('读取目录失败')) const latest = await restore.findLatestBackup() expect(latest).toBeNull() expect(logger.error).toHaveBeenCalled() }) }) describe('listBackups', () => { it('应该返回所有备份文件列表', async () => { const fs = await import('fs') vi.mocked(fs.promises.readdir).mockResolvedValue([ 'backup-2024-01-01.dump', 'some-other-file.txt', 'backup-2024-01-02.dump', ] as any) const backups = await restore.listBackups() expect(backups).toEqual([ 'backup-2024-01-01.dump', 'backup-2024-01-02.dump', ]) }) it('应该在读取目录失败时返回空数组', async () => { const fs = await import('fs') const { logger } = await import('@/utils/logger') vi.mocked(fs.promises.readdir).mockRejectedValueOnce(new Error('读取目录失败')) const backups = await restore.listBackups() expect(backups).toEqual([]) expect(logger.error).toHaveBeenCalled() }) }) describe('backupExists', () => { it('应该返回true当备份文件存在时', async () => { const fs = await import('fs') const exists = await restore.backupExists('/path/to/backup.dump') expect(exists).toBe(true) expect(fs.promises.access).toHaveBeenCalledWith('/path/to/backup.dump') }) it('应该返回false当备份文件不存在时', async () => { const fs = await import('fs') vi.mocked(fs.promises.access).mockRejectedValueOnce(new Error('文件不存在')) const exists = await restore.backupExists('/path/to/backup.dump') expect(exists).toBe(false) }) }) describe('getBackupInfo', () => { it('应该返回备份文件信息', async () => { const fs = await import('fs') const testDate = new Date() vi.mocked(fs.promises.stat).mockResolvedValueOnce({ size: 1048576, mtime: testDate, } as any) const info = await restore.getBackupInfo('/path/to/backup.dump') expect(info).toEqual({ size: 1048576, mtime: testDate, formattedSize: '1 MB', }) }) it('应该在获取信息失败时抛出错误', async () => { const fs = await import('fs') vi.mocked(fs.promises.stat).mockRejectedValueOnce(new Error('获取文件信息失败')) await expect(restore.getBackupInfo('/path/to/backup.dump')).rejects.toThrow('获取备份信息失败') }) }) describe('formatFileSize', () => { it('应该正确格式化文件大小', () => { const formatFileSize = (restore as any).formatFileSize expect(formatFileSize(0)).toBe('0 B') expect(formatFileSize(1024)).toBe('1 KB') expect(formatFileSize(1048576)).toBe('1 MB') expect(formatFileSize(1073741824)).toBe('1 GB') }) }) })