Skip to content

Commit 0e509be

Browse files
nglevinluispadron
authored andcommitted
Add high water mark for iOS tests for minimum OS version comparison.
Cherry-pick: 3da7b31
1 parent d952fdf commit 0e509be

5 files changed

Lines changed: 130 additions & 70 deletions

File tree

apple/internal/testing/apple_test_bundle_support.bzl

Lines changed: 81 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,9 @@ load(
1919
"types",
2020
)
2121
load(
22-
"@build_bazel_rules_swift//swift:swift.bzl",
22+
"@build_bazel_rules_swift//swift:providers.bzl",
2323
"SwiftInfo",
2424
)
25-
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
26-
load(
27-
"//apple:providers.bzl",
28-
"AppleBundleInfo",
29-
"AppleTestInfo",
30-
)
3125
load(
3226
"//apple/internal:apple_product_type.bzl",
3327
"apple_product_type",
@@ -41,10 +35,6 @@ load(
4135
"//apple/internal:bundling_support.bzl",
4236
"bundling_support",
4337
)
44-
load(
45-
"//apple/internal:codesigning_support.bzl",
46-
"codesigning_support",
47-
)
4838
load(
4939
"//apple/internal:experimental.bzl",
5040
"is_experimental_tree_artifact_enabled",
@@ -75,7 +65,9 @@ load(
7565
)
7666
load(
7767
"//apple/internal:providers.bzl",
68+
"AppleBundleInfo",
7869
"AppleExecutableBinaryInfo",
70+
"AppleTestInfo",
7971
"new_appleextraoutputsinfo",
8072
"new_appletestinfo",
8173
)
@@ -95,15 +87,22 @@ load(
9587
"//apple/internal/utils:clang_rt_dylibs.bzl",
9688
"clang_rt_dylibs",
9789
)
98-
load(
99-
"//apple/internal/utils:main_thread_checker_dylibs.bzl",
100-
"main_thread_checker_dylibs",
101-
)
90+
91+
visibility("//apple/...")
10292

10393
# Default test bundle ID for tests that don't have a test host or were not given
10494
# a bundle ID.
10595
_DEFAULT_TEST_BUNDLE_ID = "com.bazelbuild.rulesapple.Tests"
10696

97+
# Suffix given by the test assembler to identify test bundles; these should be stripped from user-
98+
# visible error messaging.
99+
_TEST_BUNDLE_NAME_SUFFIX = ".__internal__.__test_bundle"
100+
101+
# The lowest minimum OS version that can be used for the test mismatch warning. Higher versions will
102+
# be "fail"ed instead of issuing a warning to help enforce the minimum OS version to be the same
103+
# between the test bundle and test host, to avoid debugging issues and redundant build activity.
104+
_LOWEST_MINIMUM_OS_VERSION_FOR_TEST_MISMATCH_WARNING = "17.4"
105+
107106
def _collect_files(rule_attr, attr_names):
108107
"""Collects files from given attr_names (when present) into a depset."""
109108
transitive_files = []
@@ -272,6 +271,60 @@ def _test_host_bundle_id(test_host):
272271
test_host_bundle_info = test_host[AppleBundleInfo]
273272
return test_host_bundle_info.bundle_id
274273

274+
def _validate_test_host_shared_attributes(*, label, platform_prerequisites, test_host):
275+
"""Validates attributes between the test host and test bundle that should be the same."""
276+
if not test_host:
277+
return
278+
279+
test_attribute_mismatch_message = """The test at {test_label} does not support the exact same \
280+
{rule_attribute_name} as its test host at {test_host_label}. These must match for correctness.
281+
282+
- {test_label_name} declares "{rule_attribute_name}" of {test_rule_attribute}
283+
284+
- {test_host_label_name} declares "{rule_attribute_name}" of {test_host_rule_attribute}
285+
286+
Please assign "{rule_attribute_name}" a value of {test_host_rule_attribute} on the BUILD target \
287+
{test_label_name} to match the test host {test_host_label_name}.
288+
"""
289+
290+
test_host_bundle_info = test_host[AppleBundleInfo]
291+
test_bundle_label_no_internal = str(label).rsplit(_TEST_BUNDLE_NAME_SUFFIX)[0]
292+
test_bundle_label_name_no_internal = label.name.rsplit(_TEST_BUNDLE_NAME_SUFFIX)[0]
293+
294+
if platform_prerequisites.device_families != test_host_bundle_info.device_families:
295+
fail("\nERROR: " + test_attribute_mismatch_message.format(
296+
rule_attribute_name = "families",
297+
test_rule_attribute = platform_prerequisites.device_families,
298+
test_host_rule_attribute = test_host_bundle_info.device_families,
299+
test_label = test_bundle_label_no_internal,
300+
test_label_name = test_bundle_label_name_no_internal,
301+
test_host_label = str(test_host.label),
302+
test_host_label_name = test_host.label.name,
303+
))
304+
if platform_prerequisites.minimum_os != test_host_bundle_info.minimum_os_version:
305+
test_min_os = platform_prerequisites.minimum_os
306+
test_attribute_min_os_mismatch_message = test_attribute_mismatch_message.format(
307+
rule_attribute_name = "minimum_os_version",
308+
test_rule_attribute = test_min_os,
309+
test_host_rule_attribute = test_host_bundle_info.minimum_os_version,
310+
test_label = test_bundle_label_no_internal,
311+
test_label_name = test_bundle_label_name_no_internal,
312+
test_host_label = str(test_host.label),
313+
test_host_label_name = test_host.label.name,
314+
)
315+
316+
# TODO(b/337080510): Apply this failure case to all Apple platforms.
317+
if platform_prerequisites.platform_type != "ios" or (
318+
apple_common.dotted_version(test_min_os) > apple_common.dotted_version(
319+
_LOWEST_MINIMUM_OS_VERSION_FOR_TEST_MISMATCH_WARNING,
320+
)
321+
):
322+
fail("\nERROR: " + test_attribute_min_os_mismatch_message)
323+
324+
# There is no other way to issue a warning, so print is the only way to message.
325+
# buildifier: disable=print
326+
print("\nWARNING: " + test_attribute_min_os_mismatch_message)
327+
275328
def _apple_test_bundle_impl(*, ctx, product_type):
276329
"""Implementation for bundling XCTest bundles."""
277330
test_host = ctx.attr.test_host
@@ -328,6 +381,13 @@ def _apple_test_bundle_impl(*, ctx, product_type):
328381
uses_swift = swift_support.uses_swift(ctx.attr.deps),
329382
xcode_version_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig],
330383
)
384+
385+
_validate_test_host_shared_attributes(
386+
label = label,
387+
platform_prerequisites = platform_prerequisites,
388+
test_host = test_host,
389+
)
390+
331391
predeclared_outputs = ctx.outputs
332392
provisioning_profile = ctx.file.provisioning_profile
333393
resource_deps = ctx.attr.deps + ctx.attr.resources
@@ -346,59 +406,28 @@ def _apple_test_bundle_impl(*, ctx, product_type):
346406
# is never passed as the bundle loader, because the host application is loaded out-of-process.)
347407
if (
348408
rule_descriptor.product_type == apple_product_type.unit_test_bundle and
349-
test_host and AppleExecutableBinaryInfo in test_host and
350-
ctx.attr.test_host_is_bundle_loader
409+
test_host and AppleExecutableBinaryInfo in test_host
351410
):
352411
bundle_loader = test_host
353412
else:
354413
bundle_loader = None
355414

356415
extra_linkopts = [
357-
"-Xlinker",
358-
"-needed_framework",
359-
"-Xlinker",
360-
"XCTest",
361416
"-framework",
362417
"XCTest",
363-
"-bundle",
364418
]
365419

366-
if any([_is_swift_target(dep) for dep in ctx.attr.deps]):
367-
extra_linkopts.extend([
368-
"-Xlinker",
369-
"-needed-lXCTestSwiftSupport",
370-
"-lXCTestSwiftSupport",
371-
])
372-
373-
extra_link_inputs = []
374-
375-
if "apple.swizzle_absolute_xcttestsourcelocation" in features:
376-
# `linking_support.register_binary_linking_action` uses
377-
# `apple_common.link_multi_arch_binary`, which doesn't allow specifying
378-
# dependencies (it reads them from `ctx.attr.deps`). So we have to
379-
# manually link the `_swizzle_absolute_xcttestsourcelocation` library.
380-
swizzle_lib = ctx.attr._swizzle_absolute_xcttestsourcelocation
381-
for linker_input in swizzle_lib[CcInfo].linking_context.linker_inputs.to_list():
382-
for library in linker_input.libraries:
383-
static_library = library.static_library
384-
extra_link_inputs.append(static_library)
385-
extra_linkopts.append(
386-
"-Wl,-force_load,{}".format(static_library.path),
387-
)
388-
extra_link_inputs.extend(linker_input.additional_inputs)
389-
extra_linkopts.extend(linker_input.user_link_flags)
390-
391420
link_result = linking_support.register_binary_linking_action(
392421
ctx,
393-
cc_toolchains = cc_toolchain_forwarder,
394422
avoid_deps = getattr(ctx.attr, "frameworks", []),
395423
build_settings = apple_xplat_toolchain_info.build_settings,
396424
bundle_loader = bundle_loader,
425+
cc_toolchains = cc_toolchain_forwarder,
397426
# Unit/UI tests do not use entitlements.
398427
entitlements = None,
399428
exported_symbols_lists = ctx.files.exported_symbols_lists,
400-
extra_link_inputs = extra_link_inputs,
401429
extra_linkopts = extra_linkopts,
430+
extra_requested_features = ["link_bundle"],
402431
platform_prerequisites = platform_prerequisites,
403432
rule_descriptor = rule_descriptor,
404433
stamp = ctx.attr.stamp,
@@ -414,17 +443,12 @@ def _apple_test_bundle_impl(*, ctx, product_type):
414443
debug_dependencies.append(test_host)
415444

416445
if hasattr(ctx.attr, "frameworks"):
417-
frameworks = list(ctx.attr.frameworks)
418-
targets_to_avoid = frameworks
419-
debug_dependencies.extend(frameworks)
446+
targets_to_avoid = list(ctx.attr.frameworks)
420447
else:
421448
targets_to_avoid = []
422-
423449
if bundle_loader:
424450
targets_to_avoid.append(bundle_loader)
425451

426-
embeddable_targets = ctx.attr.deps + getattr(ctx.attr, "frameworks", [])
427-
428452
processor_partials = [
429453
partials.apple_bundle_info_partial(
430454
actions = actions,
@@ -467,23 +491,13 @@ def _apple_test_bundle_impl(*, ctx, product_type):
467491
provisioning_profile = provisioning_profile,
468492
rule_descriptor = rule_descriptor,
469493
),
470-
partials.main_thread_checker_dylibs_partial(
471-
actions = actions,
472-
apple_mac_toolchain_info = apple_mac_toolchain_info,
473-
binary_artifact = binary_artifact,
474-
features = features,
475-
label_name = label.name,
476-
platform_prerequisites = platform_prerequisites,
477-
dylibs = main_thread_checker_dylibs.get_from_toolchain(ctx),
478-
),
479494
partials.debug_symbols_partial(
480495
actions = actions,
481496
bundle_extension = bundle_extension,
482497
bundle_name = bundle_name,
483498
debug_dependencies = debug_dependencies,
484499
dsym_outputs = debug_outputs.dsym_outputs,
485500
dsym_info_plist_template = apple_mac_toolchain_info.dsym_info_plist_template,
486-
executable_name = executable_name,
487501
label_name = label.name,
488502
linkmaps = debug_outputs.linkmaps,
489503
platform_prerequisites = platform_prerequisites,
@@ -493,7 +507,7 @@ def _apple_test_bundle_impl(*, ctx, product_type):
493507
),
494508
partials.embedded_bundles_partial(
495509
bundle_embedded_bundles = True,
496-
embeddable_targets = embeddable_targets,
510+
embeddable_targets = getattr(ctx.attr, "frameworks", []),
497511
platform_prerequisites = platform_prerequisites,
498512
),
499513
partials.framework_import_partial(
@@ -536,7 +550,7 @@ def _apple_test_bundle_impl(*, ctx, product_type):
536550
),
537551
]
538552

539-
if platform_prerequisites.platform_type == apple_common.platform_type.macos:
553+
if platform_prerequisites.platform_type == "macos":
540554
processor_partials.append(
541555
partials.macos_additional_contents_partial(
542556
additional_contents = ctx.attr.additional_contents,
@@ -549,10 +563,7 @@ def _apple_test_bundle_impl(*, ctx, product_type):
549563
apple_xplat_toolchain_info = apple_xplat_toolchain_info,
550564
bundle_extension = bundle_extension,
551565
bundle_name = bundle_name,
552-
codesign_inputs = ctx.files.codesign_inputs,
553-
codesignopts = codesigning_support.codesignopts_from_rule_ctx(ctx),
554566
features = features,
555-
ipa_post_processor = ctx.executable.ipa_post_processor,
556567
partials = processor_partials,
557568
platform_prerequisites = platform_prerequisites,
558569
predeclared_outputs = predeclared_outputs,

test/starlark_tests/common.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ _min_os_ios = struct(
3939
oldest_supported = "11.0",
4040
nplus1 = "13.0",
4141
stable_swift_abi = "12.2",
42+
test_mismatch_high_threshold = "18.0",
4243
widget_configuration_intents_support = "16.0",
4344
)
4445

test/starlark_tests/ios_ui_test_tests.bzl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ def ios_ui_test_test_suite(name):
192192
tags = [name],
193193
)
194194

195+
analysis_failure_message_test(
196+
name = "{}_test_bundle_min_os_different_from_test_host_error".format(name),
197+
target_under_test = "//test/starlark_tests/targets_under_test/ios:ui_test_different_min_os",
198+
expected_error = "ERROR: The test at //test/starlark_tests/targets_under_test/ios:ui_test_different_min_os does not support the exact same minimum_os_version as its test host at //test/starlark_tests/targets_under_test/ios:app. These must match for correctness.",
199+
tags = [name],
200+
)
201+
195202
native.test_suite(
196203
name = name,
197204
tags = [name],

test/starlark_tests/ios_unit_test_tests.bzl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,13 @@ def ios_unit_test_test_suite(name):
305305
tags = [name],
306306
)
307307

308+
analysis_failure_message_test(
309+
name = "{}_test_bundle_min_os_different_from_test_host_error".format(name),
310+
target_under_test = "//test/starlark_tests/targets_under_test/ios:unit_test_different_min_os",
311+
expected_error = "ERROR: The test at //test/starlark_tests/targets_under_test/ios:unit_test_different_min_os does not support the exact same minimum_os_version as its test host at //test/starlark_tests/targets_under_test/ios:app. These must match for correctness.",
312+
tags = [name],
313+
)
314+
308315
native.test_suite(
309316
name = name,
310317
tags = [name],

test/starlark_tests/targets_under_test/ios/BUILD

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3622,6 +3622,23 @@ ios_ui_test(
36223622
],
36233623
)
36243624

3625+
ios_ui_test(
3626+
name = "ui_test_different_min_os",
3627+
families = [
3628+
"iphone",
3629+
],
3630+
infoplists = [
3631+
"//test/starlark_tests/resources:Info.plist",
3632+
],
3633+
minimum_os_version = common.min_os_ios.test_mismatch_high_threshold,
3634+
runner = "//test/starlark_tests/targets_under_test/apple:dummy_test_runner",
3635+
tags = common.fixture_tags,
3636+
test_host = ":app",
3637+
deps = [
3638+
"//test/starlark_tests/resources:objc_test_lib",
3639+
],
3640+
)
3641+
36253642
xctrunner(
36263643
name = "ui_test_xctrunner_app",
36273644
testonly = True,
@@ -3885,6 +3902,23 @@ ios_unit_test(
38853902
],
38863903
)
38873904

3905+
ios_unit_test(
3906+
name = "unit_test_different_min_os",
3907+
families = [
3908+
"iphone",
3909+
],
3910+
infoplists = [
3911+
"//test/starlark_tests/resources:Info.plist",
3912+
],
3913+
minimum_os_version = common.min_os_ios.test_mismatch_high_threshold,
3914+
runner = "//test/starlark_tests/targets_under_test/apple:dummy_test_runner",
3915+
tags = common.fixture_tags,
3916+
test_host = ":app",
3917+
deps = [
3918+
"//test/starlark_tests/resources:objc_test_lib",
3919+
],
3920+
)
3921+
38883922
# ---------------------------------------------------------------------------------------
38893923
# Targets for the app/test resource deduping test.
38903924

0 commit comments

Comments
 (0)