| // 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'); |