Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add Karma and node test for webworker (#1841)
DEV
  • Loading branch information
WenheLI authored and dsmilkov committed Jul 25, 2019
1 parent 7704743 commit ab6b88d
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 3 deletions.
33 changes: 30 additions & 3 deletions karma.conf.js
Expand Up @@ -35,8 +35,10 @@ const devConfig = {
frameworks: ['jasmine', 'karma-typescript'],
files: ['src/setup_test.ts', {pattern: 'src/**/*.ts'}],
exclude: [
'src/worker_node_test.ts',
'src/worker_test.ts',
'src/test_node.ts',
'src/test_async_backends.ts',
'src/test_async_backends.ts'
],
preprocessors: {'**/*.ts': ['karma-typescript']},
karmaTypescriptConfig,
Expand All @@ -47,8 +49,10 @@ const browserstackConfig = {
frameworks: ['browserify', 'jasmine'],
files: ['dist/setup_test.js', {pattern: 'dist/**/*_test.js'}],
exclude: [
'dist/worker_node_test.js',
'dist/worker_test.js',
'dist/test_node.js',
'dist/test_async_backends.js',
'dist/test_async_backends.js'
],
preprocessors: {'dist/**/*_test.js': ['browserify']},
browserify: {debug: false},
Expand All @@ -57,6 +61,18 @@ const browserstackConfig = {
hostname: 'bs-local.com',
};

const webworkerConfig = {
...browserstackConfig,
files: [
'dist/setup_test.js',
'dist/worker_test.js',
// Serve dist/tf-core.js as a static resource, but do not include in the test runner
{pattern: 'dist/tf-core.js', included: false}
],
exclude: [],
port: 12345
};

module.exports = function(config) {
const args = [];
// If no test environment is set unit tests will run against all registered
Expand All @@ -70,7 +86,18 @@ module.exports = function(config) {
if (config.flags) {
args.push('--flags', config.flags);
}
const extraConfig = config.browserstack ? browserstackConfig : devConfig;


let extraConfig = null;

if (config.worker) {
extraConfig = webworkerConfig;
} else if (config.browserstack) {
extraConfig = browserstackConfig;
} else {
extraConfig = devConfig;
}


config.set({
...extraConfig,
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -63,6 +63,7 @@
"lint": "tslint -p . -t verbose",
"coverage": "KARMA_COVERAGE=1 karma start --browsers='Chrome' --singleRun",
"test": "karma start",
"test-webworker": "karma start --worker",
"run-browserstack": "karma start --browserstack",
"test-bundle-size": "./scripts/test-bundle-size.js",
"test-node": "rimraf dist/ && tsc && node dist/test_node.js",
Expand Down
5 changes: 5 additions & 0 deletions scripts/test-ci.sh
Expand Up @@ -35,3 +35,8 @@ npm-run-all -p -c --aggregate-output \
"run-browserstack --browsers=bs_chrome_mac" \
"run-browserstack --browsers=bs_chrome_mac --testEnv webgl2 --flags '{\"WEBGL_CPU_FORWARD\": true}'" \
"run-browserstack --browsers=bs_chrome_mac --testEnv webgl2 --flags '{\"WEBGL_CPU_FORWARD\": false}'"

# Build dist/tf-core.js which is used by the webworker test
yarn build-npm
# Run under webworker environment
yarn test-webworker --browsers=bs_safari_mac
17 changes: 17 additions & 0 deletions src/jasmine_util.ts
Expand Up @@ -39,6 +39,23 @@ export const SYNC_BACKEND_ENVS: Constraints = {
predicate: (testEnv: TestEnv) => testEnv.isDataSync === true
};

export const HAS_WORKER = {
predicate: () => typeof(Worker) !== 'undefined'
&& typeof(Blob) !== 'undefined' && typeof(URL) !== 'undefined'
};

export const HAS_NODE_WORKER = {
predicate: () => {
let hasWorker = true;
try {
require.resolve('worker_threads');
} catch {
hasWorker = false;
}
return typeof(process) !== 'undefined' && hasWorker;
}
};

export const ALL_ENVS: Constraints = {};

// Tests whether the current environment satisfies the set of constraints.
Expand Down
1 change: 1 addition & 0 deletions src/test_async_backends.ts
Expand Up @@ -74,5 +74,6 @@ setTestEnvs([{
}]);

const runner = new jasmine();

runner.loadConfig({spec_files: ['dist/**/**_test.js'], random: false});
runner.execute();
2 changes: 2 additions & 0 deletions src/tests.ts
Expand Up @@ -107,3 +107,5 @@ import './types_test';
import './util_test';
import './variable_test';
import './version_test';
import './worker_node_test';
import './worker_test';
49 changes: 49 additions & 0 deletions src/worker_node_test.ts
@@ -0,0 +1,49 @@
/**
* @license
* Copyright 2019 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/

import {HAS_NODE_WORKER, describeWithFlags} from './jasmine_util';
import {expectArraysClose} from './test_util';

const fn2String = (fn: Function): string => {
const funcStr = '('+fn.toString()+')()';
return funcStr;
};

// The source code of a web worker.
const workerTestNode = () => {
const tf = require(`${process.cwd()}/dist/tf-core.js`);
// tslint:disable-next-line:no-require-imports
const {parentPort} = require('worker_threads');
let a = tf.tensor1d([1, 2, 3]);
const b = tf.tensor1d([3, 2, 1]);
a = a.add(b);
parentPort.postMessage({data: a.dataSync()});
};

describeWithFlags('computation in worker (node env)', HAS_NODE_WORKER, () => {
it('tensor in worker', (done) => {
// tslint:disable-next-line:no-require-imports
const {Worker} = require('worker_threads');
const worker = new Worker(fn2String(workerTestNode), {eval: true});
// tslint:disable-next-line:no-any
worker.on('message', (msg: any) => {
const data = msg.data;
expectArraysClose(data, [4, 4, 4]);
done();
});
});
});
48 changes: 48 additions & 0 deletions src/worker_test.ts
@@ -0,0 +1,48 @@
/**
* @license
* Copyright 2019 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =============================================================================
*/

import {HAS_WORKER, describeWithFlags} from './jasmine_util';
import {expectArraysClose} from './test_util';
import * as tf from './index';

const fn2workerURL = (fn: Function): string => {
const blob =
new Blob(['('+fn.toString()+')()'], {type: 'application/javascript'});
return URL.createObjectURL(blob);
};

// The source code of a web worker.
const workerTest = () => {
//@ts-ignore
importScripts('http://bs-local.com:12345/base/dist/tf-core.js');
let a = tf.tensor1d([1, 2, 3]);
const b = tf.tensor1d([3, 2, 1]);
a = a.add(b);
//@ts-ignore
self.postMessage({data: a.dataSync()});
};

describeWithFlags('computation in worker', HAS_WORKER, () => {
it('tensor in worker', (done) => {
const worker = new Worker(fn2workerURL(workerTest));
worker.onmessage = (msg) => {
const data = msg.data.data;
expectArraysClose(data, [4, 4, 4]);
done();
};
});
});

0 comments on commit ab6b88d

Please sign in to comment.