321 lines
12 KiB
Python
321 lines
12 KiB
Python
"""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
|