diff --git a/packages/bazel/src/protractor/utils/index.ts b/packages/bazel/src/protractor/utils/index.ts index 666119d516..424d2a21bb 100644 --- a/packages/bazel/src/protractor/utils/index.ts +++ b/packages/bazel/src/protractor/utils/index.ts @@ -71,24 +71,31 @@ export interface ServerSpec { port: number; } -export function runServer( - workspace: string, binary: string, portFlag: string, args: string[], +/** + * Runs the specified server binary from a given workspace and waits for the server + * being ready. The server binary will be resolved from the Bazel runfiles. Note that + * the server will be launched with a random free port in order to support test concurrency + * with Bazel. + */ +export async function runServer( + workspace: string, serverTarget: string, portFlag: string, serverArgs: string[], timeout = 5000): Promise { - return findFreeTcpPort().then(function(port) { - const runfiles_path = process.env.TEST_SRCDIR; - const cmd = path.join(runfiles_path, workspace, binary); + const serverPath = require.resolve(`${workspace}/${serverTarget}`); + const port = await findFreeTcpPort(); - args = args.concat([portFlag, port.toString()]); + // Start the Bazel server binary with a random free TCP port. + const serverProcess = child_process.spawn( + serverPath, serverArgs.concat([portFlag, port.toString()]), {stdio: 'inherit'}); - const child = child_process.spawn( - cmd, args, {cwd: path.join(runfiles_path, workspace), stdio: 'inherit'}); - - child.on('exit', function(code) { - if (code != 0) { - throw new Error(`non-zero exit code ${code} from server`); - } - }); - - return waitForServer(port, timeout).then(() => { return {port}; }); + // In case the process exited with an error, we want to propagate the error. + serverProcess.on('exit', exitCode => { + if (exitCode !== 0) { + throw new Error(`Server exited with error code: ${exitCode}`); + } }); + + // Wait for the server to be bound to the given port. + await waitForServer(port, timeout); + + return {port}; } diff --git a/packages/bazel/test/protractor-utils/BUILD.bazel b/packages/bazel/test/protractor-utils/BUILD.bazel new file mode 100644 index 0000000000..33c2d77f4f --- /dev/null +++ b/packages/bazel/test/protractor-utils/BUILD.bazel @@ -0,0 +1,29 @@ +load("//tools:defaults.bzl", "jasmine_node_test", "nodejs_binary", "ts_library") + +ts_library( + name = "protractor_utils_tests_lib", + testonly = True, + srcs = ["index_test.ts"], + deps = [ + "//packages/bazel/src/protractor/utils", + ], +) + +nodejs_binary( + name = "fake-devserver", + testonly = True, + data = [ + "fake-devserver.js", + "@ngdeps//minimist", + ], + entry_point = "angular/packages/bazel/test/protractor-utils/fake-devserver.js", +) + +jasmine_node_test( + name = "protractor_utils_tests", + size = "small", + srcs = [":protractor_utils_tests_lib"], + data = [ + ":fake-devserver", + ], +) diff --git a/packages/bazel/test/protractor-utils/fake-devserver.js b/packages/bazel/test/protractor-utils/fake-devserver.js new file mode 100644 index 0000000000..34e84d3a07 --- /dev/null +++ b/packages/bazel/test/protractor-utils/fake-devserver.js @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +const http = require('http'); +const minimist = require('minimist'); + +const {port} = minimist(process.argv); +const server = new http.Server(); + +// Basic request handler so that it could respond to fake requests. +server.on('request', (req, res) => { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Running'); +}); + +server.listen(port); + +console.info('Server running on port:', port); diff --git a/packages/bazel/test/protractor-utils/index_test.ts b/packages/bazel/test/protractor-utils/index_test.ts new file mode 100644 index 0000000000..1bc0d97731 --- /dev/null +++ b/packages/bazel/test/protractor-utils/index_test.ts @@ -0,0 +1,17 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {runServer} from '../../src/protractor/utils'; + +describe('Bazel protractor utils', () => { + + it('should be able to start devserver', async() => { + // Test will automatically time out if the server couldn't be launched as expected. + await runServer('angular', 'packages/bazel/test/protractor-utils/fake-devserver', '--port', []); + }); +});