Skip to content

Commit

Permalink
client_server_test using sh_inline_test
Browse files Browse the repository at this point in the history
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
aherrmann committed Jul 22, 2020
1 parent d24b532 commit 2248fcd
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 119 deletions.
182 changes: 73 additions & 109 deletions bazel_tools/client_server/client_server_test.bzl
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)"]
)
```
"""
2 changes: 1 addition & 1 deletion bazel_tools/client_server/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ client_server_test(
client_args = [
"--foobar",
# Use the input file passed in via `data`.
"$(rlocation $TEST_WORKSPACE/$(rootpath :client_input_file))",
"$$(rlocation $$TEST_WORKSPACE/$(rootpath :client_input_file))",
],

# Data files available to both client and server.
Expand Down
4 changes: 4 additions & 0 deletions bazel_tools/sh/BUILD.bazel
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"])
65 changes: 65 additions & 0 deletions bazel_tools/sh/sh.bzl
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
)
24 changes: 24 additions & 0 deletions bazel_tools/sh/test.sh.tpl
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
6 changes: 3 additions & 3 deletions daml-script/test/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ client_server_test(
client = ":test_client_single_participant",
client_args = [
"-w",
"--cacrt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
"--cacrt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
],
client_files = [
"$(rootpath :script-test.dar)",
Expand All @@ -241,8 +241,8 @@ client_server_test(
server_args = [
"--wall-clock-time",
"--port=0",
"--crt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.crt))",
"--pem $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.pem))",
"--crt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.crt))",
"--pem $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.pem))",
"--client-auth=none",
],
server_files = ["$(rootpath :script-test.dar)"],
Expand Down
12 changes: 6 additions & 6 deletions ledger/ledger-api-test-tool/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,16 @@ conformance_test(
server_args = [
"--contract-id-seeding=testing-weak",
"--participant participant-id=ssl-test,port=6865",
"--crt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.crt))",
"--cacrt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
"--pem $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.pem))",
"--crt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.crt))",
"--cacrt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
"--pem $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:server.pem))",
],
test_tool_args = [
"--verbose",
"--include=SemanticTests",
"--crt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:client.crt))",
"--cacrt $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
"--pem $(rlocation $TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:client.pem))",
"--crt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:client.crt))",
"--cacrt $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:ca.crt))",
"--pem $$(rlocation $$TEST_WORKSPACE/$(rootpath //ledger/test-common/test-certificates:client.pem))",
],
)

Expand Down

0 comments on commit 2248fcd

Please sign in to comment.