-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
client_server_test using sh_inline_test
client_server_test used to produce an executable shell script in form of a text file output. However, since the removal of `--noincompatible_windows_native_test_wrapper` this no longer works on Windows since `.sh` files are not directly executable on Windows. This change fixes the issue by producing the script file in a dedicated rule and then wrapping it in a `sh_test` rule which also works on Windows.
- Loading branch information
Showing
7 changed files
with
176 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,127 +1,91 @@ | ||
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
def _expand_args(ctx, args): | ||
return " ".join([ctx.expand_location(a, ctx.attr.data).replace("'", "'\\''") for a in args]) | ||
load("//bazel_tools/sh:sh.bzl", "sh_inline_test") | ||
|
||
def _client_server_test_impl(ctx): | ||
# Construct wrapper to execute the runner, which in turn | ||
# will start the client and server. | ||
wrapper = ctx.actions.declare_file(ctx.label.name + "_wrapper.sh") | ||
ctx.actions.write( | ||
output = wrapper, | ||
content = """#!/usr/bin/env bash | ||
set -eou pipefail | ||
canonicalize_rlocation() {{ | ||
# Note (MK): This is a fun one: Let’s say $TEST_WORKSPACE is "compatibility" | ||
# and the argument points to a target from an external workspace, e.g., | ||
# @daml-sdk-0.0.0//:daml. Then the short path will point to | ||
# ../daml-sdk-0.0.0/daml. Putting things together we end up with | ||
# compatibility/../daml-sdk-0.0.0/daml. On Linux and MacOS this works | ||
# just fine. However, on windows we need to normalize the path | ||
# or rlocation will fail to find the path in the manifest file. | ||
rlocation $(realpath -L -s -m --relative-to=$PWD $TEST_WORKSPACE/$1) | ||
}} | ||
def _escape_args(args): | ||
return " ".join([ | ||
a.replace("'", "'\\''") | ||
for a in args | ||
]) | ||
|
||
runner=$(canonicalize_rlocation "{runner}") | ||
def client_server_test( | ||
name, | ||
runner = "//bazel_tools/client_server/runner:runner", | ||
runner_args = [], | ||
client = None, | ||
client_args = [], | ||
client_files = [], | ||
server = None, | ||
server_args = [], | ||
server_files = [], | ||
data = [], | ||
**kwargs): | ||
"""Create a client-server test. | ||
The rule takes a client and server executables and their | ||
arguments as parameters. The server port is passed via a | ||
temporary file, which is passed to the server executable via the | ||
"--port-file" parameter. This file is parsed and the port number | ||
is passed to the client application via the "--target-port" argument. | ||
The server process is killed after the client process exits. | ||
The client and server executables can be any Bazel target that | ||
is executable, e.g. scala_binary, sh_binary, etc. | ||
The client and server files must be valid arguments to rlocation, as | ||
can be obtained using $(rootpath ...) or $(rootpaths ...). (See | ||
https://docs.bazel.build/versions/master/be/make-variables.html#predefined_label_variables.) | ||
Once expended using rlocation, those are simply appended to client | ||
and server arguments, respectively. | ||
Example: | ||
```bzl | ||
client_server_test( | ||
name = "my_test", | ||
runner_args = [], | ||
client = ":my_client", | ||
client_args = ["--extra-argument"], | ||
client_files = ["$(rootpath :target-for-client)"] | ||
server = ":my_server", | ||
server_args = ["--fast"], | ||
server_files = ["$(rootpath :target-for-client)"] | ||
) | ||
``` | ||
""" | ||
sh_inline_test( | ||
name = name, | ||
# Deduplicate in case any of runner, client, server are identical. | ||
data = depset([runner, client, server]).to_list() + data, | ||
cmd = """\ | ||
runner=$$(canonicalize_rlocation "$(rootpaths {runner})") | ||
runner_args="{runner_args}" | ||
client=$(canonicalize_rlocation "{client}") | ||
server=$(canonicalize_rlocation "{server}") | ||
client=$$(canonicalize_rlocation "$(rootpaths {client})") | ||
server=$$(canonicalize_rlocation "$(rootpaths {server})") | ||
server_args="{server_args}" | ||
for file in {server_files}; do | ||
server_args+=" $(canonicalize_rlocation $file)" | ||
server_args+=" $$(canonicalize_rlocation $$file)" | ||
done | ||
client_args="$@" | ||
if [ -z "$client_args" ]; then | ||
client_args="$$@" | ||
if [ -z "$$client_args" ]; then | ||
client_args="{client_args}" | ||
for file in {client_files}; do | ||
client_args+=" $(canonicalize_rlocation $file)" | ||
client_args+=" $$(canonicalize_rlocation $$file)" | ||
done | ||
fi | ||
$runner $client "$client_args" $server "$server_args" "$runner_args" | ||
$$runner $$client "$$client_args" $$server "$$server_args" "$$runner_args" | ||
""".format( | ||
runner = ctx.executable.runner.short_path, | ||
runner_args = _expand_args(ctx, ctx.attr.runner_args), | ||
client = ctx.executable.client.short_path, | ||
client_args = _expand_args(ctx, ctx.attr.client_args), | ||
client_files = _expand_args(ctx, ctx.attr.client_files), | ||
server = ctx.executable.server.short_path, | ||
server_args = _expand_args(ctx, ctx.attr.server_args), | ||
server_files = _expand_args(ctx, ctx.attr.server_files), | ||
runner = runner, | ||
runner_args = _escape_args(runner_args), | ||
client = client, | ||
client_args = _escape_args(client_args), | ||
client_files = _escape_args(client_files), | ||
server = server, | ||
server_args = _escape_args(server_args), | ||
server_files = _escape_args(server_files), | ||
), | ||
is_executable = True, | ||
**kwargs | ||
) | ||
|
||
runfiles = ctx.runfiles(files = [wrapper], collect_data = True) | ||
runfiles = runfiles.merge(ctx.attr.runner[DefaultInfo].default_runfiles) | ||
runfiles = runfiles.merge(ctx.attr.client[DefaultInfo].default_runfiles) | ||
runfiles = runfiles.merge(ctx.attr.server[DefaultInfo].default_runfiles) | ||
|
||
return DefaultInfo( | ||
executable = wrapper, | ||
files = depset([wrapper]), | ||
runfiles = runfiles, | ||
) | ||
|
||
client_server_test = rule( | ||
implementation = _client_server_test_impl, | ||
test = True, | ||
executable = True, | ||
attrs = { | ||
"runner": attr.label( | ||
cfg = "host", | ||
allow_single_file = True, | ||
executable = True, | ||
default = Label("@//bazel_tools/client_server/runner:runner"), | ||
), | ||
"runner_args": attr.string_list(), | ||
"client": attr.label( | ||
cfg = "target", | ||
executable = True, | ||
), | ||
"client_args": attr.string_list(), | ||
"client_files": attr.string_list(), | ||
"server": attr.label( | ||
cfg = "target", | ||
executable = True, | ||
), | ||
"server_args": attr.string_list(), | ||
"server_files": attr.string_list(), | ||
"data": attr.label_list(allow_files = True), | ||
}, | ||
) | ||
"""Create a client-server test. | ||
The rule takes a client and server executables and their | ||
arguments as parameters. The server port is passed via a | ||
temporary file, which is passed to the server executable via the | ||
"--port-file" parameter. This file is parsed and the port number | ||
is passed to the client application via the "--target-port" argument. | ||
The server process is killed after the client process exits. | ||
The client and server executables can be any Bazel target that | ||
is executable, e.g. scala_binary, sh_binary, etc. | ||
The client and server files must be valid arguments to rlocation, as | ||
can be obtained using $(rootpath ...) or $(rootpaths ...). (See | ||
https://docs.bazel.build/versions/master/be/make-variables.html#predefined_label_variables.) | ||
Once expended using rlocation, those are simply appended to client | ||
and server arguments, respectively. | ||
Example: | ||
```bzl | ||
client_server_test( | ||
name = "my_test", | ||
runner_args = [], | ||
client = ":my_client", | ||
client_args = ["--extra-argument"], | ||
client_files = ["$(rootpath :target-for-client)"] | ||
server = ":my_server", | ||
server_args = ["--fast"], | ||
server_files = ["$(rootpath :target-for-client)"] | ||
) | ||
``` | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
exports_files(["test.sh.tpl"]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
def _sh_inline_script_impl(ctx): | ||
cmd = ctx.attr.cmd | ||
cmd = ctx.expand_location(cmd, ctx.attr.data) | ||
cmd = ctx.expand_make_variables("cmd", cmd, {}) | ||
ctx.actions.expand_template( | ||
template = ctx.file._template, | ||
output = ctx.outputs.output, | ||
is_executable = True, | ||
substitutions = { | ||
"%cmd%": cmd, | ||
}, | ||
) | ||
|
||
runfiles = ctx.runfiles(files = [ctx.outputs.output] + ctx.files.data) | ||
for data_dep in ctx.attr.data: | ||
runfiles = runfiles.merge(data_dep[DefaultInfo].default_runfiles) | ||
|
||
return DefaultInfo( | ||
files = depset([ctx.outputs.output]), | ||
runfiles = runfiles, | ||
) | ||
|
||
_sh_inline_script = rule( | ||
_sh_inline_script_impl, | ||
attrs = { | ||
"cmd": attr.string( | ||
mandatory = True, | ||
), | ||
"data": attr.label_list( | ||
allow_files = True, | ||
), | ||
"output": attr.output( | ||
mandatory = True, | ||
), | ||
"_template": attr.label( | ||
allow_single_file = True, | ||
default = "//bazel_tools/sh:test.sh.tpl", | ||
), | ||
}, | ||
) | ||
|
||
def sh_inline_test( | ||
name, | ||
cmd, | ||
data = [], | ||
**kwargs): | ||
testonly = kwargs.pop("testonly", True) | ||
_sh_inline_script( | ||
name = name + "_script", | ||
cmd = cmd, | ||
output = name + ".sh", | ||
data = data, | ||
testonly = testonly, | ||
) | ||
native.sh_test( | ||
name = name, | ||
data = data, | ||
deps = ["@bazel_tools//tools/bash/runfiles"], | ||
srcs = [name + ".sh"], | ||
testonly = testonly, | ||
**kwargs | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#!/usr/bin/env bash | ||
# Copy-pasted from the Bazel Bash runfiles library v2. | ||
set +e | ||
set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash | ||
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ | ||
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ | ||
source "$0.runfiles/$f" 2>/dev/null || \ | ||
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ | ||
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ | ||
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e | ||
# --- end runfiles.bash initialization v2 --- | ||
canonicalize_rlocation() { | ||
# Note (MK): This is a fun one: Let’s say $TEST_WORKSPACE is "compatibility" | ||
# and the argument points to a target from an external workspace, e.g., | ||
# @daml-sdk-0.0.0//:daml. Then the short path will point to | ||
# ../daml-sdk-0.0.0/daml. Putting things together we end up with | ||
# compatibility/../daml-sdk-0.0.0/daml. On Linux and MacOS this works | ||
# just fine. However, on windows we need to normalize the path | ||
# or rlocation will fail to find the path in the manifest file. | ||
rlocation $(realpath -L -s -m --relative-to=$PWD $TEST_WORKSPACE/$1) | ||
} | ||
set -e | ||
%cmd% | ||
# vim: ft=sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters