Skip to content

Commit c131725

Browse files
A GooglerBlaze Rules Copybara
authored andcommitted
Support testing aspects
At the moment testing actions created by aspect is not neat, becuause testing aspect is not applied over user-land aspects. It's possible using a custom aspect, but then one needs to handle a custom provider. With this approach users can create a new testing aspect that is applied over their aspect. Standard testing functionality applies. Closes: #134 PiperOrigin-RevId: 737577457
1 parent 7d6ad05 commit c131725

File tree

6 files changed

+83
-9
lines changed

6 files changed

+83
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
### Added
1717

18-
* Nothing yet
18+
* Added support for testing actions created in an aspect, via
19+
`util.make_testing_aspect` and `analysis_test`'s `testing_aspect` parameter.
1920

2021
### Removed
2122

lib/private/analysis_test.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ def analysis_test(
139139
attr_values = {},
140140
fragments = [],
141141
config_settings = {},
142+
testing_aspect = testing_aspect,
142143
extra_target_under_test_aspects = [],
143144
provider_subject_factories = []):
144145
"""Creates an analysis test from its implementation function.
@@ -213,6 +214,7 @@ def analysis_test(
213214
--platforms flag), it's suggested to always explicitly call `Label()`
214215
on the value before passing it in. This ensures the label is resolved
215216
in your repository's context, not rule_testing's.
217+
testing_aspect: An optional override of testing_aspect. See `util.make_testing_aspect`.
216218
extra_target_under_test_aspects: An optional list of aspects to apply to the target_under_test
217219
in addition to those set up by default for the test harness itself.
218220
provider_subject_factories: Optional list of ProviderSubjectFactory structs,

lib/private/expect.bzl

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,27 @@ def _expect_that_target(self, target):
244244
Returns:
245245
[`TargetSubject`] object.
246246
"""
247+
format_str_kwargs = {
248+
"name": target.label.name,
249+
"package": target.label.package,
250+
}
251+
expr = "target({})".format(target.label)
252+
details = ["target: {}".format(target.label)]
253+
if TestingAspectInfo in target:
254+
format_str_kwargs["bindir"] = target[TestingAspectInfo].bin_path
255+
if target[TestingAspectInfo].required_aspects:
256+
expr = "aspect({aspects} over {target})".format(
257+
aspects = ", ".join(target[TestingAspectInfo].required_aspects),
258+
target = target.label,
259+
)
260+
details.extend([
261+
"aspect: {}".format(aspect)
262+
for aspect in target[TestingAspectInfo].required_aspects
263+
])
247264
return TargetSubject.new(target, self.meta.derive(
248-
expr = "target({})".format(target.label),
249-
details = ["target: {}".format(target.label)],
250-
format_str_kwargs = {
251-
"name": target.label.name,
252-
"package": target.label.package,
253-
} | {"bindir": target[TestingAspectInfo].bin_path} if TestingAspectInfo in target else {},
265+
expr = expr,
266+
details = details,
267+
format_str_kwargs = format_str_kwargs,
254268
))
255269

256270
def _expect_that_value(self, value, *, factory, expr = "value"):

lib/util.bzl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ TestingAspectInfo = provider(
161161
"actions": "The actions registered for the target under test.",
162162
"vars": "The var dict (ctx.var) for the target under text.",
163163
"bin_path": "str; the ctx.bin_dir.path value (aka execroot).",
164+
"required_aspects": "list[str]: aspects applied over this target",
164165
},
165166
)
166167

@@ -170,13 +171,31 @@ def _testing_aspect_impl(target, ctx):
170171
actions = target.actions,
171172
vars = ctx.var,
172173
bin_path = ctx.bin_dir.path,
174+
required_aspects = ctx.aspect_ids[:-1],
173175
)]
174176

175177
# TODO(ilist): make private, after switching python tests to new testing framework
176178
testing_aspect = aspect(
177179
implementation = _testing_aspect_impl,
178180
)
179181

182+
def _make_testing_aspect(aspects = []):
183+
"""Makes a testing_aspect
184+
185+
Use when you need to test actions created by aspect. Pass
186+
the returned aspect to analysis_test as `testing_aspect`.
187+
188+
Args:
189+
aspects: a list of aspects to apply testing aspect over.
190+
191+
Returns:
192+
custom testing aspect
193+
"""
194+
return aspect(
195+
implementation = _testing_aspect_impl,
196+
requires = aspects,
197+
)
198+
180199
def get_target_attrs(env):
181200
return analysistest.target_under_test(env)[TestingAspectInfo].attrs
182201

@@ -253,6 +272,7 @@ util = struct(
253272
empty_file = empty_file,
254273
force_exec_config = force_exec_config,
255274
helper_target = helper_target,
275+
make_testing_aspect = _make_testing_aspect,
256276
merge_kwargs = merge_kwargs,
257277
runfiles_map = runfiles_map,
258278
runfiles_paths = runfiles_paths,

tests/analysis_test_tests.bzl

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
1818
load("//lib:analysis_test.bzl", "analysis_test", "test_suite")
1919
load("//lib:truth.bzl", "matching")
20-
load("//lib:util.bzl", "TestingAspectInfo")
20+
load("//lib:util.bzl", "TestingAspectInfo", "util")
2121

2222
_TestingFlagsInfo = provider(
2323
doc = "Flags used for testing",
@@ -223,6 +223,42 @@ def test_inspect_aspect(name):
223223
def _test_inspect_aspect(env, target):
224224
env.expect.that_str(target[_AddedByAspectInfo].value).equals("attached by aspect")
225225

226+
####################################
227+
####### inspect_aspect_actions_test #######
228+
####################################
229+
def _inspect_actions_fake_aspect_impl(_target, ctx):
230+
out_file = ctx.actions.declare_file("aspect_out.txt")
231+
ctx.actions.run_shell(
232+
command = "echo 'hello' > %s" % out_file.basename,
233+
outputs = [out_file],
234+
mnemonic = "RunningHello",
235+
)
236+
return []
237+
238+
_inspect_actions_fake_aspect = aspect(
239+
implementation = _inspect_actions_fake_aspect_impl,
240+
)
241+
242+
_inspect_actions_fake_aspect_testing_aspect = util.make_testing_aspect(
243+
aspects = [_inspect_actions_fake_aspect],
244+
)
245+
246+
def test_inspect_aspect_actions(name):
247+
"""Test verifying actions registered by an aspect."""
248+
native.filegroup(name = name + "_subject")
249+
250+
analysis_test(
251+
name = name,
252+
target = name + "_subject",
253+
impl = _test_inspect_aspect_actions,
254+
testing_aspect = _inspect_actions_fake_aspect_testing_aspect,
255+
)
256+
257+
def _test_inspect_aspect_actions(env, target):
258+
env.expect.that_int(len(target[TestingAspectInfo].actions)).equals(1)
259+
action_output = target[TestingAspectInfo].actions[0].outputs.to_list()[0]
260+
env.expect.that_str(action_output.basename).equals("aspect_out.txt")
261+
226262
########################################
227263
####### inspect_output_dirs_test #######
228264
########################################
@@ -449,5 +485,6 @@ def analysis_test_test_suite(name):
449485
test_change_setting_with_failure,
450486
test_inspect_actions,
451487
test_inspect_aspect,
488+
test_inspect_aspect_actions,
452489
],
453490
)

tests/truth_tests.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ def _runfiles_subject_test(env, target):
12401240
"expected to contain: does-not-exist",
12411241
"actual default runfiles:",
12421242
"default_runfile1.txt",
1243-
"target: ".format(target.label),
1243+
"target: {}".format(target.label),
12441244
],
12451245
env = env,
12461246
msg = "check contains",

0 commit comments

Comments
 (0)