Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/sync/eligibility/eligibility.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ describe('EligibilityService', () => {
'stg_icm_legal_authority_admin',
'stg_icm_legal_authority',
'stg_icm_agreement',
'stg_icm_agreement_line',
// 'stg_icm_agreement_line', // temporary: agreement line ingest returns empty
'stg_icm_orders',
'stg_mis_payments',
'stg_mis_contracts',
Expand Down
3 changes: 2 additions & 1 deletion backend/src/sync/eligibility/eligibility.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ const REQUIRED_STAGING_TABLES = [
'stg_icm_legal_authority_admin',
'stg_icm_legal_authority',
'stg_icm_agreement',
'stg_icm_agreement_line',
// Temporary: agreement line ingest returns empty until ICM API is ready
// 'stg_icm_agreement_line',
'stg_icm_orders',
'stg_mis_payments',
'stg_mis_contracts',
Expand Down
21 changes: 21 additions & 0 deletions backend/src/sync/icm/data-source/icm-api-data-source.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Test, TestingModule } from '@nestjs/testing'
import { of } from 'rxjs'
import { KeycloakAuthService } from 'src/common/auth/keycloak-auth.service'
import { IcmApiConfig } from '../icm.config'
import * as icmConfig from '../icm.config'
import { OOC_AGREEMENT_LINES_FIELDS, OOC_AGREEMENT_LINES_SEARCH_SPEC } from '../agreement-lines'
import { IcmApiDataSource } from './icm-api-data-source'
import { IcmContactUpdatePayload } from './icm-data-source'
Expand All @@ -24,6 +25,8 @@ describe('IcmApiDataSource', () => {
let keycloakAuthService: { getBearerToken: ReturnType<typeof vi.fn> }

beforeEach(async () => {
vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(false)

httpService = { get: vi.fn(), put: vi.fn() }

keycloakAuthService = {
Expand Down Expand Up @@ -54,7 +57,25 @@ describe('IcmApiDataSource', () => {
service = module.get<IcmApiDataSource>(IcmApiDataSource)
})

afterEach(() => {
vi.restoreAllMocks()
})

describe('fetchAll', () => {
it('should return empty for ooc agreement lines ingest', async () => {
vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(true)

const oocConfig: IcmApiConfig = {
...mockConfig,
name: 'ooc_agreement_lines',
}

const results = await service.fetchAll(oocConfig)

expect(results).toEqual([])
expect(httpService.get).not.toHaveBeenCalled()
})

it('should paginate until fewer items than page size', async () => {
httpService.get
.mockReturnValueOnce(
Expand Down
8 changes: 7 additions & 1 deletion backend/src/sync/icm/data-source/icm-api-data-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ConfigService } from '@nestjs/config'
import { firstValueFrom } from 'rxjs'
import { KeycloakAuthService } from 'src/common/auth/keycloak-auth.service'
import { formatDatePacific } from 'src/common/utils'
import { ICM_UPDATE_BATCH_LIMIT, IcmApiConfig } from '../icm.config'
import { ICM_UPDATE_BATCH_LIMIT, IcmApiConfig, isOocAgreementLinesConfig } from '../icm.config'
import { IcmApiRecord, IcmContactUpdatePayload, IcmDataSource } from './icm-data-source'

const PAGE_SIZE = 100
Expand All @@ -22,6 +22,12 @@ export class IcmApiDataSource extends IcmDataSource {
}

async fetchAll(config: IcmApiConfig, lastUpdated?: Date): Promise<IcmApiRecord[]> {
// Temporary: agreement line ICM API is not ready in test — fake an empty paginated response.
if (isOocAgreementLinesConfig(config)) {
this.logger.warn(`${config.name}: returning empty result (temporary)`)
return []
}

const icmApiUrl = this.configService.get<string>('admin.icmApiUrl')!
const icmTrustedUsername = this.configService.get<string>('admin.icmTrustedUsername')!
const timeout = this.configService.get<number>('sync.icmRequestTimeoutMs')!
Expand Down
16 changes: 16 additions & 0 deletions backend/src/sync/icm/data-source/mock-icm-data-source.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing'
import { MockIcmDataSource } from './mock-icm-data-source'
import { IcmApiConfig } from '../icm.config'
import * as icmConfig from '../icm.config'
import * as fs from 'fs'

vi.mock('fs')
Expand All @@ -19,6 +20,7 @@ describe('MockIcmDataSource', () => {

beforeEach(async () => {
vi.clearAllMocks()
vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(false)

const module: TestingModule = await Test.createTestingModule({
providers: [MockIcmDataSource],
Expand All @@ -28,6 +30,20 @@ describe('MockIcmDataSource', () => {
})

describe('fetchAll', () => {
it('should return empty for ooc agreement lines ingest', async () => {
vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(true)

const oocConfig: IcmApiConfig = {
...testConfig,
name: 'ooc_agreement_lines',
}

const results = await service.fetchAll(oocConfig)

expect(results).toEqual([])
expect(fs.existsSync).not.toHaveBeenCalled()
})

it('should read mock .json file and return items', async () => {
vi.mocked(fs.existsSync).mockReturnValue(true)
vi.mocked(fs.readFileSync).mockReturnValue(
Expand Down
7 changes: 6 additions & 1 deletion backend/src/sync/icm/data-source/mock-icm-data-source.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { Injectable, Logger } from '@nestjs/common'
import * as fs from 'fs'
import * as path from 'path'
import { IcmApiConfig } from '../icm.config'
import { IcmApiConfig, isOocAgreementLinesConfig } from '../icm.config'
import { IcmApiRecord, IcmContactUpdatePayload, IcmDataSource } from './icm-data-source'

@Injectable()
export class MockIcmDataSource extends IcmDataSource {
private readonly logger = new Logger(MockIcmDataSource.name)

async fetchAll(config: IcmApiConfig, lastUpdated?: Date): Promise<IcmApiRecord[]> {
if (isOocAgreementLinesConfig(config)) {
this.logger.warn(`${config.name}: returning empty result (temporary)`)
return []
}

const mockDir = path.join(__dirname, '..', '..', 'mock-data', 'icm')
const mockFile = path.join(mockDir, `${config.name}.json`)

Expand Down
6 changes: 6 additions & 0 deletions backend/src/sync/icm/icm.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ export const ICM_INGESTION_CONFIGS: IcmApiConfig[] = [
},
]

export const OOC_AGREEMENT_LINES_INGEST_NAME = 'ooc_agreement_lines'

export function isOocAgreementLinesConfig(config: IcmApiConfig): boolean {
return config.name === OOC_AGREEMENT_LINES_INGEST_NAME
}

export const ICM_UPDATE_BATCH_LIMIT = 100

export const ICM_SYNC_CONFIGS: IcmApiConfig[] = [
Expand Down
Loading