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:
@@ -0,0 +1,78 @@
|
||||
"""A rejected passphrase must reach the web UI as "wrong_password:".
|
||||
|
||||
_connect_nmcli prefixes the message with "wrong_password:" and the api_v3
|
||||
wifi route turns that into ``error_type == 'wrong_password'``, which the
|
||||
setup pages key their "incorrect password" prompt off. _connect_validated
|
||||
used to replace the message on every failure branch (restore the old
|
||||
network, or bring the setup AP up), so the prefix never survived.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
|
||||
from src.wifi_manager import WiFiManager # noqa: E402
|
||||
|
||||
|
||||
def _manager(connected_ssid=None):
|
||||
manager = WiFiManager.__new__(WiFiManager) # no __init__: no real host access
|
||||
manager.has_nmcli = True
|
||||
manager._wifi_interface = "wlan0"
|
||||
manager.get_wifi_status = MagicMock(return_value=SimpleNamespace(
|
||||
connected=bool(connected_ssid), ssid=connected_ssid, ip_address=None))
|
||||
manager._is_ap_mode_active = MagicMock(return_value=False)
|
||||
manager._ensure_wifi_radio_enabled = MagicMock(return_value=True)
|
||||
manager._show_led_message = MagicMock()
|
||||
manager.disconnect_from_network = MagicMock(return_value=(True, "ok"))
|
||||
manager._wait_for_device_idle = MagicMock(return_value=True)
|
||||
manager.enable_ap_mode = MagicMock(return_value=(True, "AP up"))
|
||||
return manager
|
||||
|
||||
|
||||
def _run(manager, nmcli_result):
|
||||
manager._connect_nmcli = MagicMock(return_value=nmcli_result)
|
||||
nmcli_out = SimpleNamespace(returncode=0, stdout="GENERAL.CONNECTION:OldNet\n")
|
||||
with patch("src.wifi_manager.subprocess.run", return_value=nmcli_out), \
|
||||
patch("src.wifi_manager.time.sleep"):
|
||||
return manager._connect_validated("HomeNet", "hunter22")
|
||||
|
||||
|
||||
WRONG = (False, "wrong_password: Secrets were required, but not provided")
|
||||
|
||||
|
||||
class TestWrongPasswordSurvivesRecovery:
|
||||
def test_when_the_setup_ap_comes_back_up(self):
|
||||
ok, message = _run(_manager(), WRONG)
|
||||
assert ok is False
|
||||
assert message.startswith("wrong_password:")
|
||||
|
||||
def test_when_the_setup_ap_fails_too(self):
|
||||
manager = _manager()
|
||||
manager.enable_ap_mode.return_value = (False, "hostapd missing")
|
||||
ok, message = _run(manager, WRONG)
|
||||
assert ok is False
|
||||
assert message.startswith("wrong_password:")
|
||||
assert "hostapd missing" in message
|
||||
|
||||
@pytest.mark.parametrize("restored", [True, False])
|
||||
def test_when_the_previous_network_is_restored_or_not(self, restored):
|
||||
manager = _manager(connected_ssid="OldNet")
|
||||
manager._restore_original_connection = MagicMock(return_value=restored)
|
||||
ok, message = _run(manager, WRONG)
|
||||
assert ok is False
|
||||
assert message.startswith("wrong_password:")
|
||||
|
||||
|
||||
class TestOtherFailuresAreUnchanged:
|
||||
def test_a_generic_failure_gets_no_prefix(self):
|
||||
ok, message = _run(_manager(), (False, "Connection timed out"))
|
||||
assert ok is False
|
||||
assert message == "Connection failed. AP mode enabled."
|
||||
|
||||
def test_success_passes_through(self):
|
||||
assert _run(_manager(), (True, "Connected to HomeNet")) == (True, "Connected to HomeNet")
|
||||
Reference in New Issue
Block a user