feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
This commit is contained in:
parent
5cd1de6859
commit
708e20f747
406 changed files with 42464 additions and 6199 deletions
181
apps/desktop/tests/red/harness.ts
Normal file
181
apps/desktop/tests/red/harness.ts
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// RED 유스케이스 공통 하네스: 실제 서비스 + in-memory DB + IPC 캡처
|
||||
// 네트워크/모델 I/O 만 더블로 교체한다.
|
||||
|
||||
import { afterEach, beforeEach, vi } from 'vitest'
|
||||
import { ipcMain } from 'electron'
|
||||
import { createTestDb } from '../helpers/createTestDb'
|
||||
import { bindTestDatabase, unbindTestDatabase } from '../../src/main/db'
|
||||
import {
|
||||
initInMemoryConfig,
|
||||
resetInMemoryConfig,
|
||||
} from '../../src/main/services/ConfigService'
|
||||
import { resetHistoryServiceForTests } from '../../src/main/services/HistoryService'
|
||||
import { resetDictionaryServiceForTests } from '../../src/main/services/DictionaryService'
|
||||
import { resetCustomInstructionServiceForTests } from '../../src/main/services/CustomInstructionService'
|
||||
import { resetChainServiceForTests } from '../../src/main/services/ChainService'
|
||||
import { resetVoiceCommandServiceForTests } from '../../src/main/services/VoiceCommandService'
|
||||
import { resetLicenseServiceForTests } from '../../src/main/services/LicenseService'
|
||||
import { resetVoiceModeServiceForTests } from '../../src/main/services/VoiceModeService'
|
||||
import { resetMemoServiceForTests } from '../../src/main/services/MemoService'
|
||||
import { resetMeetingModeServiceForTests } from '../../src/main/services/MeetingModeService'
|
||||
import { resetMeetingDocTemplateServiceForTests } from '../../src/main/services/MeetingDocTemplateService'
|
||||
import { resetDictationTemplateServiceForTests } from '../../src/main/services/DictationTemplateService'
|
||||
import { resetVoiceConversationServiceForTests } from '../../src/main/services/VoiceConversationService'
|
||||
import { resetRAGServiceForTests } from '../../src/main/services/RAGService'
|
||||
import { resetVoiceActionServiceForTests } from '../../src/main/services/VoiceActionService'
|
||||
import { resetCaptionServiceForTests } from '../../src/main/services/CaptionService'
|
||||
import { resetFileTranscriptionServiceForTests } from '../../src/main/services/FileTranscriptionService'
|
||||
import { resetCloudSTTServiceForTests } from '../../src/main/services/CloudSTTService'
|
||||
import { resetPremiumLLMServiceForTests } from '../../src/main/services/PremiumLLMService'
|
||||
import { resetOnlineLLMServiceForTests } from '../../src/main/services/OnlineLLMService'
|
||||
import { resetCloudSyncServiceForTests } from '../../src/main/services/CloudSyncService'
|
||||
import { resetTTSPlaybackServiceForTests } from '../../src/main/services/TTSPlaybackService'
|
||||
import { resetMeetingSummaryServiceForTests } from '../../src/main/services/MeetingSummaryService'
|
||||
import { resetLocalLLMServiceForTests } from '../../src/main/services/LocalLLMService'
|
||||
import { resetLocalSTTServiceForTests } from '../../src/main/services/LocalSTTService'
|
||||
import type { IPCResult } from '@d3ro/core/errors'
|
||||
import type { NewHistory } from '../../src/main/db/schema'
|
||||
|
||||
const ipcHandlers = new Map<string, (...args: unknown[]) => unknown>()
|
||||
|
||||
export function resetIpcHandlers(): void {
|
||||
ipcHandlers.clear()
|
||||
vi.mocked(ipcMain.handle).mockImplementation((channel: string, handler: (...args: unknown[]) => unknown) => {
|
||||
ipcHandlers.set(channel, handler)
|
||||
})
|
||||
}
|
||||
|
||||
export async function invokeIpc<T = unknown>(
|
||||
channel: string,
|
||||
...args: unknown[]
|
||||
): Promise<IPCResult<T>> {
|
||||
const handler = ipcHandlers.get(channel)
|
||||
if (!handler) {
|
||||
throw new Error(`IPC handler not registered: ${channel}`)
|
||||
}
|
||||
return (await handler({}, ...args)) as IPCResult<T>
|
||||
}
|
||||
|
||||
export function hasIpc(channel: string): boolean {
|
||||
return ipcHandlers.has(channel)
|
||||
}
|
||||
|
||||
export function historyInput(
|
||||
overrides: Partial<Omit<NewHistory, 'id' | 'createdAt' | 'updatedAt'>> = {},
|
||||
): Omit<NewHistory, 'id' | 'createdAt' | 'updatedAt'> {
|
||||
return {
|
||||
originalText: '오늘 회의는 오후 세 시에 시작합니다',
|
||||
duration: 3.5,
|
||||
wordCount: 8,
|
||||
mode: 'dictation',
|
||||
status: 'completed',
|
||||
appVersion: '1.0.0',
|
||||
...overrides,
|
||||
}
|
||||
}
|
||||
|
||||
export function resetAllSingletons(): void {
|
||||
resetHistoryServiceForTests()
|
||||
resetDictionaryServiceForTests()
|
||||
resetCustomInstructionServiceForTests()
|
||||
resetChainServiceForTests()
|
||||
resetVoiceCommandServiceForTests()
|
||||
resetLicenseServiceForTests()
|
||||
resetVoiceModeServiceForTests()
|
||||
resetMemoServiceForTests()
|
||||
resetMeetingModeServiceForTests()
|
||||
resetMeetingDocTemplateServiceForTests()
|
||||
resetDictationTemplateServiceForTests()
|
||||
resetVoiceConversationServiceForTests()
|
||||
resetRAGServiceForTests()
|
||||
resetVoiceActionServiceForTests()
|
||||
resetCaptionServiceForTests()
|
||||
resetFileTranscriptionServiceForTests()
|
||||
resetCloudSTTServiceForTests()
|
||||
resetPremiumLLMServiceForTests()
|
||||
resetOnlineLLMServiceForTests()
|
||||
resetCloudSyncServiceForTests()
|
||||
resetTTSPlaybackServiceForTests()
|
||||
resetMeetingSummaryServiceForTests()
|
||||
resetLocalLLMServiceForTests()
|
||||
resetLocalSTTServiceForTests()
|
||||
}
|
||||
|
||||
export function useRedHarness(): void {
|
||||
let testdb: ReturnType<typeof createTestDb> | null = null
|
||||
|
||||
beforeEach(() => {
|
||||
testdb = createTestDb()
|
||||
bindTestDatabase(testdb.db)
|
||||
initInMemoryConfig()
|
||||
resetAllSingletons()
|
||||
resetIpcHandlers()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
resetAllSingletons()
|
||||
unbindTestDatabase()
|
||||
testdb?.close()
|
||||
testdb = null
|
||||
resetInMemoryConfig()
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
}
|
||||
|
||||
export type InvokeFnResult = { data: unknown; error: { message: string } | null }
|
||||
|
||||
export function makeCloudSyncFake(opts?: {
|
||||
authenticated?: boolean
|
||||
invoke?: (name: string, body: Record<string, unknown>) => Promise<InvokeFnResult>
|
||||
}): {
|
||||
isEnabled: () => boolean
|
||||
isAuthenticated: () => boolean
|
||||
getState: () => {
|
||||
authenticated: boolean
|
||||
userEmail: string | null
|
||||
lastSyncAt: number | null
|
||||
syncing: boolean
|
||||
}
|
||||
getUser: () => { id: string; email: string } | null
|
||||
invokeFunction: (name: string, body: Record<string, unknown>) => Promise<InvokeFnResult>
|
||||
pushOne: () => Promise<void>
|
||||
pushAll: () => Promise<{ pushed: number; errors: string[] }>
|
||||
pullAll: () => Promise<{ pushed: number; errors: string[] }>
|
||||
startSignIn: (provider: string) => Promise<void>
|
||||
handleAuthCallback: (code: string) => Promise<void>
|
||||
signOut: () => Promise<void>
|
||||
signInAnonymously: () => Promise<void>
|
||||
on: () => void
|
||||
off: () => void
|
||||
} {
|
||||
const authenticated = opts?.authenticated ?? false
|
||||
return {
|
||||
isEnabled: () => true,
|
||||
isAuthenticated: () => authenticated,
|
||||
getState: () => ({
|
||||
authenticated,
|
||||
userEmail: authenticated ? 'fx.user@example.test' : null,
|
||||
lastSyncAt: null,
|
||||
syncing: false,
|
||||
}),
|
||||
getUser: () =>
|
||||
authenticated ? { id: 'fx-user-id', email: 'fx.user@example.test' } : null,
|
||||
invokeFunction: opts?.invoke
|
||||
?? (async () => ({ data: null, error: { message: 'fx.cloud.unconfigured' } })),
|
||||
pushOne: async () => undefined,
|
||||
pushAll: async () => ({ pushed: 0, errors: [] }),
|
||||
pullAll: async () => ({ pushed: 0, errors: [] }),
|
||||
startSignIn: async () => {
|
||||
throw new Error('fx.oauth.not-started')
|
||||
},
|
||||
handleAuthCallback: async () => {
|
||||
throw new Error('fx.oauth.callback-rejected')
|
||||
},
|
||||
signOut: async () => undefined,
|
||||
signInAnonymously: async () => {
|
||||
throw new Error('fx.anon.not-supported')
|
||||
},
|
||||
on: () => undefined,
|
||||
off: () => undefined,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue