fix(bazel): protractor utils cannot start server on windows (#27915)

* Currently the protractor utils assume that the specified Bazel server runfile can be resolved by just using the real file system. This is not the case on Windows because the runfiles are not symlinked into the working directory and need to be resolved through the runfile manifest.

PR Close #27915
This commit is contained in:
Paul Gschwendtner 2019-01-03 20:25:51 +01:00 committed by Kara Erickson
parent 4613864fc8
commit 9de9c8ad03
4 changed files with 92 additions and 16 deletions

View File

@ -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<ServerSpec> {
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`);
// 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}`);
}
});
return waitForServer(port, timeout).then(() => { return {port}; });
});
// Wait for the server to be bound to the given port.
await waitForServer(port, timeout);
return {port};
}

View File

@ -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",
],
)

View File

@ -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);

View File

@ -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', []);
});
});