diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f6207b..1c0aefa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -112,9 +112,11 @@ jobs: cd rust && cargo clippy -- -D warnings # Critical test suite (parallel matrix) + # Push to main: runs on lab self-hosted runners (consistent perf, free minutes) + # PRs: runs on GitHub-hosted runners (untrusted code never touches lab infra) test-critical: name: Tests (Python ${{ matrix.python-version }}) - runs-on: ubuntu-latest + runs-on: ${{ github.event_name == 'push' && 'cachekit' || 'ubuntu-latest' }} timeout-minutes: 15 permissions: contents: read diff --git a/tests/unit/test_consolidated_decorator.py b/tests/unit/test_consolidated_decorator.py index 7bf0f48..8837e54 100644 --- a/tests/unit/test_consolidated_decorator.py +++ b/tests/unit/test_consolidated_decorator.py @@ -9,6 +9,8 @@ Requirements: 5.1, 5.2, 5.3 """ +from __future__ import annotations + import asyncio import time from unittest.mock import patch @@ -32,11 +34,11 @@ def test_all_feature_combinations_sync( # Use intent-based presets instead of individual feature flags if use_preset == "minimal": - decorator = cache.minimal(ttl=300, namespace="feature_test") + decorator = cache.minimal(ttl=300, namespace="feature_test_minimal") elif use_preset == "production": - decorator = cache.production(ttl=300, namespace="feature_test") + decorator = cache.production(ttl=300, namespace="feature_test_production") else: - decorator = cache(ttl=300, namespace="feature_test") + decorator = cache(ttl=300, namespace="feature_test_default") @decorator def test_function(x: int) -> str: @@ -95,11 +97,11 @@ async def test_all_feature_combinations_async( # Use intent-based presets instead of individual feature flags if use_preset == "minimal": - decorator = cache.minimal(ttl=300, namespace="async_feature_test") + decorator = cache.minimal(ttl=300, namespace="async_feature_test_minimal") elif use_preset == "production": - decorator = cache.production(ttl=300, namespace="async_feature_test") + decorator = cache.production(ttl=300, namespace="async_feature_test_production") else: - decorator = cache(ttl=300, namespace="async_feature_test") + decorator = cache(ttl=300, namespace="async_feature_test_default") @decorator async def async_test_function(x: int) -> str: diff --git a/tests/unit/test_key_generator_blake2b.py b/tests/unit/test_key_generator_blake2b.py index 7bb8234..decf729 100644 --- a/tests/unit/test_key_generator_blake2b.py +++ b/tests/unit/test_key_generator_blake2b.py @@ -91,18 +91,36 @@ def test_func(data): # Should complete within reasonable time assert blake2b_time < 1.0 - def test_blake2b_with_numpy_arrays_raises_type_error(self): - """Test that NumPy arrays raise TypeError (fail fast).""" + def test_blake2b_with_numpy_arrays_supported(self): + """Test that 1D NumPy arrays with supported dtypes generate valid keys.""" def test_func(arr): return arr.sum() - arr = np.arange(1000) + arr = np.arange(1000) # 1D, int64, well under 100KB gen = CacheKeyGenerator() - # Should raise TypeError for unsupported type - with pytest.raises(TypeError, match="Unsupported type for cache key generation"): - gen.generate_key(test_func, (arr,), {}) + # Constrained numpy arrays are now supported (round-table review 2025-12-18) + key = gen.generate_key(test_func, (arr,), {}) + assert isinstance(key, str) + assert len(key) > 0 + + # Deterministic + key2 = gen.generate_key(test_func, (arr,), {}) + assert key == key2 + + def test_blake2b_with_unsupported_numpy_arrays_raises(self): + """Test that numpy arrays violating constraints raise TypeError.""" + + def test_func(arr): + return arr.sum() + + gen = CacheKeyGenerator() + + # 2D array — not supported + arr_2d = np.arange(100).reshape(10, 10) + with pytest.raises(TypeError, match="Only 1D arrays supported"): + gen.generate_key(test_func, (arr_2d,), {}) def test_blake2b_with_custom_objects(self): """Test Blake2b with basic objects that can be pickled.""" @@ -223,14 +241,14 @@ def test_unsupported_types_raise_type_error(self): def test_func(data): return data - # Test datetime + # Test naive datetime (rejected for timezone ambiguity) import datetime - with pytest.raises(TypeError, match="Unsupported type"): + with pytest.raises(TypeError, match="Naive datetime not allowed"): gen.generate_key(test_func, (datetime.datetime.now(),), {}) - # Test set - with pytest.raises(TypeError, match="Unsupported type"): + # Test set (rejected for non-deterministic sorting) + with pytest.raises(TypeError, match="set/frozenset not supported"): gen.generate_key(test_func, ({1, 2, 3},), {}) # Test custom class