import assert from 'node:assert/strict'; import test from 'node:test'; import { loadConfig } from '../src/config/env.js'; import { connectFirstAvailableMongo } from '../src/plugins/mongo.js'; function fakeClient(error = null) { return { closed: false, async connect() { if (error) throw error; }, async close() { this.closed = true; }, }; } test('Windows에서 개발용 MongoDB와 로컬 이미지 프로필을 자동 사용한다', () => { const config = loadConfig({}, { platform: 'win32' }); assert.equal(config.nodeEnv, 'development'); assert.equal(config.mongoUri, 'mongodb://192.168.0.240:27017/our_recipe_atlas'); assert.equal(config.mongoFallbackUri, 'mongodb://172.16.0.7:27017/our_recipe_atlas'); assert.deepEqual(config.mongoCollections, { allowedEmails: 'allowed_google_emails', recipes: 'recipes_dev', users: 'users_dev', }); assert.match(config.imageRoot, /data\\images$/); }); test('OS 프로필이 환경파일의 개발·운영 선택값보다 우선한다', () => { const linuxConfig = loadConfig( { NODE_ENV: 'development', MONGO_URI: 'mongodb://192.168.0.240:27017/our_recipe_atlas_dev', IMAGE_ROOT: './data/images', AUTH_JWT_SECRET: 'production-secret', }, { platform: 'linux' }, ); assert.equal(linuxConfig.nodeEnv, 'production'); assert.equal(linuxConfig.mongoUri, 'mongodb://192.168.0.240:27017/our_recipe_atlas'); assert.deepEqual(linuxConfig.mongoCollections, { allowedEmails: 'allowed_google_emails', recipes: 'recipes', users: 'users', }); assert.equal(linuxConfig.imageRoot, '/mnt/recipe-ssd/our_recipe_atlas/images'); const windowsConfig = loadConfig( { NODE_ENV: 'production', MONGO_URI: 'mongodb://192.168.0.240:27017/our_recipe_atlas', IMAGE_ROOT: '/mnt/recipe-ssd/our_recipe_atlas/images', }, { platform: 'win32' }, ); assert.equal(windowsConfig.nodeEnv, 'development'); assert.equal(windowsConfig.mongoUri, 'mongodb://192.168.0.240:27017/our_recipe_atlas'); assert.equal(windowsConfig.mongoCollections.recipes, 'recipes_dev'); assert.match(windowsConfig.imageRoot, /data\\images$/); }); test('Linux 운영용 MongoDB와 절대 이미지 경로 설정을 허용한다', () => { const config = loadConfig( { AUTH_JWT_SECRET: 'production-secret' }, { platform: 'linux' }, ); assert.equal(config.nodeEnv, 'production'); assert.equal(config.mongoUri, 'mongodb://192.168.0.240:27017/our_recipe_atlas'); assert.equal(config.mongoFallbackUri, 'mongodb://172.16.0.7:27017/our_recipe_atlas'); assert.equal(config.imageRoot, '/mnt/recipe-ssd/our_recipe_atlas/images'); }); test('primary MongoDB 연결에 성공하면 fallback을 시도하지 않는다', async () => { const createdUris = []; const primary = fakeClient(); const result = await connectFirstAvailableMongo(['primary', 'fallback'], { createClient(uri) { createdUris.push(uri); return primary; }, }); assert.equal(result.client, primary); assert.equal(result.connectionIndex, 0); assert.deepEqual(createdUris, ['primary']); }); test('primary MongoDB 연결 실패 시 정리한 뒤 fallback으로 연결한다', async () => { const primaryError = new Error('primary unavailable'); const primary = fakeClient(primaryError); const fallback = fakeClient(); const failures = []; const result = await connectFirstAvailableMongo(['primary', 'fallback'], { createClient(uri) { return uri === 'primary' ? primary : fallback; }, onFailure(index, error) { failures.push({ index, error }); }, }); assert.equal(primary.closed, true); assert.equal(fallback.closed, false); assert.equal(result.client, fallback); assert.equal(result.connectionIndex, 1); assert.deepEqual(failures, [{ index: 0, error: primaryError }]); }); test('모든 MongoDB 연결 실패 시 마지막 오류를 반환하고 클라이언트를 정리한다', async () => { const primary = fakeClient(new Error('primary unavailable')); const fallbackError = new Error('fallback unavailable'); const fallback = fakeClient(fallbackError); await assert.rejects( connectFirstAvailableMongo(['primary', 'fallback'], { createClient(uri) { return uri === 'primary' ? primary : fallback; }, }), fallbackError, ); assert.equal(primary.closed, true); assert.equal(fallback.closed, true); });