Skip to content

Commit

Permalink
[uss_qualifier] Use iterators with action generators (#268)
Browse files Browse the repository at this point in the history
Use iterators with action generators
  • Loading branch information
BenjaminPelletier authored Oct 20, 2023
1 parent bb7a2c7 commit 3e73874
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 119 deletions.
11 changes: 7 additions & 4 deletions monitoring/uss_qualifier/action_generators/action_generator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations
from abc import ABC, abstractmethod
import inspect
from typing import Generic, Dict, Optional, TypeVar, List, Type
from typing import Generic, Dict, Optional, TypeVar, List, Type, Iterator, Any

from implicitdict import ImplicitDict
from monitoring import uss_qualifier as uss_qualifier_module
Expand All @@ -17,7 +17,6 @@
from monitoring.uss_qualifier.action_generators.documentation.definitions import (
PotentialGeneratedAction,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.definitions import ResourceID
from monitoring.uss_qualifier.resources.resource import ResourceType

Expand All @@ -43,8 +42,12 @@ def __init__(
)

@abstractmethod
def run_next_action(self) -> Optional[TestSuiteActionReport]:
"""Run the next action from the generator, or else return None if there are no more actions"""
def actions(self) -> Iterator[Any]:
"""Generate the appropriate actions.
Note that the iterator must return instances of monitoring.uss_qualifier.suites.suite.TestSuiteAction; this is
not included in type hints to avoid a circular reference.
"""
raise NotImplementedError(
"A concrete action generator must implement `actions` method"
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional
from typing import Dict, List, Iterator

from implicitdict import ImplicitDict

Expand All @@ -9,7 +9,6 @@
from monitoring.uss_qualifier.action_generators.documentation.documentation import (
list_potential_actions_for_action_declaration,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.astm.f3411 import (
DSSInstanceResource,
DSSInstancesResource,
Expand All @@ -23,7 +22,6 @@
from monitoring.uss_qualifier.suites.suite import (
ActionGenerator,
TestSuiteAction,
ReactionToFailure,
)


Expand All @@ -41,7 +39,6 @@ class ForEachDSSSpecification(ImplicitDict):
class ForEachDSS(ActionGenerator[ForEachDSSSpecification]):
_actions: List[TestSuiteAction]
_current_action: int
_failure_reaction: ReactionToFailure

@classmethod
def list_potential_actions(
Expand Down Expand Up @@ -86,15 +83,7 @@ def __init__(
)

self._current_action = 0
self._failure_reaction = specification.action_to_repeat.on_failure

def run_next_action(self) -> Optional[TestSuiteActionReport]:
if self._current_action < len(self._actions):
report = self._actions[self._current_action].run()
self._current_action += 1
if not report.successful():
if self._failure_reaction == ReactionToFailure.Abort:
self._current_action = len(self._actions)
return report
else:
return None
def actions(self) -> Iterator[TestSuiteAction]:
for a in self._actions:
yield a
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional
from typing import Dict, List, Iterator

from implicitdict import ImplicitDict

Expand All @@ -9,7 +9,6 @@
from monitoring.uss_qualifier.action_generators.documentation.documentation import (
list_potential_actions_for_action_declaration,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.astm.f3548.v21 import (
DSSInstancesResource,
DSSInstanceResource,
Expand All @@ -24,7 +23,6 @@
from monitoring.uss_qualifier.suites.suite import (
ActionGenerator,
TestSuiteAction,
ReactionToFailure,
)


Expand All @@ -42,7 +40,6 @@ class ForEachDSSSpecification(ImplicitDict):
class ForEachDSS(ActionGenerator[ForEachDSSSpecification]):
_actions: List[TestSuiteAction]
_current_action: int
_failure_reaction: ReactionToFailure

@classmethod
def list_potential_actions(
Expand Down Expand Up @@ -87,15 +84,7 @@ def __init__(
)

self._current_action = 0
self._failure_reaction = specification.action_to_repeat.on_failure

def run_next_action(self) -> Optional[TestSuiteActionReport]:
if self._current_action < len(self._actions):
report = self._actions[self._current_action].run()
self._current_action += 1
if not report.successful():
if self._failure_reaction == ReactionToFailure.Abort:
self._current_action = len(self._actions)
return report
else:
return None

def actions(self) -> Iterator[TestSuiteAction]:
for a in self._actions:
yield a
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional
from typing import Dict, List, Iterator, Optional

from implicitdict import ImplicitDict

Expand All @@ -9,7 +9,6 @@
from monitoring.uss_qualifier.action_generators.documentation.documentation import (
list_potential_actions_for_action_declaration,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.definitions import ResourceID
from monitoring.uss_qualifier.resources.flight_planning import FlightPlannersResource
from monitoring.uss_qualifier.resources.flight_planning.flight_planners import (
Expand All @@ -27,7 +26,6 @@
from monitoring.uss_qualifier.suites.suite import (
ActionGenerator,
TestSuiteAction,
ReactionToFailure,
)


Expand All @@ -50,7 +48,6 @@ class FlightPlannerCombinations(
):
_actions: List[TestSuiteAction]
_current_action: int
_failure_reaction: ReactionToFailure

@classmethod
def list_potential_actions(
Expand Down Expand Up @@ -128,15 +125,7 @@ def __init__(
break

self._current_action = 0
self._failure_reaction = specification.action_to_repeat.on_failure

def run_next_action(self) -> Optional[TestSuiteActionReport]:
if self._current_action < len(self._actions):
report = self._actions[self._current_action].run()
self._current_action += 1
if not report.successful():
if self._failure_reaction == ReactionToFailure.Abort:
self._current_action = len(self._actions)
return report
else:
return None

def actions(self) -> Iterator[TestSuiteAction]:
for a in self._actions:
yield a
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional
from typing import Dict, List, Iterator

from implicitdict import ImplicitDict
from monitoring.monitorlib.inspection import fullname
Expand All @@ -9,7 +9,6 @@
from monitoring.uss_qualifier.action_generators.documentation.documentation import (
list_potential_actions_for_action_declaration,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.definitions import ResourceID
from monitoring.uss_qualifier.resources.interuss.mock_uss.client import MockUSSsResource
from monitoring.uss_qualifier.resources.interuss.mock_uss.locality import (
Expand Down Expand Up @@ -50,7 +49,6 @@ class WithLocality(ActionGenerator[WithLocalitySpecification]):

_actions: List[TestSuiteAction]
_current_action: int
_failure_reaction: ReactionToFailure

@classmethod
def list_potential_actions(
Expand Down Expand Up @@ -137,16 +135,6 @@ def __init__(
]
self._current_action = 0

def run_next_action(self) -> Optional[TestSuiteActionReport]:
from loguru import logger

logger.debug(f"run_next_action with current action {self._current_action}")
if self._current_action < len(self._actions):
report = self._actions[self._current_action].run()
if not report.successful() and self._current_action == 0:
self._current_action = len(self._actions)
else:
self._current_action += 1
return report
else:
return None
def actions(self) -> Iterator[TestSuiteAction]:
for a in self._actions:
yield a
19 changes: 4 additions & 15 deletions monitoring/uss_qualifier/action_generators/repetition/repeat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, List, Optional
from typing import Dict, List, Iterator

from implicitdict import ImplicitDict
from monitoring.uss_qualifier.action_generators.documentation.definitions import (
Expand All @@ -7,15 +7,13 @@
from monitoring.uss_qualifier.action_generators.documentation.documentation import (
list_potential_actions_for_action_declaration,
)
from monitoring.uss_qualifier.reports.report import TestSuiteActionReport
from monitoring.uss_qualifier.resources.definitions import ResourceID
from monitoring.uss_qualifier.resources.resource import ResourceType

from monitoring.uss_qualifier.suites.definitions import TestSuiteActionDeclaration
from monitoring.uss_qualifier.suites.suite import (
ActionGenerator,
TestSuiteAction,
ReactionToFailure,
)


Expand All @@ -30,7 +28,6 @@ class RepeatSpecification(ImplicitDict):
class Repeat(ActionGenerator[RepeatSpecification]):
_actions: List[TestSuiteAction]
_current_action: int
_failure_reaction: ReactionToFailure

@classmethod
def list_potential_actions(
Expand All @@ -50,15 +47,7 @@ def __init__(
for _ in range(specification.times_to_repeat)
]
self._current_action = 0
self._failure_reaction = specification.action_to_repeat.on_failure

def run_next_action(self) -> Optional[TestSuiteActionReport]:
if self._current_action < len(self._actions):
report = self._actions[self._current_action].run()
self._current_action += 1
if not report.successful():
if self._failure_reaction == ReactionToFailure.Abort:
self._current_action = len(self._actions)
return report
else:
return None
def actions(self) -> Iterator[TestSuiteAction]:
for a in self._actions:
yield a
74 changes: 37 additions & 37 deletions monitoring/uss_qualifier/suites/suite.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
from datetime import datetime
import json
from typing import Dict, List, Optional
from typing import Dict, List, Optional, Union, Callable, Iterator

import arrow

Expand Down Expand Up @@ -145,15 +145,9 @@ def _run_action_generator(self) -> ActionGeneratorReport:
generator_type=self.action_generator.definition.generator_type,
start_time=StringBasedDateTime(arrow.utcnow()),
)
while True:
action_report = self.action_generator.run_next_action()
if action_report is None:
break
report.actions.append(action_report)
if action_report.has_critical_problem():
break
report.end_time = StringBasedDateTime(arrow.utcnow())
report.successful = all(a.successful() for a in report.actions)

_run_actions(self.action_generator.actions(), report)

return report


Expand Down Expand Up @@ -267,34 +261,15 @@ def run(self) -> TestSuiteReport:
skipped_actions=self.skipped_actions,
capability_evaluations=[],
)
success = True
for a in range(len(self.actions) + 1):
if a == len(self.actions):
# Execute report evaluation scenario as last action if specified, otherwise break loop
if self.definition.has_field_with_value("report_evaluation_scenario"):
action = self._make_report_evaluation_action(report)
else:
break
else:
action = self.actions[a]

action_report = action.run()
report.actions.append(action_report)
if action_report.has_critical_problem():
success = False
break
if not action_report.successful():
success = False
if action.declaration.on_failure == ReactionToFailure.Abort:
break
elif action.declaration.on_failure == ReactionToFailure.Continue:
continue
else:
raise ValueError(
f"Action {a} of test suite {self.definition.name} indicate an unrecognized reaction to failure: {str(action.declaration.on_failure)}"
)
report.successful = success
report.end_time = StringBasedDateTime(datetime.utcnow())
def actions() -> Iterator[TestSuiteAction]:
for a in self.actions:
yield a
# Execute report evaluation scenario as last action if specified, otherwise break loop
if self.definition.has_field_with_value("report_evaluation_scenario"):
yield self._make_report_evaluation_action(report)

_run_actions(actions(), report)

# Evaluate participants' capabilities
if (
Expand Down Expand Up @@ -325,3 +300,28 @@ def run(self) -> TestSuiteReport:
)

return report


def _run_actions(
actions: Iterator[TestSuiteAction],
report: Union[TestSuiteReport, ActionGeneratorReport],
) -> None:
success = True
for a, action in enumerate(actions):
action_report = action.run()
report.actions.append(action_report)
if action_report.has_critical_problem():
success = False
break
if not action_report.successful():
success = False
if action.declaration.on_failure == ReactionToFailure.Abort:
break
elif action.declaration.on_failure == ReactionToFailure.Continue:
continue
else:
raise ValueError(
f"Action {a} indicated an unrecognized reaction to failure: {str(action.declaration.on_failure)}"
)
report.successful = success
report.end_time = StringBasedDateTime(datetime.utcnow())

0 comments on commit 3e73874

Please sign in to comment.