Created IAC reverse generator
This commit is contained in:
222
tests/property/test_resource_inventory_completeness_prop.py
Normal file
222
tests/property/test_resource_inventory_completeness_prop.py
Normal file
@@ -0,0 +1,222 @@
|
||||
"""Property-based tests for resource inventory completeness.
|
||||
|
||||
**Validates: Requirements 1.2**
|
||||
|
||||
Property 1: Resource inventory completeness
|
||||
For any discovered resource from any on-premises provider (Docker Swarm, Kubernetes,
|
||||
Synology, Harvester, Bare Metal, Windows), the resulting inventory entry SHALL contain
|
||||
non-empty values for resource_type, unique_id, name, provider, platform_category,
|
||||
architecture, and attributes fields.
|
||||
"""
|
||||
|
||||
from hypothesis import given, settings
|
||||
from hypothesis import strategies as st
|
||||
|
||||
from iac_reverse.models import (
|
||||
CpuArchitecture,
|
||||
DiscoveredResource,
|
||||
PlatformCategory,
|
||||
ProviderType,
|
||||
ScanResult,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Hypothesis Strategies
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
provider_type_strategy = st.sampled_from(list(ProviderType))
|
||||
platform_category_strategy = st.sampled_from(list(PlatformCategory))
|
||||
cpu_architecture_strategy = st.sampled_from(list(CpuArchitecture))
|
||||
|
||||
non_empty_text_strategy = st.text(
|
||||
min_size=1,
|
||||
max_size=100,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N", "P", "S")),
|
||||
).filter(lambda s: s.strip() != "")
|
||||
|
||||
resource_type_strategy = st.text(
|
||||
min_size=1,
|
||||
max_size=50,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N"), whitelist_characters="_"),
|
||||
).filter(lambda s: len(s) > 0 and s.strip() != "")
|
||||
|
||||
unique_id_strategy = st.text(
|
||||
min_size=1,
|
||||
max_size=200,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N", "P", "S")),
|
||||
).filter(lambda s: s.strip() != "")
|
||||
|
||||
name_strategy = st.text(
|
||||
min_size=1,
|
||||
max_size=100,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N", "P", "S")),
|
||||
).filter(lambda s: s.strip() != "")
|
||||
|
||||
endpoint_strategy = st.text(
|
||||
min_size=1,
|
||||
max_size=200,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N", "P", "S")),
|
||||
).filter(lambda s: s.strip() != "")
|
||||
|
||||
non_empty_attributes_strategy = st.dictionaries(
|
||||
keys=st.text(
|
||||
min_size=1,
|
||||
max_size=30,
|
||||
alphabet=st.characters(whitelist_categories=("L", "N"), whitelist_characters="_"),
|
||||
),
|
||||
values=st.one_of(
|
||||
st.text(min_size=1, max_size=50),
|
||||
st.integers(min_value=0, max_value=10000),
|
||||
st.booleans(),
|
||||
),
|
||||
min_size=1,
|
||||
max_size=10,
|
||||
)
|
||||
|
||||
raw_references_strategy = st.lists(
|
||||
st.text(min_size=0, max_size=100),
|
||||
min_size=0,
|
||||
max_size=5,
|
||||
)
|
||||
|
||||
|
||||
discovered_resource_strategy = st.builds(
|
||||
DiscoveredResource,
|
||||
resource_type=resource_type_strategy,
|
||||
unique_id=unique_id_strategy,
|
||||
name=name_strategy,
|
||||
provider=provider_type_strategy,
|
||||
platform_category=platform_category_strategy,
|
||||
architecture=cpu_architecture_strategy,
|
||||
endpoint=endpoint_strategy,
|
||||
attributes=non_empty_attributes_strategy,
|
||||
raw_references=raw_references_strategy,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Property Tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestResourceInventoryCompleteness:
|
||||
"""Property 1: Resource inventory completeness.
|
||||
|
||||
**Validates: Requirements 1.2**
|
||||
|
||||
For any discovered resource from any on-premises provider, the resulting
|
||||
inventory entry SHALL contain non-empty values for resource_type, unique_id,
|
||||
name, provider, platform_category, architecture, and attributes fields.
|
||||
"""
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_resource_type_is_non_empty(self, resource: DiscoveredResource):
|
||||
"""resource_type field must be a non-empty string."""
|
||||
assert isinstance(resource.resource_type, str)
|
||||
assert len(resource.resource_type) > 0
|
||||
assert resource.resource_type.strip() != ""
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_unique_id_is_non_empty(self, resource: DiscoveredResource):
|
||||
"""unique_id field must be a non-empty string."""
|
||||
assert isinstance(resource.unique_id, str)
|
||||
assert len(resource.unique_id) > 0
|
||||
assert resource.unique_id.strip() != ""
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_name_is_non_empty(self, resource: DiscoveredResource):
|
||||
"""name field must be a non-empty string."""
|
||||
assert isinstance(resource.name, str)
|
||||
assert len(resource.name) > 0
|
||||
assert resource.name.strip() != ""
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_provider_is_valid_enum(self, resource: DiscoveredResource):
|
||||
"""provider field must be a valid ProviderType enum value."""
|
||||
assert isinstance(resource.provider, ProviderType)
|
||||
assert resource.provider is not None
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_platform_category_is_valid_enum(self, resource: DiscoveredResource):
|
||||
"""platform_category field must be a valid PlatformCategory enum value."""
|
||||
assert isinstance(resource.platform_category, PlatformCategory)
|
||||
assert resource.platform_category is not None
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_architecture_is_valid_enum(self, resource: DiscoveredResource):
|
||||
"""architecture field must be a valid CpuArchitecture enum value."""
|
||||
assert isinstance(resource.architecture, CpuArchitecture)
|
||||
assert resource.architecture is not None
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_attributes_is_non_empty_dict(self, resource: DiscoveredResource):
|
||||
"""attributes field must be a non-empty dictionary."""
|
||||
assert isinstance(resource.attributes, dict)
|
||||
assert len(resource.attributes) > 0
|
||||
|
||||
@given(resource=discovered_resource_strategy)
|
||||
def test_all_mandatory_fields_populated(self, resource: DiscoveredResource):
|
||||
"""All mandatory fields must be non-empty/non-None simultaneously."""
|
||||
# resource_type
|
||||
assert isinstance(resource.resource_type, str) and len(resource.resource_type) > 0
|
||||
# unique_id
|
||||
assert isinstance(resource.unique_id, str) and len(resource.unique_id) > 0
|
||||
# name
|
||||
assert isinstance(resource.name, str) and len(resource.name) > 0
|
||||
# provider
|
||||
assert isinstance(resource.provider, ProviderType)
|
||||
# platform_category
|
||||
assert isinstance(resource.platform_category, PlatformCategory)
|
||||
# architecture
|
||||
assert isinstance(resource.architecture, CpuArchitecture)
|
||||
# attributes
|
||||
assert isinstance(resource.attributes, dict) and len(resource.attributes) > 0
|
||||
|
||||
@given(
|
||||
resources=st.lists(discovered_resource_strategy, min_size=1, max_size=10),
|
||||
warnings=st.lists(st.text(min_size=0, max_size=50), max_size=3),
|
||||
errors=st.lists(st.text(min_size=0, max_size=50), max_size=3),
|
||||
)
|
||||
@settings(max_examples=50)
|
||||
def test_scan_result_resources_all_have_mandatory_fields(
|
||||
self, resources, warnings, errors
|
||||
):
|
||||
"""When a mock plugin produces resources in a ScanResult, every resource has all required fields."""
|
||||
scan_result = ScanResult(
|
||||
resources=resources,
|
||||
warnings=warnings,
|
||||
errors=errors,
|
||||
scan_timestamp="2024-01-15T10:30:00Z",
|
||||
profile_hash="test_hash_abc123",
|
||||
is_partial=False,
|
||||
)
|
||||
|
||||
for resource in scan_result.resources:
|
||||
# resource_type is non-empty string
|
||||
assert isinstance(resource.resource_type, str)
|
||||
assert len(resource.resource_type) > 0
|
||||
assert resource.resource_type.strip() != ""
|
||||
|
||||
# unique_id is non-empty string
|
||||
assert isinstance(resource.unique_id, str)
|
||||
assert len(resource.unique_id) > 0
|
||||
assert resource.unique_id.strip() != ""
|
||||
|
||||
# name is non-empty string
|
||||
assert isinstance(resource.name, str)
|
||||
assert len(resource.name) > 0
|
||||
assert resource.name.strip() != ""
|
||||
|
||||
# provider is valid enum
|
||||
assert isinstance(resource.provider, ProviderType)
|
||||
|
||||
# platform_category is valid enum
|
||||
assert isinstance(resource.platform_category, PlatformCategory)
|
||||
|
||||
# architecture is valid enum
|
||||
assert isinstance(resource.architecture, CpuArchitecture)
|
||||
|
||||
# attributes is non-empty dict
|
||||
assert isinstance(resource.attributes, dict)
|
||||
assert len(resource.attributes) > 0
|
||||
Reference in New Issue
Block a user