| 66 | } |
| 67 | |
| 68 | function createEngine(options: { |
| 69 | files: string[] |
| 70 | importResult: Awaited<ReturnType<DataImporter['importFile']>> |
| 71 | dataSource: DataSource |
| 72 | isImporting?: (sessionId: string | undefined) => boolean |
| 73 | fetchParams?: FetchParams[] |
| 74 | sessionUpdates?: Array<{ sessionId: string; updates: Partial<ImportSession> }> |
| 75 | pullResults?: Array<{ status: 'success' | 'error'; detail: string }> |
| 76 | }): PullEngine { |
| 77 | const files = [...options.files] |
| 78 | const fetcher: HttpFetcher = { |
| 79 | async fetchToTempFile( |
| 80 | _baseUrl: string, |
| 81 | _remoteSessionId: string, |
| 82 | _token: string, |
| 83 | params: FetchParams |
| 84 | ): Promise<string> { |
| 85 | options.fetchParams?.push({ ...params }) |
| 86 | const file = files.shift() |
| 87 | if (!file) throw new Error('Unexpected retry fetch') |
| 88 | return file |
| 89 | }, |
| 90 | } |
| 91 | const importer: DataImporter = { |
| 92 | sessionExists: () => true, |
| 93 | importFile: async () => options.importResult, |
| 94 | } |
| 95 | const notifier: SyncNotifier = { |
| 96 | onSessionListChanged: () => {}, |
| 97 | onPullResult: (_sourceId, _sessionId, status, detail) => { |
| 98 | options.pullResults?.push({ status, detail }) |
| 99 | }, |
| 100 | } |
| 101 | const dsManager = { |
| 102 | get: () => options.dataSource, |
| 103 | updateSession: (_sourceId: string, sessionId: string, updates: Partial<ImportSession>) => { |
| 104 | options.sessionUpdates?.push({ sessionId, updates }) |
| 105 | }, |
| 106 | } |
| 107 | |
| 108 | return new PullEngine({ |
| 109 | fetcher, |
| 110 | importer, |
| 111 | notifier, |
| 112 | dsManager: dsManager as any, |
| 113 | isImporting: options.isImporting, |
| 114 | }) |
| 115 | } |
| 116 | |
| 117 | describe('PullEngine', () => { |
| 118 | it('imports a small final page instead of treating it as empty', async () => { |