mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
fix: web UI and src.common bugs (wifi wrong-password, plugin icon, starlark toggle, API caching, scroll/logo/font helpers) (#646)
- wifi: keep the "wrong_password:" prefix through the restore/AP fallback so the UI's incorrect-password prompt fires again. - /plugins/installed returns the manifest's icon (string only). - /starlark/apps/<id>/toggle coerces `enabled` and delegates to _toggle_starlark_app (disk before memory, no KeyError, "false" is false). - /api/v3/ JSON GETs are sent Cache-Control: no-store; non-JSON keeps 5s. - ScrollHelper.set_scrolling_image converts non-RGB input (alpha onto black); create/set_scrolling_image reset last_update_time like reset_scroll. - LogoHelper backs off a failed download per path for MISSING_LOGO_RECHECK_SECONDS; cleared on invalidate/clear_cache. - refresh_placeholder_timestamp saves atomically. - FontManager.clear_cache / _clear_plugin_font_cache bump cache_generation. - Odds manager: per-game logs to DEBUG; JSON decode error caught before RequestException (same cooldown). - element_style mangled continuations; startup validator skips null plugin blocks and reuses the controller's discovery. - src/common/README lists frame_timing, json_body, render_gate. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ its requests through a session so it can identify itself to ESPN, so patching
|
||||
the module-level requests.get would no longer intercept anything.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
@@ -161,6 +162,34 @@ class TestGetOdds:
|
||||
assert result == {'stale': True}
|
||||
assert cache_manager.get_with_auto_strategy.call_count == 2
|
||||
|
||||
def test_a_bad_body_is_reported_as_a_parse_error(
|
||||
self, manager, cache_manager, mock_get, caplog):
|
||||
# requests' JSONDecodeError is a RequestException, so the JSON branch
|
||||
# sat unreachable behind it and a bad body read as a failed fetch.
|
||||
response = _make_response(None)
|
||||
response.json.side_effect = requests.exceptions.JSONDecodeError('x', 'doc', 0)
|
||||
mock_get.return_value = response
|
||||
cache_manager.get_with_auto_strategy.side_effect = [None, {'stale': True}]
|
||||
|
||||
with caplog.at_level(logging.ERROR, logger=manager.logger.name):
|
||||
result = manager.get_odds('football', 'nfl', '401')
|
||||
|
||||
assert result == {'stale': True}
|
||||
messages = [r.getMessage() for r in caplog.records]
|
||||
assert any('decoding JSON' in m for m in messages), messages
|
||||
assert not any('Error fetching odds' in m for m in messages), messages
|
||||
# The hold-off is unchanged: a bad body still backs off like a failed
|
||||
# fetch did.
|
||||
assert manager._skip_network_until > 0
|
||||
|
||||
def test_routine_fetches_log_nothing_at_info(
|
||||
self, manager, cache_manager, mock_get, caplog):
|
||||
with caplog.at_level(logging.INFO, logger=manager.logger.name):
|
||||
manager.get_odds('football', 'nfl', '401') # miss + fetch
|
||||
cache_manager.get_with_auto_strategy.return_value = {'spread': 1}
|
||||
manager.get_odds('football', 'nfl', '401') # hit
|
||||
assert [r for r in caplog.records if r.levelno == logging.INFO] == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _extract_espn_data
|
||||
|
||||
Reference in New Issue
Block a user