Skip to content
Open
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
4 changes: 4 additions & 0 deletions bazel/rules/rules_score/lobster/config/lobster_de.conf.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ requirements "Feature Requirements" {
{FEAT_REQ_SOURCES}
}

requirements "System Requirements" {
{SYSTEM_REQ_SOURCES}
}

requirements "Forwarded AoUs" {
{FORWARDED_AOU_SOURCES}
}
Expand Down
1 change: 1 addition & 0 deletions bazel/rules/rules_score/private/component.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def _component_impl(ctx):
req_lobster_files.append(req_target[ComponentRequirementsInfo].srcs)
if FeatureRequirementsInfo in req_target:
feat_req_lobster_files.append(req_target[FeatureRequirementsInfo].srcs)
feat_req_lobster_files.append(req_target[FeatureRequirementsInfo].system_req_srcs)
if AssumedSystemRequirementsInfo in req_target:
feat_req_lobster_files.append(req_target[AssumedSystemRequirementsInfo].srcs)

Expand Down
8 changes: 7 additions & 1 deletion bazel/rules/rules_score/private/dependable_element.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,11 @@ def _dependable_element_index_impl(ctx):

# Build the DE-level lobster report if feature and component traces exist
feat_req_list = feat_req_lobster_depset.to_list()
system_req_depsets = []
for req_target in ctx.attr.requirements:
if FeatureRequirementsInfo in req_target:
system_req_depsets.append(req_target[FeatureRequirementsInfo].system_req_srcs)
system_req_list = depset(transitive = system_req_depsets).to_list()
comp_req_list = comp_req_lobster_depset.to_list()
comp_test_list = comp_test_lobster_depset.to_list()
comp_arch_list = comp_arch_lobster_depset.to_list()
Expand Down Expand Up @@ -1149,6 +1154,7 @@ def _dependable_element_index_impl(ctx):
output = lobster_config,
substitutions = {
"{FEAT_REQ_SOURCES}": format_lobster_sources(feat_req_list),
"{SYSTEM_REQ_SOURCES}": format_lobster_sources(system_req_list),
"{FORWARDED_AOU_SOURCES}": format_lobster_sources(received_aou_list),
"{COMP_REQ_SOURCES}": format_lobster_sources(comp_req_list),
"{COMP_REQ_TRACE}": comp_req_trace_lines,
Expand All @@ -1161,7 +1167,7 @@ def _dependable_element_index_impl(ctx):
},
)

all_lobster_inputs = feat_req_list + comp_req_list + comp_arch_list + comp_test_list + interface_req_list + fm_list + cm_list + rc_list + received_aou_list
all_lobster_inputs = feat_req_list + system_req_list + comp_req_list + comp_arch_list + comp_test_list + interface_req_list + fm_list + cm_list + rc_list + received_aou_list
lobster_report_file = subrule_lobster_report(all_lobster_inputs, lobster_config)
lobster_html_report = subrule_lobster_html_report(lobster_report_file)

Expand Down
5 changes: 5 additions & 0 deletions bazel/rules/rules_score/private/requirements.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ def _requirements_impl(ctx):
# Build the kind-specific domain provider.
# -------------------------------------------------------------------------
if ctx.attr.req_kind == "feature":
system_req_lobster_depsets = []
for dep in ctx.attr.deps:
if AssumedSystemRequirementsInfo in dep:
system_req_lobster_depsets.append(dep[AssumedSystemRequirementsInfo].srcs)
req_provider = FeatureRequirementsInfo(
srcs = depset([lobster_file]),
system_req_srcs = depset(transitive = system_req_lobster_depsets),
name = ctx.label.name,
)
elif ctx.attr.req_kind == "component":
Expand Down
3 changes: 2 additions & 1 deletion bazel/rules/rules_score/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ UnitInfo = provider(
FeatureRequirementsInfo = provider(
doc = "Provider for feature requirements artifacts.",
fields = {
"srcs": "Depset of .lobster traceability files generated from TRLC requirement sources.",
"srcs": "Depset of .lobster traceability files generated from feature requirement TRLC sources.",
"system_req_srcs": "Depset of .lobster traceability files from system requirement deps (e.g. assumed system requirements). These are included in the dependable_element analysis so that derived_from references in feature requirements resolve correctly.",
"name": "Name of the requirements target.",
},
)
Expand Down
15 changes: 15 additions & 0 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ load(
)
load(
":seooc_test.bzl",
"de_lobster_config_includes_system_req_srcs_test",
"feat_req_system_req_srcs_populated_test",
"seooc_all_sources_relocated_test",
"seooc_artifacts_copied_test",
"seooc_index_file_provider_test",
Expand Down Expand Up @@ -576,6 +578,17 @@ seooc_index_file_provider_test(
target_under_test = ":test_dependable_element_index",
)

# Regression tests: system requirements are propagated via system_req_srcs
feat_req_system_req_srcs_populated_test(
name = "seooc_tests_feat_req_system_req_srcs_populated",
target_under_test = ":feat_req",
)

de_lobster_config_includes_system_req_srcs_test(
name = "seooc_tests_de_lobster_config_includes_system_req_srcs",
target_under_test = ":seooc_test_lib_index",
)

# ============================================================================
# Test Suites
# ============================================================================
Expand Down Expand Up @@ -642,7 +655,9 @@ test_suite(
tests = [
":seooc_tests_all_sources_relocated",
":seooc_tests_artifacts_copied",
":seooc_tests_de_lobster_config_includes_system_req_srcs",
":seooc_tests_dep_links_use_doc_dir",
":seooc_tests_feat_req_system_req_srcs_populated",
":seooc_tests_index_file_provider",
":seooc_tests_index_generation",
":seooc_tests_multi_index_files_exist",
Expand Down
81 changes: 80 additions & 1 deletion bazel/rules/rules_score/test/seooc_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Tests the SEooC (Safety Element out of Context) functionality including:
"""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("@score_tooling//bazel/rules/rules_score:providers.bzl", "SphinxIndexFileInfo", "SphinxModuleInfo", "SphinxNeedsInfo")
load("@score_tooling//bazel/rules/rules_score:providers.bzl", "FeatureRequirementsInfo", "SphinxIndexFileInfo", "SphinxModuleInfo", "SphinxNeedsInfo")

def _seooc_index_generation_test_impl(ctx):
"""Test that dependable_element generates proper index.rst file."""
Expand Down Expand Up @@ -321,3 +321,82 @@ def _seooc_index_file_provider_test_impl(ctx):
seooc_index_file_provider_test = analysistest.make(
impl = _seooc_index_file_provider_test_impl,
)

def _feat_req_system_req_srcs_populated_test_impl(ctx):
"""
Given a feature_requirements target whose deps include an assumed_system_requirements target,
When FeatureRequirementsInfo is inspected,
Then system_req_srcs must be non-empty and contain a .lobster file.
"""
env = analysistest.begin(ctx)
target_under_test = analysistest.target_under_test(env)

asserts.true(
env,
FeatureRequirementsInfo in target_under_test,
"Expected FeatureRequirementsInfo to be provided by feature_requirements target",
)

info = target_under_test[FeatureRequirementsInfo]
system_req_files = info.system_req_srcs.to_list()

asserts.true(
env,
len(system_req_files) > 0,
"Expected system_req_srcs to be non-empty when feature_requirements has assumed_system_requirements deps",
)

lobster_files = [f for f in system_req_files if f.extension == "lobster"]
asserts.true(
env,
len(lobster_files) > 0,
"Expected system_req_srcs to contain at least one .lobster file; got: " + str([f.basename for f in system_req_files]),
)

return analysistest.end(env)

feat_req_system_req_srcs_populated_test = analysistest.make(
impl = _feat_req_system_req_srcs_populated_test_impl,
)

def _de_lobster_config_includes_system_req_srcs_test_impl(ctx):
"""
Given a dependable_element whose feature_requirements deps include assumed_system_requirements,
When the lobster report action is inspected,
Then the system requirement lobster file must appear as an input to that action.
"""
env = analysistest.begin(ctx)

actions = analysistest.target_actions(env)

# Find the lobster report action: it takes de_traceability_config plus all
# lobster source files as inputs, and produces the lobster JSON report.
# Identify it by the presence of de_traceability_config in its inputs.
lobster_report_action = None
for action in actions:
input_basenames = [f.basename for f in action.inputs.to_list()]
if "de_traceability_config" in input_basenames:
lobster_report_action = action
break

asserts.true(
env,
lobster_report_action != None,
"Expected to find the lobster report action (one whose inputs include de_traceability_config)",
)

input_basenames = [f.basename for f in lobster_report_action.inputs.to_list()]
lobster_inputs = [n for n in input_basenames if n.endswith(".lobster")]

# The system requirement lobster file (from the asr_trlc fixture target) must be present
asserts.true(
env,
"asr_trlc.lobster" in lobster_inputs,
"Expected 'asr_trlc.lobster' in lobster report action inputs; got: " + str(lobster_inputs),
)

return analysistest.end(env)

de_lobster_config_includes_system_req_srcs_test = analysistest.make(
impl = _de_lobster_config_includes_system_req_srcs_test_impl,
)
Loading