mirror of https://github.com/Nezreka/SoulSync.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
5.4 KiB
148 lines
5.4 KiB
"""Regression tests for Tidal auth instruction page port rendering.
|
|
|
|
Discord-reported bug: the auth-instructions page shown after clicking
|
|
the Tidal "Authenticate" button rendered example callback URLs with
|
|
port ``8888`` (Spotify's port) instead of ``8889`` (Tidal's port).
|
|
Users who followed the instructions literally saved Spotify's port
|
|
into their ``tidal.redirect_uri`` setting; that mismatched their
|
|
Tidal Developer App's registered ``:8889`` redirect URI and Tidal
|
|
returned error 1002 (invalid redirect URI) on every auth attempt.
|
|
|
|
These tests make sure the rendered instructions show whatever port
|
|
the OAuth URL itself was built with, so the displayed example always
|
|
matches what the user must register in their Tidal app.
|
|
"""
|
|
|
|
from typing import Callable
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
|
|
# Run the route through Flask's test client so we get the real HTML
|
|
# the user would see. We patch out:
|
|
# - TidalClient (the real client tries to connect to Tidal),
|
|
# - the activity-feed call (writes to runtime state),
|
|
# - request.host detection (so the Docker code path is exercised
|
|
# and the instructions page is the one with the example URL).
|
|
@pytest.fixture
|
|
def auth_route_client(monkeypatch: pytest.MonkeyPatch):
|
|
"""Return a Flask test client wired up enough to render the
|
|
Tidal auth-instructions page."""
|
|
# Force the "remote/docker" branch by faking a remote-host request.
|
|
# Easier than mocking is_docker; the route only needs ONE of the
|
|
# two flags to render the instructions page.
|
|
monkeypatch.setattr(
|
|
"os.path.exists",
|
|
lambda p: p == "/.dockerenv" or False,
|
|
)
|
|
|
|
fake_client = MagicMock()
|
|
fake_client.client_id = "fake-id"
|
|
fake_client.code_verifier = "v" * 40
|
|
fake_client.code_challenge = "c" * 40
|
|
fake_client.auth_url = "https://login.tidal.com/authorize"
|
|
|
|
def _set_redirect_uri(value):
|
|
fake_client.redirect_uri = value
|
|
fake_client._generate_pkce_challenge = MagicMock()
|
|
|
|
with patch("core.tidal_client.TidalClient", return_value=fake_client):
|
|
with patch("web_server.add_activity_item"):
|
|
from web_server import app as flask_app
|
|
flask_app.config['TESTING'] = True
|
|
yield flask_app.test_client(), fake_client
|
|
|
|
|
|
def _extract_html(response) -> str:
|
|
return response.get_data(as_text=True)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tests
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_instructions_show_tidal_port_not_spotify_port_when_config_uses_8889(
|
|
auth_route_client, monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""The reported scenario: tidal.redirect_uri config carries port
|
|
8889, the rendered instructions must show 8889 (not Spotify's
|
|
8888) in both the Step 2 example and the Step 3 highlighted URL."""
|
|
client, fake_client = auth_route_client
|
|
|
|
fake_client.redirect_uri = "http://127.0.0.1:8889/tidal/callback"
|
|
|
|
from config.settings import config_manager
|
|
monkeypatch.setattr(
|
|
config_manager, "get",
|
|
lambda key, default=None: (
|
|
"http://127.0.0.1:8889/tidal/callback"
|
|
if key == "tidal.redirect_uri" else default
|
|
),
|
|
)
|
|
|
|
response = client.get("/auth/tidal", base_url="http://192.168.1.50:8008")
|
|
html = _extract_html(response)
|
|
|
|
# Both example URLs in the instructions must use Tidal's port.
|
|
assert ":8889/tidal/callback" in html, (
|
|
"Step 2/3 example URLs must reflect the configured Tidal port"
|
|
)
|
|
assert ":8888/tidal/callback" not in html, (
|
|
"Spotify's port must not appear in Tidal auth instructions"
|
|
)
|
|
|
|
|
|
def test_instructions_respect_custom_callback_port_from_env(
|
|
auth_route_client, monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""SOULSYNC_TIDAL_CALLBACK_PORT env var changes which port the
|
|
Tidal callback server binds to; the instructions must reflect
|
|
that custom port too, not assume the 8889 default."""
|
|
client, fake_client = auth_route_client
|
|
|
|
fake_client.redirect_uri = "http://127.0.0.1:9999/tidal/callback"
|
|
|
|
from config.settings import config_manager
|
|
monkeypatch.setattr(
|
|
config_manager, "get",
|
|
lambda key, default=None: (
|
|
"http://127.0.0.1:9999/tidal/callback"
|
|
if key == "tidal.redirect_uri" else default
|
|
),
|
|
)
|
|
monkeypatch.setenv("SOULSYNC_TIDAL_CALLBACK_PORT", "9999")
|
|
|
|
response = client.get("/auth/tidal", base_url="http://192.168.1.50:8008")
|
|
html = _extract_html(response)
|
|
|
|
assert ":9999/tidal/callback" in html
|
|
|
|
|
|
def test_instructions_fall_back_to_default_port_when_redirect_uri_is_unparseable(
|
|
auth_route_client, monkeypatch: pytest.MonkeyPatch,
|
|
) -> None:
|
|
"""Defensive: if redirect_uri somehow has no port (corrupted
|
|
config, schemeless string, etc.), the instructions fall back to
|
|
the default Tidal port from the env var instead of crashing or
|
|
showing the Spotify port."""
|
|
client, fake_client = auth_route_client
|
|
|
|
fake_client.redirect_uri = "not-a-valid-url"
|
|
|
|
from config.settings import config_manager
|
|
monkeypatch.setattr(
|
|
config_manager, "get",
|
|
lambda key, default=None: (
|
|
"not-a-valid-url" if key == "tidal.redirect_uri" else default
|
|
),
|
|
)
|
|
|
|
response = client.get("/auth/tidal", base_url="http://192.168.1.50:8008")
|
|
html = _extract_html(response)
|
|
|
|
# Falls back to Tidal default 8889, never to Spotify's 8888.
|
|
assert ":8889/tidal/callback" in html
|
|
assert ":8888/tidal/callback" not in html
|