Skip to content

Commit

Permalink
Analysis test for bazelbuild/bazel#12171
Browse files Browse the repository at this point in the history
This test asserts that transitive dependencies have identical outputs for
different transition paths. In particular, a rules_apple ios_application and an a
apple_framework that share a swift_library, :SwiftLib_swift. This test ensures
that the actions in both builds have functionally equal transitions
applied by normalizing their output directories into a set.

For instance these tests will fail if there is any delta and requires both:
- adding apple_common.multi_arch_split to apple_framework.deps - #188
- the transition yields the same result when used w/rules_apple - #196

Note:
The gist of Bazel's configuration resolver is that it will apply
relevant transitions to keys that are used by a given action. e.g. ios_multi_cpus.
src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java

In order to get the same configuration for a rule, a given transition has
to produce the same values for dependent keys for all possible combinations
of edges in a given build.
  • Loading branch information
jerrymarino committed Jan 16, 2021
1 parent 85ee17f commit 5b69026
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
3 changes: 3 additions & 0 deletions tests/ios/app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ load("//rules:framework.bzl", "apple_framework")
load("//rules:app.bzl", "ios_application")
load("//rules:test.bzl", "ios_unit_test")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load(":analysis-tests.bzl", "make_tests")

apple_framework(
name = "CppLib",
Expand Down Expand Up @@ -280,3 +281,5 @@ ios_application(
":SwiftLib",
],
)

make_tests()
100 changes: 100 additions & 0 deletions tests/ios/app/analysis-tests.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")

_TestFiles = provider(
fields = {
"files": "A glob of files collected for later assertions",
},
)

def _identical_outputs_test_impl(ctx):
env = analysistest.begin(ctx)
all_files = []
asserts.true(env, len(ctx.attr.deps) > 1)

for dep in ctx.attr.deps:
if not _TestFiles in dep:
continue

# The input root is the part of the file usually rooted in bazel-out.
# For starlark transitions output dirs are fingerprinted by the hash of the
# relevant configuration keys.
# src/main/java/com/google/devtools/build/lib/analysis/starlark/FunctionTransitionUtil.java
for input in dep[_TestFiles].files.to_list():
all_files.append(input.root.path)

# Expect that we have recieved multiple swiftmodules
asserts.true(env, len(all_files) > 1)

# Assert all swiftmodules have identical outputs ( and most importantly an
# identical output directory )
asserts.equals(env, 1, len(depset(all_files).to_list()))
return analysistest.end(env)

def _collect_transitive_outputs_impl(target, ctx):
# Collect trans swift_library outputs
out = []
if ctx.rule.kind == "swift_library":
out.extend(target[DefaultInfo].files.to_list())

if _TestFiles in target:
out.extend(target[_TestFiles].files.to_list())
if hasattr(ctx.rule.attr, "srcs"):
for d in ctx.rule.attr.srcs:
if _TestFiles in d:
out.extend(d[_TestFiles].files.to_list())
if hasattr(ctx.rule.attr, "deps"):
for d in ctx.rule.attr.deps:
if _TestFiles in d:
out.extend(d[_TestFiles].files.to_list())
return _TestFiles(files = depset(out))

_collect_transitive_outputs = aspect(
implementation = _collect_transitive_outputs_impl,
attr_aspects = ["deps", "srcs"],
)

_identical_outputs_test = analysistest.make(
_identical_outputs_test_impl,
expect_failure = False,
attrs = {
"deps": attr.label_list(
aspects = [_collect_transitive_outputs],
),
},
)

def make_tests():
# This test asserts that transitive dependencies have identical outputs for
# different transition paths. In particular, a rules_apple ios_application and an a
# apple_framework that share a swift_library, :SwiftLib_swift. This test ensures
# that the actions in both builds have functionally equal transitions
# applied by normalizing their output directories into a set.
#
# For instance these tests will fail if there is any delta and requires both:
# - adding apple_common.multi_arch_split to apple_framework.deps - #188
# - the transition yields the same result when used w/rules_apple - #196

# Note:
# The gist of Bazel's configuration resolver is that it will apply
# relevant transitions to keys that are used by a given action. e.g. ios_multi_cpus.
# src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
#
# In order to get the same configuration for a rule, a given transition has
# to produce the same values for dependent keys for all possible combinations
# of edges

_identical_outputs_test(
name = "test_DependencyEquivilance",
target_under_test = ":AppWithSelectableCopts",

# These inputs *must* be passed seperately, in order to
# have different transitions applied by Skyframe.
deps = [":AppWithSelectableCopts", ":SwiftLib"],
)

native.test_suite(
name = "AnalysisTests",
tests = [
":test_DependencyEquivilance",
],
)

0 comments on commit 5b69026

Please sign in to comment.