chromium/ui/file_manager/image_loader/scheduler_unittest.ts

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

import {assertEquals} from 'chrome://webui-test/chromeos/chai_assert.js';

import type {ImageRequestTask} from './image_request_task.js';
import {MAXIMUM_IN_PARALLEL, Scheduler} from './scheduler.js';


/**
 * Fake global clock used to record the "time" at which a task was run.
 */
let globalTime = 0;

export function setUp() {
  globalTime = 0;
}

interface FakeImageRequestTask {
  cancelCallCount: number;
  runTime: number;
  getId(): string;
  getPriority(): number;
  cancel(): void;
  loadFromCacheAndProcess(onSuccess: VoidCallback, onFailure: VoidCallback):
      void;
}

function newTask(taskId: string, priority: number): FakeImageRequestTask {
  return {
    // Counts how many times cancel method was called.
    // Used to test multiple cancellation of the same task.
    cancelCallCount: 0,

    // Records value of globalTime variable at the time the main method,
    // loadFromCacheAndProcess is called. Used to test if the task was
    // executed and in what orders tasks were executed.
    runTime: 0,

    getId(): string {
      return taskId;
    },

    getPriority(): number {
      return priority;
    },

    cancel() {
      ++this.cancelCallCount;
    },

    loadFromCacheAndProcess(resolve: VoidCallback, _reject: VoidCallback) {
      this.runTime = ++globalTime;
      setTimeout(resolve);
    },
  };
}

/**
 * Checks that adding and removing tasks before the scheduler is started works.
 */
export function testIdleSchedulerAddRemove() {
  const scheduler = new Scheduler();
  const fakeTask = newTask('task-1', 0);
  scheduler.add(fakeTask as unknown as ImageRequestTask);
  assertEquals(0, fakeTask.cancelCallCount);
  scheduler.remove('task-1');
  assertEquals(1, fakeTask.cancelCallCount);
  scheduler.remove('task-1');
  assertEquals(1, fakeTask.cancelCallCount);
}

/**
 * Checks that tasks that were in newTasks are correctly copied to pending
 * tasks when scheduler is started. They also should be executed in the
 * order of their priorities.
 */
export function testNewTasksMovedAndRunInPriorityOrder() {
  const fakeTask1 = newTask('task-1', 1);
  const fakeTask2 = newTask('task-2', 0);

  const scheduler = new Scheduler();
  scheduler.add(fakeTask1 as unknown as ImageRequestTask);
  scheduler.add(fakeTask2 as unknown as ImageRequestTask);

  scheduler.start();
  assertEquals(2, fakeTask1.runTime);
  assertEquals(1, fakeTask2.runTime);
}

/**
 * Checks that the scheduler only launches MAXIMUM_IN_PARALLEL tasks.
 */
export function testParallelTasks() {
  const scheduler = new Scheduler();
  const taskList = [];
  for (let i = 0; i <= MAXIMUM_IN_PARALLEL; ++i) {
    taskList.push(newTask(`task-${i}`, 0));
    scheduler.add(taskList[i] as unknown as ImageRequestTask);
  }
  scheduler.start();
  for (let i = 0; i < MAXIMUM_IN_PARALLEL; ++i) {
    assertEquals(i + 1, taskList[i]!.runTime, `task ${i} did not run`);
  }
  assertEquals(0, taskList[MAXIMUM_IN_PARALLEL]!.runTime);
}