|
1 | 1 | /** @vitest-environment node */ |
2 | 2 | import { |
| 3 | + credentialGroupEnrollment, |
3 | 4 | document, |
4 | 5 | embedding, |
5 | 6 | knowledgeBase, |
6 | 7 | knowledgeConnector, |
| 8 | + knowledgeConnectorMember, |
7 | 9 | member, |
8 | 10 | organizationSearchIntegration, |
9 | 11 | user, |
@@ -96,6 +98,7 @@ function source(id: string, connectorType = 'google_drive', accessMode = 'admin' |
96 | 98 | memberSyncStatus: 'idle', |
97 | 99 | lastSyncAt: LAST_SYNC as Date | null, |
98 | 100 | hasRetainedSyncError: false, |
| 101 | + hasViewerMemberSyncError: false, |
99 | 102 | lastMemberSyncAt: null as Date | null, |
100 | 103 | credentialGroupId: 'group-secret', |
101 | 104 | credentialGroupOptionId: 'option-secret', |
@@ -129,6 +132,26 @@ beforeEach(() => { |
129 | 132 | }) |
130 | 133 |
|
131 | 134 | describe('Search source summaries', () => { |
| 135 | + it('retains the viewer account failure after an otherwise successful empty run', async () => { |
| 136 | + seed([{ ...source('github', 'google_drive', 'members'), hasViewerMemberSyncError: true }]) |
| 137 | + const result = await listSearchSources.execute({ principal, input }) |
| 138 | + expect(result.sources[0]).toMatchObject({ hasSyncError: true, isSyncing: false }) |
| 139 | + expect(dbChainMockFns.where).toHaveBeenCalledWith( |
| 140 | + expect.objectContaining({ |
| 141 | + type: 'and', |
| 142 | + conditions: expect.arrayContaining([ |
| 143 | + { type: 'eq', left: credentialGroupEnrollment.userId, right: principal.userId }, |
| 144 | + { |
| 145 | + type: 'eq', |
| 146 | + left: knowledgeConnectorMember.connectorId, |
| 147 | + right: knowledgeConnector.id, |
| 148 | + }, |
| 149 | + { type: 'isNotNull', column: knowledgeConnectorMember.lastError }, |
| 150 | + ]), |
| 151 | + }) |
| 152 | + ) |
| 153 | + }) |
| 154 | + |
132 | 155 | it.each(['read', 'write', 'admin'])( |
133 | 156 | 'allows a current workspace %s without exposing credentials or other members', |
134 | 157 | async (role) => { |
@@ -297,7 +320,7 @@ describe('Search source summaries', () => { |
297 | 320 | sources: [], |
298 | 321 | nextCursor: null, |
299 | 322 | }) |
300 | | - expect(dbChainMockFns.where.mock.calls[0][0]).toEqual({ |
| 323 | + expect(dbChainMockFns.where).toHaveBeenCalledWith({ |
301 | 324 | type: 'and', |
302 | 325 | conditions: expect.arrayContaining([ |
303 | 326 | { |
@@ -493,6 +516,26 @@ describe('organization Search source summaries', () => { |
493 | 516 | }) |
494 | 517 |
|
495 | 518 | describe('bounded Search progress', () => { |
| 519 | + it('keeps reporting an unresolved viewer account failure between retries', async () => { |
| 520 | + queueTableRows(knowledgeConnector, [ |
| 521 | + { |
| 522 | + connectorId: 'github', |
| 523 | + approved: true, |
| 524 | + status: 'active', |
| 525 | + accessMode: 'members', |
| 526 | + memberSyncStatus: 'idle', |
| 527 | + hasViewerMemberSyncError: true, |
| 528 | + isIndexing: false, |
| 529 | + hasIndexingError: false, |
| 530 | + }, |
| 531 | + ]) |
| 532 | + const result = await readSearchSourceProgress.execute({ |
| 533 | + principal, |
| 534 | + input: { ...input, connectorIds: ['github'] }, |
| 535 | + }) |
| 536 | + expect(result.sources[0]).toMatchObject({ hasSyncError: true, isSyncing: false }) |
| 537 | + }) |
| 538 | + |
496 | 539 | it('reports visible pending and failed work without counting documents or chunks', async () => { |
497 | 540 | queueTableRows(knowledgeConnector, [ |
498 | 541 | { |
|
0 commit comments