diff --git a/backend/src/sync/eligibility/eligibility.service.spec.ts b/backend/src/sync/eligibility/eligibility.service.spec.ts index b525528b..f833ded1 100644 --- a/backend/src/sync/eligibility/eligibility.service.spec.ts +++ b/backend/src/sync/eligibility/eligibility.service.spec.ts @@ -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', diff --git a/backend/src/sync/eligibility/eligibility.service.ts b/backend/src/sync/eligibility/eligibility.service.ts index d9496845..e8d7515e 100644 --- a/backend/src/sync/eligibility/eligibility.service.ts +++ b/backend/src/sync/eligibility/eligibility.service.ts @@ -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', diff --git a/backend/src/sync/icm/data-source/icm-api-data-source.spec.ts b/backend/src/sync/icm/data-source/icm-api-data-source.spec.ts index 380efb2c..8d5439a8 100644 --- a/backend/src/sync/icm/data-source/icm-api-data-source.spec.ts +++ b/backend/src/sync/icm/data-source/icm-api-data-source.spec.ts @@ -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' @@ -24,6 +25,8 @@ describe('IcmApiDataSource', () => { let keycloakAuthService: { getBearerToken: ReturnType } beforeEach(async () => { + vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(false) + httpService = { get: vi.fn(), put: vi.fn() } keycloakAuthService = { @@ -54,7 +57,25 @@ describe('IcmApiDataSource', () => { service = module.get(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( diff --git a/backend/src/sync/icm/data-source/icm-api-data-source.ts b/backend/src/sync/icm/data-source/icm-api-data-source.ts index 58473903..f4019529 100644 --- a/backend/src/sync/icm/data-source/icm-api-data-source.ts +++ b/backend/src/sync/icm/data-source/icm-api-data-source.ts @@ -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 @@ -22,6 +22,12 @@ export class IcmApiDataSource extends IcmDataSource { } async fetchAll(config: IcmApiConfig, lastUpdated?: Date): Promise { + // 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('admin.icmApiUrl')! const icmTrustedUsername = this.configService.get('admin.icmTrustedUsername')! const timeout = this.configService.get('sync.icmRequestTimeoutMs')! diff --git a/backend/src/sync/icm/data-source/mock-icm-data-source.spec.ts b/backend/src/sync/icm/data-source/mock-icm-data-source.spec.ts index d4c2da0a..39c8fc6a 100644 --- a/backend/src/sync/icm/data-source/mock-icm-data-source.spec.ts +++ b/backend/src/sync/icm/data-source/mock-icm-data-source.spec.ts @@ -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') @@ -19,6 +20,7 @@ describe('MockIcmDataSource', () => { beforeEach(async () => { vi.clearAllMocks() + vi.spyOn(icmConfig, 'isOocAgreementLinesConfig').mockReturnValue(false) const module: TestingModule = await Test.createTestingModule({ providers: [MockIcmDataSource], @@ -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( diff --git a/backend/src/sync/icm/data-source/mock-icm-data-source.ts b/backend/src/sync/icm/data-source/mock-icm-data-source.ts index 79bdbc85..f6607ee5 100644 --- a/backend/src/sync/icm/data-source/mock-icm-data-source.ts +++ b/backend/src/sync/icm/data-source/mock-icm-data-source.ts @@ -1,7 +1,7 @@ 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() @@ -9,6 +9,11 @@ export class MockIcmDataSource extends IcmDataSource { private readonly logger = new Logger(MockIcmDataSource.name) async fetchAll(config: IcmApiConfig, lastUpdated?: Date): Promise { + 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`) diff --git a/backend/src/sync/icm/icm.config.ts b/backend/src/sync/icm/icm.config.ts index 5d250549..628c1178 100644 --- a/backend/src/sync/icm/icm.config.ts +++ b/backend/src/sync/icm/icm.config.ts @@ -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[] = [