Skip to content

Commit

Permalink
Ongoing cron - not running for incomplete reports (#2783)
Browse files Browse the repository at this point in the history
* feat: ongoing cron - not running for incomplete reports

* feat: added a test to ongoing-monitoring.cron.intg.test.ts
  • Loading branch information
tomer-shvadron authored Oct 16, 2024
1 parent 17d9fd4 commit 0a934ec
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PrismaService } from '@/prisma/prisma.service';
import { AppLoggerService } from '@/common/app-logger/app-logger.service';
import { CustomerService } from '@/customer/customer.service';
import { BusinessService } from '@/business/business.service';
import { Business, Project } from '@prisma/client';
import { Business, BusinessReportStatus, BusinessReportType, Project } from '@prisma/client';
import {
FEATURE_LIST,
TCustomerWithFeatures,
Expand All @@ -20,7 +20,7 @@ describe('OngoingMonitoringCron', () => {
let customerService: CustomerService;
let businessService: BusinessService;
let loggerService: AppLoggerService;
// Add other services as needed
let businessReportService: BusinessReportService;

beforeEach(async () => {
const module = await Test.createTestingModule({
Expand All @@ -40,6 +40,7 @@ describe('OngoingMonitoringCron', () => {
prismaService = module.get<PrismaService>(PrismaService);
customerService = module.get<CustomerService>(CustomerService);
businessService = module.get<BusinessService>(BusinessService);
businessReportService = module.get<BusinessReportService>(BusinessReportService);
loggerService = module.get<AppLoggerService>(AppLoggerService);
});

Expand All @@ -66,6 +67,37 @@ describe('OngoingMonitoringCron', () => {
expect(errorLogSpy).toHaveBeenCalledWith(expect.stringContaining('An error occurred'));
});

it('should not create an ongoing report when the last business report is incomplete', async () => {
jest.spyOn(prismaService, 'acquireLock').mockResolvedValue(true);
jest.spyOn(customerService, 'list').mockResolvedValue(mockCustomers());
jest
.spyOn(businessService, 'list')
.mockResolvedValue(mockBusinesses().filter(business => business.id === 'business3'));
jest.spyOn(businessReportService, 'createBusinessReportAndTriggerReportCreation');
jest.spyOn(businessReportService, 'findMany').mockResolvedValue([
{
id: 'business1',
reportId: 'mockReport1',
report: {},
riskScore: 0,
batchId: null,
projectId: '1',
businessId: 'business3',
status: BusinessReportStatus.in_progress,
type: BusinessReportType.MERCHANT_REPORT_T1,
createdAt: new Date(new Date().setDate(new Date().getDate() - 31)),
updatedAt: new Date(new Date().setDate(new Date().getDate() - 30)),
},
]);

await service.handleCron();

expect(businessReportService.findMany).toHaveBeenCalled();
expect(
businessReportService.createBusinessReportAndTriggerReportCreation,
).not.toHaveBeenCalled();
});

it('should always release the lock after processing', async () => {
jest.spyOn(prismaService, 'acquireLock').mockResolvedValue(true);
const releaseLockSpy = jest.spyOn(prismaService, 'releaseLock');
Expand All @@ -83,7 +115,7 @@ describe('OngoingMonitoringCron', () => {
});

const mockWorkflowService = {
createOrUpdateWorkflowRuntime: jest.fn().mockImplementation(params => {
createOrUpdateWorkflowRuntime: jest.fn().mockImplementation(() => {
return Promise.resolve(true);
}),
};
Expand All @@ -108,25 +140,23 @@ describe('OngoingMonitoringCron', () => {
};

const mockBusinessReportService = {
findMany: jest.fn().mockImplementation(criteria => {
// Return an array of mock reports or a Promise of such an array
return Promise.resolve([
findMany: jest.fn().mockImplementation(() =>
Promise.resolve([
{
id: 'mockReport1',
reportId: 'mockReport1',
createdAt: new Date(new Date().setDate(new Date().getDate() - 30)),
report: { reportId: 'mockReport1' },
},
{ id: 'mockReport2', createdAt: new Date(), report: { reportId: 'mockReport2' } },
]); // Example, adjust as needed
}),
// Simulate other needed service methods
]),
),
createBusinessReportAndTriggerReportCreation: jest.fn(),
createReport: jest.fn().mockImplementation(reportDetails => {
return Promise.resolve({ id: 'newMockReport', ...reportDetails });
}),
};

// Mock data generators
const mockCustomers = async () => {
return [
{
Expand All @@ -149,7 +179,7 @@ describe('OngoingMonitoringCron', () => {
},
},
},
projects: [{ id: 1 } as unknown as Project],
projects: [{ id: '1' } as unknown as Project],
},
] satisfies TCustomerWithFeatures[];
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { WorkflowService } from '@/workflow/workflow.service';
import { isErrorWithMessage, ObjectValues } from '@ballerine/common';
import { Injectable } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Business, BusinessReportType } from '@prisma/client';
import { Business, BusinessReportStatus, BusinessReportType } from '@prisma/client';
import get from 'lodash/get';

const ONE_DAY = 24 * 60 * 60 * 1000;
Expand Down Expand Up @@ -81,13 +81,22 @@ export class OngoingMonitoringCron {

if (!lastReceivedReport?.reportId) {
this.logger.log(
`No initial report found for business: ${business.companyName} (id: ${business.id})`,
`No initial report found for business ${business.companyName} (id: ${business.id})`,
);

continue;
}

if (lastReceivedReport.status !== BusinessReportStatus.completed) {
this.logger.log(
`Last report for business ${business.companyName} (id: ${business.id}) was not completed`,
);

continue;
}

const now = new Date().getTime();

const { options } = featureConfig;

const lastReceivedReportTime = lastReceivedReport.createdAt.getTime();
Expand Down

0 comments on commit 0a934ec

Please sign in to comment.