Open source one version tests (ignore-relnotes) PiperOrigin-RevId: 910688799 Change-Id: Ifa9ae668c58137ff14eb2aa1a2875c8ac5fe0b37
diff --git a/java/common/BUILD b/java/common/BUILD index 9881236..7887b1f 100644 --- a/java/common/BUILD +++ b/java/common/BUILD
@@ -36,7 +36,10 @@ name = "semantics_bzl", srcs = ["java_semantics.bzl"], visibility = ["//visibility:public"], - deps = ["@rules_cc//cc/common:cc_helper_bzl"], + deps = [ + "@bazel_features//:features", + "@rules_cc//cc/common:cc_helper_bzl", + ], ) bzl_library(
diff --git a/java/common/java_semantics.bzl b/java/common/java_semantics.bzl index e847d87..919553e 100644 --- a/java/common/java_semantics.bzl +++ b/java/common/java_semantics.bzl
@@ -13,6 +13,7 @@ # limitations under the License. """Bazel Java Semantics""" +load("@bazel_features//private:util.bzl", _bazel_version_ge = "ge") load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/common:cc_helper.bzl", "cc_helper") @@ -126,4 +127,5 @@ INCOMPATIBLE_DISABLE_NON_EXECUTABLE_JAVA_BINARY = False, # Flip when java_single_jar is feature complete update_args_for_import_deps = _update_args_for_import_deps, expand_javacopts_make_variables = True, + java_toolchain_supports_one_version = _bazel_version_ge("8.0.0"), # can be dropped once we no longer support Bazel 7 )
diff --git a/test/java/common/rules/java_binary_tests.bzl b/test/java/common/rules/java_binary_tests.bzl index 7ee9eb1..f2ab5be 100644 --- a/test/java/common/rules/java_binary_tests.bzl +++ b/test/java/common/rules/java_binary_tests.bzl
@@ -1,6 +1,7 @@ """Tests for the java_binary rule""" load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") @@ -8,9 +9,12 @@ load("@rules_testing//lib:util.bzl", "util") load("//java:java_binary.bzl", "java_binary") load("//java:java_library.bzl", "java_library") +load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") load("//test/java/common/rules:common_launcher_java_binary_tests.bzl", "JAVA_BINARY_LAUNCHER_TESTS") load("//test/java/testutil:helper.bzl", "always_passes") load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_toolchain") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") load("//test/java/testutil:rules/forward_java_info.bzl", "java_info_forwarding_rule") @@ -250,6 +254,158 @@ # ensure they don't propagate to `bin` because they're a part of the `deploy_env` env.expect.that_target(targets.bin).output_group("_validation").contains_exactly([]) +def _test_one_version_check_action(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/c", + srcs = [name + "/c.java"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = [name + "/a.java"], + deps = [name + "/c"], + ) + util.helper_target( + java_binary, + name = name + "/b", + srcs = [name + "/b.java"], + deps = [name + "/a"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_action_impl, + target = name + "/b", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + attrs = { + "_windows_constraints": attr.label_list( + default = [paths.join(semantics.PLATFORMS_ROOT, "os:windows")], + ), + }, + ) + +def _test_one_version_check_action_impl(env, target): + assert_target = env.expect.that_target(target) + assert_target.default_outputs().contains_exactly([ + "{package}/{test_name}/b.jar", + "{package}/{test_name}/b" + (".exe" if helper.is_target_platform_windows(env.ctx) else ""), + ]) + assert_target.output_group("_validation").contains( + "{package}/{name}-one-version.txt", + ) + assert_action = assert_target.action_generating("{package}/{name}-one-version.txt") + assert_action.mnemonic().equals("JavaOneVersion") + assert_action.inputs().contains_at_least([ + "{package}/{test_name}/b.jar", + "{package}/lib{test_name}/a.jar", + "{package}/lib{test_name}/c.jar", + ]) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist", + "--inputs", + "{bindir}/{package}/{test_name}/b.jar,//{package}:{test_name}/b", + "{bindir}/{package}/lib{test_name}/a.jar,//{package}:{test_name}/a", + "{bindir}/{package}/lib{test_name}/c.jar,//{package}:{test_name}/c", + ]).in_order() + +def _test_one_version_check_violations_allowed(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_binary, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_violations_allowed_impl, + target = name + "/foo", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "WARNING", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_violations_allowed_impl(env, target): + assert_action = env.expect.that_target(target).action_generating( + "{package}/{name}-one-version.txt", + ) + env.expect.that_target(target).output_group("_validation").contains( + "{package}/{name}-one-version.txt", + ) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist", + "--succeed_on_found_violations", + "--inputs", + "{bindir}/{package}/{test_name}/foo.jar,//{package}:{test_name}/foo", + ]).in_order() + +def _test_one_version_check_disabled(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_binary, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_disabled_impl, + target = name + "/foo", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "OFF", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_disabled_impl(env, target): + action_mnemonics = [a.mnemonic for a in env.expect.that_target(target).actual.actions] + env.expect.that_collection(action_mnemonics).not_contains("JavaOneVersion") + def java_binary_tests(name): test_suite( name = "_basic_" + name, @@ -260,6 +416,9 @@ _test_java_binary_propagates_direct_native_libraries, _test_java_compile_only, _test_java_binary_can_set_transitive_validation, + _test_one_version_check_action, + _test_one_version_check_violations_allowed, + _test_one_version_check_disabled, ], )
diff --git a/test/java/common/rules/java_test_tests.bzl b/test/java/common/rules/java_test_tests.bzl index 6c71d33..995872f 100644 --- a/test/java/common/rules/java_test_tests.bzl +++ b/test/java/common/rules/java_test_tests.bzl
@@ -1,18 +1,21 @@ """Tests for the java_test rule""" load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") load("@rules_testing//lib:truth.bzl", "matching", "subjects") load("@rules_testing//lib:util.bzl", "util") +load("//java:java_binary.bzl", "java_binary") load("//java:java_library.bzl", "java_library") load("//java:java_test.bzl", "java_test") load("//java/common:java_info.bzl", "JavaInfo") load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") load("//test/java/testutil:helper.bzl", "always_passes") load("//test/java/testutil:mock_cc_toolchain.bzl", "mock_cc_toolchain") -load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_runtime_toolchain") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_runtime_toolchain", "mock_java_toolchain") load("//test/java/testutil:mock_test_toolchain.bzl", "mock_test_toolchains") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") @@ -326,6 +329,111 @@ matching.str_matches("-Djava.security.manager=allow"), ) +def _test_one_version_check_java_test(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + java_test, + name = name + "/foo_test", + srcs = [name + "/foo_test.java"], + deps = [name + "/foo"], + use_testrunner = False, + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + oneversion_allowlist_for_tests = "one_version_allowlist_for_tests", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_java_test_impl, + target = name + "/foo_test", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + attrs = { + "_windows_constraints": attr.label_list( + default = [paths.join(semantics.PLATFORMS_ROOT, "os:windows")], + ), + }, + ) + +def _test_one_version_check_java_test_impl(env, target): + assert_target = env.expect.that_target(target) + assert_target.default_outputs().contains_exactly([ + "{package}/{test_name}/foo_test.jar", + "{package}/{test_name}/foo_test" + (".exe" if helper.is_target_platform_windows(env.ctx) else ""), + ]) + assert_action = assert_target.action_generating( + "{package}/{name}-one-version.txt", + ) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist_for_tests", + "--inputs", + "{bindir}/{package}/{test_name}/foo_test.jar,//{package}:{test_name}/foo_test", + "{bindir}/{package}/lib{test_name}/foo.jar,//{package}:{test_name}/foo", + ]).in_order() + +def _test_one_version_check_disabled_for_java_test(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_test, + name = name + "/foo_test", + srcs = [name + "/foo.java"], + use_testrunner = False, + ) + util.helper_target( + java_binary, + name = name + "/foo_binary", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_disabled_for_java_test_impl, + targets = { + "bin": name + "/foo_binary", + "test": name + "/foo_test", + }, + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:one_version_enforcement_on_java_tests": False, + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_disabled_for_java_test_impl(env, targets): + binary_action_mnemonics = [a.mnemonic for a in env.expect.that_target(targets.bin).actual.actions] + test_action_mnemonics = [a.mnemonic for a in env.expect.that_target(targets.test).actual.actions] + env.expect.that_collection(binary_action_mnemonics).contains("JavaOneVersion") + env.expect.that_collection(test_action_mnemonics).not_contains("JavaOneVersion") + def java_test_tests(name): test_suite( name = name, @@ -338,5 +446,7 @@ _test_add_test_support_to_compile_time_deps_flag, _test_mac_requires_darwin_for_execution, _test_java_test_sets_securiry_manager_property_jdk17, + _test_one_version_check_java_test, + _test_one_version_check_disabled_for_java_test, ], )
diff --git a/test/java/testutil/mock_java_toolchain.bzl b/test/java/testutil/mock_java_toolchain.bzl index de824b1..aae0afd 100644 --- a/test/java/testutil/mock_java_toolchain.bzl +++ b/test/java/testutil/mock_java_toolchain.bzl
@@ -15,11 +15,19 @@ ijar = "ijar", genclass = "genclass", java_runtime = None, + oneversion = None, + oneversion_allowlist = None, + oneversion_allowlist_for_tests = None, tags = None, # for util.helper_target **kwargs): if not java_runtime: java_runtime = name + "_runtime" _java_runtime_rule(name = java_runtime) + one_version_args = { + "oneversion": oneversion, + "oneversion_allowlist": oneversion_allowlist, + "oneversion_allowlist_for_tests": oneversion_allowlist_for_tests, + } if semantics.java_toolchain_supports_one_version else {} java_toolchain( name = name + "_java", javabuilder = javabuilder, @@ -30,7 +38,7 @@ java_runtime = java_runtime, genclass = genclass, tags = tags, - **kwargs + **(kwargs | one_version_args) ) native.toolchain( name = name,