fennec-be/src/pipeline-tasks/pipeline-task.consumer.spec.ts
2021-04-05 20:20:43 +08:00

243 lines
7.8 KiB
TypeScript

import { Test, TestingModule } from '@nestjs/testing';
import { Job } from 'bull';
import { join } from 'path';
import { ReposService } from '../repos/repos.service';
import { PipelineUnits } from './enums/pipeline-units.enum';
import { PipelineTaskConsumer } from './pipeline-task.consumer';
import { PipelineTask } from './pipeline-task.entity';
import { PipelineTasksService } from './pipeline-tasks.service';
import { PipelineTaskLogMessage } from './models/pipeline-task-log-message.module';
import { Pipeline } from '../pipelines/pipeline.entity';
import { Project } from '../projects/project.entity';
import { TaskStatuses } from './enums/task-statuses.enum';
import { PipelineTaskLogsService } from './pipeline-task-logs.service';
import { ApplicationException } from '../commons/exceptions/application.exception';
describe('PipelineTaskConsumer', () => {
let consumer: PipelineTaskConsumer;
let tasksService: PipelineTasksService;
let logsService: PipelineTaskLogsService;
const getJob = () =>
({
data: {
pipelineId: 'test',
units: [PipelineUnits.checkout, PipelineUnits.test],
},
} as Job<PipelineTask>);
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: PipelineTasksService,
useValue: {
doNextTask: () => undefined,
updateTask: async (value) => value,
},
},
{
provide: ReposService,
useValue: {
getWorkspaceRootByTask: () => 'workspace-root',
checkout: async () => undefined,
},
},
{
provide: PipelineTaskLogsService,
useValue: {
recordLog: async () => undefined,
readLogsAsPipelineTaskLogs: async () => [],
},
},
PipelineTaskConsumer,
],
}).compile();
tasksService = module.get(PipelineTasksService);
logsService = module.get(PipelineTaskLogsService);
consumer = module.get(PipelineTaskConsumer);
});
it('should be defined', () => {
expect(consumer).toBeDefined();
});
describe('onCompleted', () => {
it('should call doNextTask()', () => {
const job = getJob();
const doNextTask = jest.spyOn(tasksService, 'doNextTask');
consumer.onCompleted(job);
expect(doNextTask).toHaveBeenCalledTimes(1);
});
});
describe('runScript', () => {
let logText: string;
let errorText: string;
let recordLog: jest.SpyInstance;
beforeEach(() => {
logText = '';
errorText = '';
recordLog = jest
.spyOn(logsService, 'recordLog')
.mockImplementation(async (log: PipelineTaskLogMessage) => {
logText += log.message;
if (log.isError) {
errorText += log.message;
}
});
});
it('should success and log right message', async () => {
await consumer.runScript(
'node one-second-work.js',
join(__dirname, '../../test/data'),
);
expect(logText).toMatch(/10.+20.+30.+40.+50.+60.+70.+80.+90/s);
expect(recordLog).toHaveBeenCalledTimes(10);
expect(
((recordLog.mock.calls[8][0] as unknown) as PipelineTaskLogMessage)
.message,
).toMatch(/^90/);
});
it('should failed and log right message', async () => {
await expect(
consumer.runScript(
'node bad-work.js',
join(__dirname, '../../test/data'),
),
).rejects.toThrowError(/exec script failed/);
expect(errorText).toMatch(/Error Message/);
const logs = recordLog.mock.calls
.map((call) => ((call[0] as unknown) as PipelineTaskLogMessage).message)
.join('');
expect(logs).toMatch(/10.+20.+30.+40.+50/s);
});
it('should log with task', async () => {
const task = new PipelineTask();
task.id = 'test';
const recordLog = jest.spyOn(logsService, 'recordLog');
await expect(
consumer.runScript(
'node bad-work.js',
join(__dirname, '../../test/data'),
task,
),
).rejects.toThrowError(/exec script failed/);
expect(errorText).toMatch(/Error Message 2/);
expect(
((recordLog.mock.calls[2][0] as unknown) as PipelineTaskLogMessage)
.task,
).toMatchObject(task);
});
});
describe('doTask', () => {
let task: PipelineTask;
beforeEach(() => {
task = new PipelineTask();
task.id = 'test-id';
task.logs = [];
task.pipeline = new Pipeline();
task.pipeline.workUnitMetadata = {
version: 1,
units: [
{
type: PipelineUnits.checkout,
scripts: [],
},
{
type: PipelineUnits.installDependencies,
scripts: ["echo ' Hello, Fennec!'"],
},
],
};
task.units = task.pipeline.workUnitMetadata.units.map(
(unit) => unit.type,
);
task.pipeline.project = new Project();
task.pipeline.project.name = 'test-project';
});
it('success and update task on db', async () => {
const job: Job = ({
data: task,
update: jest.fn().mockImplementation(() => undefined),
} as unknown) as Job;
jest
.spyOn(consumer, 'runScript')
.mockImplementation(async () => undefined);
const updateTask = jest.spyOn(tasksService, 'updateTask');
await consumer.doTask(job);
expect(updateTask).toHaveBeenCalledTimes(4);
expect(updateTask.mock.calls[0][0].startedAt).toBeDefined();
expect(updateTask.mock.calls[1][0].endedAt).toBeDefined();
expect(updateTask.mock.calls[1][0].status).toEqual(TaskStatuses.success);
});
it('failed and update task on db', async () => {
const job: Job = ({
data: task,
update: jest.fn().mockImplementation(() => undefined),
} as unknown) as Job;
jest.spyOn(consumer, 'runScript').mockImplementation(async () => {
throw new ApplicationException('exec script failed');
});
const updateTask = jest.spyOn(tasksService, 'updateTask');
await consumer.doTask(job);
expect(updateTask).toHaveBeenCalledTimes(4);
expect(updateTask.mock.calls[0][0].startedAt).toBeDefined();
expect(updateTask.mock.calls[1][0].endedAt).toBeDefined();
expect(updateTask.mock.calls[1][0].status).toEqual(TaskStatuses.failed);
});
it('should do all task', async () => {
const job: Job = ({
data: task,
update: jest.fn().mockImplementation(() => undefined),
} as unknown) as Job;
const runScript = jest
.spyOn(consumer, 'runScript')
.mockImplementation(async () => undefined);
const updateTask = jest.spyOn(tasksService, 'updateTask');
await consumer.doTask(job);
expect(runScript).toHaveBeenCalledTimes(1);
expect(updateTask).toHaveBeenCalledTimes(4);
const taskDto: PipelineTask = updateTask.mock.calls[0][0];
expect(taskDto.logs).toHaveLength(2);
expect(taskDto.logs[0].status).toEqual(TaskStatuses.success);
expect(taskDto.logs[0].unit).toEqual(PipelineUnits.checkout);
});
it('should log error message', async () => {
const job: Job = ({
data: task,
update: jest.fn().mockImplementation(() => undefined),
} as unknown) as Job;
const runScript = jest
.spyOn(consumer, 'runScript')
.mockImplementation(async () => {
throw new Error('bad message');
});
const updateTask = jest.spyOn(tasksService, 'updateTask');
await consumer.doTask(job);
expect(updateTask).toHaveBeenCalledTimes(4);
const taskDto: PipelineTask = updateTask.mock.calls[0][0];
expect(taskDto.logs).toHaveLength(2);
expect(taskDto.logs[0].status).toEqual(TaskStatuses.success);
expect(taskDto.logs[1].status).toEqual(TaskStatuses.failed);
});
});
});