[ct] Add chromium-analysis-sk element.
Change-Id: Ia51e0143dd171ebbd0538bc73e5573f27f7aefb0
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/298836
Reviewed-by: Ravi Mistry <rmistry@google.com>
Commit-Queue: Weston Tracey <westont@google.com>
diff --git a/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.html b/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.html
new file mode 100644
index 0000000..becbfd0
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Chromium Perf Demo</title>
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ </head>
+ <body>
+ <h2>chromium-analysis-sk demo</h2><theme-chooser-sk></theme-chooser-sk>
+ <div id=container></div>
+ <error-toast-sk></error-toast-sk>
+ </body>
+</html>
diff --git a/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.js b/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.js
new file mode 100644
index 0000000..8d12fed
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/chromium-analysis-sk-demo.js
@@ -0,0 +1,25 @@
+import './index';
+import '../../../infra-sk/modules/theme-chooser-sk';
+import { $$ } from 'common-sk/modules/dom';
+import { fetchMock } from 'fetch-mock';
+import { benchmarks_platforms } from './test_data';
+import { pageSets } from '../pageset-selector-sk/test_data';
+import { priorities } from '../task-priority-sk/test_data';
+import { chromiumPatchResult } from '../patch-sk/test_data';
+import 'elements-sk/error-toast-sk';
+
+fetchMock.config.overwriteRoutes = false;
+fetchMock.post('begin:/_/page_sets/', pageSets);
+fetchMock.post('begin:/_/benchmarks_platforms/', benchmarks_platforms);
+fetchMock.get('begin:/_/task_priorities/', priorities);
+fetchMock.post('begin:/_/cl_data', chromiumPatchResult, { delay: 1000 });
+// For determining running tasks for the user we just say 2.
+fetchMock.postOnce('begin:/_/get', {
+ data: [], ids: [], pagination: { offset: 0, size: 1, total: 2 }, permissions: [],
+});
+fetchMock.post('begin:/_/get', {
+ data: [], ids: [], pagination: { offset: 0, size: 1, total: 0 }, permissions: [],
+});
+
+const chromiumPerf = document.createElement('chromium-analysis-sk');
+$$('#container').appendChild(chromiumPerf);
diff --git a/ct/modules/chromium-analysis-sk/chromium-analysis-sk.js b/ct/modules/chromium-analysis-sk/chromium-analysis-sk.js
new file mode 100644
index 0000000..f691b87
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/chromium-analysis-sk.js
@@ -0,0 +1,426 @@
+/**
+ * @fileoverview The bulk of the Analysis page of CT.
+ */
+
+import 'elements-sk/icon/delete-icon-sk';
+import 'elements-sk/icon/cancel-icon-sk';
+import 'elements-sk/icon/check-circle-icon-sk';
+import 'elements-sk/icon/help-icon-sk';
+import 'elements-sk/toast-sk';
+import '../../../infra-sk/modules/confirm-dialog-sk';
+import '../suggest-input-sk';
+import '../input-sk';
+import '../patch-sk';
+import '../pageset-selector-sk';
+import '../task-repeater-sk';
+import '../task-priority-sk';
+
+import { $$, $ } from 'common-sk/modules/dom';
+import { define } from 'elements-sk/define';
+import 'elements-sk/select-sk';
+import { errorMessage } from 'elements-sk/errorMessage';
+import { html } from 'lit-html';
+
+import { ElementSk } from '../../../infra-sk/modules/ElementSk';
+import {
+ combineClDescriptions,
+ missingLiveSitesWithCustomWebpages,
+ moreThanThreeActiveTasksChecker,
+ fetchBenchmarksAndPlatforms,
+} from '../ctfe_utils';
+
+// Chromium analysis doesn't support 1M pageset, and only Linux supports 100k.
+const unsupportedPageSetStrings = ['All', '100k'];
+const unsupportedPageSetStringsLinux = ['All'];
+
+const template = (el) => html`
+<confirm-dialog-sk id=confirm_dialog></confirm-dialog-sk>
+
+<table class=options>
+ <tr>
+ <td>Benchmark Name</td>
+ <td>
+ <suggest-input-sk
+ id=benchmark_name
+ .options=${el._benchmarks}
+ .label=${'Hit <enter> at end if entering custom benchmark'}
+ accept-custom-value
+ @value-changed=${el._refreshBenchmarkDoc}
+ ></suggest-input-sk>
+ <div>
+ <a hidden id=benchmark_doc href=#
+ target=_blank rel="noopener noreferrer">
+ Documentation
+ </a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Target Platform</td>
+ <td>
+ <select-sk id=platform_selector @selection-changed=${el._platformChanged}>
+ ${el._platforms.map((p, i) => (html`<div ?selected=${i === 1}>${p[1]}</div>`))}
+ </select-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Run on GCE
+ </td>
+ <td>
+ <select-sk id=run_on_gce>
+ <div selected id=gce_true>True</div>
+ <div id=gce_false>False</div>
+ </select-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>PageSets Type</td>
+ <td>
+ <pageset-selector-sk id=pageset_selector></pageset-selector-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Run in Parallel<br/>
+ Read about the trade-offs <a href="https://docs.google.com/document/d/1GhqosQcwsy6F-eBAmFn_ITDF7_Iv_rY9FhCKwAnk9qQ/edit?pli=1#heading=h.xz46aihphb8z">here</a>
+ </td>
+ <td>
+ <select-sk id=run_in_parallel @selection-changed=${el._updatePageSets}>
+ <div selected>True</div>
+ <div>False</div>
+ </select-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Look for text in stdout</td>
+ <td>
+ <input-sk value="" id=match_stdout_txt class=long-field></input-sk>
+ <span class=smaller-font><b>Note:</b> All lines that contain this field in stdout will show up under CT_stdout_lines in the output CSV.</span><br/>
+ <span class=smaller-font><b>Note:</b> The count of non-overlapping exact matches of this field in stdout will show up under CT_stdout_count in the output CSV.</span><br/>
+ </td>
+ </tr>
+ <tr>
+ <td>Benchmark Arguments</td>
+ <td>
+ <input-sk value="--output-format=csv --skip-typ-expectations-tags-validation --legacy-json-trace-format" id=benchmark_args class=long-field></input-sk>
+ <span class=smaller-font><b>Note:</b> Use --num-analysis-retries=[num] to specify how many times run_benchmark should be retried. 2 is the default. 0 calls run_benchmark once.</span><br/>
+ <span class=smaller-font><b>Note:</b> Use --run-benchmark-timeout=[secs] to specify the timeout of the run_benchmark script. 300 is the default.</span><br/>
+ <span class=smaller-font><b>Note:</b> Use --max-pages-per-bot=[num] to specify the number of pages to run per bot. 100 is the default.</span>
+ </td>
+ </tr>
+ <tr>
+ <td>Browser Arguments</td>
+ <td>
+ <input-sk value="" id=browser_args class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Field Value Column Name</td>
+ <td>
+ <input-sk value="avg" id=value_column_name class="medium-field"></input-sk>
+ <span class=smaller-font>Which column's entries to use as field values.</span>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Chromium Git patch (optional)<br/>
+ Applied to Chromium ToT<br/>
+ or to the hash specified below.
+ </td>
+ <td>
+ <patch-sk id=chromium_patch
+ patchType=chromium
+ @cl-description-changed=${el._patchChanged}>
+ </patch-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Custom APK location (optional)<br/> (See
+ <a href="https://bugs.chromium.org/p/skia/issues/detail?id=9805">skbug/9805</a>)
+ </td>
+ <td>
+ <input-sk value="" id=apk_gs_path label="Eg: gs://chrome-unsigned/android-B0urB0N/73.0.3655.0/arm_64/ChromeModern.apk" class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Telemetry Isolate Hash (optional))<br/> (See
+ <a href="https://bugs.chromium.org/p/skia/issues/detail?id=9853">skbug/9853</a>)
+ </td>
+ <td>
+ <input-sk value="" id=telemetry_isolate_hash class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Chromium hash to sync to (optional)<br/></td>
+ <td>
+ <input-sk value="" id=chromium_hash class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Skia Git patch (optional)<br/>
+ Applied to Skia Rev in <a href="https://chromium.googlesource.com/chromium/src/+show/HEAD/DEPS">DEPS</a>
+ </td>
+ <td>
+ <patch-sk id=skia_patch
+ patchType=skia
+ @cl-description-changed=${el._patchChanged}>
+ </patch-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ V8 Git patch (optional)<br/>
+ Applied to V8 Rev in <a href="https://chromium.googlesource.com/chromium/src/+show/HEAD/DEPS">DEPS</a>
+ </td>
+ <td>
+ <patch-sk id=v8_patch
+ patchType=v8
+ @cl-description-changed=${el._patchChanged}>
+ </patch-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Catapult Git patch (optional)<br/>
+ Applied to Catapult Rev in <a href="https://chromium.googlesource.com/chromium/src/+show/HEAD/DEPS">DEPS</a>
+ </td>
+ <td>
+ <patch-sk id=catapult_patch
+ patchType=catapult
+ @cl-description-changed=${el._patchChanged}>
+ </patch-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Repeat this task</td>
+ <td>
+ <task-repeater-sk id=repeat_after_days></task-repeater-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Task Priority</td>
+ <td>
+ <task-priority-sk id=task_priority></task-priority-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Notifications CC list (optional)<br/>
+ Email will be sent by ct@skia.org
+ </td>
+ <td>
+ <input-sk value="" id=cc_list label="email1,email2,email3" class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ Group name (optional)<br/>
+ Will be used to track runs
+ </td>
+ <td>
+ <input-sk value="" id=group_name class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td>Description</td>
+ <td>
+ <input-sk value="" id=description label="Description is required" class=long-field></input-sk>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" class="center">
+ <div class="triggering-spinner">
+ <spinner-sk .active=${el._triggeringTask} alt="Trigger task"></spinner-sk>
+ </div>
+ <button id=submit ?disabled=${el._triggeringTask} @click=${el._validateTask}>Queue Task</button>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=2 class=center>
+ <button id=view_history @click=${el._gotoRunsHistory}>View runs history</button>
+ </td>
+ </tr>
+</table>
+`;
+
+define('chromium-analysis-sk', class extends ElementSk {
+ constructor() {
+ super(template);
+ this._benchmarksToDocs = {};
+ this._benchmarks = [];
+ this._platforms = [];
+ this._triggeringTask = false;
+ this._unsupportedPageSets = unsupportedPageSetStringsLinux;
+ this._moreThanThreeActiveTasks = moreThanThreeActiveTasksChecker();
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ this._render();
+ fetchBenchmarksAndPlatforms((json) => {
+ this._benchmarksToDocs = json.benchmarks;
+ this._benchmarks = Object.keys(json.benchmarks);
+ // { 'p1' : 'p1Desc', ... } -> [[p1, p1Desc], ...]
+ // Allows rendering descriptions in the select-sk, and converting the
+ // integer selection to platform name easily.
+ this._platforms = Object.entries(json.platforms);
+ this._render();
+ // Do this after the template is rendered, or else it fails, and don't
+ // inline a child 'selected' attribute since it won't rationalize in
+ // select-sk until later via the mutationObserver.
+ $$('#platform_selector', this).selection = 1;
+ // This gets the defaults in a valid state.
+ this._platformChanged();
+ });
+ }
+
+ _refreshBenchmarkDoc(e) {
+ const benchmarkName = e.detail.value;
+ const docElement = $$('#benchmark_doc', this);
+ if (benchmarkName && this._benchmarksToDocs[benchmarkName]) {
+ docElement.hidden = false;
+ docElement.href = this._benchmarksToDocs[benchmarkName];
+ } else {
+ docElement.hidden = true;
+ docElement.href = '#';
+ }
+ }
+
+ _platformChanged() {
+ const trueIndex = 0;
+ const falseIndex = 1;
+ const platform = this._platform();
+ let offerGCETrue = true;
+ let offerGCEFalse = true;
+ let offerParallelTrue = true;
+ if (platform === 'Android') {
+ offerGCETrue = false;
+ offerParallelTrue = false;
+ } else if (platform === 'Windows') {
+ offerGCEFalse = false;
+ }
+ // We default to use GCE for Linux, require if for Windows, and
+ // disallow it for Android.
+ const runOnGCE = $$('#run_on_gce', this);
+ runOnGCE.children[trueIndex].hidden = !offerGCETrue;
+ runOnGCE.children[falseIndex].hidden = !offerGCEFalse;
+ runOnGCE.selection = offerGCETrue ? trueIndex : falseIndex;
+
+ // We default to run in parallel, except for Android which disallows it.
+ const runInParallel = $$('#run_in_parallel', this);
+ runInParallel.children[trueIndex].hidden = !offerParallelTrue;
+ runInParallel.selection = offerParallelTrue ? trueIndex : falseIndex;
+
+ this._updatePageSets();
+ }
+
+ _updatePageSets() {
+ const platform = this._platform();
+ const runInParallel = this._runInParallel();
+ const unsupportedPageSets = (platform === 'Linux' && runInParallel)
+ ? unsupportedPageSetStringsLinux
+ : unsupportedPageSetStrings;
+ const pageSetDefault = (platform === 'Android')
+ ? 'Mobile10k'
+ : '10k';
+ const pagesetSelector = $$('pageset-selector-sk', this);
+ pagesetSelector.hideIfKeyContains = unsupportedPageSets;
+ pagesetSelector.selected = pageSetDefault;
+ }
+
+ _platform() {
+ return this._platforms[$$('#platform_selector', this).selection][0];
+ }
+
+ _runInParallel() {
+ return $$('#run_in_parallel', this).selection === 0;
+ }
+
+ _patchChanged() {
+ $$('#description', this).value = combineClDescriptions(
+ $('patch-sk', this).map((patch) => patch.clDescription),
+ );
+ }
+
+ _validateTask() {
+ if (!$('patch-sk', this).every((patch) => patch.validate())) {
+ return;
+ }
+ if (!$$('#description', this).value) {
+ errorMessage('Please specify a description');
+ $$('#description', this).focus();
+ return;
+ }
+ if (!$$('#benchmark_name', this).value) {
+ errorMessage('Please specify a benchmark');
+ $$('#benchmark_name', this).focus();
+ return;
+ }
+ if (missingLiveSitesWithCustomWebpages(
+ $$('#pageset_selector', this).customPages, $$('#benchmark_args', this).value,
+ )) {
+ $$('#benchmark_args', this).focus();
+ return;
+ }
+ if (this._moreThanThreeActiveTasks()) {
+ return;
+ }
+ $$('#confirm_dialog', this).open('Proceed with queueing task?')
+ .then(() => this._queueTask())
+ .catch(() => {
+ errorMessage('Unable to queue task');
+ });
+ }
+
+ _queueTask() {
+ this._triggeringTask = true;
+ const params = {};
+ params.benchmark = $$('#benchmark_name', this).value;
+ params.platform = this._platforms[$$('#platform_selector', this).selection][0];
+ params.page_sets = $$('#pageset_selector', this).selected;
+ params.run_on_gce = $$('#run_on_gce', this).selection === 0;
+ params.match_stdout_txt = $$('#match_stdout_txt', this).value;
+ params.apk_gs_path = $$('#apk_gs_path', this).value;
+ params.telemetry_isolate_hash = $$('#telemetry_isolate_hash', this).value;
+ params.custom_webpages = $$('#pageset_selector', this).customPages;
+ params.run_in_parallel = $$('#run_in_parallel', this).selection === 0;
+ params.benchmark_args = $$('#benchmark_args', this).value;
+ params.browser_args = $$('#browser_args', this).value;
+ params.value_column_name = $$('#value_column_name', this).value;
+ params.desc = $$('#description', this).value;
+ params.chromium_patch = $$('#chromium_patch', this).patch;
+ params.skia_patch = $$('#skia_patch', this).patch;
+ params.v8_patch = $$('#v8_patch', this).patch;
+ params.catapult_patch = $$('#catapult_patch', this).patch;
+ params.chromium_hash = $$('#chromium_hash', this).value;
+ params.repeat_after_days = $$('#repeat_after_days', this).frequency;
+ params.task_priority = $$('#task_priority', this).priority;
+ if ($$('#cc_list', this).value) {
+ params.cc_list = $$('#cc_list', this).value.split(',');
+ }
+ if ($$('#group_name', this).value) {
+ params.group_name = $$('#group_name', this).value;
+ }
+
+ fetch('/_/add_chromium_analysis_task', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(params),
+ })
+ .then(() => this._gotoRunsHistory())
+ .catch((e) => {
+ this._triggeringTask = false;
+ errorMessage(e);
+ });
+ }
+
+ _gotoRunsHistory() {
+ window.location.href = '/chromium_analysis_runs/';
+ }
+});
diff --git a/ct/modules/chromium-analysis-sk/chromium-analysis-sk.scss b/ct/modules/chromium-analysis-sk/chromium-analysis-sk.scss
new file mode 100644
index 0000000..a60fbea
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/chromium-analysis-sk.scss
@@ -0,0 +1,45 @@
+@import '../colors.css';
+
+chromium-analysis-sk {
+ table.options {
+ padding: 2em;
+ margin: 1em;
+ border-style: solid;
+ }
+
+ select-sk {
+ * {
+ padding: 0;
+ }
+ [selected] {
+ background-color: var(--primary-variant);
+ }
+ }
+
+ .triggering-spinner {
+ margin: auto;
+ vertical-align: middle;
+ }
+
+
+ .long-field {
+ width: 40em;
+ }
+
+ .smaller-font {
+ font-size: 80%;
+ }
+
+ table.options>tbody>tr>td {
+ padding: 1em 2em;
+ }
+
+ td.center {
+ text-align:center;
+ padding-top:2em;
+ }
+}
+
+.darkmode chromium-analysis-sk table.options {
+ background-color: var(--surface-2dp);
+}
diff --git a/ct/modules/chromium-analysis-sk/chromium-analysis-sk_test.js b/ct/modules/chromium-analysis-sk/chromium-analysis-sk_test.js
new file mode 100644
index 0000000..bce0eb5
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/chromium-analysis-sk_test.js
@@ -0,0 +1,185 @@
+import './index';
+
+import { $, $$ } from 'common-sk/modules/dom';
+import { fetchMock } from 'fetch-mock';
+import { benchmarks_platforms } from './test_data';
+import { pageSets } from '../pageset-selector-sk/test_data';
+import { priorities } from '../task-priority-sk/test_data';
+import { chromiumPatchResult } from '../patch-sk/test_data';
+import {
+ eventPromise,
+ setUpElementUnderTest,
+} from '../../../infra-sk/modules/test_util';
+
+describe('chromium-analysis-sk', () => {
+ fetchMock.config.overwriteRoutes = false;
+ const factory = setUpElementUnderTest('chromium-analysis-sk');
+ // Returns a new element with the pagesets, task priorirites, and
+ // active tasks fetches complete, and benchmarks and platforms set.
+ const newInstance = async (activeTasks, init) => {
+ fetchMock.postOnce('begin:/_/page_sets/', pageSets);
+ fetchMock.postOnce('begin:/_/benchmarks_platforms/', benchmarks_platforms);
+ fetchMock.getOnce('begin:/_/task_priorities/', priorities);
+ mockActiveTasks(activeTasks);
+ const wrappedInit = (ele) => {
+ if (init) {
+ init(ele);
+ }
+ };
+ const ele = factory(wrappedInit);
+ await fetchMock.flush(true);
+ return ele;
+ };
+
+ // Make our test object global to make helper functions convenient.
+ let chromiumAnalysis;
+
+ afterEach(() => {
+ // Check all mock fetches called at least once and reset.
+ expect(fetchMock.done()).to.be.true;
+ fetchMock.reset();
+ });
+
+ const mockActiveTasks = (n) => {
+ n = n || 0;
+ // For running tasks for the user we put a nonzero total in one of the
+ // responses, and 0 in the remaining 6.
+ fetchMock.postOnce('begin:/_/get', {
+ data: [],
+ ids: [],
+ pagination: { offset: 0, size: 1, total: n },
+ permissions: [],
+ });
+ fetchMock.post('begin:/_/get', {
+ data: [],
+ ids: [],
+ pagination: { offset: 0, size: 1, total: 0 },
+ permissions: [],
+ }, { repeat: 6 });
+ };
+
+ const setDescription = (d) => {
+ $$('#description', chromiumAnalysis).value = d;
+ };
+
+ const setBenchmark = (b) => {
+ $$('#benchmark_name', chromiumAnalysis).value = b;
+ };
+
+ const setPatch = async (patchtype, value, response) => {
+ fetchMock.postOnce('begin:/_/cl_data', response);
+ const input = $$(`#${patchtype}_patch input-sk`);
+ input.value = value;
+ input.dispatchEvent(new Event('input', {
+ bubbles: true,
+ }));
+ await fetchMock.flush(true);
+ };
+
+ const clickSubmit = () => {
+ $$('#submit', chromiumAnalysis).click();
+ };
+
+ const expectTaskTriggered = () => {
+ fetchMock.postOnce('begin:/_/add_chromium_analysis_task', {});
+ };
+
+ it('loads, has defaults set', async () => {
+ chromiumAnalysis = await newInstance();
+ expect(chromiumAnalysis._platforms[$$('#platform_selector', chromiumAnalysis)
+ .selection][0]).to.equal('Linux');
+ expect($$('#pageset_selector', chromiumAnalysis)).to.have.property('selected', '10k');
+ expect($$('#pageset_selector', chromiumAnalysis)).to.have.property('customPages', '');
+ expect($$('#repeat_after_days', this)).to.have.property('frequency', '0');
+ expect($$('#task_priority', this)).to.have.property('priority', '100');
+ expect($$('#benchmark_args', this)).to.have.property('value',
+ '--output-format=csv --skip-typ-expectations-tags-validation'
+ + ' --legacy-json-trace-format');
+ expect($$('#value_column_name', this)).to.have.property('value', 'avg');
+ });
+
+ it('requires description', async () => {
+ chromiumAnalysis = await newInstance();
+ const event = eventPromise('error-sk');
+ clickSubmit();
+ const err = await event;
+ expect(err.detail.message).to.equal('Please specify a description');
+ });
+
+ it('requires benchmark', async () => {
+ chromiumAnalysis = await newInstance();
+ setDescription('Testing things');
+ const event = eventPromise('error-sk');
+ clickSubmit();
+ const err = await event;
+ expect(err.detail.message).to.equal('Please specify a benchmark');
+ });
+
+ it('rejects bad patch', async () => {
+ chromiumAnalysis = await newInstance();
+ setDescription('Testing things');
+ setBenchmark('a benchmark');
+ await setPatch('skia', '1234', { cl: '1234' }); // Patch result is bogus.
+ let event = eventPromise('error-sk');
+ clickSubmit();
+ let err = await event;
+ expect(err.detail.message).to.contain('Unable to fetch skia patch from CL 1234');
+
+ await setPatch('skia', '1234', {}); // CL doesn't load.
+ event = eventPromise('error-sk');
+ clickSubmit();
+ err = await event;
+ expect(err.detail.message).to.contain('Unable to load skia CL 1234');
+ });
+
+ it('triggers a new task', async () => {
+ chromiumAnalysis = await newInstance();
+ setDescription('Testing things');
+ setBenchmark('a benchmark');
+ await setPatch('chromium', '1234', chromiumPatchResult);
+ // Karma can't handle page reloads, so disable it.
+ chromiumAnalysis._gotoRunsHistory = () => { };
+ expectTaskTriggered();
+ clickSubmit();
+ $('#confirm_dialog button')[1].click(); // brittle way to press 'ok'
+ await fetchMock.flush(true);
+ const taskJson = JSON.parse(fetchMock.lastOptions().body);
+ // Here we test the 'interesting' arguments. We try a single patch,
+ // and we don't bother filling in the simple string arguments.
+ const expectation = {
+ benchmark: 'a benchmark',
+ page_sets: '10k',
+ match_stdout_txt: '',
+ benchmark_args: '--output-format=csv --skip-typ-expectations-tags-validation --legacy-json-trace-format',
+ browser_args: '',
+ value_column_name: 'avg',
+ desc: 'Testing https://chromium-review.googlesource.com/c/2222715/3 (Roll Skia from cc7ec24ca824 to 1dbc3b533962 (3 revisions))',
+ chromium_patch: '\n\ndiff --git a/DEPS b/DEPS\nindex 849ae22..ee07579 100644\n--- a/DEPS\n+++ b/DEPS\n@@ -178,7 +178,7 @@\n # Three lines of non-changing comments so that\n # the commit queue can handle CLs rolling Skia\n # and whatever else without interference from each other.\n- \'skia_revision\': \'cc7ec24ca824ca13d5a8a8e562fcec695ae54390\',\n+ \'skia_revision\': \'1dbc3b533962b0ae803a2a5ee89f61146228d73b\',\n # Three lines of non-changing comments so that\n # the commit queue can handle CLs rolling V8\n # and whatever else without interference from each other.\n',
+ chromium_hash: '',
+ apk_gs_path: '',
+ telemetry_isolate_hash: '',
+ repeat_after_days: '0',
+ task_priority: '100',
+ run_in_parallel: true,
+ platform: 'Linux',
+ run_on_gce: true,
+ custom_webpages: '',
+ skia_patch: '',
+ v8_patch: '',
+ catapult_patch: '',
+ };
+
+ expect(taskJson).to.deep.equal(expectation);
+ });
+
+ it('rejects if too many active tasks', async () => {
+ // Report user as having 4 active tasks.
+ chromiumAnalysis = await newInstance(4);
+ setDescription('Testing things');
+ setBenchmark('a benchmark');
+ const event = eventPromise('error-sk');
+ clickSubmit();
+ const err = await event;
+ expect(err.detail.message).to.contain('You have 4 currently running tasks');
+ });
+});
diff --git a/ct/modules/chromium-analysis-sk/index.js b/ct/modules/chromium-analysis-sk/index.js
new file mode 100644
index 0000000..09f9880
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/index.js
@@ -0,0 +1,2 @@
+import './chromium-analysis-sk';
+import './chromium-analysis-sk.scss';
diff --git a/ct/modules/chromium-analysis-sk/test_data.js b/ct/modules/chromium-analysis-sk/test_data.js
new file mode 100644
index 0000000..9f122a4
--- /dev/null
+++ b/ct/modules/chromium-analysis-sk/test_data.js
@@ -0,0 +1,20 @@
+export const benchmarks_platforms = {
+ benchmarks: {
+ 'ad_tagging.cluster_telemetry': 'https://docs.google.com/document/d/1zlWQoLjGuYOWDR_vkVRYoVbU89JetNDOlcDuOaNAzDc/',
+ generic_trace_ct: 'https://docs.google.com/document/d/1vGd7dnrxayMYHPO72wWkwTvjMnIRrel4yxzCr1bMiis/',
+ 'leak_detection.cluster_telemetry': 'https://docs.google.com/document/d/1wUWa7dWUdvr6dLdYHFfMQdnvgzt7lrrvzYfpAK-_6e0/',
+ 'loading.cluster_telemetry': 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/v8_loading_ct.py',
+ 'memory.cluster_telemetry': 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/memory_ct.py',
+ rasterize_and_record_micro_ct: 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/rasterize_and_record_micro_ct.py',
+ 'rendering.cluster_telemetry': 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/rendering_ct.py',
+ repaint_ct: 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/repaint.py',
+ usecounter_ct: 'https://docs.google.com/document/d/1FSzJm2L2ow6pZTM_CuyHNJecXuX7Mx3XmBzL4SFHyLA/',
+ 'v8.loading.cluster_telemetry': 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/v8_loading_ct.py',
+ 'v8.loading_runtime_stats.cluster_telemetry': 'https://cs.chromium.org/chromium/src/tools/analysis/contrib/cluster_telemetry/v8_loading_runtime_stats_ct.py',
+ },
+ platforms: {
+ Android: 'Android (Pixel2 devices)',
+ Linux: 'Linux (Ubuntu18.04 machines)',
+ Windows: 'Windows (2016 DataCenter Server cloud instances)',
+ },
+};
diff --git a/ct/modules/chromium-perf-sk/chromium-perf-sk.js b/ct/modules/chromium-perf-sk/chromium-perf-sk.js
index 5e9e87b..20f2b7d 100644
--- a/ct/modules/chromium-perf-sk/chromium-perf-sk.js
+++ b/ct/modules/chromium-perf-sk/chromium-perf-sk.js
@@ -63,7 +63,7 @@
</td>
</tr>
<tr>
- <td>PagestSets Type</td>
+ <td>PageSets Type</td>
<td>
<pageset-selector-sk id=pageset_selector
.hideIfKeyContains=${unsupportedPageSetStrings}>
@@ -220,7 +220,7 @@
<div class="triggering-spinner">
<spinner-sk .active=${el._triggeringTask} alt="Trigger task"></spinner-sk>
</div>
- <button id=submit ?disabled=${el._triggeringTask} @click=${el._validateTask}>Queue Task</button>
+ <button id=submit ?disabled=${el._triggeringTask} @click=${el._validateTask}>Queue Task</button>
</td>
</tr>
<tr>