Best JavaScript code snippet using fast-check-monorepo
TaskManager.test.ts
Source:TaskManager.test.ts
1import type { PromiseCancellable } from '@matrixai/async-cancellable';2import type { ContextTimed } from '@/contexts/types';3import type { Task, TaskHandlerId, TaskPath } from '@/tasks/types';4import fs from 'fs';5import path from 'path';6import os from 'os';7import { DB } from '@matrixai/db';8import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';9import { Lock } from '@matrixai/async-locks';10import * as fc from 'fast-check';11import TaskManager from '@/tasks/TaskManager';12import * as tasksErrors from '@/tasks/errors';13import * as utils from '@/utils';14import { promise, sleep, never } from '@/utils';15describe(TaskManager.name, () => {16 const logger = new Logger(`${TaskManager.name} test`, LogLevel.WARN, [17 new StreamHandler(),18 ]);19 const handlerId = 'testId' as TaskHandlerId;20 let dataDir: string;21 let db: DB;22 beforeEach(async () => {23 dataDir = await fs.promises.mkdtemp(24 path.join(os.tmpdir(), 'polykey-test-'),25 );26 const dbPath = path.join(dataDir, 'db');27 db = await DB.createDB({28 dbPath,29 logger,30 });31 });32 afterEach(async () => {33 await db.stop();34 await fs.promises.rm(dataDir, { recursive: true, force: true });35 });36 test('can start and stop', async () => {37 const taskManager = await TaskManager.createTaskManager({38 db,39 lazy: false,40 logger,41 });42 await taskManager.stop();43 await taskManager.start();44 await taskManager.stop();45 });46 // TODO: use timer mocking to speed up testing47 test('tasks persist between Tasks object creation', async () => {48 let taskManager = await TaskManager.createTaskManager({49 db,50 lazy: true,51 logger,52 });53 const handlerId = 'asd' as TaskHandlerId;54 const handler = jest.fn();55 handler.mockImplementation(async () => {});56 taskManager.registerHandler(handlerId, handler);57 await taskManager.startProcessing();58 await taskManager.scheduleTask({59 handlerId,60 parameters: [1],61 delay: 1000,62 lazy: true,63 });64 await taskManager.scheduleTask({65 handlerId,66 parameters: [2],67 delay: 100,68 lazy: true,69 });70 await taskManager.scheduleTask({71 handlerId,72 parameters: [3],73 delay: 2000,74 lazy: true,75 });76 await taskManager.scheduleTask({77 handlerId,78 parameters: [4],79 delay: 10,80 lazy: true,81 });82 await taskManager.scheduleTask({83 handlerId,84 parameters: [5],85 delay: 10,86 lazy: true,87 });88 await taskManager.scheduleTask({89 handlerId,90 parameters: [6],91 delay: 10,92 lazy: true,93 });94 await taskManager.scheduleTask({95 handlerId,96 parameters: [7],97 delay: 3000,98 lazy: true,99 });100 await sleep(500);101 await taskManager.stop();102 expect(handler).toHaveBeenCalledTimes(4);103 handler.mockClear();104 taskManager = await TaskManager.createTaskManager({105 db,106 lazy: true,107 logger,108 });109 taskManager.registerHandler(handlerId, handler);110 await taskManager.startProcessing();111 await sleep(4000);112 await taskManager.stop();113 expect(handler).toHaveBeenCalledTimes(3);114 });115 // TODO: use timer mocking to speed up testing116 test('tasks persist between Tasks stop and starts', async () => {117 const taskManager = await TaskManager.createTaskManager({118 db,119 lazy: true,120 logger,121 });122 const handlerId = 'asd' as TaskHandlerId;123 const handler = jest.fn();124 handler.mockImplementation(async () => {});125 taskManager.registerHandler(handlerId, handler);126 await taskManager.startProcessing();127 await taskManager.scheduleTask({128 handlerId,129 parameters: [1],130 delay: 1000,131 lazy: true,132 });133 await taskManager.scheduleTask({134 handlerId,135 parameters: [2],136 delay: 100,137 lazy: true,138 });139 await taskManager.scheduleTask({140 handlerId,141 parameters: [3],142 delay: 2000,143 lazy: true,144 });145 await taskManager.scheduleTask({146 handlerId,147 parameters: [4],148 delay: 10,149 lazy: true,150 });151 await taskManager.scheduleTask({152 handlerId,153 parameters: [5],154 delay: 10,155 lazy: true,156 });157 await taskManager.scheduleTask({158 handlerId,159 parameters: [6],160 delay: 10,161 lazy: true,162 });163 await taskManager.scheduleTask({164 handlerId,165 parameters: [7],166 delay: 3000,167 lazy: true,168 });169 await sleep(500);170 await taskManager.stop();171 expect(handler).toHaveBeenCalledTimes(4);172 handler.mockClear();173 await taskManager.start();174 await sleep(4000);175 await taskManager.stop();176 expect(handler).toHaveBeenCalledTimes(3);177 });178 // FIXME: needs more experimenting to get this to work.179 test.skip('tasks persist between Tasks stop and starts TIMER FAKING', async () => {180 const taskManager = await TaskManager.createTaskManager({181 db,182 lazy: true,183 logger,184 });185 const handlerId = 'asd' as TaskHandlerId;186 const handler = jest.fn();187 handler.mockImplementation(async () => {});188 taskManager.registerHandler(handlerId, handler);189 // Console.log('a');190 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 1000 });191 const t1 = await taskManager.scheduleTask({192 handlerId,193 parameters: [1],194 delay: 100,195 lazy: false,196 });197 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 2000 });198 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });199 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });200 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 10 });201 await taskManager.scheduleTask({ handlerId, parameters: [1], delay: 3000 });202 // Setting up actions203 jest.useFakeTimers();204 setTimeout(async () => {205 // Console.log('starting processing');206 await taskManager.startProcessing();207 }, 0);208 setTimeout(async () => {209 // Console.log('stop');210 await taskManager.stop();211 }, 500);212 setTimeout(async () => {213 // Console.log('start');214 await taskManager.start();215 }, 1000);216 // Running tests here...217 // after 600 ms we should stop and 4 taskManager should've run218 jest.advanceTimersByTime(400);219 jest.runAllTimers();220 jest.advanceTimersByTime(200);221 // Console.log(jest.getTimerCount());222 jest.runAllTimers();223 // Console.log(jest.getTimerCount());224 await t1.promise();225 expect(handler).toHaveBeenCalledTimes(4);226 // After another 5000ms the rest should've been called227 handler.mockClear();228 jest.advanceTimersByTime(5000);229 // Expect(handler).toHaveBeenCalledTimes(3);230 jest.useRealTimers();231 await taskManager.stop();232 });233 test('activeLimit is enforced', async () => {234 const activeLimit = 5;235 const taskArb = fc236 .record({237 handlerId: fc.constant(handlerId),238 delay: fc.integer({ min: 10, max: 1000 }),239 parameters: fc.constant([]),240 priority: fc.integer({ min: -200, max: 200 }),241 })242 .noShrink();243 const scheduleCommandArb = taskArb.map(244 (taskSpec) => async (context: { taskManager: TaskManager }) => {245 return await context.taskManager.scheduleTask({246 ...taskSpec,247 lazy: false,248 });249 },250 );251 const sleepCommandArb = fc252 .integer({ min: 10, max: 100 })253 .noShrink()254 .map((value) => async (_context) => {255 await sleep(value);256 });257 const commandsArb = fc.array(258 fc.oneof(259 { arbitrary: scheduleCommandArb, weight: 2 },260 { arbitrary: sleepCommandArb, weight: 1 },261 ),262 { maxLength: 50, minLength: 50 },263 );264 await fc.assert(265 fc.asyncProperty(commandsArb, async (commands) => {266 const taskManager = await TaskManager.createTaskManager({267 activeLimit,268 db,269 fresh: true,270 logger,271 });272 const handler = jest.fn();273 handler.mockImplementation(async () => {274 await sleep(200);275 });276 taskManager.registerHandler(handlerId, handler);277 await taskManager.startProcessing();278 const context = { taskManager };279 // Scheduling taskManager to be scheduled280 const pendingTasks: Array<PromiseCancellable<any>> = [];281 for (const command of commands) {282 expect(taskManager.activeCount).toBeLessThanOrEqual(activeLimit);283 const task = await command(context);284 if (task != null) pendingTasks.push(task.promise());285 }286 let completed = false;287 const waitForcompletionProm = (async () => {288 await Promise.all(pendingTasks);289 completed = true;290 })();291 // Check for active tasks while tasks are still running292 while (!completed) {293 expect(taskManager.activeCount).toBeLessThanOrEqual(activeLimit);294 await Promise.race([sleep(100), waitForcompletionProm]);295 }296 await taskManager.stop();297 }),298 { interruptAfterTimeLimit: globalThis.defaultTimeout - 2000, numRuns: 3 },299 );300 });301 // TODO: Use fastCheck for this302 test('tasks are handled exactly once per task', async () => {303 const handler = jest.fn();304 const pendingLock = new Lock();305 const [lockReleaser] = await pendingLock.lock()();306 const resolvedTasks = new Map<number, number>();307 const totalTasks = 50;308 handler.mockImplementation(async (_ctx, _taskInfo, number: number) => {309 resolvedTasks.set(number, (resolvedTasks.get(number) ?? 0) + 1);310 if (resolvedTasks.size >= totalTasks) await lockReleaser();311 });312 const taskManager = await TaskManager.createTaskManager({313 db,314 handlers: { [handlerId]: handler },315 logger,316 });317 await db.withTransactionF(async (tran) => {318 for (let i = 0; i < totalTasks; i++) {319 await taskManager.scheduleTask(320 {321 handlerId,322 parameters: [i],323 lazy: true,324 },325 tran,326 );327 }328 });329 await pendingLock.waitForUnlock();330 // Each task called exactly once331 resolvedTasks.forEach((value) => expect(value).toEqual(1));332 await taskManager.stop();333 expect(handler).toHaveBeenCalledTimes(totalTasks);334 });335 // TODO: use fastCheck336 test('awaited taskPromises resolve', async () => {337 const handler = jest.fn();338 handler.mockImplementation(async (_ctx, _taskInfo, fail) => {339 if (!fail) throw Error('three');340 return fail;341 });342 const taskManager = await TaskManager.createTaskManager({343 db,344 handlers: { [handlerId]: handler },345 logger,346 });347 const taskSucceed = await taskManager.scheduleTask({348 handlerId,349 parameters: [true],350 lazy: false,351 });352 // Promise should succeed with result353 const taskSucceedP = taskSucceed!.promise();354 await expect(taskSucceedP).resolves.toBe(true);355 await taskManager.stop();356 });357 // TODO: use fastCheck358 test('awaited taskPromises reject', async () => {359 const handler = jest.fn();360 handler.mockImplementation(async (_ctx, _taskInfo, fail) => {361 if (!fail) throw Error('three');362 return fail;363 });364 const taskManager = await TaskManager.createTaskManager({365 db,366 handlers: { [handlerId]: handler },367 logger,368 });369 const taskFail = await taskManager.scheduleTask({370 handlerId,371 parameters: [false],372 lazy: false,373 });374 // Promise should throw375 const taskFailP = taskFail.promise();376 await expect(taskFailP).rejects.toThrow(Error);377 await taskManager.stop();378 });379 // TODO: use fastCheck380 test('awaited taskPromises resolve or reject', async () => {381 const handler = jest.fn();382 handler.mockImplementation(async (_ctx, _taskInfo, fail) => {383 if (!fail) throw Error('three');384 return fail;385 });386 const taskManager = await TaskManager.createTaskManager({387 db,388 handlers: { [handlerId]: handler },389 logger,390 });391 const taskFail = await taskManager.scheduleTask({392 handlerId,393 parameters: [false],394 lazy: false,395 });396 const taskSuccess = await taskManager.scheduleTask({397 handlerId,398 parameters: [true],399 lazy: false,400 });401 // Promise should succeed with result402 await expect(taskSuccess.promise()).resolves.toBe(true);403 await expect(taskFail.promise()).rejects.toThrow(Error);404 await taskManager.stop();405 });406 test('tasks fail with no handler', async () => {407 const taskManager = await TaskManager.createTaskManager({408 db,409 logger,410 });411 const taskFail = await taskManager.scheduleTask({412 handlerId,413 parameters: [],414 lazy: false,415 });416 // Promise should throw417 const taskFailP = taskFail.promise();418 await expect(taskFailP).rejects.toThrow(419 tasksErrors.ErrorTaskHandlerMissing,420 );421 await taskManager.stop();422 });423 test('tasks fail with unregistered handler', async () => {424 const handler = jest.fn();425 handler.mockImplementation(async (_ctx, _taskInfo, fail) => {426 if (!fail) throw Error('three');427 return fail;428 });429 const taskManager = await TaskManager.createTaskManager({430 db,431 handlers: { [handlerId]: handler },432 logger,433 });434 const taskSucceed = await taskManager.scheduleTask({435 handlerId,436 parameters: [false],437 lazy: false,438 });439 // Promise should succeed440 const taskSucceedP = taskSucceed.promise();441 await expect(taskSucceedP).rejects.not.toThrow(442 tasksErrors.ErrorTaskHandlerMissing,443 );444 // Deregister445 taskManager.deregisterHandler(handlerId);446 const taskFail = await taskManager.scheduleTask({447 handlerId,448 parameters: [false],449 lazy: false,450 });451 const taskFailP = taskFail.promise();452 await expect(taskFailP).rejects.toThrow(453 tasksErrors.ErrorTaskHandlerMissing,454 );455 await taskManager.stop();456 });457 test('eager taskPromise resolves when awaited after task completion', async () => {458 const handler = jest.fn();459 handler.mockImplementation(async (_ctx, _taskInfo, fail) => {460 if (!fail) throw Error('three');461 return fail;462 });463 const taskManager = await TaskManager.createTaskManager({464 db,465 handlers: { [handlerId]: handler },466 lazy: true,467 logger,468 });469 const taskSucceed1 = await taskManager.scheduleTask({470 handlerId,471 parameters: [true],472 lazy: false,473 });474 await taskManager.startProcessing();475 await expect(taskSucceed1.promise()).resolves.toBe(true);476 const taskSucceed2 = await taskManager.scheduleTask({477 handlerId,478 parameters: [true],479 lazy: false,480 });481 await expect(taskSucceed2.promise()).resolves.toBe(true);482 await taskManager.stop();483 });484 test('lazy taskPromise rejects when awaited after task completion', async () => {485 const handler = jest.fn();486 handler.mockImplementation(async () => {});487 const taskManager = await TaskManager.createTaskManager({488 db,489 handlers: { [handlerId]: handler },490 lazy: true,491 logger,492 });493 const taskSucceed = await taskManager.scheduleTask({494 handlerId,495 parameters: [],496 lazy: true,497 });498 const taskProm = taskManager.getTaskPromise(taskSucceed.id);499 await taskManager.startProcessing();500 await taskProm;501 await expect(taskSucceed.promise()).rejects.toThrow();502 await taskManager.stop();503 });504 test('Task Promises should be singletons', async () => {505 const taskManager = await TaskManager.createTaskManager({506 db,507 lazy: true,508 logger,509 });510 const task1 = await taskManager.scheduleTask({511 handlerId,512 parameters: [],513 lazy: false,514 });515 const task2 = await taskManager.scheduleTask({516 handlerId,517 parameters: [],518 lazy: true,519 });520 expect(task1.promise()).toBe(task1.promise());521 expect(task1.promise()).toBe(taskManager.getTaskPromise(task1.id));522 expect(taskManager.getTaskPromise(task1.id)).toBe(523 taskManager.getTaskPromise(task1.id),524 );525 expect(task2.promise()).toBe(task2.promise());526 expect(task2.promise()).toBe(taskManager.getTaskPromise(task2.id));527 expect(taskManager.getTaskPromise(task2.id)).toBe(528 taskManager.getTaskPromise(task2.id),529 );530 await taskManager.stop();531 });532 test('can cancel scheduled task, clean up and reject taskPromise', async () => {533 const taskManager = await TaskManager.createTaskManager({534 db,535 lazy: true,536 logger,537 });538 const task1 = await taskManager.scheduleTask({539 handlerId,540 parameters: [],541 lazy: false,542 });543 const task2 = await taskManager.scheduleTask({544 handlerId,545 parameters: [],546 lazy: true,547 });548 // Cancellation should reject promise549 const taskPromise = task1.promise();550 taskPromise.cancel('cancelled');551 await expect(taskPromise).rejects.toBe('cancelled');552 // Should cancel without awaiting anything553 task2.cancel('cancelled');554 await sleep(200);555 // Task should be cleaned up556 expect(await taskManager.getTask(task1.id)).toBeUndefined();557 expect(await taskManager.getTask(task2.id)).toBeUndefined();558 await taskManager.stop();559 });560 test('can cancel queued task, clean up and reject taskPromise', async () => {561 const taskManager = await TaskManager.createTaskManager({562 db,563 lazy: true,564 logger,565 });566 const task1 = await taskManager.scheduleTask({567 handlerId,568 parameters: [],569 lazy: false,570 });571 const task2 = await taskManager.scheduleTask({572 handlerId,573 parameters: [],574 lazy: true,575 });576 // @ts-ignore: private method577 await taskManager.startScheduling();578 await sleep(100);579 // Cancellation should reject promise580 const taskPromise = task1.promise();581 taskPromise.cancel('cancelled');582 await expect(taskPromise).rejects.toBe('cancelled');583 task2.cancel('cancelled');584 await sleep(200);585 // Task should be cleaned up586 expect(await taskManager.getTask(task1.id)).toBeUndefined();587 expect(await taskManager.getTask(task2.id)).toBeUndefined();588 await taskManager.stop();589 });590 test('can cancel active task, clean up and reject taskPromise', async () => {591 const handler = jest.fn();592 const pauseProm = promise();593 handler.mockImplementation(async (ctx: ContextTimed) => {594 const abortProm = new Promise((resolve, reject) =>595 ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),596 );597 await Promise.race([pauseProm.p, abortProm]);598 });599 const taskManager = await TaskManager.createTaskManager({600 db,601 handlers: { [handlerId]: handler },602 lazy: true,603 logger,604 });605 const task1 = await taskManager.scheduleTask({606 handlerId,607 parameters: [],608 lazy: false,609 });610 const task2 = await taskManager.scheduleTask({611 handlerId,612 parameters: [],613 lazy: true,614 });615 await taskManager.startProcessing();616 await sleep(100);617 // Cancellation should reject promise618 const taskPromise = task1.promise();619 taskPromise.cancel('cancelled');620 // Await taskPromise.catch(reason => console.error(reason));621 await expect(taskPromise).rejects.toBe('cancelled');622 task2.cancel('cancelled');623 await sleep(200);624 // Task should be cleaned up625 expect(await taskManager.getTask(task1.id, true)).toBeUndefined();626 expect(await taskManager.getTask(task2.id, true)).toBeUndefined();627 pauseProm.resolveP();628 await taskManager.stop();629 });630 test('incomplete active tasks cleaned up during startup', async () => {631 const handler = jest.fn();632 handler.mockImplementation(async () => {});633 const taskManager = await TaskManager.createTaskManager({634 db,635 handlers: { [handlerId]: handler },636 lazy: true,637 logger,638 });639 // Seeding data640 const task = await taskManager.scheduleTask({641 handlerId,642 parameters: [],643 deadline: 100,644 lazy: false,645 });646 // Moving task to active in database647 const taskScheduleTime = task.scheduled.getTime();648 // @ts-ignore: private property649 const tasksScheduledDbPath = taskManager.tasksScheduledDbPath;650 // @ts-ignore: private property651 const tasksActiveDbPath = taskManager.tasksActiveDbPath;652 const taskIdBuffer = task.id.toBuffer();653 await db.withTransactionF(async (tran) => {654 await tran.del([655 ...tasksScheduledDbPath,656 utils.lexiPackBuffer(taskScheduleTime),657 taskIdBuffer,658 ]);659 await tran.put([...tasksActiveDbPath, taskIdBuffer], null);660 });661 // Task should be active662 const newTask1 = await taskManager.getTask(task.id);663 expect(newTask1!.status).toBe('active');664 // Restart to clean up665 await taskManager.stop();666 await taskManager.start({ lazy: true });667 // Task should be back to queued668 const newTask2 = await taskManager.getTask(task.id, false);669 expect(newTask2!.status).toBe('queued');670 await taskManager.startProcessing();671 await newTask2!.promise();672 await taskManager.stop();673 });674 test('stopping should gracefully end active tasks', async () => {675 const handler = jest.fn();676 const pauseProm = promise();677 handler.mockImplementation(async (ctx: ContextTimed) => {678 const abortProm = new Promise((resolve, reject) =>679 ctx.signal.addEventListener('abort', () =>680 reject(681 new tasksErrors.ErrorTaskRetry(undefined, {682 cause: ctx.signal.reason,683 }),684 ),685 ),686 );687 await Promise.race([pauseProm.p, abortProm]);688 });689 const taskManager = await TaskManager.createTaskManager({690 db,691 handlers: { [handlerId]: handler },692 lazy: true,693 logger,694 });695 const task1 = await taskManager.scheduleTask({696 handlerId,697 parameters: [],698 lazy: true,699 });700 const task2 = await taskManager.scheduleTask({701 handlerId,702 parameters: [],703 lazy: true,704 });705 await taskManager.startProcessing();706 await sleep(100);707 await taskManager.stop();708 // TaskManager should still exist.709 await taskManager.start({ lazy: true });710 expect(await taskManager.getTask(task1.id)).toBeDefined();711 expect(await taskManager.getTask(task2.id)).toBeDefined();712 await taskManager.stop();713 });714 test('stopped tasks should run again if allowed', async () => {715 const pauseProm = promise();716 const handlerId1 = 'handler1' as TaskHandlerId;717 const handler1 = jest.fn();718 handler1.mockImplementation(async (ctx: ContextTimed) => {719 const abortProm = new Promise((resolve, reject) =>720 ctx.signal.addEventListener('abort', () =>721 reject(722 new tasksErrors.ErrorTaskRetry(undefined, {723 cause: ctx.signal.reason,724 }),725 ),726 ),727 );728 await Promise.race([pauseProm.p, abortProm]);729 });730 const handlerId2 = 'handler2' as TaskHandlerId;731 const handler2 = jest.fn();732 handler2.mockImplementation(async (ctx: ContextTimed) => {733 const abortProm = new Promise((resolve, reject) =>734 ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),735 );736 await Promise.race([pauseProm.p, abortProm]);737 });738 const taskManager = await TaskManager.createTaskManager({739 db,740 handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },741 lazy: true,742 logger,743 });744 const task1 = await taskManager.scheduleTask({745 handlerId: handlerId1,746 parameters: [],747 lazy: true,748 });749 const task2 = await taskManager.scheduleTask({750 handlerId: handlerId2,751 parameters: [],752 lazy: true,753 });754 await taskManager.startProcessing();755 await sleep(100);756 await taskManager.stop();757 // Tasks were run758 expect(handler1).toHaveBeenCalled();759 expect(handler2).toHaveBeenCalled();760 handler1.mockClear();761 handler2.mockClear();762 await taskManager.start({ lazy: true });763 const task1New = await taskManager.getTask(task1.id, false);764 const task2New = await taskManager.getTask(task2.id, false);765 await taskManager.startProcessing();766 // Task1 should still exist767 expect(task1New).toBeDefined();768 // Task2 should've been removed769 expect(task2New).toBeUndefined();770 pauseProm.resolveP();771 await expect(task1New?.promise()).resolves.toBeUndefined();772 // Tasks were run773 expect(handler1).toHaveBeenCalled();774 expect(handler2).not.toHaveBeenCalled();775 await taskManager.stop();776 });777 test('tests for taskPath', async () => {778 const taskManager = await TaskManager.createTaskManager({779 db,780 lazy: true,781 logger,782 });783 await taskManager.scheduleTask({784 handlerId,785 parameters: [1],786 path: ['one'],787 lazy: true,788 });789 await taskManager.scheduleTask({790 handlerId,791 parameters: [2],792 path: ['two'],793 lazy: true,794 });795 await taskManager.scheduleTask({796 handlerId,797 parameters: [3],798 path: ['two'],799 lazy: true,800 });801 await taskManager.scheduleTask({802 handlerId,803 parameters: [4],804 path: ['group1', 'three'],805 lazy: true,806 });807 await taskManager.scheduleTask({808 handlerId,809 parameters: [5],810 path: ['group1', 'four'],811 lazy: true,812 });813 await taskManager.scheduleTask({814 handlerId,815 parameters: [6],816 path: ['group1', 'four'],817 lazy: true,818 });819 await taskManager.scheduleTask({820 handlerId,821 parameters: [7],822 path: ['group2', 'five'],823 lazy: true,824 });825 await taskManager.scheduleTask({826 handlerId,827 parameters: [8],828 path: ['group2', 'six'],829 lazy: true,830 });831 const listTasks = async (taskGroup: TaskPath) => {832 const taskManagerList: Array<Task> = [];833 for await (const task of taskManager.getTasks(834 undefined,835 true,836 taskGroup,837 )) {838 taskManagerList.push(task);839 }840 return taskManagerList;841 };842 expect(await listTasks(['one'])).toHaveLength(1);843 expect(await listTasks(['two'])).toHaveLength(2);844 expect(await listTasks(['group1'])).toHaveLength(3);845 expect(await listTasks(['group1', 'four'])).toHaveLength(2);846 expect(await listTasks(['group2'])).toHaveLength(2);847 expect(await listTasks([])).toHaveLength(8);848 });849 test('getTask', async () => {850 const taskManager = await TaskManager.createTaskManager({851 db,852 lazy: true,853 logger,854 });855 const task1 = await taskManager.scheduleTask({856 handlerId,857 parameters: [1],858 lazy: true,859 });860 const task2 = await taskManager.scheduleTask({861 handlerId,862 parameters: [2],863 lazy: true,864 });865 const gotTask1 = await taskManager.getTask(task1.id, true);866 expect(task1.toString()).toEqual(gotTask1?.toString());867 const gotTask2 = await taskManager.getTask(task2.id, true);868 expect(task2.toString()).toEqual(gotTask2?.toString());869 });870 test('getTasks', async () => {871 const taskManager = await TaskManager.createTaskManager({872 db,873 lazy: true,874 logger,875 });876 await taskManager.scheduleTask({ handlerId, parameters: [1], lazy: true });877 await taskManager.scheduleTask({ handlerId, parameters: [2], lazy: true });878 await taskManager.scheduleTask({ handlerId, parameters: [3], lazy: true });879 await taskManager.scheduleTask({ handlerId, parameters: [4], lazy: true });880 const taskList: Array<Task> = [];881 for await (const task of taskManager.getTasks()) {882 taskList.push(task);883 }884 expect(taskList.length).toBe(4);885 });886 test('updating tasks while scheduled', async () => {887 const handlerId1 = 'handler1' as TaskHandlerId;888 const handlerId2 = 'handler2' as TaskHandlerId;889 const handler1 = jest.fn();890 const handler2 = jest.fn();891 const taskManager = await TaskManager.createTaskManager({892 db,893 handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },894 lazy: true,895 logger,896 });897 const task1 = await taskManager.scheduleTask({898 handlerId: handlerId1,899 delay: 100000,900 parameters: [],901 lazy: false,902 });903 await taskManager.updateTask(task1.id, {904 handlerId: handlerId2,905 delay: 0,906 parameters: [1],907 priority: 100,908 deadline: 100,909 path: ['newPath'],910 });911 // Task should be updated912 const oldTask = await taskManager.getTask(task1.id);913 if (oldTask == null) never();914 expect(oldTask.id.equals(task1.id)).toBeTrue();915 expect(oldTask.handlerId).toEqual(handlerId2);916 expect(oldTask.delay).toBe(0);917 expect(oldTask.parameters).toEqual([1]);918 expect(oldTask.priority).toEqual(100);919 expect(oldTask.deadline).toEqual(100);920 expect(oldTask.path).toEqual(['newPath']);921 // Path should've been updated922 let task_: Task | undefined;923 for await (const task of taskManager.getTasks(undefined, true, [924 'newPath',925 ])) {926 task_ = task;927 expect(task.id.equals(task1.id)).toBeTrue();928 }929 expect(task_).toBeDefined();930 await taskManager.stop();931 });932 test('updating tasks while queued or active should fail', async () => {933 const handler = jest.fn();934 handler.mockImplementation(async (_ctx, _taskInfo, value) => value);935 const taskManager = await TaskManager.createTaskManager({936 db,937 handlers: { [handlerId]: handler },938 lazy: true,939 logger,940 });941 // @ts-ignore: private method, only schedule tasks942 await taskManager.startScheduling();943 const task1 = await taskManager.scheduleTask({944 handlerId,945 delay: 0,946 parameters: [],947 lazy: false,948 });949 await sleep(100);950 await expect(951 taskManager.updateTask(task1.id, {952 delay: 1000,953 parameters: [1],954 }),955 ).rejects.toThrow(tasksErrors.ErrorTaskRunning);956 // Task has not been updated957 const oldTask = await taskManager.getTask(task1.id);958 if (oldTask == null) never();959 expect(oldTask.delay).toBe(0);960 expect(oldTask.parameters).toEqual([]);961 await taskManager.stop();962 });963 test('updating tasks delay should update schedule timer', async () => {964 const handlerId1 = 'handler1' as TaskHandlerId;965 const handlerId2 = 'handler2' as TaskHandlerId;966 const handler1 = jest.fn();967 const handler2 = jest.fn();968 handler1.mockImplementation(async (_ctx, _taskInfo, value) => value);969 handler2.mockImplementation(async (_ctx, _taskInfo, value) => value);970 const taskManager = await TaskManager.createTaskManager({971 db,972 handlers: { [handlerId1]: handler1, [handlerId2]: handler2 },973 lazy: true,974 logger,975 });976 const task1 = await taskManager.scheduleTask({977 handlerId: handlerId1,978 delay: 100000,979 parameters: [],980 lazy: false,981 });982 const task2 = await taskManager.scheduleTask({983 handlerId: handlerId1,984 delay: 100000,985 parameters: [],986 lazy: false,987 });988 await taskManager.updateTask(task1.id, {989 delay: 0,990 parameters: [1],991 });992 // Task should be updated993 const newTask = await taskManager.getTask(task1.id);994 if (newTask == null) never();995 expect(newTask.delay).toBe(0);996 expect(newTask.parameters).toEqual([1]);997 // Task should resolve with new parameter998 await taskManager.startProcessing();999 await expect(task1.promise()).resolves.toBe(1);1000 await sleep(100);1001 expect(handler1).toHaveBeenCalledTimes(1);1002 // Updating task should update existing timer1003 await taskManager.updateTask(task2.id, {1004 delay: 0,1005 parameters: [1],1006 handlerId: handlerId2,1007 });1008 await expect(task2.promise()).resolves.toBe(1);1009 expect(handler1).toHaveBeenCalledTimes(1);1010 expect(handler2).toHaveBeenCalledTimes(1);1011 await taskManager.stop();1012 });1013 test('task should run after scheduled delay', async () => {1014 const handler = jest.fn();1015 const taskManager = await TaskManager.createTaskManager({1016 db,1017 handlers: { [handlerId]: handler },1018 lazy: true,1019 logger,1020 });1021 // Edge case delays1022 // same as 0 delay1023 await taskManager.scheduleTask({1024 handlerId,1025 delay: NaN,1026 lazy: true,1027 });1028 // Same as max delay1029 await taskManager.scheduleTask({1030 handlerId,1031 delay: Infinity,1032 lazy: true,1033 });1034 // Normal delays1035 await taskManager.scheduleTask({1036 handlerId,1037 delay: 500,1038 lazy: true,1039 });1040 await taskManager.scheduleTask({1041 handlerId,1042 delay: 1000,1043 lazy: true,1044 });1045 await taskManager.scheduleTask({1046 handlerId,1047 delay: 1500,1048 lazy: true,1049 });1050 expect(handler).toHaveBeenCalledTimes(0);1051 await taskManager.startProcessing();1052 await sleep(250);1053 expect(handler).toHaveBeenCalledTimes(1);1054 await sleep(500);1055 expect(handler).toHaveBeenCalledTimes(2);1056 await sleep(500);1057 expect(handler).toHaveBeenCalledTimes(3);1058 await sleep(500);1059 expect(handler).toHaveBeenCalledTimes(4);1060 await taskManager.stop();1061 });1062 test('queued tasks should be started in priority order', async () => {1063 const handler = jest.fn();1064 const pendingProm = promise();1065 const totalTasks = 31;1066 const completedTaskOrder: Array<number> = [];1067 handler.mockImplementation(async (_ctx, _taskInfo, priority) => {1068 completedTaskOrder.push(priority);1069 if (completedTaskOrder.length >= totalTasks) pendingProm.resolveP();1070 });1071 const taskManager = await TaskManager.createTaskManager({1072 db,1073 handlers: { [handlerId]: handler },1074 lazy: true,1075 logger,1076 });1077 const expectedTaskOrder: Array<number> = [];1078 for (let i = 0; i < totalTasks; i += 1) {1079 const priority = 150 - i * 10;1080 expectedTaskOrder.push(priority);1081 await taskManager.scheduleTask({1082 handlerId,1083 parameters: [priority],1084 priority,1085 lazy: true,1086 });1087 }1088 // @ts-ignore: start scheduling first1089 await taskManager.startScheduling();1090 await sleep(500);1091 // @ts-ignore: Then queueing1092 await taskManager.startQueueing();1093 // Wait for all tasks to complete1094 await pendingProm.p;1095 expect(completedTaskOrder).toEqual(expectedTaskOrder);1096 await taskManager.stop();1097 });1098 test('task exceeding deadline should abort and clean up', async () => {1099 const handler = jest.fn();1100 const pauseProm = promise();1101 handler.mockImplementation(async (ctx: ContextTimed) => {1102 const abortProm = new Promise((resolve, reject) =>1103 ctx.signal.addEventListener('abort', () => reject(ctx.signal.reason)),1104 );1105 await Promise.race([pauseProm.p, abortProm]);1106 });1107 const taskManager = await TaskManager.createTaskManager({1108 db,1109 handlers: { [handlerId]: handler },1110 lazy: true,1111 logger,1112 });1113 const task = await taskManager.scheduleTask({1114 handlerId,1115 parameters: [],1116 deadline: 100,1117 lazy: false,1118 });1119 await taskManager.startProcessing();1120 // Cancellation should reject promise1121 const taskPromise = task.promise();1122 // FIXME: check for deadline timeout error1123 await expect(taskPromise).rejects.toThrow(tasksErrors.ErrorTaskTimeOut);1124 // Task should be cleaned up1125 const oldTask = await taskManager.getTask(task.id);1126 expect(oldTask).toBeUndefined();1127 pauseProm.resolveP();1128 await taskManager.stop();1129 });1130 test.todo('scheduled task times should not conflict');1131 // TODO: this should move the clock backwards with mocking1132 test.todo('taskIds are monotonic');1133 // TODO: needs fast check1134 test.todo('general concurrent API usage to test robustness');...
commands.spec.ts
Source:commands.spec.ts
1import * as fc from 'fast-check';2import { commands } from '../../../src/arbitrary/commands';3import prand from 'pure-rand';4import { Command } from '../../../src/check/model/command/Command';5import { Random } from '../../../src/random/generator/Random';6import { Arbitrary } from '../../../src/check/arbitrary/definition/Arbitrary';7import { Value } from '../../../src/check/arbitrary/definition/Value';8import { Stream } from '../../../src/stream/Stream';9import { tuple } from '../../../src/arbitrary/tuple';10import { nat } from '../../../src/arbitrary/nat';11import { isStrictlySmallerArray } from './__test-helpers__/ArrayHelpers';12type Model = Record<string, unknown>;13type Real = unknown;14type Cmd = Command<Model, Real>;15const model: Model = Object.freeze({});16const real: Real = Object.freeze({});17describe('commands (integration)', () => {18 function simulateCommands(cmds: Iterable<Cmd>): void {19 for (const c of cmds) {20 if (!c.check(model)) continue;21 try {22 c.run(model, real);23 } catch (err) {24 return;25 }26 }27 }28 it('should generate a cloneable instance', () => {29 fc.assert(30 fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {31 // Arrange32 const mrng = new Random(prand.xorshift128plus(seed));33 const logOnCheck: { data: string[] } = { data: [] };34 // Act35 const commandsArb = commands([36 new FakeConstant(new SuccessCommand(logOnCheck)),37 new FakeConstant(new SkippedCommand(logOnCheck)),38 new FakeConstant(new FailureCommand(logOnCheck)),39 ]);40 const baseCommands = commandsArb.generate(mrng, biasFactor);41 // Assert42 return baseCommands.hasToBeCloned;43 })44 );45 });46 it('should skip skipped commands on shrink', () => {47 fc.assert(48 fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {49 // Arrange50 const mrng = new Random(prand.xorshift128plus(seed));51 const logOnCheck: { data: string[] } = { data: [] };52 // Act53 const commandsArb = commands([54 new FakeConstant(new SuccessCommand(logOnCheck)),55 new FakeConstant(new SkippedCommand(logOnCheck)),56 new FakeConstant(new FailureCommand(logOnCheck)),57 ]);58 const baseCommands = commandsArb.generate(mrng, biasFactor);59 simulateCommands(baseCommands.value);60 // Assert61 const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);62 for (const shrunkCmds of shrinks) {63 logOnCheck.data = [];64 [...shrunkCmds.value].forEach((c) => c.check(model));65 expect(logOnCheck.data.every((e) => e !== 'skipped')).toBe(true);66 }67 })68 );69 });70 it('should shrink with failure at the end', () => {71 fc.assert(72 fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {73 // Arrange74 const mrng = new Random(prand.xorshift128plus(seed));75 const logOnCheck: { data: string[] } = { data: [] };76 // Act77 const commandsArb = commands([78 new FakeConstant(new SuccessCommand(logOnCheck)),79 new FakeConstant(new SkippedCommand(logOnCheck)),80 new FakeConstant(new FailureCommand(logOnCheck)),81 ]);82 const baseCommands = commandsArb.generate(mrng, biasFactor);83 simulateCommands(baseCommands.value);84 fc.pre(logOnCheck.data[logOnCheck.data.length - 1] === 'failure');85 // Assert86 const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);87 for (const shrunkCmds of shrinks) {88 logOnCheck.data = [];89 [...shrunkCmds.value].forEach((c) => c.check(model));90 if (logOnCheck.data.length > 0) {91 // either empty or ending by the failure92 expect(logOnCheck.data[logOnCheck.data.length - 1]).toEqual('failure');93 }94 }95 })96 );97 });98 it('should shrink with at most one failure and all successes', () => {99 fc.assert(100 fc.property(fc.integer(), fc.option(fc.integer({ min: 2 }), { nil: undefined }), (seed, biasFactor) => {101 // Arrange102 const mrng = new Random(prand.xorshift128plus(seed));103 const logOnCheck: { data: string[] } = { data: [] };104 // Act105 const commandsArb = commands([106 new FakeConstant(new SuccessCommand(logOnCheck)),107 new FakeConstant(new SkippedCommand(logOnCheck)),108 new FakeConstant(new FailureCommand(logOnCheck)),109 ]);110 const baseCommands = commandsArb.generate(mrng, biasFactor);111 simulateCommands(baseCommands.value);112 // Assert113 const shrinks = commandsArb.shrink(baseCommands.value_, baseCommands.context);114 for (const shrunkCmds of shrinks) {115 logOnCheck.data = [];116 [...shrunkCmds.value].forEach((c) => c.check(model));117 expect(logOnCheck.data.every((e) => e === 'failure' || e === 'success')).toBe(true);118 expect(logOnCheck.data.filter((e) => e === 'failure').length <= 1).toBe(true);119 }120 })121 );122 });123 it('should provide commands which have never run', () => {124 const commandsArb = commands([new FakeConstant(new SuccessCommand({ data: [] }))], {125 disableReplayLog: true,126 });127 const manyArbsIncludingCommandsOne = tuple(nat(16), commandsArb, nat(16));128 const assertCommandsNotStarted = (value: Value<[number, Iterable<Cmd>, number]>) => {129 // Check the commands have never been executed130 // by checking the toString of the iterable is empty131 expect(String(value.value_[1])).toEqual('');132 };133 const startCommands = (value: Value<[number, Iterable<Cmd>, number]>) => {134 // Iterate over all the generated commands to run them all135 let ranOneCommand = false;136 for (const cmd of value.value_[1]) {137 ranOneCommand = true;138 cmd.run({}, {});139 }140 // Confirming that executing at least one command will make the toString of the iterable141 // not empty142 if (ranOneCommand) {143 expect(String(value.value_[1])).not.toEqual('');144 }145 };146 fc.assert(147 fc.property(148 fc.integer().noShrink(),149 fc.infiniteStream(fc.nat()),150 fc.option(fc.integer({ min: 2 }), { nil: undefined }),151 (seed, shrinkPath, biasFactor) => {152 // Generate the first Value153 const it = shrinkPath[Symbol.iterator]();154 const mrng = new Random(prand.xorshift128plus(seed));155 let currentValue: Value<[number, Iterable<Cmd>, number]> | null = manyArbsIncludingCommandsOne.generate(156 mrng,157 biasFactor158 );159 // Check status and update first Value160 assertCommandsNotStarted(currentValue);161 startCommands(currentValue);162 // Traverse the shrink tree in order to detect already seen ids163 while (currentValue !== null) {164 currentValue = manyArbsIncludingCommandsOne165 .shrink(currentValue.value_, currentValue.context)166 .map((nextValue) => {167 // Check nothing starting for the next one168 assertCommandsNotStarted(nextValue);169 // Start everything: not supposed to impact any other shrinkable170 startCommands(nextValue);171 return nextValue;172 })173 .getNthOrLast(it.next().value);174 }175 }176 )177 );178 });179 it('should shrink to smaller values', () => {180 const commandsArb = commands([nat(3).map((id) => new SuccessIdCommand(id))]);181 fc.assert(182 fc.property(183 fc.integer().noShrink(),184 fc.infiniteStream(fc.nat()),185 fc.option(fc.integer({ min: 2 }), { nil: undefined }),186 (seed, shrinkPath, biasFactor) => {187 // Generate the first Value188 const it = shrinkPath[Symbol.iterator]();189 const mrng = new Random(prand.xorshift128plus(seed));190 let currentValue: Value<Iterable<Cmd>> | null = commandsArb.generate(mrng, biasFactor);191 // Run all commands of first Value192 simulateCommands(currentValue.value_);193 // Traverse the shrink tree in order to detect already seen ids194 const extractIdRegex = /^custom\((\d+)\)$/;195 while (currentValue !== null) {196 const currentItems = [...currentValue.value_].map((c) => +extractIdRegex.exec(c.toString())![1]);197 currentValue = commandsArb198 .shrink(currentValue.value_, currentValue.context)199 .map((nextValue) => {200 // Run all commands of nextShrinkable201 simulateCommands(nextValue.value_);202 // Check nextShrinkable is strictly smaller than current one203 const nextItems = [...nextValue.value_].map((c) => +extractIdRegex.exec(c.toString())![1]);204 expect(isStrictlySmallerArray(nextItems, currentItems)).toBe(true);205 // Next is eligible for shrinking206 return nextValue;207 })208 .getNthOrLast(it.next().value);209 }210 }211 )212 );213 });214 it('should shrink the same way when based on replay data', () => {215 fc.assert(216 fc.property(217 fc.integer().noShrink(),218 fc.nat(100),219 fc.option(fc.integer({ min: 2 }), { nil: undefined }),220 (seed, numValues, biasFactor) => {221 // create unused logOnCheck222 const logOnCheck: { data: string[] } = { data: [] };223 // generate scenario and simulate execution224 const rng = prand.xorshift128plus(seed);225 const refArbitrary = commands([226 new FakeConstant(new SuccessCommand(logOnCheck)),227 new FakeConstant(new SkippedCommand(logOnCheck)),228 new FakeConstant(new FailureCommand(logOnCheck)),229 nat().map((v) => new SuccessIdCommand(v)),230 ]);231 const refValue: Value<Iterable<Cmd>> = refArbitrary.generate(new Random(rng), biasFactor);232 simulateCommands(refValue.value_);233 // trigger computation of replayPath234 // and extract shrinks for ref235 const refShrinks = [236 ...refArbitrary237 .shrink(refValue.value_, refValue.context)238 .take(numValues)239 .map((s) => [...s.value_].map((c) => c.toString())),240 ];241 // extract replayPath242 const replayPath = /\/\*replayPath=['"](.*)['"]\*\//.exec(refValue.value_.toString())![1];243 // generate scenario but do not simulate execution244 const noExecArbitrary = commands(245 [246 new FakeConstant(new SuccessCommand(logOnCheck)),247 new FakeConstant(new SkippedCommand(logOnCheck)),248 new FakeConstant(new FailureCommand(logOnCheck)),249 nat().map((v) => new SuccessIdCommand(v)),250 ],251 { replayPath }252 );253 const noExecValue: Value<Iterable<Cmd>> = noExecArbitrary.generate(new Random(rng), biasFactor);254 // check shrink values are identical255 const noExecShrinks = [256 ...noExecArbitrary257 .shrink(noExecValue.value_, noExecValue.context)258 .take(numValues)259 .map((s) => [...s.value_].map((c) => c.toString())),260 ];261 expect(noExecShrinks).toEqual(refShrinks);262 }263 )264 );265 });266});267// Helpers268class FakeConstant extends Arbitrary<Cmd> {269 constructor(private readonly cmd: Cmd) {270 super();271 }272 generate(): Value<Cmd> {273 return new Value(this.cmd, undefined);274 }275 canShrinkWithoutContext(value: unknown): value is Cmd {276 return false;277 }278 shrink(): Stream<Value<Cmd>> {279 return Stream.nil();280 }281}282class SuccessIdCommand implements Cmd {283 constructor(readonly id: number) {}284 check = () => true;285 run = () => {};286 toString = () => `custom(${this.id})`;287}288class SuccessCommand implements Cmd {289 constructor(readonly log: { data: string[] }) {}290 check = () => {291 this.log.data.push(this.toString());292 return true;293 };294 run = () => {};295 toString = () => 'success';296}297class SkippedCommand implements Cmd {298 constructor(readonly log: { data: string[] }) {}299 check = () => {300 this.log.data.push(this.toString());301 return false;302 };303 run = () => {};304 toString = () => 'skipped';305}306class FailureCommand implements Cmd {307 constructor(readonly log: { data: string[] }) {}308 check = () => {309 this.log.data.push(this.toString());310 return true;311 };312 run = () => {313 throw 'error';314 };315 toString = () => 'failure';...
dequeue.spec.ts
Source:dequeue.spec.ts
1// Copyright 2019 Ryan Zeigler2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14import { expect } from "chai";15import fc, { Arbitrary, Command } from "fast-check";16import * as O from "fp-ts/lib/Option";17import { none, some } from "fp-ts/lib/Option";18import * as p from "fp-ts/lib/pipeable";19import { pipe } from "fp-ts/lib/pipeable";20import { Dequeue, empty } from "../src/support/dequeue";21describe("Dequeue", () => {22 it("take on empty is none", () => {23 expect(empty().take()).to.deep.equal(none);24 });25 it("pull on empty is none", () => {26 expect(empty().pull()).to.deep.equal(none);27 });28 it("take after offer is a value", () => {29 const queue = empty().offer(42);30 const result = pipe(queue.take(), O.map((v) => v[0]));31 expect(result).to.deep.equal(some(42));32 });33 it("pull after offer is a value", () => {34 const queue = empty<number>().offer(42);35 const result = queue.pull();36 p.pipe(37 result,38 O.fold(39 () => { throw new Error("expected some"); },40 (tuple) => expect(tuple[0]).to.equal(42)41 )42 );43 });44 it("take after multiple offers is the first", () => {45 const queue = empty()46 .offer(42)47 .offer(43)48 .offer(44);49 const result = queue.take();50 p.pipe(51 result,52 O.fold(53 () => { throw new Error("expected some"); },54 (tuple) => {55 expect(tuple[0]).to.equal(42);56 expect(tuple[1].size()).to.equal(2);57 }58 )59 );60 });61 it("pull after multiple offers is the last", () => {62 const queue = empty()63 .offer(42)64 .offer(43)65 .offer(44);66 const result = queue.pull();67 p.pipe(68 result,69 O.fold(70 () => { throw new Error("expected some"); },71 (tuple) => {72 expect(tuple[0]).to.equal(44);73 expect(tuple[1].size()).to.equal(2);74 }75 )76 );77 });78 interface Model {79 fake: number[];80 }81 interface Real {82 actual: Dequeue<number>;83 }84 // push addss to the right, offer adds to the left85 // pull takes from the left, take takes from the right86 const pushCommandArb: Arbitrary<Command<Model, Real>> = fc.nat()87 .map((n) => {88 return {89 check(_m: Model): boolean {90 return true;91 },92 run(m: Model, r: Real): void {93 m.fake.push(n);94 r.actual = r.actual.push(n);95 },96 toString() {97 return `push ${n}`;98 }99 };100 });101 const pullCommandArb: Arbitrary<Command<Model, Real>> = fc.constant({102 check(_m: Model): boolean {103 return true;104 },105 run(m: Model, r: Real): void {106 const expected = m.fake.shift();107 p.pipe(108 r.actual.pull(),109 O.fold(110 () => {111 if (expected) {112 throw new Error("expected there to be something");113 }114 },115 ([n, q]) => {116 expect(n).to.equal(expected);117 r.actual = q;118 }119 )120 );121 },122 toString() {123 return "pull";124 }125 });126 const offerCommandArb: Arbitrary<Command<Model, Real>> = fc.nat()127 .map((n) => {128 return {129 check(_m: Model): boolean {130 return true;131 },132 run(m: Model, r: Real): void {133 m.fake.unshift(n);134 r.actual = r.actual.offer(n);135 },136 toString() {137 return `offer ${n}`;138 }139 };140 });141 const takeCommandArb: Arbitrary<Command<Model, Real>> = fc.constant({142 check(_m: Model): boolean {143 return true;144 },145 run(m: Model, r: Real): void {146 const expected = m.fake.pop();147 p.pipe(148 r.actual.take(),149 O.fold(150 () => {151 if (expected) {152 throw new Error("expected there to be something");153 }154 },155 ([n, q]) => {156 expect(n).to.equal(expected);157 r.actual = q;158 }159 )160 );161 },162 toString() {163 return "take";164 }165 });166 const commandsArb = fc.commands([pushCommandArb, pullCommandArb, offerCommandArb, takeCommandArb]);167 it("should never lose elements", () => {168 fc.assert(169 fc.property(commandsArb, (commands) => {170 fc.modelRun(() => ({model: {fake: []}, real: {actual: empty()}}), commands);171 })172 );173 });...
Using AI Code Generation
1import { commandsArb } from 'fast-check-monorepo';2import { commandsArb } from 'fast-check';3import { commandsArb } from 'fast-check/lib/check/arbitrary/CommandArbitrary.js';4import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';5import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';6import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';7import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';8import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';9import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';10import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';11import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';12import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';13import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';14import { commandsArb } from 'fast-check-monorepo/lib/check/arbitrary/CommandArbitrary.js';
Using AI Code Generation
1const fc = require('fast-check');2const { commandsArb } = require('fast-check-monorepo');3const commandsArb = commandsArb();4fc.assert(5 fc.property(commandsArb, (commands) => {6 })7);8const fc = require('fast-check');9const { commandsArb } = require('fast-check-monorepo');10const commandsArb = commandsArb();11fc.assert(12 fc.property(commandsArb, (commands) => {13 })14);15const fc = require('fast-check');16const { commandsArb } = require('fast-check-monorepo');17const commandsArb = commandsArb();18fc.assert(19 fc.property(commandsArb, (commands) => {20 })21);22const fc = require('fast-check');23const { commandsArb } = require('fast-check-monorepo');24const commandsArb = commandsArb();25fc.assert(26 fc.property(commandsArb, (commands) => {27 })28);29const fc = require('fast-check');30const { commandsArb } = require('fast-check-monorepo');31const commandsArb = commandsArb();32fc.assert(33 fc.property(commandsArb, (commands) => {34 })35);36const fc = require('fast-check');37const { commandsArb } = require('fast-check-monorepo');38const commandsArb = commandsArb();39fc.assert(40 fc.property(commandsArb, (commands) => {41 })42);43const fc = require('fast-check');44const { commandsArb } = require('fast-check-monorepo');
Using AI Code Generation
1import fc from 'fast-check';2import { commandsArb } from 'fast-check-monorepo';3fc.assert(4 fc.property(commandsArb(), commands => {5 })6);7import fc from 'fast-check';8import { commandsArb } from 'fast-check-monorepo';9fc.assert(10 fc.property(commandsArb(), commands => {11 })12);13import fc from 'fast-check';14import { commandsArb } from 'fast-check-monorepo';15fc.assert(16 fc.property(commandsArb(), commands => {17 })18);19import fc from 'fast-check';20import { commandsArb } from 'fast-check-monorepo';21fc.assert(22 fc.property(commandsArb(), commands => {23 })24);25import fc from 'fast-check';26import { commandsArb } from 'fast-check-monorepo';27fc.assert(28 fc.property(commandsArb(), commands => {29 })30);31import fc from 'fast-check';32import { commandsArb } from 'fast-check-monorepo';33fc.assert(34 fc.property(commandsArb(), commands => {35 })36);37import fc from 'fast-check';38import { commandsArb } from 'fast-check-monorepo';39fc.assert(40 fc.property(commandsArb(), commands => {41 })42);43import fc from 'fast-check';44import { commandsArb } from 'fast-check-monorepo';45fc.assert(46 fc.property(commandsArb(), commands => {47 })
Using AI Code Generation
1const { commandsArb } = require('fast-check-monorepo');2const commands = commandsArb().generate().value;3console.log(commands);4{5 "scripts": {6 },7 "dependencies": {8 }9}10const { operationsArb } = require('fast-check-monorepo');11const operations = operationsArb().generate().value;12console.log(operations);13{14 "scripts": {15 },16 "dependencies": {17 }18}19[ { type: 'C', source: 'foo', destination: 'bar' },20 { type: 'M', source: 'foo', destination: 'bar' },21 { type: 'R', source: 'foo', destination: 'bar' } ]
Using AI Code Generation
1const fc = require('fast-check');2const commandsArb = require('fast-check-monorepo').commandsArb;3const model = { value: 0 };4const run = (model, cmd) => {5 switch (cmd) {6 model.value++;7 break;8 model.value--;9 break;10 throw new Error('Unknown command');11 }12 return model;13};14fc.assert(15 fc.property(commandsArb(['inc', 'dec']), cmds => {16 cmds.reduce(run, model);17 return model.value === 0;18 })19);
Using AI Code Generation
1const { commandsArb } = require("fast-check-monorepo");2const { Command } = require("fast-check-monorepo");3const myCommand = new Command("myCommand", () => {4});5const myOtherCommand = new Command("myOtherCommand", () => {6});7const myCommandList = [myCommand, myOtherCommand];8const myCommandArb = commandsArb(myCommandList);9const { commandsArb } = require("fast-check-monorepo");10const { Command } = require("fast-check-monorepo");11const myCommand = new Command("myCommand", () => {12});13const myOtherCommand = new Command("myOtherCommand", () => {14});15const myCommandList = [myCommand, myOtherCommand];16const myCommandArb = commandsArb(myCommandList);17const { commandsArb } = require("fast-check-monorepo");18const { Command } = require("fast-check-monorepo");19const myCommand = new Command("myCommand", () => {20});21const myOtherCommand = new Command("myOtherCommand", () => {22});23const myCommandList = [myCommand, myOtherCommand];24const myCommandArb = commandsArb(myCommandList);25const { commandsArb } = require("fast-check-monorepo");26const { Command } = require("fast-check-monorepo");27const myCommand = new Command("myCommand", () => {28});29const myOtherCommand = new Command("myOtherCommand", () => {30});31const myCommandList = [myCommand, myOtherCommand];32const myCommandArb = commandsArb(myCommandList);33const { commandsArb } = require("fast
Using AI Code Generation
1const { commandsArb } = require('fast-check-monorepo');2const { Command } = require('fast-check-monorepo/lib/check/model/command/Command');3const { Model } = require('fast-check-monorepo/lib/check/model/Model');4const { Arbitrary } = require('fast-check-monorepo/lib/check/arbitrary/definition/Arbitrary');5const { assert } = require('chai');6class MyModel extends Model {7 constructor() {8 super();9 this._value = 0;10 }11 get value() {12 return this._value;13 }14 increment() {15 this._value += 1;16 }17}18class MyCommand extends Command {19 constructor() {20 super();21 this._name = 'increment';22 }23 check(m) {24 return m instanceof MyModel;25 }26 run(m) {27 m.increment();28 }29}30const myArbitrary = Arbitrary.constant(new MyCommand());31const modelRun = (m, c) => {32 if (c instanceof MyCommand) {33 m.increment();34 }35};36const realRun = (m, c) => {37 if (c instanceof MyCommand) {38 m.increment();39 }40};41const pre = (m, c) => {42 return true;43};44const post = (m, c, r) => {45 return m.value === r.value;46};47const equal = (m, r) => {48 return m.value === r.value;49};50const shrink = (c) => {51 return [];52};53const beforeEach = (m) => {54 m._value = 0;55};56const afterEach = (m, r) => {57 assert.equal(m.value, r.value);58};59const beforeEachCommand = (m, c) => {60 console.log('beforeEachCommand');61};
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!