Skip to content

Commit

Permalink
Update all the things
Browse files Browse the repository at this point in the history
* Run CI in main branch

* Test with Node.js 16

* Update TypeScript, XO and other stuff
  • Loading branch information
novemberborn authored Jun 20, 2021
1 parent daa4afd commit 085086b
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 54 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Install and test @ava/cooperate
on:
push:
branches:
- master
- main
pull_request:
paths-ignore:
- "*.md"
Expand All @@ -13,7 +13,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node-version: [^12.17.0, ^14.0.0, ^15.0.0]
node-version: [^12.17.0, ^14.0.0, ^16.0.0]
steps:
- uses: actions/checkout@v1
with:
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "0.1.1",
"description": "Plugin to enable cooperation between AVA test files",
"engines": {
"node": ">=12.17.0 <13 || >=14.0.0 <15 || >=15"
"node": ">=12.17.0 <13 || >=14.0.0 <15 || >=16"
},
"files": [
"dist/source",
Expand All @@ -29,16 +29,16 @@
"license": "MIT",
"devDependencies": {
"@ava/typescript": "^1.1.1",
"@sindresorhus/tsconfig": "^0.7.0",
"@sindresorhus/tsconfig": "^1.0.2",
"ava": "^3.13.0",
"c8": "^7.3.1",
"del-cli": "^3.0.1",
"delay": "^4.4.0",
"typescript": "^4.0.3",
"xo": "^0.33.1"
"c8": "^7.7.3",
"del-cli": "^4.0.0",
"delay": "^5.0.0",
"typescript": "^4.3.4",
"xo": "^0.40.2"
},
"dependencies": {
"never": "^1.0.2"
"never": "^1.0.3"
},
"peerDependencies": {
"ava": "*"
Expand Down
35 changes: 20 additions & 15 deletions source/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,27 +247,32 @@ export class SemaphoreDownError extends Error {
}
}

const creationMessage = (semaphore: Semaphore, {initialValue, managed}: SemaphoreCreationFailed) => {
const initialValueSuffix = `initial value ${semaphore.initialValue} (got ${initialValue})`;
if (semaphore instanceof ManagedSemaphore) {
if (managed) {
return `Failed to create semaphore: expected ${initialValueSuffix}`;
}

return `Failed to create semaphore: expected unmanaged and ${initialValueSuffix}`;
}

if (managed) {
return `Failed to create unmanaged semaphore: expected managed and ${initialValueSuffix}`;
}

return `Failed to create unmanaged semaphore: expected ${initialValueSuffix}`;
};

export class SemaphoreCreationError extends Error {
readonly semaphoreId: string;

get name() {
return 'SemaphoreCreationError';
}

constructor(semaphore: Semaphore, {initialValue, managed}: SemaphoreCreationFailed) {
const initialValueSuffix = `initial value ${semaphore.initialValue} (got ${initialValue})`;
if (semaphore instanceof ManagedSemaphore) {
if (managed) {
super(`Failed to create semaphore: expected ${initialValueSuffix}`);
} else {
super(`Failed to create semaphore: expected unmanaged and ${initialValueSuffix}`);
}
} else if (managed) {
super(`Failed to create unmanaged semaphore: expected managed and ${initialValueSuffix}`);
} else {
super(`Failed to create unmanaged semaphore: expected ${initialValueSuffix}`);
}

constructor(semaphore: Semaphore, reason: SemaphoreCreationFailed) {
super(creationMessage(semaphore, reason));
this.semaphoreId = semaphore.id;
}
}
Expand Down Expand Up @@ -299,7 +304,7 @@ export class SharedContext {

for await (const {data} of message.replies()) {
if (data.type === MessageType.RESERVED_INDEXES) {
return data.indexes.map(index => values[index]);
return data.indexes.map(index => values[index] ?? never());
}
}

Expand Down
2 changes: 1 addition & 1 deletion source/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const enum MessageType {
SEMAPHORE_FAILED = 32,
SEMAPHORE_RELEASE = 33,
SEMAPHORE_SUCCEEDED = 34,
SEMAPHORE_UP = 35,
SEMAPHORE_UP = 35
}

export type Lock = {
Expand Down
57 changes: 42 additions & 15 deletions source/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,42 @@ const factory: SharedWorker.Factory = async ({negotiateProtocol}) => {

for await (const message of protocol.subscribe()) {
const {data} = message;
if (data.type === MessageType.LOCK) {
void acquireLock(message, data);
} else if (data.type === MessageType.RESERVE) {
reserve(message, data);
} else if (data.type === MessageType.SEMAPHORE_DOWN) {
void downSemaphore(message, data);
} else if (data.type === MessageType.SEMAPHORE_UP) {
upSemaphore(message, data);
switch (data.type) {
case MessageType.LOCK: {
void acquireLock(message, data);

break;
}

case MessageType.RESERVE: {
reserve(message, data);

break;
}

case MessageType.SEMAPHORE_DOWN: {
void downSemaphore(message, data);

break;
}

case MessageType.SEMAPHORE_UP: {
upSemaphore(message, data);

break;
}

// No default
default:
continue;
}
}
};

export default factory;

type Context = {
locks: Map<string, {holderId: string; waiting: Array<{ holderId: string; notify: () => void }>}>;
locks: Map<string, {holderId: string; waiting: Array<{holderId: string; notify: () => void}>}>;
reservedValues: Set<bigint | number | string>;
semaphores: Map<string, Semaphore>;
};
Expand Down Expand Up @@ -68,14 +88,14 @@ async function acquireLock(message: ReceivedMessage, {contextId, lockId, wait}:
return;
}

if (current.waiting.length === 0) {
const [next, ...waiting] = current.waiting;
if (next === undefined) {
// We have the lock, but nobody else wants it. Delete it.
context.locks.delete(lockId);
return;
}

// Transfer the lock to the next in line.
const [next, ...waiting] = current.waiting;
context.locks.set(lockId, {
holderId: next.holderId,
waiting
Expand Down Expand Up @@ -134,7 +154,7 @@ function reserve(message: ReceivedMessage, {contextId, values}: Reservation): vo

message.testWorker.teardown(() => {
for (const index of indexes) {
context.reservedValues.delete(values[index]);
context.reservedValues.delete(values[index] ?? never());
}
});

Expand Down Expand Up @@ -185,8 +205,13 @@ class Semaphore {
up(amount: number) {
this.value += amount;

while (this.queue.length > 0 && this.tryDown(this.queue[0].amount)) {
this.queue.shift()?.resolve();
for (const item of this.queue) {
if (!this.tryDown(item.amount)) {
break;
}

item.resolve();
this.queue.shift();
}
}
}
Expand Down Expand Up @@ -245,7 +270,9 @@ async function downSemaphore(
} else if (semaphore.tryDown(amount)) {
acquired = amount;

release = message.testWorker.teardown(() => semaphore.up(acquired));
release = message.testWorker.teardown(() => {
semaphore.up(acquired);
});
} else {
message.reply({
type: MessageType.SEMAPHORE_FAILED
Expand Down
28 changes: 20 additions & 8 deletions test/semaphore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ async function probeManualRelease(semaphore: UnmanagedSemaphore) {
await semaphore.up(amount);
amount++;
}
} catch (error) {
} catch (error: unknown) {
if (error instanceof SemaphoreDownError) {
return amount - 1;
}
Expand All @@ -75,7 +75,7 @@ async function probeManagement(semaphore: ManagedSemaphore): Promise<number> {
release();
amount++;
}
} catch (error) {
} catch (error: unknown) {
if (error instanceof SemaphoreDownError) {
return amount - 1;
}
Expand Down Expand Up @@ -154,13 +154,17 @@ test('managed semaphore amounts can\'t be negative', async t => {

{
const release = await semaphore.acquire();
t.throws(() => release(-1), {instanceOf: RangeError});
t.throws(() => {
release(-1);
}, {instanceOf: RangeError});
release();
}

{
const release = await semaphore.acquireNow();
t.throws(() => release(-1), {instanceOf: RangeError});
t.throws(() => {
release(-1);
}, {instanceOf: RangeError});
release();
}
});
Expand All @@ -182,7 +186,9 @@ test('managed semaphore values must be integers', async t => {
await t.throwsAsync(semaphore.acquire(0.75), {instanceOf: RangeError});
await t.throwsAsync(semaphore.acquireNow(0.75), {instanceOf: RangeError});
const release1 = await semaphore.acquire(1);
t.throws(() => release1(0.25), {instanceOf: RangeError});
t.throws(() => {
release1(0.25);
}, {instanceOf: RangeError});
});

test('attempt to acquire() semaphore concurrently in different processes', async t => {
Expand Down Expand Up @@ -246,7 +252,9 @@ test(testPartialRelease, ManagedSemaphore.prototype.acquireNow);
async function overRelease(t: ExecutionContext, acquire: Acquirer) {
const semaphore = new SharedContext(test.meta.file).createSemaphore(t.title, 4);
const release = await acquire.call(semaphore, 2);
t.throws(() => release(3), {
t.throws(() => {
release(3);
}, {
instanceOf: RangeError
});
}
Expand All @@ -261,7 +269,9 @@ async function overReleaseRemaining(t: ExecutionContext, acquire: Acquirer) {
const semaphore = new SharedContext(test.meta.file).createSemaphore(t.title, 4);
const release = await acquire.call(semaphore, 3);
release(2);
t.throws(() => release(2));
t.throws(() => {
release(2);
});
}

overReleaseRemaining.title = (provided: string, acquire: Acquirer) =>
Expand All @@ -274,7 +284,9 @@ test('can always release zero', async t => {
const semaphore = new SharedContext(test.meta.file).createSemaphore(t.title, 4);
const release = await semaphore.acquire(1);
release(1);
t.notThrows(() => release(0));
t.notThrows(() => {
release(0);
});
});

test('managed and unmanaged semaphores share their ID space', async t => {
Expand Down
5 changes: 1 addition & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
"extends": "@sindresorhus/tsconfig",
"compilerOptions": {
"outDir": "dist",
"target": "es2019", // Node.js 12
"lib": [
"es2019"
],
"module": "CommonJS",
"esModuleInterop": true,
"sourceMap": true
},
Expand Down
5 changes: 4 additions & 1 deletion xo.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ module.exports = {
rules: {
'@typescript-eslint/prefer-readonly-parameter-types': 'off',
'no-void': ['error', {allowAsStatement: true}],
'no-await-in-loop': 'off'
'no-await-in-loop': 'off',
'unicorn/prefer-module': 'off',
'unicorn/prefer-node-protocol': 'off',
'import/extensions': 'off'
},
overrides: [
{
Expand Down

0 comments on commit 085086b

Please sign in to comment.