summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/web-locks/ifAvailable.https.any.js
blob: 63e6d568fe513512cb558bd66eebea1b625d54c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// META: title=Web Locks API: ifAvailable option
// META: script=resources/helpers.js
// META: global=window,dedicatedworker,sharedworker,serviceworker

'use strict';

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, {ifAvailable: true}, async lock => {
    callback_called = true;
    assert_not_equals(lock, null, 'lock should be granted');
  });
  assert_true(callback_called, 'callback should be called');
}, 'Lock request with ifAvailable - lock available');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    // Request would time out if |ifAvailable| was not specified.
    const result = await navigator.locks.request(
      res, {ifAvailable: true}, async lock => {
        callback_called = true;
        assert_equals(lock, null, 'lock should not be granted');
        return 123;
      });
    assert_equals(result, 123, 'result should be value returned by callback');
  });
  assert_true(callback_called, 'callback should be called');
}, 'Lock request with ifAvailable - lock not available');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    try {
      // Request would time out if |ifAvailable| was not specified.
      await navigator.locks.request(res, {ifAvailable: true}, async lock => {
        callback_called = true;
        assert_equals(lock, null, 'lock should not be granted');
        throw 123;
      });
      assert_unreached('call should throw');
    } catch (ex) {
      assert_equals(ex, 123, 'ex should be value thrown by callback');
    }
  });
  assert_true(callback_called, 'callback should be called');
}, 'Lock request with ifAvailable - lock not available, callback throws');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    // Request with a different name - should be grantable.
    await navigator.locks.request('different', {ifAvailable: true}, async lock => {
      callback_called = true;
      assert_not_equals(lock, null, 'lock should be granted');
    });
  });
  assert_true(callback_called, 'callback should be called');
}, 'Lock request with ifAvailable - unrelated lock held');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, {mode: 'shared'}, async lock => {
    await navigator.locks.request(
      res, {mode: 'shared', ifAvailable: true}, async lock => {
        callback_called = true;
        assert_not_equals(lock, null, 'lock should be granted');
      });
  });
  assert_true(callback_called, 'callback should be called');
}, 'Shared lock request with ifAvailable - shared lock held');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, {mode: 'shared'}, async lock => {
    // Request would time out if |ifAvailable| was not specified.
    await navigator.locks.request(res, {ifAvailable: true}, async lock => {
      callback_called = true;
      assert_equals(lock, null, 'lock should not be granted');
    });
  });
  assert_true(callback_called, 'callback should be called');
}, 'Exclusive lock request with ifAvailable - shared lock held');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    // Request would time out if |ifAvailable| was not specified.
    await navigator.locks.request(
      res, {mode: 'shared', ifAvailable: true}, async lock => {
        callback_called = true;
        assert_equals(lock, null, 'lock should not be granted');
      });
  });
  assert_true(callback_called, 'callback should be called');
}, 'Shared lock request with ifAvailable - exclusive lock held');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    callback_called = true;
    const test_error = {name: 'test'};
    const p = navigator.locks.request(
      res, {ifAvailable: true}, lock => {
        assert_equals(lock, null, 'lock should not be available');
        throw test_error;
      });
    assert_equals(Promise.resolve(p), p, 'request() result is a Promise');
    await promise_rejects_exactly(t, test_error, p, 'result should reject');
  });
  assert_true(callback_called, 'callback should be called');
}, 'Returned Promise rejects if callback throws synchronously');

promise_test(async t => {
  const res = self.uniqueName(t);
  let callback_called = false;
  await navigator.locks.request(res, async lock => {
    callback_called = true;
    const test_error = {name: 'test'};
    const p = navigator.locks.request(
      res, {ifAvailable: true}, async lock => {
        assert_equals(lock, null, 'lock should not be available');
        throw test_error;
      });
    assert_equals(Promise.resolve(p), p, 'request() result is a Promise');
    await promise_rejects_exactly(t, test_error, p, 'result should reject');
  });
  assert_true(callback_called, 'callback should be called');
}, 'Returned Promise rejects if async callback yields rejected promise');

// Regression test for: https://crbug.com/840994
promise_test(async t => {
  const res1 = self.uniqueName(t);
  const res2 = self.uniqueName(t);
  let callback1_called = false;
  await navigator.locks.request(res1, async lock => {
    callback1_called = true;
    let callback2_called = false;
    await navigator.locks.request(res2, async lock => {
      callback2_called = true;
    });
    assert_true(callback2_called, 'callback2 should be called');

    let callback3_called = false;
    await navigator.locks.request(res2, {ifAvailable: true}, async lock => {
      callback3_called = true;
      // This request would fail if the "is this grantable?" test
      // failed, e.g. due to the release without a pending request
      // skipping steps.
      assert_not_equals(lock, null, 'Lock should be available');
    });
    assert_true(callback3_called, 'callback2 should be called');
  });
  assert_true(callback1_called, 'callback1 should be called');
}, 'Locks are available once previous release is processed');