// META: title=Web Locks API: Mixed Modes // META: script=resources/helpers.js // META: global=window,dedicatedworker,sharedworker,serviceworker 'use strict'; promise_test(async t => { let unblock; const blocked = new Promise(r => { unblock = r; }); const granted = []; // These should be granted immediately, and held until unblocked. navigator.locks.request('a', {mode: 'shared'}, async lock => { granted.push('a-shared-1'); await blocked; }); navigator.locks.request('a', {mode: 'shared'}, async lock => { granted.push('a-shared-2'); await blocked; }); navigator.locks.request('a', {mode: 'shared'}, async lock => { granted.push('a-shared-3'); await blocked; }); // This should be blocked. let exclusive_lock; const exclusive_request = navigator.locks.request('a', async lock => { granted.push('a-exclusive'); exclusive_lock = lock; }); // This should be granted immediately (different name). await navigator.locks.request('b', {mode: 'exclusive'}, lock => { granted.push('b-exclusive'); }); assert_array_equals( granted, ['a-shared-1', 'a-shared-2', 'a-shared-3', 'b-exclusive']); // Release the shared locks granted above. unblock(); // Now the blocked request can be granted. await exclusive_request; assert_equals(exclusive_lock.mode, 'exclusive'); assert_array_equals( granted, ['a-shared-1', 'a-shared-2', 'a-shared-3', 'b-exclusive', 'a-exclusive']); }, 'Lock requests are granted in order'); promise_test(async t => { const res = uniqueName(t); let [promise, resolve] = makePromiseAndResolveFunc(); const exclusive = navigator.locks.request(res, () => promise); for (let i = 0; i < 5; i++) { requestLockAndHold(t, res, { mode: "shared" }); } let answer = await navigator.locks.query(); assert_equals(answer.held.length, 1, "An exclusive lock is held"); assert_equals(answer.pending.length, 5, "Requests for shared locks are pending"); resolve(); await exclusive; answer = await navigator.locks.query(); assert_equals(answer.held.length, 5, "Shared locks are held"); assert_true(answer.held.every(l => l.mode === "shared"), "All held locks are shared ones"); }, 'Releasing exclusive lock grants multiple shared locks'); promise_test(async t => { const res = uniqueName(t); let [sharedPromise, sharedResolve] = makePromiseAndResolveFunc(); let [exclusivePromise, exclusiveResolve] = makePromiseAndResolveFunc(); const sharedReleasedPromise = Promise.all(new Array(5).fill(0).map( () => navigator.locks.request(res, { mode: "shared" }, () => sharedPromise)) ); const exclusiveReleasedPromise = navigator.locks.request(res, () => exclusivePromise); for (let i = 0; i < 5; i++) { requestLockAndHold(t, res, { mode: "shared" }); } let answer = await navigator.locks.query(); assert_equals(answer.held.length, 5, "Shared locks are held"); assert_true(answer.held.every(l => l.mode === "shared"), "All held locks are shared ones"); sharedResolve(); await sharedReleasedPromise; answer = await navigator.locks.query(); assert_equals(answer.held.length, 1, "An exclusive lock is held"); assert_equals(answer.held[0].mode, "exclusive"); exclusiveResolve(); await exclusiveReleasedPromise; answer = await navigator.locks.query(); assert_equals(answer.held.length, 5, "The next shared locks are held"); assert_true(answer.held.every(l => l.mode === "shared"), "All held locks are shared ones"); }, 'An exclusive lock between shared locks');