chromium/chrome/test/data/webui/net_internals/task_queue.js

// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js';

import {assertEquals, assertFalse, assertNotReached, assertTrue} from 'chrome://webui-test/chai_assert.js';

/**
 * This class allows multiple Tasks to be queued up to be run sequentially.
 */
export class TaskQueue {
  constructor() {
    // Test fixture for passing to tasks.
    this.tasks_ = [];
    this.whenDonePromise_ = null;
  }

  /**
   * Adds a Task to the end of the queue.  Each Task may only be added once
   * to a single queue.  Also passes the text fixture to the Task.
   * @param {Task}: task The Task to add.
   */
  addTask(task) {
    this.tasks_.push(task);
    task.setTaskQueue_(this);
  }

  /**
   * Adds a Task to the end of the queue.  The task will call the provided
   * function, and then complete.
   * @param {function}: taskFunction The function the task will call.
   */
  addFunctionTask(taskFunction) {
    this.addTask(new CallFunctionTask(taskFunction));
  }

  /**
   * Starts running the Tasks in the queue, passing its arguments, if any,
   * to the first Task's start function.  May only be called once.
   * @return {!Promise} Promise that resolves when all tasks have run.
   */
  run() {
    assertEquals(null, this.whenDonePromise_);
    this.whenDonePromise_ = new PromiseResolver();
    this.runNextTask(Array.prototype.slice.call(arguments));
    return this.whenDonePromise_.promise;
  }

  /**
   * If there are any Tasks in |tasks_|, removes the first one and runs it.
   * Otherwise, resolves the promise returned by run().
   * @param {array} argArray arguments to be passed on to next Task's start
   *     method.  May be a 0-length array.
   */
  runNextTask(argArray) {
    assertTrue(!!this.whenDonePromise_);

    if (this.tasks_.length > 0) {
      const nextTask = this.tasks_.shift();
      nextTask.start.apply(nextTask, argArray);
    } else {
      this.whenDonePromise_.resolve();
      this.whenDonePromise_ = null;
    }
  }
}

  /**
   * A Task that can be added to a TaskQueue.  A Task is started with a call to
   * the start function, and must call its own onTaskDone when complete.
   */
export class Task {
  constructor() {
    this.taskQueue_ = null;
    this.isDone_ = false;
  }

  /**
   * Starts running the Task.  Only called once per Task, must be overridden.
   * Any arguments passed to the last Task's onTaskDone, or to run (If the
   * first task) will be passed along.
   */
  start() {
    assertNotReached('Start function not overridden.');
  }

  /**
   * @return {bool} True if this task has completed by calling onTaskDone.
   */
  isDone() {
    return this.isDone_;
  }

  /**
   * Sets the TaskQueue used by the task in the onTaskDone function.  May only
   * be called by the TaskQueue.
   * @param {TaskQueue}: taskQueue The TaskQueue |this| has been added to.
   */
  setTaskQueue_(taskQueue) {
    assertEquals(null, this.taskQueue_);
    this.taskQueue_ = taskQueue;
  }

  /**
   * Must be called when a task is complete, and can only be called once for a
   * task.  Runs the next task, if any, passing along all arguments.
   */
  onTaskDone() {
    assertFalse(this.isDone_);
    this.isDone_ = true;

    // Run the next task in the queue.
    this.taskQueue_.runNextTask(Array.prototype.slice.call(arguments));
  }
}

/**
 * A Task that can be added to a TaskQueue.  A Task is started with a call to
 * the start function, and must call its own onTaskDone when complete.
 * @extends {Task}
 * @constructor
 */
class CallFunctionTask extends Task {
  constructor(taskFunction) {
    super();
    assertEquals('function', typeof taskFunction);
    this.taskFunction_ = taskFunction;
  }

  /**
   * Runs the function and then completes.  Passes all arguments, if any,
   * along to the function.
   */
  start() {
    this.taskFunction_.apply(null, Array.prototype.slice.call(arguments));
    this.onTaskDone();
  }
}