diff --git a/monitoring/uss_qualifier/resources/README.md b/monitoring/uss_qualifier/resources/README.md index e53d100d7a..e3eb1cad78 100644 --- a/monitoring/uss_qualifier/resources/README.md +++ b/monitoring/uss_qualifier/resources/README.md @@ -33,13 +33,13 @@ Resources for a given test configuration are all declared in a single global res 3. Every type of test resource must define how to create an instance of the test resource from an instance of the resource specification. -## Resource modifiers +## Resource-modifying resources -A `ResourceModifier` is a resource that wraps another resource and produces variants of it based on an integer index. This is useful when a test scenario needs multiple unique-but-related instances of a resource (e.g., distinct flights derived from a single base flight). +A `ResourceModifyingResource` is a resource capable of spawning other resources by modifying a template/base resource according to a desired key, such as an index. This is useful when a test scenario needs multiple unique-but-related instances of a resource (e.g., distinct flights derived from a single base flight). -To use a `ResourceModifier`: +To use a `ResourceModifyingResource`: 1. Declare it like any other resource, with its `base_resource` dependency pointing to the resource to be modified. -2. When need, call `adjust(index)` to obtain a modified copy of the base resource. Different `index` values produce different (unique) variants; the same `index` produces equivalent results. +2. When a variant of the base/template resource is needed, call `modify(key)` to obtain a modified copy of the base resource. Different `key` values generally produce different variants; the same `key` should produce equivalent results. -The base resource itself remains available as `base_resource` on the modifier. +The base/template resource itself remains available as `base_resource` on the modifier. diff --git a/monitoring/uss_qualifier/resources/dev/__init__.py b/monitoring/uss_qualifier/resources/dev/__init__.py index d666e7f23e..7b572b03de 100644 --- a/monitoring/uss_qualifier/resources/dev/__init__.py +++ b/monitoring/uss_qualifier/resources/dev/__init__.py @@ -1,4 +1,6 @@ from .noop import NoOpResource as NoOpResource from .test_exclusions import TestExclusionsResource as TestExclusionsResource -from .test_modifier import TestModifierModifierResource as TestModifierModifierResource -from .test_modifier import TestModifierResource as TestModifierResource +from .test_modifier import ( + NumberGeneratorModifierResource as NumberGeneratorModifierResource, +) +from .test_modifier import NumberGeneratorResource as NumberGeneratorResource diff --git a/monitoring/uss_qualifier/resources/dev/test_modifier.py b/monitoring/uss_qualifier/resources/dev/test_modifier.py index ba0e53fa16..0fdbd405e1 100644 --- a/monitoring/uss_qualifier/resources/dev/test_modifier.py +++ b/monitoring/uss_qualifier/resources/dev/test_modifier.py @@ -1,20 +1,23 @@ from implicitdict import ImplicitDict -from monitoring.uss_qualifier.resources.resource import Resource, ResourceModifier +from monitoring.uss_qualifier.resources.resource import ( + Resource, + ResourceModifyingResource, +) -class TestModifierSpecification(ImplicitDict): +class NumberGeneratorSpecification(ImplicitDict): base_id: int -class TestModifierResource(Resource[TestModifierSpecification]): - """TestModifierResource is a simple resource returing 10 number, starting from base_id. Used for unit tests.""" +class NumberGeneratorResource(Resource[NumberGeneratorSpecification]): + """A simple resource returing 10 numbers, starting from base_id. Used for unit tests.""" - _spec: TestModifierSpecification + _spec: NumberGeneratorSpecification def __init__( self, - specification: TestModifierSpecification, + specification: NumberGeneratorSpecification, resource_origin: str, ): super().__init__(specification, resource_origin) @@ -24,22 +27,24 @@ def build_ids(self) -> list[int]: return list(range(self._spec.base_id, self._spec.base_id + 10)) -class TestModifierModifierSpecification(ImplicitDict): +class NumberGeneratorModifierSpecification(ImplicitDict): shift_interval: int -class TestModifierModifierResource( - ResourceModifier[TestModifierModifierSpecification, TestModifierResource] +class NumberGeneratorModifierResource( + ResourceModifyingResource[ + NumberGeneratorModifierSpecification, int, NumberGeneratorResource + ] ): - """Modifier for a TestModifierResource. Used for unit tests.""" + """Modifier for a NumberGeneratorResource. Used for unit tests.""" - def adjust(self, index: int) -> TestModifierResource: + def provide_resource_for(self, key: int) -> NumberGeneratorResource: # 'Clone' the resource with new specs - return TestModifierResource( - TestModifierSpecification( + return NumberGeneratorResource( + NumberGeneratorSpecification( base_id=self.base_resource._spec.base_id - + self._spec.shift_interval * index, + + self._spec.shift_interval * key, ), - resource_origin=self.base_resource.resource_origin, + resource_origin=self._modified_resource_origin(str(key)), ) diff --git a/monitoring/uss_qualifier/resources/resource.py b/monitoring/uss_qualifier/resources/resource.py index 5089c5a2ad..6d487b02bc 100644 --- a/monitoring/uss_qualifier/resources/resource.py +++ b/monitoring/uss_qualifier/resources/resource.py @@ -41,15 +41,36 @@ def is_type(self, resource_type: str) -> bool: ResourceType = TypeVar("ResourceType", bound=Resource) +SpawnKeyType = TypeVar("SpawnKeyType") -class ResourceModifier[SpecificationType: ImplicitDict, ResourceType]( - Resource[SpecificationType], ABC -): - """A specifc type of resources that can return adjusted an resource that shall unique based on a specifc 'index'. - The underlying resource shall be a dependency named 'base_resource'. +class ResourceProvidingResource[ + SpecificationType: ImplicitDict, + SpawnKeyType, + ResourceType: Resource, +](Resource[SpecificationType], ABC): + """Resource capable of spawning ResourceType resources according to a desired key, such as an index.""" - Concrete subclass must implement 'adjust' as needed. + @abstractmethod + def provide_resource_for(self, key: SpawnKeyType) -> ResourceType: + """Provide a resource corresponding with the provided key.""" + raise NotImplementedError() + + def _provided_resource_origin(self, key_name: str) -> str: + """Method that should generally be used to describe the origin of a resource provided by this resource.""" + return f"Resource for {key_name} provided by {self.resource_origin}" + + +class ResourceModifyingResource[ + SpecificationType: ImplicitDict, + SpawnKeyType, + ResourceType: Resource, +](ResourceProvidingResource[SpecificationType, SpawnKeyType, ResourceType], ABC): + """Resource capable of providing ResourceType resources by modifying a template/base + ResourceType resource according to a desired key, such as an index. + + Useful for deconflicting multiple copies of a resource so many different variants of the same + test can be performed without conflicting with each other. """ _spec: SpecificationType @@ -65,12 +86,17 @@ def __init__( self._spec = specification self.base_resource = base_resource + def _modified_resource_origin(self, modification_name: str) -> str: + """Method that should generally be used to describe the origin of a resource provided by this resource.""" + return f"Modification {modification_name} of {self.base_resource.resource_origin} by {self.resource_origin}" + @abstractmethod - def adjust(self, index: int) -> ResourceType: - """ - Return a new instance of the base resource, modified to be unique based on 'index' value. + def provide_resource_for(self, key: SpawnKeyType) -> ResourceType: + """Provide a resource formed by modifying the template/base resource according to the provided key. + + Different `key` values generally produce different variants; the same `key` should produce equivalent results. """ - pass + raise NotImplementedError() class MissingResourceError(ValueError): diff --git a/monitoring/uss_qualifier/resources/resources_test.py b/monitoring/uss_qualifier/resources/resources_test.py index c80bff6cbc..cb7a8b486a 100644 --- a/monitoring/uss_qualifier/resources/resources_test.py +++ b/monitoring/uss_qualifier/resources/resources_test.py @@ -5,72 +5,74 @@ ResourceID, ) from monitoring.uss_qualifier.resources.dev.test_modifier import ( - TestModifierModifierSpecification, - TestModifierSpecification, + NumberGeneratorModifierSpecification, + NumberGeneratorSpecification, ) from monitoring.uss_qualifier.resources.resource import create_resources -class TestResourceModifier(unittest.TestCase): - def _build_test_modifier_declaration( +class TestModifierResource(unittest.TestCase): + def _build_number_generator_declaration( self, base_id ) -> dict[ResourceID, ResourceDeclaration]: return { - "test": ResourceDeclaration( - resource_type="resources.dev.TestModifierResource", - specification=TestModifierSpecification(base_id=base_id), + "number_generator": ResourceDeclaration( + resource_type="resources.dev.NumberGeneratorResource", + specification=NumberGeneratorSpecification(base_id=base_id), ) } - def _build_test_modifier_modifier_declaration( + def _build_modifier_declaration( self, base_id, shift_interval ) -> dict[ResourceID, ResourceDeclaration]: return { - "test": self._build_test_modifier_declaration(base_id)["test"], - "test_modifier": ResourceDeclaration( - resource_type="resources.dev.TestModifierModifierResource", - specification=TestModifierModifierSpecification( + "number_generator": self._build_number_generator_declaration(base_id)[ + "number_generator" + ], + "modifier": ResourceDeclaration( + resource_type="resources.dev.NumberGeneratorModifierResource", + specification=NumberGeneratorModifierSpecification( shift_interval=shift_interval ), dependencies={ - "base_resource": "test", + "base_resource": "number_generator", }, ), } def test_base_resource(self): """Test basic usage of the resource""" - declaration = self._build_test_modifier_declaration(42) + declaration = self._build_number_generator_declaration(42) - resources = create_resources(declaration, "test", True) - assert "test" in resources + resources = create_resources(declaration, "unittest", True) + assert "number_generator" in resources - resource = resources["test"] + resource = resources["number_generator"] assert resource.build_ids() == [42, 43, 44, 45, 46, 47, 48, 49, 50, 51] def test_base_resource_base_id(self): """Test that base id works as expected""" - declaration = self._build_test_modifier_declaration(52) + declaration = self._build_number_generator_declaration(52) - resources = create_resources(declaration, "test", True) - assert "test" in resources + resources = create_resources(declaration, "unittest", True) + assert "number_generator" in resources - resource = resources["test"] + resource = resources["number_generator"] assert resource.build_ids() == [52, 53, 54, 55, 56, 57, 58, 59, 60, 61] def test_modifier_resource(self): - """Test basic usage of the resource modifier""" - declaration = self._build_test_modifier_modifier_declaration(42, 10) + """Test basic usage of the resource modifier resource""" + declaration = self._build_modifier_declaration(42, 10) - resources = create_resources(declaration, "test", True) - assert "test_modifier" in resources + resources = create_resources(declaration, "unittest", True) + assert "modifier" in resources - resource = resources["test_modifier"] + resource = resources["modifier"] - assert resource.adjust(0).build_ids() == [ + assert resource.provide_resource_for(0).build_ids() == [ 42, 43, 44, @@ -82,7 +84,7 @@ def test_modifier_resource(self): 50, 51, ] - assert resource.adjust(1).build_ids() == [ + assert resource.provide_resource_for(1).build_ids() == [ 52, 53, 54, @@ -97,14 +99,14 @@ def test_modifier_resource(self): def test_modifier_resource_shift(self): """Test shift usage of the resource modifier""" - declaration = self._build_test_modifier_modifier_declaration(42, 20) + declaration = self._build_modifier_declaration(42, 20) - resources = create_resources(declaration, "test", True) - assert "test_modifier" in resources + resources = create_resources(declaration, "unittest", True) + assert "modifier" in resources - resource = resources["test_modifier"] + resource = resources["modifier"] - assert resource.adjust(0).build_ids() == [ + assert resource.provide_resource_for(0).build_ids() == [ 42, 43, 44, @@ -116,7 +118,7 @@ def test_modifier_resource_shift(self): 50, 51, ] - assert resource.adjust(1).build_ids() == [ + assert resource.provide_resource_for(1).build_ids() == [ 62, 63, 64, diff --git a/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierModifierSpecification.json b/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorModifierSpecification.json similarity index 66% rename from schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierModifierSpecification.json rename to schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorModifierSpecification.json index 24a9d04c65..a767c59bda 100644 --- a/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierModifierSpecification.json +++ b/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorModifierSpecification.json @@ -1,7 +1,7 @@ { - "$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierModifierSpecification.json", + "$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorModifierSpecification.json", "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "monitoring.uss_qualifier.resources.dev.test_modifier.TestModifierModifierSpecification, as defined in monitoring/uss_qualifier/resources/dev/test_modifier.py", + "description": "monitoring.uss_qualifier.resources.dev.test_modifier.NumberGeneratorModifierSpecification, as defined in monitoring/uss_qualifier/resources/dev/test_modifier.py", "properties": { "$ref": { "description": "Path to content that replaces the $ref", diff --git a/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierSpecification.json b/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorSpecification.json similarity index 67% rename from schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierSpecification.json rename to schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorSpecification.json index 1824bdad7e..b1f66f3b5e 100644 --- a/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierSpecification.json +++ b/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorSpecification.json @@ -1,7 +1,7 @@ { - "$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/TestModifierSpecification.json", + "$id": "https://github.com/interuss/monitoring/blob/main/schemas/monitoring/uss_qualifier/resources/dev/test_modifier/NumberGeneratorSpecification.json", "$schema": "https://json-schema.org/draft/2020-12/schema", - "description": "monitoring.uss_qualifier.resources.dev.test_modifier.TestModifierSpecification, as defined in monitoring/uss_qualifier/resources/dev/test_modifier.py", + "description": "monitoring.uss_qualifier.resources.dev.test_modifier.NumberGeneratorSpecification, as defined in monitoring/uss_qualifier/resources/dev/test_modifier.py", "properties": { "$ref": { "description": "Path to content that replaces the $ref",