Commit 773cc572 authored by Zentaro Kavanagh's avatar Zentaro Kavanagh Committed by Commit Bot

Diagnostics: Add RoutineListExecutor

- Takes a list of routines and runs them sequentially using the mojo
  interface SystemRoutineController

Bug: 1125150
Test: browser_tests --gtest_filter=DiagnosticsApp*
Change-Id: Ia535db169eb141d611ecf94cd600a0e6920339b3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2464072Reviewed-by: default avatarBailey Berro <baileyberro@chromium.org>
Commit-Queue: Zentaro Kavanagh <zentaro@chromium.org>
Cr-Commit-Position: refs/heads/master@{#816376}
parent 650ccc13
......@@ -21,6 +21,7 @@ GEN('#include "content/public/test/browser_test.h"');
['FakeMojoInterface', 'diagnostics/mojo_interface_provider_test.js'],
['FakeSystemDataProvider', 'diagnostics/fake_system_data_provider_test.js'],
['FakeMethodProvider', 'diagnostics/fake_method_provider_test.js'],
['RoutineListExecutor', 'diagnostics/routine_list_executor_test.js'],
['RoutineResultEntry', 'diagnostics/routine_result_entry_test.js'],
['RoutineResultList', 'diagnostics/routine_result_list_test.js'],
['RoutineSection', 'diagnostics/routine_section_test.js'],
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(jimmyxgong): Use es6 module for mojo binding (crbug/1004256).
import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js';
import {RoutineName, RoutineResultInfo, StandardRoutineResult} from 'chrome://diagnostics/diagnostics_types.js';
import {FakeSystemRoutineController} from 'chrome://diagnostics/fake_system_routine_controller.js';
import {ExecutionProgress, ResultStatusItem, RoutineListExecutor} from 'chrome://diagnostics/routine_list_executor.js';
suite('FakeRoutineListExecutorTest', () => {
/** @type {?FakeSystemRoutineController} */
let controller = null;
/** @type {?RoutineListExecutor} */
let executor = null;
setup(() => {
controller = new FakeSystemRoutineController();
executor = new RoutineListExecutor(controller);
});
teardown(() => {
controller = null;
executor = null;
});
/**
* Helper function that takes an array of RoutineResultInfo which contains
* the routine name and expected result, initializes the fake routine runner,
* then executes and validates the results.
* @param {!Array<!RoutineResultInfo>} routines
*/
function runRoutinesAndAssertResults(routines) {
let expectedCallbacks = [];
let routineNames = [];
routines.forEach((routine) => {
// Set the result into the fake.
assertNotEquals(undefined, routine);
assertNotEquals(undefined, routine.result);
assertNotEquals(undefined, routine.result.simple_result);
controller.setFakeStandardRoutineResult(
routine.name, routine.result.simple_result);
// Build the list of routines to run.
routineNames.push(routine.name);
// Add the "running" callback to the list.
let status = new ResultStatusItem(routine.name);
status.progress = ExecutionProgress.kRunning;
expectedCallbacks.push(status);
// Add the "completed" callback to the list.
status = new ResultStatusItem(routine.name);
status.progress = ExecutionProgress.kCompleted;
status.result = routine.result;
expectedCallbacks.push(status);
});
// Create the callback that validates the arguments.
let upto = 0;
/** @type {!function(!ResultStatusItem)} */
let statusCallback = (status) => {
assertTrue(upto < expectedCallbacks.length);
assertEquals(expectedCallbacks[upto].name, status.name);
assertEquals(expectedCallbacks[upto].progress, status.progress);
if (status.progress === ExecutionProgress.kRunning) {
assertEquals(null, status.result);
} else {
assertEquals(
expectedCallbacks[upto].result.simple_result,
status.result.simple_result);
}
upto++;
};
return executor.runRoutines(routineNames, statusCallback).then(() => {
// Ensure that all the callbacks were sent.
assertEquals(expectedCallbacks.length, upto);
});
}
test('SingleTest', () => {
/** @type {!Array<!RoutineResultInfo>} */
const routines = [{
name: RoutineName.kCpuStress,
result: {simple_result: StandardRoutineResult.kTestFailed}
}];
return runRoutinesAndAssertResults(routines);
});
test('MultipleTests', () => {
/** @type {!Array<!RoutineResultInfo>} */
const routines = [
{
name: RoutineName.kCpuStress,
result: {simple_result: StandardRoutineResult.kTestPassed}
},
{
name: RoutineName.kCpuCache,
result: {simple_result: StandardRoutineResult.kTestFailed}
},
{
name: RoutineName.kFloatingPoint,
result: {simple_result: StandardRoutineResult.kTestPassed}
},
{
name: RoutineName.kPrimeSearch,
result: {simple_result: StandardRoutineResult.kTestFailed}
}
];
return runRoutinesAndAssertResults(routines);
});
});
......@@ -26,6 +26,7 @@ js_type_check("closure_compile_module") {
":overview_card",
":percent_bar_chart",
":realtime_cpu_chart",
":routine_list_executor",
":routine_result_entry",
":routine_result_list",
":routine_section",
......@@ -136,6 +137,10 @@ js_library("realtime_cpu_chart") {
]
}
js_library("routine_list_executor") {
deps = [ "//ui/webui/resources/js:cr.m" ]
}
js_library("routine_result_entry") {
deps = [
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
......
......@@ -31,6 +31,7 @@
<include name="IDR_DIAGNOSTICS_OVERVIEW_CARD_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/overview_card.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_PERCENT_BAR_CHART_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/percent_bar_chart.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_REALTIME_CPU_CHART_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/realtime_cpu_chart.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_ROUTINE_LIST_EXECUTOR_JS" file="routine_list_executor.js" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_ROUTINE_RESULT_ENTRY_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/routine_result_entry.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_ROUTINE_RESULT_LIST_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/routine_result_list.js" use_base_dir="false" type="BINDATA"/>
<include name="IDR_DIAGNOSTICS_ROUTINE_SECTION_JS" file="${root_gen_dir}/chromeos/components/diagnostics_ui/resources/routine_section.js" use_base_dir="false" type="BINDATA"/>
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chrome://resources/js/assert.m.js';
import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
import {RoutineName, RoutineResult, RoutineResultInfo, SystemRoutineControllerInterface} from './diagnostics_types.js';
/**
* Represents the execution progress of a test routine.
* @enum {number}
*/
export let ExecutionProgress = {
kNotStarted: 0,
kRunning: 1,
kCompleted: 2,
kCancelled: 3,
};
/**
* Represents the input to a single routine-result-entry in a
* routine-result-list.
*/
export class ResultStatusItem {
constructor(routine) {
/** @type {!RoutineName} */
this.routine = routine;
/** @type {!ExecutionProgress} */
this.progress = ExecutionProgress.kNotStarted;
/** @type {?RoutineResult} */
this.result = null;
}
};
/**
* The type of the status callback function.
* @typedef {!function(!ResultStatusItem)}
*/
export let StatusCallbackFunction;
/**
* Implements the RoutineRunner remote. Creates a resolver and resolves it when
* the onRoutineResult function is called.
*/
class ExecutionContext {
constructor() {
/** @private {!PromiseResolver} */
this.resolver_ = new PromiseResolver();
}
/**
* Implements RoutineRunner.onRoutineResult.
* @param {!RoutineResultInfo} result
**/
onRoutineResult(result) {
this.resolver_.resolve(result);
}
whenComplete() {
return this.resolver_.promise;
}
}
/**
* Executes a list of test routines, firing a status callback with a
* ResultStatusItem before and after each test. The resulting ResultStatusItem
* maps directly to an entry in a routine-result-list.
*/
export class RoutineListExecutor {
/**
* @param {!SystemRoutineControllerInterface} routineController
*/
constructor(routineController) {
/** @private {!SystemRoutineControllerInterface} */
this.routineController_ = routineController;
}
/*
* Executes a list of routines providing a status callback as each test
* starts and finishes. The return promise will resolve when all tests are
* completed.
* @param {!Array<!RoutineName>} routines
* @type {!function(!ResultStatusItem)} statusCallback
* @param {!Promise}
*/
runRoutines(routines, statusCallback) {
assert(routines.length > 0);
// Create a chain of promises that each schedule the next routine when
// they complete, firing the status callback before and after each test.
let promise = Promise.resolve();
routines.forEach((name) => {
promise = promise.then(() => {
// Notify the status callback that a test started running.
const status = new ResultStatusItem(name);
status.progress = ExecutionProgress.kRunning;
statusCallback(status);
// Create a new remote and execute the next test.
let test = new ExecutionContext();
return this.routineController_.runRoutine(name, test).then(() => {
// When the test completes, notify the status callback of the
// result.
return test.whenComplete().then((info) => {
assert(info.name === name);
const status = new ResultStatusItem(name);
status.progress = ExecutionProgress.kCompleted;
status.result = info.result;
statusCallback(status);
});
});
});
});
return promise;
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment