"""End to end tests for rust toolchains.""" load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") load("@bazel_skylib//rules:write_file.bzl", "write_file") load("//rust:defs.bzl", "rust_library", "rust_shared_library") load("//rust:toolchain.bzl", "rust_stdlib_filegroup", "rust_toolchain") EXEC_TOOLCHAIN_FLAG = "missing" TOOLCHAIN_FLAG = "before" CONFIG_FLAG = "after" CRATE_FLAGS = {"cdylib": ["cdylib_flag"], "rlib": ["rlib_flag"]} def _toolchain_adds_rustc_flags_impl(ctx, crate_type): """ Tests adding extra_rustc_flags on the toolchain, asserts that: - extra_rustc_flags added by the toolchain are applied BEFORE flags added by a config on the commandline - The exec flags from the toolchain don't go on the commandline for a non-exec target - crate type rustc flags are added """ env = analysistest.begin(ctx) target = analysistest.target_under_test(env) action = target[DepActionsInfo].actions[0] asserts.equals(env, "Rustc", action.mnemonic) asserts.true( env, action.argv[-2:] == [TOOLCHAIN_FLAG, CONFIG_FLAG], "Unexpected rustc flags: {}\nShould have ended with: {}".format( action.argv, [TOOLCHAIN_FLAG, CONFIG_FLAG], ), ) asserts.true( env, action.argv[-3] == CRATE_FLAGS[crate_type][0], "Unexpected rustc flags: {}\nShould have contained: {}".format( action.argv, CRATE_FLAGS["rlib"], ), ) for type in CRATE_FLAGS.keys(): if type == crate_type: continue asserts.false( env, CRATE_FLAGS[type][0] in action.argv, "Unexpected rustc flags: {}\nShould not contain: {}".format( action.argv, CRATE_FLAGS[type], ), ) asserts.true( env, EXEC_TOOLCHAIN_FLAG not in action.argv, "Found exec toolchain flag ({}) in rustc flags: {}".format(EXEC_TOOLCHAIN_FLAG, action.argv), ) found_sysroot = False for arg in action.argv: if arg.startswith("--sysroot") and arg.endswith("test/toolchain/rust_extra_flags_toolchain"): found_sysroot = True asserts.true( env, found_sysroot, "Missing --sysroot flag or --sysroot does not point to correct sysroot directory", ) return analysistest.end(env) def _toolchain_adds_rustc_flags_lib_impl(ctx): return _toolchain_adds_rustc_flags_impl(ctx, "rlib") def _toolchain_adds_rustc_flags_shared_lib_impl(ctx): return _toolchain_adds_rustc_flags_impl(ctx, "cdylib") toolchain_adds_rustc_flags_lib_test = analysistest.make( _toolchain_adds_rustc_flags_lib_impl, config_settings = { str(Label("//:extra_rustc_flags")): [CONFIG_FLAG], str(Label("//rust/settings:experimental_toolchain_generated_sysroot")): True, }, ) toolchain_adds_rustc_flags_shared_lib_test = analysistest.make( _toolchain_adds_rustc_flags_shared_lib_impl, config_settings = { str(Label("//:extra_rustc_flags")): [CONFIG_FLAG], str(Label("//rust/settings:experimental_toolchain_generated_sysroot")): True, }, ) def _extra_toolchain_transition_impl(settings, _attr): return {"//command_line_option:extra_toolchains": [ "@rules_rust//test/toolchain:extra_flags_toolchain", ] + settings["//command_line_option:extra_toolchains"]} _extra_toolchain_transition = transition( implementation = _extra_toolchain_transition_impl, inputs = ["//command_line_option:extra_toolchains"], outputs = ["//command_line_option:extra_toolchains"], ) DepActionsInfo = provider( "Contains information about dependencies actions.", fields = {"actions": "List[Action]"}, ) def _collect_dep_actions_aspect_impl(target, ctx): actions = [] actions.extend(target.actions) for dep in ctx.rule.attr.deps: actions.extend(dep[DepActionsInfo].actions) return [DepActionsInfo(actions = actions)] collect_dep_actions_aspect = aspect( implementation = _collect_dep_actions_aspect_impl, attr_aspects = ["deps"], ) def _extra_toolchain_wrapper_impl(ctx): return [ctx.attr.dep[DepActionsInfo]] extra_toolchain_wrapper = rule( implementation = _extra_toolchain_wrapper_impl, attrs = { "dep": attr.label(aspects = [collect_dep_actions_aspect]), "_allowlist_function_transition": attr.label( default = "@bazel_tools//tools/allowlists/function_transition_allowlist", ), }, cfg = _extra_toolchain_transition, ) def _define_targets(): rust_library( name = "lib", srcs = ["lib.rs"], edition = "2021", ) rust_shared_library( name = "shared_lib", srcs = ["lib.rs"], edition = "2021", ) native.filegroup( name = "stdlib_srcs", srcs = ["config.txt"], ) rust_stdlib_filegroup( name = "std_libs", srcs = [":stdlib_srcs"], ) write_file( name = "mock_rustc", out = "mock_rustc.exe", content = [], is_executable = True, ) write_file( name = "mock_rustdoc", out = "mock_rustdoc.exe", content = [], is_executable = True, ) rust_toolchain( name = "rust_extra_flags_toolchain", binary_ext = "", dylib_ext = ".so", exec_triple = "x86_64-unknown-none", target_triple = "x86_64-unknown-none", rust_doc = ":mock_rustdoc", rust_std = ":std_libs", rustc = ":mock_rustc", staticlib_ext = ".a", stdlib_linkflags = [], extra_rustc_flags = [TOOLCHAIN_FLAG], extra_exec_rustc_flags = [EXEC_TOOLCHAIN_FLAG], extra_rustc_flags_for_crate_types = CRATE_FLAGS, visibility = ["//visibility:public"], ) native.toolchain( name = "extra_flags_toolchain", toolchain = ":rust_extra_flags_toolchain", toolchain_type = "@rules_rust//rust:toolchain", ) extra_toolchain_wrapper( name = "lib_with_extra_toolchain", dep = ":lib", ) extra_toolchain_wrapper( name = "shared_lib_with_extra_toolchain", dep = ":shared_lib", ) def _rust_stdlib_filegroup_provides_runfiles_test_impl(ctx): env = analysistest.begin(ctx) target = analysistest.target_under_test(env) runfiles = target[DefaultInfo].default_runfiles asserts.true(env, len(runfiles.files.to_list()) > 0) return analysistest.end(env) rust_stdlib_filegroup_provides_runfiles_test = analysistest.make( _rust_stdlib_filegroup_provides_runfiles_test_impl, ) def toolchain_test_suite(name): """ Instantiates tests for rust toolchains. Args: name: a name for the test suite """ _define_targets() toolchain_adds_rustc_flags_lib_test( name = "toolchain_adds_rustc_flags_lib_test", target_under_test = ":lib_with_extra_toolchain", ) toolchain_adds_rustc_flags_shared_lib_test( name = "toolchain_adds_rustc_flags_shared_lib_test", target_under_test = ":shared_lib_with_extra_toolchain", ) rust_stdlib_filegroup_provides_runfiles_test( name = "rust_stdlib_filegroup_provides_runfiles_test", target_under_test = ":std_libs", ) native.test_suite( name = name, tests = [ ":toolchain_adds_rustc_flags_lib_test", ":toolchain_adds_rustc_flags_shared_lib_test", ":rust_stdlib_filegroup_provides_runfiles_test", ], )