first commit
This commit is contained in:
320
netbox_librenms_plugin/tests/test_coverage_cache.py
Normal file
320
netbox_librenms_plugin/tests/test_coverage_cache.py
Normal file
@@ -0,0 +1,320 @@
|
||||
"""Coverage tests for netbox_librenms_plugin.import_utils.cache module."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
class TestGetLocationChoicesCacheKey:
|
||||
"""Tests for get_location_choices_cache_key (line 14)."""
|
||||
|
||||
def test_returns_correct_format(self):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_location_choices_cache_key
|
||||
|
||||
result = get_location_choices_cache_key("default")
|
||||
assert result == "librenms_locations_choices:default"
|
||||
|
||||
def test_different_server_keys(self):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_location_choices_cache_key
|
||||
|
||||
assert get_location_choices_cache_key("primary") == "librenms_locations_choices:primary"
|
||||
assert get_location_choices_cache_key("secondary") == "librenms_locations_choices:secondary"
|
||||
|
||||
|
||||
class TestGetActiveCachedSearches:
|
||||
"""Tests for get_active_cached_searches (lines 52-131)."""
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_empty_cache_index_returns_empty_list(self, mock_cache):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
mock_cache.get.return_value = []
|
||||
result = get_active_cached_searches("default")
|
||||
assert result == []
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_none_cache_index_returns_empty_list(self, mock_cache):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
# cache.get(cache_index_key, []) returns [] when cache misses
|
||||
mock_cache.get.side_effect = lambda key, default=None: default if "cache_index" in key else None
|
||||
result = get_active_cached_searches("default")
|
||||
assert result == []
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_entry_with_remaining_time_is_returned(self, mock_cache):
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
cached_at = now.isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["some_cache_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "some_cache_key":
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": cached_at,
|
||||
"filters": {},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert len(result) == 1
|
||||
assert result[0]["remaining_seconds"] > 0
|
||||
assert result[0]["cache_key"] == "some_cache_key"
|
||||
assert result[0]["display_filters"] == {}
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_expired_entry_is_cleaned_up(self, mock_cache):
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
# Cached at epoch (way in the past)
|
||||
old_time = datetime.fromtimestamp(0, timezone.utc).isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["expired_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "expired_key":
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": old_time,
|
||||
"filters": {},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
# Expired entries should NOT be in results
|
||||
assert result == []
|
||||
# Cache index should be updated to remove expired keys
|
||||
mock_cache.set.assert_called_once()
|
||||
call_args = mock_cache.set.call_args
|
||||
assert "cache_index" in call_args[0][0]
|
||||
assert call_args[0][1] == []
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_location_id_enriched_from_cache(self, mock_cache):
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
cached_at = now.isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["search_key"]
|
||||
if key == "librenms_locations_choices:default":
|
||||
return [("42", "New York DC"), ("99", "London DC")]
|
||||
if key == "search_key":
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": cached_at,
|
||||
"filters": {"location": "42"},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert len(result) == 1
|
||||
assert result[0]["display_filters"]["location"] == "New York DC"
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_type_code_enriched_to_display_name(self, mock_cache):
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
cached_at = now.isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["search_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "search_key":
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": cached_at,
|
||||
"filters": {"type": "network"},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert len(result) == 1
|
||||
assert result[0]["display_filters"]["type"] == "Network"
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_missing_filters_key_falls_back_to_empty_dict(self, mock_cache):
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
cached_at = now.isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["search_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "search_key":
|
||||
# No 'filters' key
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": cached_at,
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert len(result) == 1
|
||||
assert result[0]["display_filters"] == {}
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_timezone_naive_cached_at_normalized_to_utc(self, mock_cache):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
# naive datetime string (no tzinfo)
|
||||
naive_ts = "2099-01-01T12:00:00"
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["search_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "search_key":
|
||||
return {
|
||||
"cache_timeout": 99999999,
|
||||
"cached_at": naive_ts,
|
||||
"filters": {},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
# Should not raise; remaining_seconds should be > 0
|
||||
assert len(result) == 1
|
||||
assert result[0]["remaining_seconds"] > 0
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_malformed_cached_at_falls_back_to_epoch(self, mock_cache):
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["search_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "search_key":
|
||||
return {
|
||||
"cache_timeout": 300,
|
||||
"cached_at": "NOT_A_VALID_DATETIME",
|
||||
"filters": {},
|
||||
}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
# malformed cached_at → epoch → expired → empty result
|
||||
result = get_active_cached_searches("default")
|
||||
assert result == []
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_metadata_none_skipped(self, mock_cache):
|
||||
"""Cache key in index but metadata is None → skip."""
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["gone_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
# metadata expired from cache
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert result == []
|
||||
# Should update index to remove the gone key
|
||||
mock_cache.set.assert_called_once()
|
||||
|
||||
@patch("netbox_librenms_plugin.import_utils.cache.cache")
|
||||
def test_results_sorted_by_cached_at_most_recent_first(self, mock_cache):
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from netbox_librenms_plugin.import_utils.cache import get_active_cached_searches
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
older = (now - timedelta(seconds=60)).isoformat()
|
||||
newer = now.isoformat()
|
||||
|
||||
def mock_get(key, default=None):
|
||||
if "cache_index" in key:
|
||||
return ["older_key", "newer_key"]
|
||||
if "librenms_locations_choices" in key:
|
||||
return None
|
||||
if key == "older_key":
|
||||
return {"cache_timeout": 300, "cached_at": older, "filters": {}}
|
||||
if key == "newer_key":
|
||||
return {"cache_timeout": 300, "cached_at": newer, "filters": {}}
|
||||
return default
|
||||
|
||||
mock_cache.get.side_effect = mock_get
|
||||
|
||||
result = get_active_cached_searches("default")
|
||||
assert len(result) == 2
|
||||
assert result[0]["cached_at"] >= result[1]["cached_at"]
|
||||
|
||||
|
||||
class TestGetCacheMetadataKeyDeterminism:
|
||||
"""Tests that get_cache_metadata_key is deterministic."""
|
||||
|
||||
def test_different_filter_values_produce_different_keys(self):
|
||||
"""Different filter values should produce different cache keys."""
|
||||
from netbox_librenms_plugin.import_utils.cache import get_cache_metadata_key
|
||||
|
||||
key1 = get_cache_metadata_key("default", {"location": "NYC"}, False)
|
||||
key2 = get_cache_metadata_key("default", {"location": "LON"}, False)
|
||||
assert key1 != key2
|
||||
|
||||
def test_same_filters_produce_same_key(self):
|
||||
"""Same filters in any insertion order should produce the same cache key."""
|
||||
from netbox_librenms_plugin.import_utils.cache import get_cache_metadata_key
|
||||
|
||||
key1 = get_cache_metadata_key("default", {"location": "NYC", "type": "network"}, True)
|
||||
key2 = get_cache_metadata_key("default", {"type": "network", "location": "NYC"}, True)
|
||||
assert key1 == key2
|
||||
|
||||
def test_none_values_excluded_from_hash(self):
|
||||
"""None filter values should be excluded and produce same key as absent."""
|
||||
from netbox_librenms_plugin.import_utils.cache import get_cache_metadata_key
|
||||
|
||||
key_with_none = get_cache_metadata_key("default", {"location": "NYC", "type": None}, False)
|
||||
key_without = get_cache_metadata_key("default", {"location": "NYC"}, False)
|
||||
assert key_with_none == key_without
|
||||
|
||||
def test_different_server_keys_produce_different_keys(self):
|
||||
"""Different server keys should produce different cache metadata keys."""
|
||||
from netbox_librenms_plugin.import_utils.cache import get_cache_metadata_key
|
||||
|
||||
key1 = get_cache_metadata_key("production", {"location": "NYC"}, False)
|
||||
key2 = get_cache_metadata_key("staging", {"location": "NYC"}, False)
|
||||
assert key1 != key2
|
||||
Reference in New Issue
Block a user