Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 23 additions & 15 deletions bazel/rules/rules_score/private/component.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ def _component_impl(ctx):
# and bubble up SphinxSourcesInfo from sub-components/units.
#
# Only ComponentRequirementsInfo-providing targets contribute their own
# rendered RST here. feature_requirements targets are commonly also listed
# in `requirements` (see below) purely so their .lobster file can resolve
# derived_from references from the component requirements; they are
# already rendered once at the dependable_element level, so re-rendering
# them per component would duplicate the feature requirements page across
# every component that references the same feature.
# rendered RST here. feature_requirements / assumed_system_requirements
# targets are commonly also listed in `requirements` (see below) purely so
# their .lobster file can resolve derived_from references from the component
# requirements; they are already rendered once at the dependable_element
# level, so re-rendering them per component would duplicate the upstream
# requirements page across every component that references the same item.
# -------------------------------------------------------------------------
req_sphinx_files = []
for req_target in ctx.attr.requirements:
Expand All @@ -181,7 +181,10 @@ def _component_impl(ctx):

# -------------------------------------------------------------------------
# Lobster Tracing: collect .lobster files from component_requirements targets
# and feature_requirements targets (needed to resolve derived_from references).
# and from upstream requirements targets -- feature_requirements, or
# assumed_system_requirements when a SEooC traces component requirements
# directly to ASRs without a feature requirements layer. Both feed the
# config's upstream level, so derived_from references resolve either way.
# -------------------------------------------------------------------------
req_lobster_files = []
req_lobster_transitive_files = []
Expand Down Expand Up @@ -367,8 +370,9 @@ _component_test = rule(
),
"requirements": attr.label_list(
default = [],
providers = [[ComponentRequirementsInfo], [FeatureRequirementsInfo]],
doc = "Component requirements artifacts (component_requirements or feature_requirements targets)",
providers = [[ComponentRequirementsInfo], [FeatureRequirementsInfo], [AssumedSystemRequirementsInfo]],
doc = "Component requirements artifacts (component_requirements, feature_requirements or " +
"assumed_system_requirements targets)",
),
"components": attr.label_list(
providers = [[ComponentInfo], [UnitInfo]],
Expand Down Expand Up @@ -429,12 +433,16 @@ def component(
name: The name of the component. Used as the target name.
requirements: List of labels to component_requirements targets
that define the requirements for this component. A
feature_requirements target may also be listed here so its
.lobster file is available to resolve derived_from references
from the component requirements; only component_requirements
targets contribute rendered RST to the component's Sphinx docs,
so listing a feature_requirements target does not duplicate it
in the generated documentation.
feature_requirements or assumed_system_requirements target may
also be listed here so its .lobster file is available to resolve
derived_from references from the component requirements; only
component_requirements targets contribute rendered RST to the
component's Sphinx docs, so listing an upstream requirements
target does not duplicate it in the generated documentation.
A SEooC that derives its component requirements directly from
Assumed System Requirements (without an intermediate feature
requirements layer) lists the assumed_system_requirements target
here.
components: List of labels to nested component targets (for hierarchical
component structures).
tests: List of labels to Bazel test targets that verify the component
Expand Down
35 changes: 35 additions & 0 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ load(
)
load(
":unit_component_test.bzl",
"component_direct_asr_test",
"component_excludes_feature_req_docs_test",
"component_provider_test",
"component_requirements_transitive_test",
Expand Down Expand Up @@ -286,6 +287,14 @@ component_requirements(
# (AoUs reach a dependable_element as `safety_measures` of its safety_analysis; see
# :aou_root_cause_aous.)

# Component requirements tracing directly to an AssumedSystemReq, with no
# feature_requirements layer (used by :test_component_direct_asr).
component_requirements(
name = "comp_req_direct_asr",
srcs = ["fixtures/seooc_test/component_requirements_direct_asr.trlc"],
deps = [":asr_trlc"],
)

# - Architecture Design: wp__component_arch
architectural_design(
name = "arch_design",
Expand Down Expand Up @@ -1349,6 +1358,24 @@ component(
tests = [], # Empty for testing
)

# Test Component tracing straight to Assumed System Requirements, i.e. with no
# feature_requirements layer in between (see
# fixtures/seooc_test/component_requirements_direct_asr.trlc). The
# assumed_system_requirements target must be accepted in `requirements` so its
# .lobster file reaches the component's lobster config; otherwise lobster-trace
# fails with "unknown tracing target req TestSEooC.ASR_TEST_001".
component(
name = "test_component_direct_asr",
testonly = True,
components = [":test_unit"],
requirements = [
":comp_req_direct_asr",
":asr_trlc",
],
tags = ["manual"],
tests = [],
)

# Test Dependable Element.
# maturity = "development": this fixture intentionally omits a
# test_case_coverage.lock.yaml, so under the release traceability gate its
Expand Down Expand Up @@ -2054,6 +2081,14 @@ component_excludes_feature_req_docs_test(
target_under_test = ":test_component",
)

# Regression test for component() rejecting assumed_system_requirements targets
# in `requirements`, which blocked SEooCs that trace component requirements
# directly to ASRs (no feature requirements layer).
component_direct_asr_test(
name = "component_direct_asr_test",
target_under_test = ":test_component_direct_asr",
)

component_test_case_coverage_lock_test(
name = "component_test_case_coverage_lock_test",
target_under_test = ":test_component_with_test_case_coverage_lock",
Expand Down
41 changes: 41 additions & 0 deletions bazel/rules/rules_score/test/unit_component_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,46 @@ def _component_excludes_feature_req_docs_test_impl(ctx):

component_excludes_feature_req_docs_test = analysistest.make(_component_excludes_feature_req_docs_test_impl)

def _component_direct_asr_test_impl(ctx):
"""Test that a component whose component_requirements trace straight to
Assumed System Requirements -- with no feature_requirements layer -- can
list the assumed_system_requirements target in `requirements`, and that its
.lobster file reaches the generated lobster config.

Regression test: the rule's `requirements` attribute used to only accept
[ComponentRequirementsInfo] / [FeatureRequirementsInfo], so passing an
assumed_system_requirements target failed analysis with "does not have
mandatory providers" even though the implementation already handled
AssumedSystemRequirementsInfo. Without the ASR .lobster in the config,
lobster-trace reports "unknown tracing target req <pkg>.<AssumedSystemReq>".
"""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

asserts.true(
env,
ComponentInfo in target_under_test,
"Component tracing directly to ASRs should provide ComponentInfo",
)

# The ASR .lobster must be wired into the component's lobster pipeline as an
# upstream source, otherwise derived_from references cannot be resolved.
input_basenames = []
for action in analysistest.target_actions(env):
for f in action.inputs.to_list():
input_basenames.append(f.basename)

asserts.true(
env,
"asr_trlc.lobster" in input_basenames,
"The assumed_system_requirements .lobster file should feed the " +
"component's lobster actions (inputs found: %s)" % input_basenames,
)

return analysistest.end(env)

component_direct_asr_test = analysistest.make(_component_direct_asr_test_impl)

# ============================================================================
# Test Case Coverage Lock Tests
# ============================================================================
Expand Down Expand Up @@ -338,6 +378,7 @@ def unit_component_test_suite(name):
":component_provider_test",
":component_sphinx_sources_test",
":component_excludes_feature_req_docs_test",
":component_direct_asr_test",
":component_test_case_coverage_lock_test",
":component_requirements_transitive_test",
":test_case_coverage_lock_check_action_release_test",
Expand Down
Loading