Skip to content
This repository was archived by the owner on Aug 15, 2019. It is now read-only.

Commit 92df253

Browse files
author
Nikhil Thorat
authored
Fix unit tests to ensure that test registrations happen before tests. (#1788)
Previously the test registries would happen as a function of imports. This doesn't ensure that unconstrained tests run before tests get registered. This PR creates a `setup_test.ts` file like we do in WebGPU which imports the registries and then parses the karma flags. This ensures the expected order. This PR also adds --testEnv as a command line flag instead of --backend. DEV
1 parent c787f1d commit 92df253

7 files changed

+119
-62
lines changed

DEVELOPMENT.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,10 @@ $ yarn test --single-run
4848
To run the tests in an environment that does not have GPU support (such as Chrome Remote Desktop):
4949

5050
```bash
51-
$ yarn test --backend cpu
51+
$ yarn test --testEnv cpu
5252
```
5353

54+
Available test environments: cpu, webgl1, webgl2.
5455

5556
#### Packaging (browser and npm)
5657

karma.conf.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ if (coverageEnabled) {
3333

3434
const devConfig = {
3535
frameworks: ['jasmine', 'karma-typescript'],
36-
files: [{pattern: 'src/**/*.ts'}],
36+
files: ['src/setup_test.ts', {pattern: 'src/**/*.ts'}],
3737
exclude: [
3838
'src/test_node.ts',
3939
'src/backends/webgpu/**/*.ts',
@@ -46,7 +46,7 @@ const devConfig = {
4646

4747
const browserstackConfig = {
4848
frameworks: ['browserify', 'jasmine'],
49-
files: [{pattern: 'dist/**/*_test.js'}],
49+
files: ['dist/setup_test.js', {pattern: 'dist/**/*_test.js'}],
5050
exclude: [
5151
'dist/test_node.js',
5252
'dist/test_async_backends.js',
@@ -60,8 +60,10 @@ const browserstackConfig = {
6060

6161
module.exports = function(config) {
6262
const args = [];
63-
if (config.backend) {
64-
args.push('--backend', config.backend);
63+
// If no test environment is set unit tests will run against all registered
64+
// test environments.
65+
if (config.testEnv) {
66+
args.push('--testEnv', config.testEnv);
6567
}
6668
if (config.grep) {
6769
args.push('--grep', config.grep);

scripts/enumerate-tests.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
// limitations under the License.
1515
// =============================================================================
1616

17+
/**
18+
* This script generates the tests.ts file which enumerates all the
19+
* backend-agonstic tests. These are the tests that get executed from other
20+
* packages (e.g. WebGPU).
21+
*/
1722
// Call this script from the root of the repo.
1823

1924
const LICENSE = `/**
@@ -50,7 +55,8 @@ function findTestFiles(dir, files) {
5055
!file.startsWith('.') && fs.statSync(filePath).isDirectory() &&
5156
!fs.existsSync(path.join(filePath, 'package.json'))) {
5257
files = findTestFiles(filePath, files);
53-
} else if (filePath.endsWith('_test.ts')) {
58+
} else if (
59+
filePath.endsWith('_test.ts') && filePath !== 'src/setup_test.ts') {
5460
files.push(filePath.replace('src/', './').replace('.ts', ''));
5561
}
5662
});

scripts/test-ci.sh

+7-7
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ yarn test-node-ci
2222

2323
# Run the first karma separately so it can download the BrowserStack binary
2424
# without conflicting with others.
25-
yarn run-browserstack --browsers=bs_safari_mac --backend webgl --flags '{"WEBGL_CPU_FORWARD": false, "WEBGL_SIZE_UPLOAD_UNIFORM": 0}'
25+
yarn run-browserstack --browsers=bs_safari_mac --testEnv webgl1 --flags '{"WEBGL_CPU_FORWARD": false, "WEBGL_SIZE_UPLOAD_UNIFORM": 0}'
2626

2727
# Run the rest of the karma tests in parallel. These runs will reuse the
2828
# already downloaded binary.
2929
npm-run-all -p -c --aggregate-output \
30-
"run-browserstack --browsers=bs_safari_mac --flags '{\"HAS_WEBGL\": false}' --backend cpu" \
31-
"run-browserstack --browsers=win_10_chrome --backend webgl --flags '{\"WEBGL_CPU_FORWARD\": false, \"WEBGL_SIZE_UPLOAD_UNIFORM\": 0}'" \
32-
"run-browserstack --browsers=bs_ios_11 --backend webgl --flags '{\"WEBGL_CPU_FORWARD\": false, \"WEBGL_SIZE_UPLOAD_UNIFORM\": 0}'" \
33-
"run-browserstack --browsers=bs_ios_11 --flags '{\"HAS_WEBGL\": false}' --backend cpu" \
30+
"run-browserstack --browsers=bs_safari_mac --flags '{\"HAS_WEBGL\": false}' --testEnv cpu" \
31+
"run-browserstack --browsers=win_10_chrome --testEnv webgl2 --flags '{\"WEBGL_CPU_FORWARD\": false, \"WEBGL_SIZE_UPLOAD_UNIFORM\": 0}'" \
32+
"run-browserstack --browsers=bs_ios_11 --testEnv webgl1 --flags '{\"WEBGL_CPU_FORWARD\": false, \"WEBGL_SIZE_UPLOAD_UNIFORM\": 0}'" \
33+
"run-browserstack --browsers=bs_ios_11 --flags '{\"HAS_WEBGL\": false}' --testEnv cpu" \
3434
"run-browserstack --browsers=bs_firefox_mac" \
3535
"run-browserstack --browsers=bs_chrome_mac" \
36-
"run-browserstack --browsers=bs_chrome_mac --backend webgl --flags '{\"WEBGL_CPU_FORWARD\": true}'" \
37-
"run-browserstack --browsers=bs_chrome_mac --backend webgl --flags '{\"WEBGL_CPU_FORWARD\": false}'"
36+
"run-browserstack --browsers=bs_chrome_mac --testEnv webgl2 --flags '{\"WEBGL_CPU_FORWARD\": true}'" \
37+
"run-browserstack --browsers=bs_chrome_mac --testEnv webgl2 --flags '{\"WEBGL_CPU_FORWARD\": false}'"

src/jasmine_util.ts

+35-30
Original file line numberDiff line numberDiff line change
@@ -61,45 +61,57 @@ export function envSatisfiesConstraints(
6161
return true;
6262
}
6363

64-
// tslint:disable-next-line:no-any
65-
declare let __karma__: any;
66-
67-
export function parseKarmaFlags(args: string[]): TestEnv {
64+
export function parseTestEnvFromKarmaFlags(
65+
args: string[], registeredTestEnvs: TestEnv[]): TestEnv {
6866
let flags: Flags;
69-
let factory: () => Promise<KernelBackend>| KernelBackend;
70-
let backendName = '';
71-
const backendNames = ENGINE.backendNames()
72-
.map(backendName => '\'' + backendName + '\'')
73-
.join(', ');
67+
let testEnvName: string;
7468

7569
args.forEach((arg, i) => {
7670
if (arg === '--flags') {
7771
flags = JSON.parse(args[i + 1]);
78-
} else if (arg === '--backend') {
79-
const type = args[i + 1];
80-
backendName = type;
81-
factory = ENGINE.findBackendFactory(backendName.toLowerCase());
82-
if (factory == null) {
83-
throw new Error(
84-
`Unknown value ${type} for flag --backend. ` +
85-
`Allowed values are ${backendNames}.`);
86-
}
72+
} else if (arg === '--testEnv') {
73+
testEnvName = args[i + 1];
8774
}
8875
});
8976

90-
if (flags == null && factory == null) {
77+
const testEnvNames = registeredTestEnvs.map(env => env.name).join(', ');
78+
if (flags != null && testEnvName == null) {
79+
throw new Error(
80+
'--testEnv flag is required when --flags is present. ' +
81+
`Available values are [${testEnvNames}].`);
82+
}
83+
if (testEnvName == null) {
9184
return null;
9285
}
93-
if (flags != null && factory == null) {
86+
87+
let testEnv: TestEnv;
88+
registeredTestEnvs.forEach(env => {
89+
if (env.name === testEnvName) {
90+
testEnv = env;
91+
}
92+
});
93+
if (testEnv == null) {
9494
throw new Error(
95-
'--backend flag is required when --flags is present. ' +
96-
`Available values are ${backendNames}.`);
95+
`Test environment with name ${testEnvName} not ` +
96+
`found. Available test environment names are ` +
97+
`${testEnvNames}`);
98+
}
99+
if (flags != null) {
100+
testEnv.flags = flags;
97101
}
98-
return {flags: flags || {}, name: backendName, backendName};
102+
103+
return testEnv;
99104
}
100105

101106
export function describeWithFlags(
102107
name: string, constraints: Constraints, tests: (env: TestEnv) => void) {
108+
if (TEST_ENVS.length === 0) {
109+
throw new Error(
110+
`Found no test environments. This is likely due to test environment ` +
111+
`registries never being imported or test environment registries ` +
112+
`being registered too late.`);
113+
}
114+
103115
TEST_ENVS.forEach(testEnv => {
104116
ENV.setFlags(testEnv.flags);
105117
if (envSatisfiesConstraints(ENV, testEnv, constraints)) {
@@ -138,13 +150,6 @@ export function registerTestEnv(testEnv: TestEnv) {
138150
TEST_ENVS.push(testEnv);
139151
}
140152

141-
if (typeof __karma__ !== 'undefined') {
142-
const testEnv = parseKarmaFlags(__karma__.config.args);
143-
if (testEnv != null) {
144-
setTestEnvs([testEnv]);
145-
}
146-
}
147-
148153
function executeTests(
149154
testName: string, tests: (env: TestEnv) => void, testEnv: TestEnv) {
150155
describe(testName, () => {

src/jasmine_util_test.ts

+28-19
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
*/
1717

1818
import {Environment} from './environment';
19-
import * as tf from './index';
20-
import {envSatisfiesConstraints, parseKarmaFlags, TestKernelBackend} from './jasmine_util';
19+
import {envSatisfiesConstraints, parseTestEnvFromKarmaFlags, TestEnv} from './jasmine_util';
2120

2221
describe('jasmine_util.envSatisfiesConstraints', () => {
2322
it('ENV satisfies empty constraints', () => {
@@ -100,40 +99,50 @@ describe('jasmine_util.envSatisfiesConstraints', () => {
10099
});
101100

102101
describe('jasmine_util.parseKarmaFlags', () => {
102+
const registeredTestEnvs: TestEnv[] = [
103+
{name: 'test-env', backendName: 'test-backend', isDataSync: true, flags: {}}
104+
];
105+
103106
it('parse empty args', () => {
104-
const res = parseKarmaFlags([]);
107+
const res = parseTestEnvFromKarmaFlags([], registeredTestEnvs);
105108
expect(res).toBeNull();
106109
});
107110

108-
it('--backend test-backend --flags {"IS_NODE": true}', () => {
109-
const backend = new TestKernelBackend();
110-
tf.registerBackend('test-backend', () => backend);
111-
112-
const res = parseKarmaFlags(
113-
['--backend', 'test-backend', '--flags', '{"IS_NODE": true}']);
114-
expect(res.name).toBe('test-backend');
111+
it('--testEnv test-env --flags {"IS_NODE": true}', () => {
112+
const res = parseTestEnvFromKarmaFlags(
113+
['--testEnv', 'test-env', '--flags', '{"IS_NODE": true}'],
114+
registeredTestEnvs);
115+
expect(res.name).toBe('test-env');
115116
expect(res.backendName).toBe('test-backend');
116117
expect(res.flags).toEqual({IS_NODE: true});
117-
118-
tf.removeBackend('test-backend');
119118
});
120119

121-
it('"--backend unknown" throws error', () => {
122-
expect(() => parseKarmaFlags(['--backend', 'unknown'])).toThrowError();
120+
it('"--testEnv unknown" throws error', () => {
121+
expect(
122+
() => parseTestEnvFromKarmaFlags(
123+
['--testEnv', 'unknown'], registeredTestEnvs))
124+
.toThrowError();
123125
});
124126

125-
it('"--flags {}" throws error since --backend is missing', () => {
126-
expect(() => parseKarmaFlags(['--flags', '{}'])).toThrowError();
127+
it('"--flags {}" throws error since --testEnv is missing', () => {
128+
expect(
129+
() => parseTestEnvFromKarmaFlags(['--flags', '{}'], registeredTestEnvs))
130+
.toThrowError();
127131
});
128132

129-
it('"--backend cpu --flags" throws error since features value is missing',
133+
it('"--testEnv cpu --flags" throws error since features value is missing',
130134
() => {
131-
expect(() => parseKarmaFlags(['--backend', 'cpu', '--flags']))
135+
expect(
136+
() => parseTestEnvFromKarmaFlags(
137+
['--testEnv', 'test-env', '--flags'], registeredTestEnvs))
132138
.toThrowError();
133139
});
134140

135141
it('"--backend cpu --flags notJson" throws error', () => {
136-
expect(() => parseKarmaFlags(['--backend', 'cpu', '--flags', 'notJson']))
142+
expect(
143+
() => parseTestEnvFromKarmaFlags(
144+
['--testEnv', 'test-env', '--flags', 'notJson'],
145+
registeredTestEnvs))
137146
.toThrowError();
138147
});
139148
});

src/setup_test.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google LLC. All Rights Reserved.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
* =============================================================================
16+
*/
17+
18+
/**
19+
* This file is necessary so we register all test environments before we start
20+
* executing tests.
21+
*/
22+
import './backends/cpu/backend_cpu_test_registry';
23+
import './backends/webgl/backend_webgl_test_registry';
24+
25+
import {parseTestEnvFromKarmaFlags, setTestEnvs, TEST_ENVS} from './jasmine_util';
26+
27+
// tslint:disable-next-line:no-any
28+
declare let __karma__: any;
29+
if (typeof __karma__ !== 'undefined') {
30+
const testEnv = parseTestEnvFromKarmaFlags(__karma__.config.args, TEST_ENVS);
31+
if (testEnv != null) {
32+
setTestEnvs([testEnv]);
33+
}
34+
}

0 commit comments

Comments
 (0)