SCRAPE-12: Implement in-process mutex (isScraperRunning flag) (#17)
Co-authored-by: Stephen Minakian <stephenminakian@gmail.com> Co-committed-by: Stephen Minakian <stephenminakian@gmail.com>
This commit is contained in:
151
__tests__/scraper/scraperJob.test.js
Normal file
151
__tests__/scraper/scraperJob.test.js
Normal file
@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Tests for scraperJob.js - In-process mutex (isScraperRunning flag)
|
||||
* Following TDD - these tests are written BEFORE implementation
|
||||
*/
|
||||
|
||||
const {
|
||||
isScraperRunning,
|
||||
getCurrentJobId,
|
||||
acquireLock,
|
||||
releaseLock
|
||||
} = require('../../jobs/scraperJob');
|
||||
|
||||
describe('scraperJob - mutex lock', () => {
|
||||
// Reset state between each test
|
||||
afterEach(() => {
|
||||
releaseLock();
|
||||
});
|
||||
|
||||
describe('isScraperRunning()', () => {
|
||||
test('should return false when not running', () => {
|
||||
expect(isScraperRunning()).toBe(false);
|
||||
});
|
||||
|
||||
test('should return true after acquireLock()', () => {
|
||||
acquireLock('test-job-1');
|
||||
|
||||
expect(isScraperRunning()).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false after releaseLock()', () => {
|
||||
acquireLock('test-job-2');
|
||||
releaseLock();
|
||||
|
||||
expect(isScraperRunning()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCurrentJobId()', () => {
|
||||
test('should return null when not running', () => {
|
||||
expect(getCurrentJobId()).toBeNull();
|
||||
});
|
||||
|
||||
test('should return jobId when running', () => {
|
||||
const jobId = 'my-unique-job-id';
|
||||
acquireLock(jobId);
|
||||
|
||||
expect(getCurrentJobId()).toBe(jobId);
|
||||
});
|
||||
|
||||
test('should return null after releaseLock()', () => {
|
||||
acquireLock('test-job-3');
|
||||
releaseLock();
|
||||
|
||||
expect(getCurrentJobId()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('acquireLock()', () => {
|
||||
test('should return true when lock is available', () => {
|
||||
const result = acquireLock('job-1');
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false when lock is already held', () => {
|
||||
acquireLock('job-1');
|
||||
|
||||
const result = acquireLock('job-2');
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('should set isScraperRunning to true', () => {
|
||||
acquireLock('job-1');
|
||||
|
||||
expect(isScraperRunning()).toBe(true);
|
||||
});
|
||||
|
||||
test('should set currentJobId to the provided jobId', () => {
|
||||
const jobId = 'specific-job-id';
|
||||
acquireLock(jobId);
|
||||
|
||||
expect(getCurrentJobId()).toBe(jobId);
|
||||
});
|
||||
|
||||
test('should not overwrite existing lock when already held', () => {
|
||||
const firstJobId = 'first-job';
|
||||
const secondJobId = 'second-job';
|
||||
|
||||
acquireLock(firstJobId);
|
||||
acquireLock(secondJobId);
|
||||
|
||||
// Should still have the first job's ID
|
||||
expect(getCurrentJobId()).toBe(firstJobId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('releaseLock()', () => {
|
||||
test('should clear running state', () => {
|
||||
acquireLock('job-to-release');
|
||||
|
||||
releaseLock();
|
||||
|
||||
expect(isScraperRunning()).toBe(false);
|
||||
});
|
||||
|
||||
test('should clear currentJobId', () => {
|
||||
acquireLock('job-to-release');
|
||||
|
||||
releaseLock();
|
||||
|
||||
expect(getCurrentJobId()).toBeNull();
|
||||
});
|
||||
|
||||
test('should allow a new lock to be acquired after release', () => {
|
||||
acquireLock('first-job');
|
||||
releaseLock();
|
||||
|
||||
const result = acquireLock('second-job');
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(getCurrentJobId()).toBe('second-job');
|
||||
expect(isScraperRunning()).toBe(true);
|
||||
});
|
||||
|
||||
test('should be safe to call when no lock is held', () => {
|
||||
// Should not throw when called without an active lock
|
||||
expect(() => releaseLock()).not.toThrow();
|
||||
expect(isScraperRunning()).toBe(false);
|
||||
expect(getCurrentJobId()).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('module exports', () => {
|
||||
test('should export isScraperRunning as a function', () => {
|
||||
expect(typeof isScraperRunning).toBe('function');
|
||||
});
|
||||
|
||||
test('should export getCurrentJobId as a function', () => {
|
||||
expect(typeof getCurrentJobId).toBe('function');
|
||||
});
|
||||
|
||||
test('should export acquireLock as a function', () => {
|
||||
expect(typeof acquireLock).toBe('function');
|
||||
});
|
||||
|
||||
test('should export releaseLock as a function', () => {
|
||||
expect(typeof releaseLock).toBe('function');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user