Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[uss_qualifier] Make skipped actions first-class actions in report #278

Merged
merged 5 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
60 changes: 44 additions & 16 deletions monitoring/uss_qualifier/reports/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,9 +362,14 @@ class TestSuiteActionReport(ImplicitDict):
action_generator: Optional[ActionGeneratorReport]
"""If this action was an action generator, this field will hold its report"""

skipped_action: Optional[SkippedActionReport]
"""If this action was skipped, this field will hold its report"""

def get_applicable_report(self) -> Tuple[bool, bool, bool]:
"""Determine which type of report is applicable for this action.

Note that skipped_action is applicable if none of the other return values are true.

Returns:
* Whether test_suite is applicable
* Whether test_scenario is applicable
Expand All @@ -375,15 +380,21 @@ def get_applicable_report(self) -> Tuple[bool, bool, bool]:
action_generator = (
"action_generator" in self and self.action_generator is not None
)
skipped_action = "skipped_action" in self and self.skipped_action is not None
if (
sum(
1 if case else 0
for case in [test_suite, test_scenario, action_generator]
for case in [
test_suite,
test_scenario,
action_generator,
skipped_action,
]
)
!= 1
):
raise ValueError(
"Exactly one of `test_suite`, `test_scenario`, or `action_generator` must be populated"
"Exactly one of `test_suite`, `test_scenario`, `action_generator`, or `skipped_action` must be populated"
)
return test_suite, test_scenario, action_generator

Expand All @@ -392,6 +403,7 @@ def _conditional(
test_suite_func: Union[Callable[[TestSuiteReport], Any], Callable[[Any], Any]],
test_scenario_func: Optional[Callable[[TestScenarioReport], Any]] = None,
action_generator_func: Optional[Callable[[ActionGeneratorReport], Any]] = None,
skipped_action_func: Optional[Callable[[SkippedActionReport], Any]] = None,
) -> Any:
test_suite, test_scenario, action_generator = self.get_applicable_report()
if test_suite:
Expand All @@ -406,11 +418,10 @@ def _conditional(
return action_generator_func(self.action_generator)
else:
return test_suite_func(self.action_generator)

# This line should not be possible to reach
raise RuntimeError(
"Case selection logic failed for TestSuiteActionReport; none of test_suite, test_scenario, nor action_generator were populated"
)
if skipped_action_func is not None:
return skipped_action_func(self.skipped_action)
else:
return test_suite_func(self.skipped_action)

def successful(self) -> bool:
return self._conditional(lambda report: report.successful)
Expand All @@ -435,9 +446,7 @@ def query_passed_checks(
report = self.action_generator
prefix = "action_generator"
else:
raise RuntimeError(
"Case selection logic failed for TestSuiteActionReport; none of test_suite, test_scenario, nor action_generator were populated"
)
return

for path, pc in report.query_passed_checks(participant_id):
yield f"{prefix}.{path}", pc
Expand All @@ -456,9 +465,7 @@ def query_failed_checks(
report = self.action_generator
prefix = "action_generator"
else:
raise RuntimeError(
"Case selection logic failed for TestSuiteActionReport; none of test_suite, test_scenario, nor action_generator were populated"
)
return

for path, fc in report.query_failed_checks(participant_id):
yield f"{prefix}.{path}", fc
Expand Down Expand Up @@ -621,6 +628,30 @@ class SkippedActionReport(ImplicitDict):
declaration: TestSuiteActionDeclaration
"""Full declaration of the action that was skipped."""

@property
def successful(self) -> bool:
return True

def has_critical_problem(self) -> bool:
return False

def all_participants(self) -> Set[ParticipantID]:
return set()

def queries(self) -> List[fetch.Query]:
return []

def participant_ids(self) -> Set[ParticipantID]:
return set()

@property
def start_time(self) -> Optional[StringBasedDateTime]:
return self.timestamp

@property
def end_time(self) -> Optional[StringBasedDateTime]:
return self.timestamp


class TestSuiteReport(ImplicitDict):
name: str
Expand All @@ -638,9 +669,6 @@ class TestSuiteReport(ImplicitDict):
actions: List[TestSuiteActionReport]
"""Reports from test scenarios and test suites comprising the test suite for this report, in order of execution."""

skipped_actions: List[SkippedActionReport]
"""Reports for actions configured but not executed."""

end_time: Optional[StringBasedDateTime]
"""Time at which the test suite completed"""

Expand Down
10 changes: 1 addition & 9 deletions monitoring/uss_qualifier/reports/sequence_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,12 +497,6 @@ def _compute_action_node(report: TestSuiteActionReport, indexer: Indexer) -> Act
)
elif is_test_suite:
children = [_compute_action_node(a, indexer) for a in report.test_suite.actions]
for skipped_action in report.test_suite.skipped_actions:
i = 0
for i, a in enumerate(report.test_suite.actions):
if a.start_time.datetime > skipped_action.timestamp.datetime:
break
children.insert(i, _skipped_action_of(skipped_action))
return ActionNode(
name=report.test_suite.name,
node_type=ActionNodeType.Suite,
Expand All @@ -521,9 +515,7 @@ def _compute_action_node(report: TestSuiteActionReport, indexer: Indexer) -> Act
],
)
else:
raise ValueError(
"Invalid TestSuiteActionReport; doesn't specify scenario, suite, or action generator"
)
return _skipped_action_of(report.skipped_action)


def _compute_overview_rows(node: ActionNode) -> Iterator[OverviewRow]:
Expand Down
2 changes: 1 addition & 1 deletion monitoring/uss_qualifier/reports/tested_requirements.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ def _populate_breakdown_with_action_report(
breakdown, subaction, participant_id, req_set
)
else:
raise ValueError(f"Unsupported test suite report type")
pass # Skipped action


def _populate_breakdown_with_scenario_report(
Expand Down
17 changes: 6 additions & 11 deletions monitoring/uss_qualifier/reports/validation/report_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,7 @@ def _validate_action_no_skipped_actions(
if test_scenario:
success = True
elif test_suite:
if (
"skipped_actions" not in report.test_suite
or not report.test_suite.skipped_actions
):
success = True
else:
success = False
for sa in report.test_suite.skipped_actions:
logger.error(
f"No skipped actions not achieved because {context}.test_suite had a skipped action for action index {sa.action_declaration_index}: {sa.reason}"
)
success = True
for i, a in enumerate(report.test_suite.actions):
success = success and _validate_action_no_skipped_actions(
a, JSONAddress(context + f".test_suite.actions[{i}]")
Expand All @@ -76,6 +66,11 @@ def _validate_action_no_skipped_actions(
success = success and _validate_action_no_skipped_actions(
a, JSONAddress(context + f".action_generator.actions[{i}]")
)
else:
logger.error(
f"No skipped actions not achieved because {context}.test_suite had a skipped action for action index {report.skipped_action.action_declaration_index}: {report.skipped_action.reason}"
)
success = False
return success


Expand Down
19 changes: 9 additions & 10 deletions monitoring/uss_qualifier/suites/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ class TestSuite(object):
definition: TestSuiteDefinition
documentation_url: str
local_resources: Dict[ResourceID, ResourceType]
actions: List[TestSuiteAction]
skipped_actions: List[SkippedActionReport]
actions: List[Union[TestSuiteAction, SkippedActionReport]]

def __init__(
self,
Expand Down Expand Up @@ -204,8 +203,7 @@ def __init__(
raise ValueError(
f'Test suite "{self.definition.name}" expected resource {resource_id} to be {resource_type}, but instead it was provided {fullname(self.local_resources[resource_id].__class__)}'
)
actions: List[TestSuiteAction] = []
skipped_actions: List[SkippedActionReport] = []
actions: List[Union[TestSuiteAction, SkippedActionReport]] = []
for a, action_dec in enumerate(self.definition.actions):
try:
actions.append(
Expand All @@ -215,7 +213,7 @@ def __init__(
logger.warning(
f"Skipping action {a} ({action_dec.get_action_type()} {action_dec.get_child_type()}) because {str(e)}"
)
skipped_actions.append(
actions.append(
SkippedActionReport(
timestamp=StringBasedDateTime(arrow.utcnow().datetime),
reason=str(e),
Expand All @@ -224,7 +222,6 @@ def __init__(
)
)
self.actions = actions
self.skipped_actions = skipped_actions

def _make_report_evaluation_action(
self, report: TestSuiteReport
Expand Down Expand Up @@ -258,11 +255,10 @@ def run(self) -> TestSuiteReport:
documentation_url=self.documentation_url,
start_time=StringBasedDateTime(datetime.utcnow()),
actions=[],
skipped_actions=self.skipped_actions,
capability_evaluations=[],
)

def actions() -> Iterator[TestSuiteAction]:
def actions() -> Iterator[Union[TestSuiteAction, SkippedActionReport]]:
for a in self.actions:
yield a
# Execute report evaluation scenario as last action if specified, otherwise break loop
Expand Down Expand Up @@ -303,12 +299,15 @@ def actions() -> Iterator[TestSuiteAction]:


def _run_actions(
actions: Iterator[TestSuiteAction],
actions: Iterator[Union[TestSuiteAction, SkippedActionReport]],
report: Union[TestSuiteReport, ActionGeneratorReport],
) -> None:
success = True
for a, action in enumerate(actions):
action_report = action.run()
if isinstance(action, SkippedActionReport):
action_report = TestSuiteActionReport(skipped_action=action)
else:
action_report = action.run()
report.actions.append(action_report)
if action_report.has_critical_problem():
success = False
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,56 @@
{
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/reports/report/TestSuiteActionReport.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"description": "monitoring.uss_qualifier.reports.report.TestSuiteActionReport, as defined in monitoring/uss_qualifier/reports/report.py",
"properties": {
"$ref": {
"type": "string",
"description": "Path to content that replaces the $ref"
"description": "Path to content that replaces the $ref",
"type": "string"
},
"test_scenario": {
"action_generator": {
"description": "If this action was an action generator, this field will hold its report",
"oneOf": [
{
"type": "null"
},
{
"$ref": "TestScenarioReport.json"
"$ref": "ActionGeneratorReport.json"
}
],
"description": "If this action was a test scenario, this field will hold its report"
]
},
"action_generator": {
"skipped_action": {
"description": "If this action was skipped, this field will hold its report",
"oneOf": [
{
"type": "null"
},
{
"$ref": "ActionGeneratorReport.json"
"$ref": "SkippedActionReport.json"
}
],
"description": "If this action was an action generator, this field will hold its report"
]
},
"test_scenario": {
"description": "If this action was a test scenario, this field will hold its report",
"oneOf": [
{
"type": "null"
},
{
"$ref": "TestScenarioReport.json"
}
]
},
"test_suite": {
"description": "If this action was a test suite, this field will hold its report",
"oneOf": [
{
"type": "null"
},
{
"$ref": "TestSuiteReport.json"
}
],
"description": "If this action was a test suite, this field will hold its report"
]
}
},
"$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/reports/report/TestSuiteActionReport.json",
"description": "monitoring.uss_qualifier.reports.report.TestSuiteActionReport, as defined in monitoring/uss_qualifier/reports/report.py"
"type": "object"
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@
"description": "Name of this test suite",
"type": "string"
},
"skipped_actions": {
"description": "Reports for actions configured but not executed.",
"items": {
"$ref": "SkippedActionReport.json"
},
"type": "array"
},
"start_time": {
"description": "Time at which the test suite started",
"format": "date-time",
Expand All @@ -63,7 +56,6 @@
"capability_evaluations",
"documentation_url",
"name",
"skipped_actions",
"start_time",
"suite_type"
],
Expand Down
Loading