2024-11-10 23:49:10 +01:00
|
|
|
"""Test Module for CacheFileStore Module."""
|
|
|
|
|
|
|
|
import io
|
|
|
|
import pickle
|
2024-12-29 18:42:49 +01:00
|
|
|
from datetime import date, datetime, timedelta
|
2024-11-10 23:49:10 +01:00
|
|
|
from time import sleep
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
2024-12-15 14:40:03 +01:00
|
|
|
from akkudoktoreos.utils.cacheutil import CacheFileStore, cache_in_file
|
2024-12-29 18:42:49 +01:00
|
|
|
from akkudoktoreos.utils.datetimeutil import compare_datetimes, to_datetime, to_duration
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# -----------------------------
|
|
|
|
# CacheFileStore
|
|
|
|
# -----------------------------
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
def cache_store():
|
|
|
|
"""A pytest fixture that creates a new CacheFileStore instance for testing."""
|
2024-12-29 18:42:49 +01:00
|
|
|
cache = CacheFileStore()
|
|
|
|
cache.clear(clear_all=True)
|
|
|
|
assert len(cache._store) == 0
|
|
|
|
return cache
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_generate_cache_file_key(cache_store):
|
|
|
|
"""Test cache file key generation based on URL and date."""
|
|
|
|
key = "http://example.com"
|
2024-12-29 18:42:49 +01:00
|
|
|
|
|
|
|
# Provide until date - assure until_dt is used.
|
|
|
|
until_dt = to_datetime("2024-10-01")
|
|
|
|
cache_file_key, cache_file_until_dt, ttl_duration = cache_store._generate_cache_file_key(
|
|
|
|
key=key, until_datetime=until_dt
|
|
|
|
)
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file_key is not None
|
2024-12-29 18:42:49 +01:00
|
|
|
assert compare_datetimes(cache_file_until_dt, until_dt).equal
|
|
|
|
|
|
|
|
# Provide until date again - assure same key is generated.
|
|
|
|
cache_file_key1, cache_file_until_dt1, ttl_duration1 = cache_store._generate_cache_file_key(
|
|
|
|
key=key, until_datetime=until_dt
|
|
|
|
)
|
|
|
|
assert cache_file_key1 == cache_file_key
|
|
|
|
assert compare_datetimes(cache_file_until_dt1, until_dt).equal
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Provide no until date - assure today EOD is used.
|
2024-12-29 18:42:49 +01:00
|
|
|
no_until_dt = to_datetime().end_of("day")
|
|
|
|
cache_file_key, cache_file_until_dt, ttl_duration = cache_store._generate_cache_file_key(key)
|
|
|
|
assert cache_file_key is not None
|
|
|
|
assert compare_datetimes(cache_file_until_dt, no_until_dt).equal
|
|
|
|
|
|
|
|
# Provide with_ttl - assure until_dt is used.
|
|
|
|
until_dt = to_datetime().add(hours=1)
|
|
|
|
cache_file_key, cache_file_until_dt, ttl_duration = cache_store._generate_cache_file_key(
|
|
|
|
key, with_ttl="1 hour"
|
|
|
|
)
|
|
|
|
assert cache_file_key is not None
|
|
|
|
assert compare_datetimes(cache_file_until_dt, until_dt).approximately_equal
|
|
|
|
assert ttl_duration == to_duration("1 hour")
|
|
|
|
|
|
|
|
# Provide with_ttl again - assure same key is generated.
|
|
|
|
until_dt = to_datetime().add(hours=1)
|
|
|
|
cache_file_key1, cache_file_until_dt1, ttl_duration1 = cache_store._generate_cache_file_key(
|
|
|
|
key=key, with_ttl="1 hour"
|
|
|
|
)
|
|
|
|
assert cache_file_key1 == cache_file_key
|
|
|
|
assert compare_datetimes(cache_file_until_dt1, until_dt).approximately_equal
|
|
|
|
assert ttl_duration1 == to_duration("1 hour")
|
|
|
|
|
|
|
|
# Provide different with_ttl - assure different key is generated.
|
|
|
|
until_dt = to_datetime().add(hours=1, minutes=1)
|
|
|
|
cache_file_key2, cache_file_until_dt2, ttl_duration2 = cache_store._generate_cache_file_key(
|
|
|
|
key=key, with_ttl="1 hour 1 minute"
|
|
|
|
)
|
|
|
|
assert cache_file_key2 != cache_file_key
|
|
|
|
assert compare_datetimes(cache_file_until_dt2, until_dt).approximately_equal
|
|
|
|
assert ttl_duration2 == to_duration("1 hour 1 minute")
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_get_file_path(cache_store):
|
|
|
|
"""Test get file path from cache file object."""
|
|
|
|
cache_file = cache_store.create("test_file", mode="w+", suffix=".txt")
|
|
|
|
file_path = cache_store._get_file_path(cache_file)
|
|
|
|
|
|
|
|
assert file_path is not None
|
|
|
|
|
|
|
|
|
2024-12-29 18:42:49 +01:00
|
|
|
def test_until_datetime_by_options(cache_store):
|
|
|
|
"""Test until datetime calculation based on options."""
|
|
|
|
now = to_datetime()
|
|
|
|
|
|
|
|
# Test with until_datetime
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(until_datetime=now)
|
|
|
|
assert result == now
|
|
|
|
assert ttl_duration is None
|
|
|
|
|
|
|
|
# -- From now on we expect a until_datetime in one hour
|
|
|
|
ttl_duration_expected = to_duration("1 hour")
|
|
|
|
|
|
|
|
# Test with with_ttl as timedelta
|
|
|
|
until_datetime_expected = to_datetime().add(hours=1)
|
|
|
|
ttl = timedelta(hours=1)
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(with_ttl=ttl)
|
|
|
|
assert compare_datetimes(result, until_datetime_expected).approximately_equal
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# Test with with_ttl as int (seconds)
|
|
|
|
until_datetime_expected = to_datetime().add(hours=1)
|
|
|
|
ttl_seconds = 3600
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(with_ttl=ttl_seconds)
|
|
|
|
assert compare_datetimes(result, until_datetime_expected).approximately_equal
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# Test with with_ttl as string ("1 hour")
|
|
|
|
until_datetime_expected = to_datetime().add(hours=1)
|
|
|
|
ttl_string = "1 hour"
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(with_ttl=ttl_string)
|
|
|
|
assert compare_datetimes(result, until_datetime_expected).approximately_equal
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# -- From now on we expect a until_datetime today at end of day
|
|
|
|
until_datetime_expected = to_datetime().end_of("day")
|
|
|
|
ttl_duration_expected = None
|
|
|
|
|
|
|
|
# Test default case (end of today)
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options()
|
|
|
|
assert compare_datetimes(result, until_datetime_expected).equal
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# -- From now on we expect a until_datetime in one day at end of day
|
|
|
|
until_datetime_expected = to_datetime().add(days=1).end_of("day")
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# Test with until_date as date
|
|
|
|
until_date = date.today() + timedelta(days=1)
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(until_date=until_date)
|
|
|
|
assert compare_datetimes(result, until_datetime_expected).equal
|
|
|
|
assert ttl_duration == ttl_duration_expected
|
|
|
|
|
|
|
|
# -- Test with multiple options (until_datetime takes precedence)
|
|
|
|
specific_datetime = to_datetime().add(days=2)
|
|
|
|
result, ttl_duration = cache_store._until_datetime_by_options(
|
|
|
|
until_date=to_datetime().add(days=1).date(),
|
|
|
|
until_datetime=specific_datetime,
|
|
|
|
with_ttl=ttl,
|
|
|
|
)
|
|
|
|
assert compare_datetimes(result, specific_datetime).equal
|
|
|
|
assert ttl_duration is None
|
|
|
|
|
|
|
|
# Test with invalid inputs
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
cache_store._until_datetime_by_options(until_date="invalid-date")
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
cache_store._until_datetime_by_options(with_ttl="invalid-ttl")
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
cache_store._until_datetime_by_options(until_datetime="invalid-datetime")
|
|
|
|
|
|
|
|
|
2024-11-10 23:49:10 +01:00
|
|
|
def test_create_cache_file(cache_store):
|
|
|
|
"""Test the creation of a cache file and ensure it is stored correctly."""
|
|
|
|
# Create a cache file for today's date
|
|
|
|
cache_file = cache_store.create("test_file", mode="w+", suffix=".txt")
|
|
|
|
|
|
|
|
# Check that the file exists in the store and is a file-like object
|
|
|
|
assert cache_file is not None
|
|
|
|
assert hasattr(cache_file, "name")
|
|
|
|
assert cache_file.name.endswith(".txt")
|
|
|
|
|
|
|
|
# Write some data to the file
|
|
|
|
cache_file.seek(0)
|
|
|
|
cache_file.write("Test data")
|
|
|
|
cache_file.seek(0) # Reset file pointer
|
|
|
|
assert cache_file.read() == "Test data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_cache_file(cache_store):
|
|
|
|
"""Test retrieving an existing cache file by key."""
|
|
|
|
# Create a cache file and write data to it
|
|
|
|
cache_file = cache_store.create("test_file", mode="w+")
|
|
|
|
cache_file.seek(0)
|
|
|
|
cache_file.write("Test data")
|
|
|
|
cache_file.seek(0)
|
|
|
|
|
|
|
|
# Retrieve the cache file and verify the data
|
|
|
|
retrieved_file = cache_store.get("test_file")
|
|
|
|
assert retrieved_file is not None
|
|
|
|
retrieved_file.seek(0)
|
|
|
|
assert retrieved_file.read() == "Test data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_set_custom_file_object(cache_store):
|
|
|
|
"""Test setting a custom file-like object (BytesIO or StringIO) in the store."""
|
|
|
|
# Create a BytesIO object and set it into the cache
|
|
|
|
file_obj = io.BytesIO(b"Binary data")
|
|
|
|
cache_store.set("binary_file", file_obj)
|
|
|
|
|
|
|
|
# Retrieve the file from the store
|
|
|
|
retrieved_file = cache_store.get("binary_file")
|
|
|
|
assert isinstance(retrieved_file, io.BytesIO)
|
|
|
|
retrieved_file.seek(0)
|
|
|
|
assert retrieved_file.read() == b"Binary data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_delete_cache_file(cache_store):
|
|
|
|
"""Test deleting a cache file from the store."""
|
|
|
|
# Create multiple cache files
|
|
|
|
cache_file1 = cache_store.create("file1")
|
|
|
|
assert hasattr(cache_file1, "name")
|
|
|
|
cache_file2 = cache_store.create("file2")
|
|
|
|
assert hasattr(cache_file2, "name")
|
|
|
|
|
|
|
|
# Ensure the files are in the store
|
|
|
|
assert cache_store.get("file1") is cache_file1
|
|
|
|
assert cache_store.get("file2") is cache_file2
|
|
|
|
|
|
|
|
# Delete cache files
|
|
|
|
cache_store.delete("file1")
|
|
|
|
cache_store.delete("file2")
|
|
|
|
|
|
|
|
# Ensure the store is empty
|
|
|
|
assert cache_store.get("file1") is None
|
|
|
|
assert cache_store.get("file2") is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_clear_all_cache_files(cache_store):
|
|
|
|
"""Test clearing all cache files from the store."""
|
|
|
|
# Create multiple cache files
|
|
|
|
cache_file1 = cache_store.create("file1")
|
|
|
|
assert hasattr(cache_file1, "name")
|
|
|
|
cache_file2 = cache_store.create("file2")
|
|
|
|
assert hasattr(cache_file2, "name")
|
|
|
|
|
|
|
|
# Ensure the files are in the store
|
|
|
|
assert cache_store.get("file1") is cache_file1
|
|
|
|
assert cache_store.get("file2") is cache_file2
|
|
|
|
|
|
|
|
# Clear all cache files
|
|
|
|
cache_store.clear(clear_all=True)
|
|
|
|
|
|
|
|
# Ensure the store is empty
|
|
|
|
assert cache_store.get("file1") is None
|
|
|
|
assert cache_store.get("file2") is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_clear_cache_files_by_date(cache_store):
|
|
|
|
"""Test clearing cache files from the store by date."""
|
|
|
|
# Create multiple cache files
|
|
|
|
cache_file1 = cache_store.create("file1")
|
|
|
|
assert hasattr(cache_file1, "name")
|
|
|
|
cache_file2 = cache_store.create("file2")
|
|
|
|
assert hasattr(cache_file2, "name")
|
|
|
|
|
|
|
|
# Ensure the files are in the store
|
|
|
|
assert cache_store.get("file1") is cache_file1
|
|
|
|
assert cache_store.get("file2") is cache_file2
|
|
|
|
|
|
|
|
# Clear cache files that are older than today
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_store.clear(before_datetime=to_datetime().start_of("day"))
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Ensure the files are in the store
|
|
|
|
assert cache_store.get("file1") is cache_file1
|
|
|
|
assert cache_store.get("file2") is cache_file2
|
|
|
|
|
|
|
|
# Clear cache files that are older than tomorrow
|
|
|
|
cache_store.clear(before_datetime=datetime.now() + timedelta(days=1))
|
|
|
|
|
|
|
|
# Ensure the store is empty
|
|
|
|
assert cache_store.get("file1") is None
|
|
|
|
assert cache_store.get("file2") is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_cache_file_with_date(cache_store):
|
|
|
|
"""Test creating and retrieving cache files with a specific date."""
|
|
|
|
# Use a specific date for cache file creation
|
|
|
|
specific_date = datetime(2023, 10, 10)
|
|
|
|
cache_file = cache_store.create("dated_file", mode="w+", until_date=specific_date)
|
|
|
|
|
|
|
|
# Write data to the cache file
|
|
|
|
cache_file.write("Dated data")
|
|
|
|
cache_file.seek(0)
|
|
|
|
|
|
|
|
# Retrieve the cache file with the specific date
|
|
|
|
retrieved_file = cache_store.get("dated_file", until_date=specific_date)
|
|
|
|
assert retrieved_file is not None
|
|
|
|
retrieved_file.seek(0)
|
|
|
|
assert retrieved_file.read() == "Dated data"
|
|
|
|
|
|
|
|
|
|
|
|
def test_recreate_existing_cache_file(cache_store):
|
|
|
|
"""Test creating a cache file with an existing key does not overwrite the existing file."""
|
|
|
|
# Create a cache file
|
|
|
|
cache_file = cache_store.create("test_file", mode="w+")
|
|
|
|
cache_file.write("Original data")
|
|
|
|
cache_file.seek(0)
|
|
|
|
|
|
|
|
# Attempt to recreate the same file (should return the existing one)
|
|
|
|
new_file = cache_store.create("test_file")
|
|
|
|
assert new_file is cache_file # Should be the same object
|
|
|
|
new_file.seek(0)
|
|
|
|
assert new_file.read() == "Original data" # Data should be preserved
|
|
|
|
|
|
|
|
# Assure cache file store is a singleton
|
|
|
|
cache_store2 = CacheFileStore()
|
|
|
|
new_file = cache_store2.get("test_file")
|
|
|
|
assert new_file is cache_file # Should be the same object
|
|
|
|
|
|
|
|
|
|
|
|
def test_cache_store_is_singleton(cache_store):
|
|
|
|
"""Test re-creating a cache store provides the same store."""
|
|
|
|
# Create a cache file
|
|
|
|
cache_file = cache_store.create("test_file", mode="w+")
|
|
|
|
cache_file.write("Original data")
|
|
|
|
cache_file.seek(0)
|
|
|
|
|
|
|
|
# Assure cache file store is a singleton
|
|
|
|
cache_store2 = CacheFileStore()
|
|
|
|
new_file = cache_store2.get("test_file")
|
|
|
|
assert new_file is cache_file # Should be the same object
|
|
|
|
|
|
|
|
|
|
|
|
def test_cache_in_file_decorator_caches_function_result(cache_store):
|
|
|
|
"""Test that the cache_in_file decorator caches a function result."""
|
|
|
|
# Clear store to assure it is empty
|
|
|
|
cache_store.clear(clear_all=True)
|
|
|
|
assert len(cache_store._store) == 0
|
|
|
|
|
|
|
|
# Define a simple function to decorate
|
|
|
|
@cache_in_file(mode="w+")
|
|
|
|
def my_function(until_date=None):
|
|
|
|
return "Some expensive computation result"
|
|
|
|
|
|
|
|
# Call the decorated function (should store result in cache)
|
|
|
|
result = my_function(until_date=datetime.now() + timedelta(days=1))
|
|
|
|
assert result == "Some expensive computation result"
|
|
|
|
|
|
|
|
# Assert that the create method was called to store the result
|
|
|
|
assert len(cache_store._store) == 1
|
|
|
|
|
|
|
|
# Check if the result was written to the cache file
|
|
|
|
key = next(iter(cache_store._store))
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file = cache_store._store[key].cache_file
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file is not None
|
|
|
|
|
|
|
|
# Assert correct content was written to the file
|
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == "Some expensive computation result"
|
|
|
|
|
|
|
|
|
|
|
|
def test_cache_in_file_decorator_uses_cache(cache_store):
|
|
|
|
"""Test that the cache_in_file decorator reuses cached file on subsequent calls."""
|
|
|
|
# Clear store to assure it is empty
|
|
|
|
cache_store.clear(clear_all=True)
|
|
|
|
assert len(cache_store._store) == 0
|
|
|
|
|
|
|
|
# Define a simple function to decorate
|
|
|
|
@cache_in_file(mode="w+")
|
|
|
|
def my_function(until_date=None):
|
|
|
|
return "New result"
|
|
|
|
|
|
|
|
# Call the decorated function (should store result in cache)
|
2024-12-29 18:42:49 +01:00
|
|
|
result = my_function(until_date=to_datetime().add(days=1))
|
2024-11-10 23:49:10 +01:00
|
|
|
assert result == "New result"
|
|
|
|
|
|
|
|
# Assert result was written to cache file
|
|
|
|
key = next(iter(cache_store._store))
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file = cache_store._store[key].cache_file
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file is not None
|
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == result
|
|
|
|
|
|
|
|
# Modify cache file
|
|
|
|
result2 = "Cached result"
|
|
|
|
cache_file.seek(0)
|
|
|
|
cache_file.write(result2)
|
|
|
|
|
|
|
|
# Call the decorated function again (should get result from cache)
|
2024-12-29 18:42:49 +01:00
|
|
|
result = my_function(until_date=to_datetime().add(days=1))
|
2024-11-10 23:49:10 +01:00
|
|
|
assert result == result2
|
|
|
|
|
|
|
|
|
2024-12-15 14:40:03 +01:00
|
|
|
def test_cache_in_file_decorator_forces_update_data(cache_store):
|
2024-11-10 23:49:10 +01:00
|
|
|
"""Test that the cache_in_file decorator reuses cached file on subsequent calls."""
|
|
|
|
# Clear store to assure it is empty
|
|
|
|
cache_store.clear(clear_all=True)
|
|
|
|
assert len(cache_store._store) == 0
|
|
|
|
|
|
|
|
# Define a simple function to decorate
|
|
|
|
@cache_in_file(mode="w+")
|
|
|
|
def my_function(until_date=None):
|
|
|
|
return "New result"
|
|
|
|
|
2024-12-29 18:42:49 +01:00
|
|
|
until_date = to_datetime().add(days=1).date()
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Call the decorated function (should store result in cache)
|
|
|
|
result1 = "New result"
|
|
|
|
result = my_function(until_date=until_date)
|
|
|
|
assert result == result1
|
|
|
|
|
|
|
|
# Assert result was written to cache file
|
|
|
|
key = next(iter(cache_store._store))
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file = cache_store._store[key].cache_file
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file is not None
|
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == result
|
|
|
|
|
|
|
|
# Modify cache file
|
|
|
|
result2 = "Cached result"
|
|
|
|
cache_file.seek(0)
|
|
|
|
cache_file.write(result2)
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == result2
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Call the decorated function again with force update (should get result from function)
|
2024-11-26 22:28:05 +01:00
|
|
|
result = my_function(until_date=until_date, force_update=True) # type: ignore[call-arg]
|
2024-11-10 23:49:10 +01:00
|
|
|
assert result == result1
|
|
|
|
|
|
|
|
# Assure result was written to the same cache file
|
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == result1
|
|
|
|
|
|
|
|
|
|
|
|
def test_cache_in_file_handles_ttl(cache_store):
|
|
|
|
"""Test that the cache_infile decorator handles the with_ttl parameter."""
|
|
|
|
|
|
|
|
# Define a simple function to decorate
|
|
|
|
@cache_in_file(mode="w+")
|
|
|
|
def my_function():
|
|
|
|
return "New result"
|
|
|
|
|
|
|
|
# Call the decorated function
|
2024-12-29 18:42:49 +01:00
|
|
|
result1 = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
|
|
|
assert result1 == "New result"
|
|
|
|
assert len(cache_store._store) == 1
|
|
|
|
key = list(cache_store._store.keys())[0]
|
2024-11-10 23:49:10 +01:00
|
|
|
|
2024-12-29 18:42:49 +01:00
|
|
|
# Assert result was written to cache file
|
2024-11-10 23:49:10 +01:00
|
|
|
key = next(iter(cache_store._store))
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file = cache_store._store[key].cache_file
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file is not None
|
|
|
|
cache_file.seek(0) # Move to the start of the file
|
2024-12-29 18:42:49 +01:00
|
|
|
assert cache_file.read() == result1
|
|
|
|
|
|
|
|
# Modify cache file
|
|
|
|
result2 = "Cached result"
|
|
|
|
cache_file.seek(0)
|
|
|
|
cache_file.write(result2)
|
2024-11-10 23:49:10 +01:00
|
|
|
cache_file.seek(0) # Move to the start of the file
|
2024-12-29 18:42:49 +01:00
|
|
|
assert cache_file.read() == result2
|
2024-11-10 23:49:10 +01:00
|
|
|
|
2024-12-29 18:42:49 +01:00
|
|
|
# Call the decorated function again
|
2024-11-26 22:28:05 +01:00
|
|
|
result = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file.seek(0) # Move to the start of the file
|
|
|
|
assert cache_file.read() == result2
|
|
|
|
assert result == result2
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Wait one second to let the cache time out
|
2024-12-29 18:42:49 +01:00
|
|
|
sleep(2)
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
# Call again - cache should be timed out
|
2024-11-26 22:28:05 +01:00
|
|
|
result = my_function(with_ttl="1 second") # type: ignore[call-arg]
|
2024-12-29 18:42:49 +01:00
|
|
|
assert result == result1
|
2024-11-10 23:49:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_cache_in_file_handles_bytes_return(cache_store):
|
|
|
|
"""Test that the cache_infile decorator handles bytes returned from the function."""
|
|
|
|
# Clear store to assure it is empty
|
|
|
|
cache_store.clear(clear_all=True)
|
|
|
|
assert len(cache_store._store) == 0
|
|
|
|
|
|
|
|
# Define a function that returns bytes
|
|
|
|
@cache_in_file()
|
2024-11-26 22:28:05 +01:00
|
|
|
def my_function(until_date=None) -> bytes:
|
2024-11-10 23:49:10 +01:00
|
|
|
return b"Some binary data"
|
|
|
|
|
|
|
|
# Call the decorated function
|
|
|
|
result = my_function(until_date=datetime.now() + timedelta(days=1))
|
|
|
|
|
|
|
|
# Check if the binary data was written to the cache file
|
|
|
|
key = next(iter(cache_store._store))
|
2024-12-29 18:42:49 +01:00
|
|
|
cache_file = cache_store._store[key].cache_file
|
2024-11-26 22:28:05 +01:00
|
|
|
assert len(cache_store._store) == 1
|
2024-11-10 23:49:10 +01:00
|
|
|
assert cache_file is not None
|
|
|
|
cache_file.seek(0)
|
|
|
|
result1 = pickle.load(cache_file)
|
|
|
|
assert result1 == result
|
2024-11-26 22:28:05 +01:00
|
|
|
|
|
|
|
# Access cache
|
|
|
|
result = my_function(until_date=datetime.now() + timedelta(days=1))
|
|
|
|
assert len(cache_store._store) == 1
|
2024-12-29 18:42:49 +01:00
|
|
|
assert cache_store._store[key].cache_file is not None
|
2024-11-26 22:28:05 +01:00
|
|
|
assert result1 == result
|