// META: title=Web Locks API: AbortSignal integration
// META: script=resources/helpers.js
// META: global=window,dedicatedworker,sharedworker,serviceworker

'use strict';

promise_test(async t => {
  const res = uniqueName(t);

  // These cases should not work:
  for (const signal of ['string', 12.34, false, {}, Symbol(), () => {}, self]) {
    await promise_rejects_js(
      t, TypeError,
      navigator.locks.request(
        res, {signal}, t.unreached_func('callback should not run')),
      'Bindings should throw if the signal option is a not an AbortSignal');
  }
}, 'The signal option must be an AbortSignal');

promise_test(async t => {
  const res = uniqueName(t);
  const controller = new AbortController();
  controller.abort();

  await promise_rejects_dom(
    t, 'AbortError',
    navigator.locks.request(res, {signal: controller.signal},
                            t.unreached_func('callback should not run')),
    'Request should reject with AbortError');
}, 'Passing an already aborted signal aborts');

promise_test(async t => {
  const res = uniqueName(t);

  // Grab a lock and hold it until this subtest completes.
  requestLockAndHold(t, res);

  const controller = new AbortController();

  const promise =
    navigator.locks.request(res, {signal: controller.signal},
                            t.unreached_func('callback should not run'));

  // Verify the request is enqueued:
  const state = await navigator.locks.query();
  assert_equals(state.held.filter(lock => lock.name === res).length, 1,
                'Number of held locks');
  assert_equals(state.pending.filter(lock => lock.name === res).length, 1,
                'Number of pending locks');

  const rejected = promise_rejects_dom(
    t, 'AbortError', promise, 'Request should reject with AbortError');

  controller.abort();

  await rejected;

}, 'An aborted request results in AbortError');

promise_test(async t => {
  const res = uniqueName(t);

  // Grab a lock and hold it until this subtest completes.
  requestLockAndHold(t, res);

  const controller = new AbortController();

  const promise =
    navigator.locks.request(res, {signal: controller.signal}, lock => {});

  // Verify the request is enqueued:
  const state = await navigator.locks.query();
  assert_equals(state.held.filter(lock => lock.name === res).length, 1,
                'Number of held locks');
  assert_equals(state.pending.filter(lock => lock.name === res).length, 1,
                'Number of pending locks');

  const rejected = promise_rejects_dom(
    t, 'AbortError', promise, 'Request should reject with AbortError');

  let callback_called = false;
  t.step_timeout(() => {
    callback_called = true;
    controller.abort();
  }, 10);

  await rejected;
  assert_true(callback_called, 'timeout should have caused the abort');

}, 'Abort after a timeout');

promise_test(async t => {
  const res = uniqueName(t);

  const controller = new AbortController();

  let got_lock = false;
  await navigator.locks.request(
    res, {signal: controller.signal}, async lock => { got_lock = true; });

  assert_true(got_lock, 'Lock should be acquired if abort is not signaled.');

}, 'Signal that is not aborted');

promise_test(async t => {
  const res = uniqueName(t);

  const controller = new AbortController();

  let got_lock = false;
  const p = navigator.locks.request(
    res, {signal: controller.signal}, lock => { got_lock = true; });

  // Even though lock is grantable, this abort should be processed synchronously.
  controller.abort();

  await promise_rejects_dom(t, 'AbortError', p, 'Request should abort');

  assert_false(got_lock, 'Request should be aborted if signal is synchronous');

  await navigator.locks.request(res, lock => { got_lock = true; });
  assert_true(got_lock, 'Subsequent request should not be blocked');

}, 'Synchronously signaled abort');

promise_test(async t => {
  const res = uniqueName(t);

  const controller = new AbortController();

  // Make a promise that resolves when the lock is acquired.
  const [acquired_promise, acquired_func] = makePromiseAndResolveFunc();

  // Request the lock.
  let release_func;
  const released_promise = navigator.locks.request(
    res, {signal: controller.signal}, lock => {
      acquired_func();

      // Hold lock until release_func is called.
      const [waiting_promise, waiting_func] = makePromiseAndResolveFunc();
      release_func = waiting_func;
      return waiting_promise;
    });

  // Wait for the lock to be acquired.
  await acquired_promise;

  // Signal an abort.
  controller.abort();

  // Release the lock.
  release_func('resolved ok');

  assert_equals(await released_promise, 'resolved ok',
                'Lock released promise should not reject');

}, 'Abort signaled after lock granted');

promise_test(async t => {
  const res = uniqueName(t);

  const controller = new AbortController();

  // Make a promise that resolves when the lock is acquired.
  const [acquired_promise, acquired_func] = makePromiseAndResolveFunc();

  // Request the lock.
  let release_func;
  const released_promise = navigator.locks.request(
    res, {signal: controller.signal}, lock => {
      acquired_func();

      // Hold lock until release_func is called.
      const [waiting_promise, waiting_func] = makePromiseAndResolveFunc();
      release_func = waiting_func;
      return waiting_promise;
    });

  // Wait for the lock to be acquired.
  await acquired_promise;

  // Release the lock.
  release_func('resolved ok');

  // Signal an abort.
  controller.abort();

  assert_equals(await released_promise, 'resolved ok',
                'Lock released promise should not reject');

}, 'Abort signaled after lock released');

promise_test(async t => {
  const res = uniqueName(t);

  const controller = new AbortController();
  const first = requestLockAndHold(t, res, { signal: controller.signal });
  const next = navigator.locks.request(res, () => "resolved");
  controller.abort();

  await promise_rejects_dom(t, "AbortError", first, "Request should abort");
  assert_equals(
    await next,
    "resolved",
    "The next request is processed after abort"
  );
}, "Abort should process the next pending lock request");
