"""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