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
49 changes: 47 additions & 2 deletions bazel/rules/rules_score/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -622,25 +622,70 @@ dependable_element(

# Minimal dependable element used as a dependency target to test
# the deps attribute of dependable_element (i.e. SEooC depending on another SEooC).
# Composed of a single component/unit pair so it satisfies the
# non-empty-composition validation (see check_non_empty_composition).
unit(
name = "dep_unit",
testonly = True,
scope = ["//:mock_lib1"],
tests = [],
unit_design = [":test_unit_design"],
implementation = [":mock_lib1"],
)

component(
name = "dep_component",
testonly = True,
components = [":dep_unit"],
requirements = [
":comp_req",
":feat_req",
],
tests = [],
)

dependable_element(
name = "dep_seooc_lib",
architectural_design = [":arch_design_dep"],
assumptions_of_use = [":aous"],
components = [],
components = [":dep_component"],
dependability_analysis = [":dependability_analysis_target"],
integrity_level = "B",
maturity = "development",
requirements = [":feat_req"],
tests = [],
deps = [],
)

unit(
name = "seooc_test_unit",
testonly = True,
scope = ["//:mock_lib1"],
tests = [],
unit_design = [":test_unit_design"],
implementation = [":mock_lib1"],
)

component(
name = "seooc_test_component",
testonly = True,
components = [":seooc_test_unit"],
requirements = [
":comp_req",
":feat_req",
],
tests = [],
)

# maturity = "development": same rationale as dep_seooc_lib above.
dependable_element(
name = "seooc_test_lib",
architectural_design = [":arch_design"],
assumptions_of_use = [":aous"],
components = [],
components = [":seooc_test_component"],
dependability_analysis = [":dependability_analysis_target"],
integrity_level = "B",
maturity = "development",
requirements = [":feat_req"],
tests = [],
deps = [":dep_seooc_lib"], # dependency to other seoocs/score_components
Expand Down
6 changes: 5 additions & 1 deletion bazel/rules/rules_score/test/fixtures/dep_seooc_lib.puml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

@startuml dep_seooc_lib

package "Dependency SEooC Library" as dep_seooc_lib <<SEooC>>
package "Dependency SEooC Library" as dep_seooc_lib <<SEooC>> {
component "Dep Component" as dep_component <<component>> {
component "Dep Unit" as dep_unit <<unit>>
}
}

@enduml
6 changes: 5 additions & 1 deletion bazel/rules/rules_score/test/fixtures/seooc_test_lib.puml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

@startuml seooc_test_lib

package "SEooC Test Library" as seooc_test_lib <<SEooC>>
package "SEooC Test Library" as seooc_test_lib <<SEooC>> {
component "SEooC Test Component" as seooc_test_component <<component>> {
component "SEooC Test Unit" as seooc_test_unit <<unit>>
}
}

@enduml
10 changes: 10 additions & 0 deletions validation/core/docs/requirements/tool_requirements.trlc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ section "Tool Requirements" {
satisfied_by = Verifier
}

ToolQualification.ToolRequirement BazelComponentNonEmptyComposition {
description = '''The validator shall report an error when a
Bazel `dependable_element` or `component` target decomposes
into zero nested `component` or `unit` targets, even when the
corresponding PlantUML entity likewise shows no nested
elements.'''
derived_from = [UseCases.Validate_Architecture_Specification_Documents]
satisfied_by = Verifier
}

}

section "Component Sequence Validator" {
Expand Down
21 changes: 21 additions & 0 deletions validation/core/docs/specifications/bazel_component.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,25 @@ entity defined in the same component diagram. An entity referencing an
undefined parent is rejected with a `[Design]` error naming the missing
parent ID.

### Non-Empty Composition

Every Bazel `dependable_element` and `component` target must decompose into
at least one nested `component` or `unit`. A target with an empty
`components` attribute (and, for components, no nested `unit`) is reported
even if the PlantUML diagram agrees and shows the same element as empty --
the set-difference checks above only compare presence between Bazel and
PlantUML, so a childless entry that matches on both sides would otherwise go
unnoticed.
*(Requirement: {requirement:downstream-ref}`Tools.BazelComponentNonEmptyComposition`)*

```starlark
# Flagged: component_example has no nested unit() or component().
component(
name = "component_example",
components = [],
)
```

## Failure Cases

| Failure case | Validation rule |
Expand All @@ -141,6 +160,8 @@ parent ID.
| Duplicate Bazel entity key (same name/parent from different labels) | Duplicate Entity Detection |
| Duplicate PlantUML entity ID (case-insensitive collision) | Duplicate Entity Detection |
| PlantUML entity references an undefined parent | Parent Reference Validity |
| Empty dependable element in Bazel build graph | Non-Empty Composition |
| Empty component in Bazel build graph | Non-Empty Composition |

## PlantUML Stereotype Reference

Expand Down
1 change: 1 addition & 0 deletions validation/core/integration_test/bazel_component/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ filegroup(
"//validation/core/integration_test/bazel_component/negative_duplicate_component_key:case_data",
"//validation/core/integration_test/bazel_component/negative_duplicate_dependable_element_key:case_data",
"//validation/core/integration_test/bazel_component/negative_duplicate_unit_key:case_data",
"//validation/core/integration_test/bazel_component/negative_empty_component:case_data",
"//validation/core/integration_test/bazel_component/negative_empty_target_name_label:case_data",
"//validation/core/integration_test/bazel_component/negative_extra_component:case_data",
"//validation/core/integration_test/bazel_component/negative_extra_unit:case_data",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,8 @@ fn negative_duplicate_component_key_suite_case() {
fn negative_empty_target_name_label_suite_case() {
assert_case("negative_empty_target_name_label");
}

#[test]
fn negative_empty_component_suite_case() {
assert_case("negative_empty_component");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

load("//bazel/rules/rules_score:rules_score.bzl", "architectural_design")
load("//validation/core/integration_test:puml_fixture.bzl", "provider_fbs_fixture_bundle")

architectural_design(
name = "design",
static = ["component_diagram.puml"],
visibility = ["//visibility:private"],
)

provider_fbs_fixture_bundle(
name = "fbs",
visibility = ["//visibility:public"],
deps = [":design"],
)

filegroup(
name = "case_data",
srcs = [
"architecture.json",
"expected.yaml",
":fbs",
],
visibility = ["//visibility:public"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"components": {
"safety_software_seooc_example": {
"units": [],
"components": [
"@//bazel/rules/rules_score/examples/seooc:component_example"
]
},
"@//bazel/rules/rules_score/examples/seooc:component_example": {
"units": [],
"components": []
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
' *******************************************************************************
' Copyright (c) 2026 Contributors to the Eclipse Foundation
'
' See the NOTICE file(s) distributed with this work for additional
' information regarding copyright ownership.
'
' This program and the accompanying materials are made available under the
' terms of the Apache License Version 2.0 which is available at
' https://www.apache.org/licenses/LICENSE-2.0
'
' SPDX-License-Identifier: Apache-2.0
' *******************************************************************************

@startuml component_diagram

package "Sample Seooc" as safety_software_seooc_example <<SEooC>> {
component "Component Example" as component_example <<component>> {
}
}

@enduml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
should_pass: false
error_contains:
- "Empty component in Bazel build graph"
- 'Alias : "component_example"'
Loading
Loading