97 lines
3.5 KiB
Python
97 lines
3.5 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
"""
|
|
Unified test to ensure wrapper implementations implement all methods
|
|
defined in their base interface classes.
|
|
|
|
This test uses parameterization to handle multiple base classes and their
|
|
implementations, making it easy to add new completeness checks.
|
|
"""
|
|
|
|
# Third Party
|
|
import pytest
|
|
|
|
# First Party
|
|
from lmcache.v1.lookup_client.abstract_client import LookupClientInterface
|
|
from lmcache.v1.lookup_client.chunk_statistics_lookup_client import (
|
|
ChunkStatisticsLookupClient,
|
|
)
|
|
from lmcache.v1.lookup_client.hit_limit_lookup_client import HitLimitLookupClient
|
|
from lmcache.v1.storage_backend.connector.audit_connector import AuditConnector
|
|
from lmcache.v1.storage_backend.connector.base_connector import RemoteConnector
|
|
from lmcache.v1.storage_backend.connector.instrumented_connector import (
|
|
InstrumentedRemoteConnector,
|
|
)
|
|
from tests.v1.utils import (
|
|
check_method_signatures,
|
|
get_abstract_methods,
|
|
get_all_methods_from_base,
|
|
get_methods_implemented_in_class,
|
|
)
|
|
|
|
|
|
class TestImplementationCompleteness:
|
|
"""Test that wrapper implementations implement all base interface methods"""
|
|
|
|
@pytest.mark.parametrize(
|
|
"base_class,impl_class",
|
|
[
|
|
# Lookup client implementations
|
|
(LookupClientInterface, HitLimitLookupClient),
|
|
(LookupClientInterface, ChunkStatisticsLookupClient),
|
|
# Storage backend connector implementations
|
|
(RemoteConnector, AuditConnector),
|
|
(RemoteConnector, InstrumentedRemoteConnector),
|
|
],
|
|
)
|
|
def test_implementation_completeness(self, base_class, impl_class):
|
|
"""
|
|
Verify implementations have all methods from their base class.
|
|
"""
|
|
base_name = base_class.__name__
|
|
impl_name = impl_class.__name__
|
|
|
|
# 1. Get all methods from base class
|
|
base_methods = get_all_methods_from_base(base_class)
|
|
|
|
# 2. Get methods actually implemented in the class
|
|
impl_methods = get_methods_implemented_in_class(impl_class, base_class)
|
|
|
|
# 3. Check which base methods are missing in the implementation
|
|
missing_methods = base_methods - impl_methods
|
|
|
|
assert len(missing_methods) == 0, (
|
|
f"{impl_name} is missing {len(missing_methods)} methods from "
|
|
f"{base_name}: {sorted(missing_methods)}\n"
|
|
f"Base methods: {sorted(base_methods)}\n"
|
|
f"Implemented methods: {sorted(impl_methods)}"
|
|
)
|
|
|
|
# 4. Check all abstract methods are implemented
|
|
abstract_methods = get_abstract_methods(base_class)
|
|
missing_abstract = []
|
|
for method_name in abstract_methods:
|
|
# Check if the method is actually implemented in the class
|
|
if method_name not in impl_methods:
|
|
missing_abstract.append(method_name)
|
|
|
|
assert len(missing_abstract) == 0, (
|
|
f"{impl_name} has not implemented {len(missing_abstract)} "
|
|
f"abstract methods: {sorted(missing_abstract)}"
|
|
)
|
|
|
|
# 5. Check method signatures match
|
|
signature_mismatches = check_method_signatures(base_class, impl_class)
|
|
|
|
assert len(signature_mismatches) == 0, (
|
|
f"{impl_name} has {len(signature_mismatches)} method signature "
|
|
f"mismatches:\n"
|
|
+ "\n".join(
|
|
f" - {m['method']}: base={m['base_params']}, impl={m['impl_params']}"
|
|
for m in signature_mismatches
|
|
)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
pytest.main([__file__, "-v", "-s"])
|