Skip to content

Commit

Permalink
Restore ?worker and ?worker=1 to mean ?worker=dedicated (take 2) (#3570)
Browse files Browse the repository at this point in the history
* (Clean reland) "Restore ?worker and ?worker=1 to mean ?worker=dedicated (#3485)"

(Clean except for removing the cache hash changes.)

This reverts commit 68753bb.

* Use nullable options instead of empty string
  • Loading branch information
kainino0x authored Apr 2, 2024
1 parent 2f0de1e commit 71d872b
Show file tree
Hide file tree
Showing 8 changed files with 174 additions and 149 deletions.
2 changes: 1 addition & 1 deletion docs/intro/developing.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The following url parameters change how the harness runs:

- `runnow=1` runs all matching tests on page load.
- `debug=1` enables verbose debug logging from tests.
- `worker=dedicated` runs the tests on a dedicated worker instead of the main thread.
- `worker=dedicated` (or `worker` or `worker=1`) runs the tests on a dedicated worker instead of the main thread.
- `worker=shared` runs the tests on a shared worker instead of the main thread.
- `worker=service` runs the tests on a service worker instead of the main thread.
- `power_preference=low-power` runs most tests passing `powerPreference: low-power` to `requestAdapter`
Expand Down
4 changes: 2 additions & 2 deletions src/common/internal/query/query.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TestParams } from '../../framework/fixture.js';
import { optionString } from '../../runtime/helper/options.js';
import { optionWorkerMode } from '../../runtime/helper/options.js';
import { assert, unreachable } from '../../util/util.js';
import { Expectation } from '../logging/result.js';

Expand Down Expand Up @@ -193,7 +193,7 @@ Expectation should be of the form path/to/cts.https.html?debug=0&q=suite:test_pa
);

const params = expectationURL.searchParams;
if (optionString('worker', params) !== optionString('worker', wptURL.searchParams)) {
if (optionWorkerMode('worker', params) !== optionWorkerMode('worker', wptURL.searchParams)) {
continue;
}

Expand Down
48 changes: 36 additions & 12 deletions src/common/runtime/helper/options.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { unreachable } from '../../util/util.js';

let windowURL: URL | undefined = undefined;
function getWindowURL() {
if (windowURL === undefined) {
Expand All @@ -6,6 +8,7 @@ function getWindowURL() {
return windowURL;
}

/** Parse a runner option that is always boolean-typed. False if missing or '0'. */
export function optionEnabled(
opt: string,
searchParams: URLSearchParams = getWindowURL().searchParams
Expand All @@ -14,33 +17,54 @@ export function optionEnabled(
return val !== null && val !== '0';
}

/** Parse a runner option that is string-typed. If the option is missing, returns `null`. */
export function optionString(
opt: string,
searchParams: URLSearchParams = getWindowURL().searchParams
): string {
return searchParams.get(opt) || '';
): string | null {
return searchParams.get(opt);
}

/** Runtime modes for running tests in different types of workers. */
export type WorkerMode = 'dedicated' | 'service' | 'shared';
/** Parse a runner option for different worker modes (as in `?worker=shared`). Null if no worker. */
export function optionWorkerMode(
opt: string,
searchParams: URLSearchParams = getWindowURL().searchParams
): WorkerMode | null {
const value = searchParams.get(opt);
if (value === null || value === '0') {
return null;
} else if (value === 'service') {
return 'service';
} else if (value === 'shared') {
return 'shared';
} else if (value === '' || value === '1' || value === 'dedicated') {
return 'dedicated';
}
unreachable('invalid worker= option value');
}

/**
* The possible options for the tests.
*/
export interface CTSOptions {
worker?: 'dedicated' | 'shared' | 'service' | '';
worker: WorkerMode | null;
debug: boolean;
compatibility: boolean;
forceFallbackAdapter: boolean;
unrollConstEvalLoops: boolean;
powerPreference: GPUPowerPreference | '';
powerPreference: GPUPowerPreference | null;
logToWebSocket: boolean;
}

export const kDefaultCTSOptions: CTSOptions = {
worker: '',
worker: null,
debug: true,
compatibility: false,
forceFallbackAdapter: false,
unrollConstEvalLoops: false,
powerPreference: '',
powerPreference: null,
logToWebSocket: false,
};

Expand All @@ -49,8 +73,8 @@ export const kDefaultCTSOptions: CTSOptions = {
*/
export interface OptionInfo {
description: string;
parser?: (key: string, searchParams?: URLSearchParams) => boolean | string;
selectValueDescriptions?: { value: string; description: string }[];
parser?: (key: string, searchParams?: URLSearchParams) => boolean | string | null;
selectValueDescriptions?: { value: string | null; description: string }[];
}

/**
Expand All @@ -65,9 +89,9 @@ export type OptionsInfos<Type> = Record<keyof Type, OptionInfo>;
export const kCTSOptionsInfo: OptionsInfos<CTSOptions> = {
worker: {
description: 'run in a worker',
parser: optionString,
parser: optionWorkerMode,
selectValueDescriptions: [
{ value: '', description: 'no worker' },
{ value: null, description: 'no worker' },
{ value: 'dedicated', description: 'dedicated worker' },
{ value: 'shared', description: 'shared worker' },
{ value: 'service', description: 'service worker' },
Expand All @@ -81,7 +105,7 @@ export const kCTSOptionsInfo: OptionsInfos<CTSOptions> = {
description: 'set default powerPreference for some tests',
parser: optionString,
selectValueDescriptions: [
{ value: '', description: 'default' },
{ value: null, description: 'default' },
{ value: 'low-power', description: 'low-power' },
{ value: 'high-performance', description: 'high-performance' },
],
Expand Down Expand Up @@ -110,7 +134,7 @@ function getOptionsInfoFromSearchString<Type extends CTSOptions>(
searchString: string
): Type {
const searchParams = new URLSearchParams(searchString);
const optionValues: Record<string, boolean | string> = {};
const optionValues: Record<string, boolean | string | null> = {};
for (const [optionName, info] of Object.entries(optionsInfos)) {
const parser = info.parser || optionEnabled;
optionValues[optionName] = parser(camelCaseToSnakeCase(optionName), searchParams);
Expand Down
4 changes: 2 additions & 2 deletions src/common/runtime/helper/test_worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { TestQueryWithExpectation } from '../../internal/query/query.js';
import { timeout } from '../../util/timeout.js';
import { assert } from '../../util/util.js';

import { CTSOptions, kDefaultCTSOptions } from './options.js';
import { CTSOptions, WorkerMode, kDefaultCTSOptions } from './options.js';
import { WorkerTestRunRequest } from './utils_worker.js';

/** Query all currently-registered service workers, and unregister them. */
Expand All @@ -28,7 +28,7 @@ class TestBaseWorker {
protected readonly ctsOptions: CTSOptions;
protected readonly resolvers = new Map<string, (result: LiveTestCaseResult) => void>();

constructor(worker: CTSOptions['worker'], ctsOptions?: CTSOptions) {
constructor(worker: WorkerMode, ctsOptions?: CTSOptions) {
this.ctsOptions = { ...(ctsOptions || kDefaultCTSOptions), ...{ worker } };
}

Expand Down
38 changes: 19 additions & 19 deletions src/common/runtime/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,16 @@ const logger = new Logger();

setBaseResourcePath('../out/resources');

const dedicatedWorker =
options.worker === 'dedicated' ? new TestDedicatedWorker(options) : undefined;
const sharedWorker = options.worker === 'shared' ? new TestSharedWorker(options) : undefined;
const serviceWorker = options.worker === 'service' ? new TestServiceWorker(options) : undefined;
const testWorker =
options.worker === null
? null
: options.worker === 'dedicated'
? new TestDedicatedWorker(options)
: options.worker === 'shared'
? new TestSharedWorker(options)
: options.worker === 'service'
? new TestServiceWorker(options)
: unreachable();

const autoCloseOnPass = document.getElementById('autoCloseOnPass') as HTMLInputElement;
const resultsVis = document.getElementById('resultsVis')!;
Expand Down Expand Up @@ -173,12 +179,8 @@ function makeCaseHTML(t: TestTreeLeaf): VisualizedSubtree {

const [rec, res] = logger.record(name);
caseResult = res;
if (dedicatedWorker) {
await dedicatedWorker.run(rec, name);
} else if (sharedWorker) {
await sharedWorker.run(rec, name);
} else if (serviceWorker) {
await serviceWorker.run(rec, name);
if (testWorker) {
await testWorker.run(rec, name);
} else {
await t.run(rec);
}
Expand Down Expand Up @@ -515,13 +517,11 @@ function makeTreeNodeHeaderHTML(
// Collapse s:f:t:* or s:f:t:c by default.
let lastQueryLevelToExpand: TestQueryLevel = 2;

type ParamValue = string | undefined | null | boolean | string[];

/**
* Takes an array of string, ParamValue and returns an array of pairs
* of [key, value] where value is a string. Converts boolean to '0' or '1'.
*/
function keyValueToPairs([k, v]: [string, ParamValue]): [string, string][] {
function keyValueToPairs([k, v]: [string, boolean | string | null]): [string, string][] {
const key = camelCaseToSnakeCase(k);
if (typeof v === 'boolean') {
return [[key, v ? '1' : '0']];
Expand All @@ -542,17 +542,17 @@ function keyValueToPairs([k, v]: [string, ParamValue]): [string, string][] {
* @param params Some object with key value pairs.
* @returns a search string.
*/
function prepareParams(params: Record<string, ParamValue>): string {
function prepareParams(params: Record<string, boolean | string | null>): string {
const pairsArrays = Object.entries(params)
.filter(([, v]) => !!v)
.filter(([, v]) => !(v === false || v === null || v === '0'))
.map(keyValueToPairs);
const pairs = pairsArrays.flat();
return new URLSearchParams(pairs).toString();
}

// This is just a cast in one place.
export function optionsToRecord(options: CTSOptions) {
return options as unknown as Record<string, boolean | string>;
return options as unknown as Record<string, boolean | string | null>;
}

/**
Expand Down Expand Up @@ -612,15 +612,15 @@ void (async () => {
};

const createSelect = (optionName: string, info: OptionInfo) => {
const select = $('<select>').on('change', function () {
optionValues[optionName] = (this as HTMLInputElement).value;
const select = $('<select>').on('change', function (this: HTMLSelectElement) {
optionValues[optionName] = JSON.parse(this.value);
updateURLsWithCurrentOptions();
});
const currentValue = optionValues[optionName];
for (const { value, description } of info.selectValueDescriptions!) {
$('<option>')
.text(description)
.val(value)
.val(JSON.stringify(value))
.prop('selected', value === currentValue)
.appendTo(select);
}
Expand Down
4 changes: 2 additions & 2 deletions src/common/runtime/wpt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { parseQuery } from '../internal/query/parseQuery.js';
import { parseExpectationsForTestQuery, relativeQueryString } from '../internal/query/query.js';
import { assert } from '../util/util.js';

import { optionEnabled, optionString } from './helper/options.js';
import { optionEnabled, optionWorkerMode } from './helper/options.js';
import { TestDedicatedWorker, TestServiceWorker, TestSharedWorker } from './helper/test_worker.js';

// testharness.js API (https://web-platform-tests.org/writing-tests/testharness-api.html)
Expand All @@ -31,7 +31,7 @@ setup({
});

void (async () => {
const workerString = optionString('worker');
const workerString = optionWorkerMode('worker');
const dedicatedWorker = workerString === 'dedicated' ? new TestDedicatedWorker() : undefined;
const sharedWorker = workerString === 'shared' ? new TestSharedWorker() : undefined;
const serviceWorker = workerString === 'service' ? new TestServiceWorker() : undefined;
Expand Down
Loading

0 comments on commit 71d872b

Please sign in to comment.