Rewrite compile tests from BazelProtoCommonTest to Starlark. This is using rules_analysis for testing. The tests are super fast (cca. 1s for all of the to run). The tests work either with a redirect (calling native rule) or with actual implementation in the protobuf repository. PiperOrigin-RevId: 651748083pull/18339/head
parent
d9fb893ba7
commit
dc17de7c7b
6 changed files with 556 additions and 0 deletions
@ -0,0 +1,3 @@ |
||||
load(":proto_common_compile_tests.bzl", "proto_common_compile_test_suite") |
||||
|
||||
proto_common_compile_test_suite(name = "proto_common_compile_test_suite") |
@ -0,0 +1,361 @@ |
||||
"""Tests for `proto_common.compile` function.""" |
||||
|
||||
load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") |
||||
load("@rules_testing//lib:truth.bzl", "matching") |
||||
load("@rules_testing//lib:util.bzl", "util") |
||||
load("//bazel:proto_library.bzl", "proto_library") |
||||
load("//bazel/tests/testdata:compile_rule.bzl", "compile_rule") |
||||
|
||||
protocol_compiler = "/protoc" |
||||
|
||||
def proto_common_compile_test_suite(name): |
||||
util.helper_target( |
||||
proto_library, |
||||
name = "simple_proto", |
||||
srcs = ["A.proto"], |
||||
) |
||||
test_suite( |
||||
name = name, |
||||
tests = [ |
||||
_test_compile_basic, |
||||
_test_compile_noplugin, |
||||
_test_compile_with_plugin_output, |
||||
_test_compile_with_directory_plugin_output, |
||||
_test_compile_additional_args, |
||||
_test_compile_additional_tools, |
||||
_test_compile_additional_tools_no_plugin, |
||||
_test_compile_additional_inputs, |
||||
_test_compile_resource_set, |
||||
_test_compile_protoc_opts, |
||||
_test_compile_direct_generated_protos, |
||||
_test_compile_indirect_generated_protos, |
||||
], |
||||
) |
||||
|
||||
# Verifies basic usage of `proto_common.compile`. |
||||
def _test_compile_basic(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_basic_impl, |
||||
) |
||||
|
||||
def _test_compile_basic_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
action.mnemonic().equals("MyMnemonic") |
||||
|
||||
# Verifies usage of proto_common.generate_code with no plugin specified by toolchain. |
||||
def _test_compile_noplugin(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
toolchain = "//bazel/tests/testdata:toolchain_noplugin", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_noplugin_impl, |
||||
) |
||||
|
||||
def _test_compile_noplugin_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. |
||||
def _test_compile_with_plugin_output(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
plugin_output = "single", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_with_plugin_output_impl, |
||||
) |
||||
|
||||
def _test_compile_with_plugin_output_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.str_matches("--java_out=param1,param2:b*-out/*/test_compile_with_plugin_output_compile"), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `plugin_output` parameter set to file. |
||||
def _test_compile_with_directory_plugin_output(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
plugin_output = "multiple", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_with_directory_plugin_output_impl, |
||||
) |
||||
|
||||
def _test_compile_with_directory_plugin_output_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.str_matches("--java_out=param1,param2:b*-out/*/bin"), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `additional_args` parameter |
||||
def _test_compile_additional_args(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
additional_args = ["--a", "--b"], |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_additional_args_impl, |
||||
) |
||||
|
||||
def _test_compile_additional_args_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.equals_wrapper("--a"), |
||||
matching.equals_wrapper("--b"), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `additional_tools` parameter |
||||
def _test_compile_additional_tools(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
additional_tools = [ |
||||
"//bazel/tests/testdata:_tool1", |
||||
"//bazel/tests/testdata:_tool2", |
||||
], |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_additional_tools_impl, |
||||
) |
||||
|
||||
def _test_compile_additional_tools_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.inputs().contains_at_least_predicates( |
||||
[ |
||||
matching.file_basename_equals("_tool1"), |
||||
matching.file_basename_equals("_tool2"), |
||||
matching.file_basename_equals("plugin"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. |
||||
def _test_compile_additional_tools_no_plugin(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
additional_tools = [ |
||||
"//bazel/tests/testdata:_tool1", |
||||
"//bazel/tests/testdata:_tool2", |
||||
], |
||||
toolchain = "//bazel/tests/testdata:toolchain_noplugin", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_additional_tools_no_plugin_impl, |
||||
) |
||||
|
||||
def _test_compile_additional_tools_no_plugin_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.inputs().contains_at_least_predicates( |
||||
[ |
||||
matching.file_basename_equals("_tool1"), |
||||
matching.file_basename_equals("_tool2"), |
||||
], |
||||
) |
||||
action.inputs().not_contains_predicate(matching.file_basename_equals("plugin")) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `additional_inputs` parameter. |
||||
def _test_compile_additional_inputs(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
additional_inputs = ["input1.txt", "input2.txt"], |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_additional_inputs_impl, |
||||
) |
||||
|
||||
def _test_compile_additional_inputs_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.inputs().contains_at_least_predicates( |
||||
[ |
||||
matching.file_basename_equals("input1.txt"), |
||||
matching.file_basename_equals("input2.txt"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `additional_tools` parameter and no plugin on the toolchain. |
||||
def _test_compile_resource_set(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
use_resource_set = True, |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_resource_set_impl, |
||||
) |
||||
|
||||
def _test_compile_resource_set_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") # @unused |
||||
# We can't check the specification of the resource set, but we at least verify analysis passes |
||||
|
||||
# Verifies `--protocopts` are passed to command line. |
||||
def _test_compile_protoc_opts(name): |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = ":simple_proto", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
config_settings = {"//command_line_option:protocopt": ["--foo", "--bar"]}, |
||||
impl = _test_compile_protoc_opts_impl, |
||||
) |
||||
|
||||
def _test_compile_protoc_opts_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.equals_wrapper("--foo"), |
||||
matching.equals_wrapper("--bar"), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies `proto_common.compile`> correctly handles direct generated `.proto` files. |
||||
def _test_compile_direct_generated_protos(name): |
||||
util.helper_target(native.genrule, name = name + "_generate_G", cmd = "", outs = ["G.proto"]) |
||||
util.helper_target( |
||||
proto_library, |
||||
name = name + "_directly_generated_proto", |
||||
srcs = ["A.proto", "G.proto"], |
||||
) |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = name + "_directly_generated_proto", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_direct_generated_protos_impl, |
||||
) |
||||
|
||||
def _test_compile_direct_generated_protos_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.str_matches("-Ib*-out/*/*"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
matching.str_matches("*-out/*/*/*/G.proto"), |
||||
], |
||||
) |
||||
|
||||
# Verifies usage of `proto_common.compile` with `plugin_output` parameter |
||||
def _test_compile_indirect_generated_protos(name): |
||||
util.helper_target(native.genrule, name = "_generate_h", srcs = ["A.txt"], cmd = "", outs = ["H.proto"]) |
||||
util.helper_target(proto_library, name = "_generated_proto", srcs = ["H.proto"]) |
||||
util.helper_target( |
||||
proto_library, |
||||
name = name + "_indirectly_generated_proto", |
||||
srcs = ["A.proto"], |
||||
deps = [":_generated_proto"], |
||||
) |
||||
util.helper_target( |
||||
compile_rule, |
||||
name = name + "_compile", |
||||
proto_dep = name + "_indirectly_generated_proto", |
||||
) |
||||
|
||||
analysis_test( |
||||
name = name, |
||||
target = name + "_compile", |
||||
impl = _test_compile_indirect_generated_protos_impl, |
||||
) |
||||
|
||||
def _test_compile_indirect_generated_protos_impl(env, target): |
||||
action = env.expect.that_target(target).action_named("MyMnemonic") |
||||
action.argv().contains_exactly_predicates( |
||||
[ |
||||
matching.str_endswith(protocol_compiler), |
||||
matching.str_matches("--plugin=b*-out/*-exec-*/bin/*/testdata/plugin"), |
||||
matching.str_matches("-Ib*-out/*/*"), |
||||
matching.equals_wrapper("-I."), |
||||
matching.str_endswith("/A.proto"), |
||||
], |
||||
) |
@ -0,0 +1,130 @@ |
||||
package(default_visibility = ["//visibility:public"]) |
||||
|
||||
proto_lang_toolchain( |
||||
name = "toolchain", |
||||
blacklisted_protos = [":denied"], |
||||
command_line = "--java_out=param1,param2:$(OUT)", |
||||
mnemonic = "MyMnemonic", |
||||
plugin = ":plugin", |
||||
plugin_format_flag = "--plugin=%s", |
||||
progress_message = "Progress Message %{label}", |
||||
runtime = ":runtime", |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
proto_lang_toolchain( |
||||
name = "toolchain_noplugin", |
||||
blacklisted_protos = [":denied"], |
||||
command_line = "--java_out=param1,param2:$(OUT)", |
||||
mnemonic = "MyMnemonic", |
||||
progress_message = "Progress Message %{label}", |
||||
runtime = ":runtime", |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "plugin", |
||||
srcs = ["plugin.cc"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
cc_library( |
||||
name = "runtime", |
||||
srcs = ["runtime.cc"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
filegroup( |
||||
name = "descriptors", |
||||
srcs = [ |
||||
"descriptor.proto", |
||||
"metadata.proto", |
||||
], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
filegroup( |
||||
name = "any", |
||||
srcs = ["any.proto"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
filegroup( |
||||
name = "something", |
||||
srcs = ["something.proto"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
proto_library( |
||||
name = "mixed", |
||||
srcs = [ |
||||
":descriptors", |
||||
":something", |
||||
], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
proto_library( |
||||
name = "denied", |
||||
srcs = [ |
||||
":any", |
||||
":descriptors", |
||||
], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "_tool1", |
||||
srcs = ["tool1.cc"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
||||
|
||||
cc_binary( |
||||
name = "_tool2", |
||||
srcs = ["tool2.cc"], |
||||
tags = [ |
||||
"manual", |
||||
"nobuilder", |
||||
"notap", |
||||
], |
||||
) |
@ -0,0 +1,50 @@ |
||||
"""Testing function for proto_common module""" |
||||
|
||||
load("//bazel/common:proto_common.bzl", "proto_common") |
||||
|
||||
def _resource_set_callback(_os, inputs_size): |
||||
return {"memory": 25 + 0.15 * inputs_size, "cpu": 1} |
||||
|
||||
def _impl(ctx): |
||||
outfile = ctx.actions.declare_file(ctx.attr.name) |
||||
kwargs = {} |
||||
if ctx.attr.plugin_output == "single": |
||||
kwargs["plugin_output"] = outfile.path |
||||
elif ctx.attr.plugin_output == "multiple": |
||||
kwargs["plugin_output"] = ctx.bin_dir.path |
||||
elif ctx.attr.plugin_output == "wrong": |
||||
kwargs["plugin_output"] = ctx.bin_dir.path + "///" |
||||
if ctx.attr.additional_args: |
||||
additional_args = ctx.actions.args() |
||||
additional_args.add_all(ctx.attr.additional_args) |
||||
kwargs["additional_args"] = additional_args |
||||
if ctx.files.additional_tools: |
||||
kwargs["additional_tools"] = ctx.files.additional_tools |
||||
if ctx.files.additional_inputs: |
||||
kwargs["additional_inputs"] = depset(ctx.files.additional_inputs) |
||||
if ctx.attr.use_resource_set: |
||||
kwargs["resource_set"] = _resource_set_callback |
||||
if ctx.attr.progress_message: |
||||
kwargs["experimental_progress_message"] = ctx.attr.progress_message |
||||
proto_common.compile( |
||||
ctx.actions, |
||||
ctx.attr.proto_dep[ProtoInfo], |
||||
ctx.attr.toolchain[proto_common.ProtoLangToolchainInfo], |
||||
[outfile], |
||||
**kwargs |
||||
) |
||||
return [DefaultInfo(files = depset([outfile]))] |
||||
|
||||
compile_rule = rule( |
||||
_impl, |
||||
attrs = { |
||||
"proto_dep": attr.label(), |
||||
"plugin_output": attr.string(), |
||||
"toolchain": attr.label(default = ":toolchain"), |
||||
"additional_args": attr.string_list(), |
||||
"additional_tools": attr.label_list(cfg = "exec"), |
||||
"additional_inputs": attr.label_list(allow_files = True), |
||||
"use_resource_set": attr.bool(), |
||||
"progress_message": attr.string(), |
||||
}, |
||||
) |
Loading…
Reference in new issue