import pytest from fastapi.testclient import TestClient from app.core.auth_dependency import require_session from app.db import get_db from app.main import app from app.models.channel import Channel from app.services import sync from app.services.youtube_client import YouTubeInsufficientScope @pytest.fixture def client(db_session): def _get_db_override(): yield db_session app.dependency_overrides[get_db] = _get_db_override app.dependency_overrides[require_session] = lambda: None # Deliberately not using `with TestClient(app)`: that runs the app's # lifespan, which would try to reach the real MeTube instance and DB. yield TestClient(app) del app.dependency_overrides[get_db] del app.dependency_overrides[require_session] def _seed_channel(db_session, youtube_subscription_id="sub1"): channel = Channel( youtube_channel_id="chanA", youtube_subscription_id=youtube_subscription_id, title="Channel A", subscribed=True, ) db_session.add(channel) db_session.commit() db_session.refresh(channel) return channel def test_unsubscribe_success(client, db_session, monkeypatch): channel = _seed_channel(db_session) monkeypatch.setattr(sync.google_oauth, "get_credentials", lambda db: object()) calls = {} monkeypatch.setattr( sync.youtube_client, "unsubscribe", lambda creds, sub_id: calls.setdefault("sub_id", sub_id), ) resp = client.post(f"/api/channels/{channel.id}/unsubscribe") assert resp.status_code == 200 assert resp.json()["subscribed"] is False assert calls["sub_id"] == "sub1" db_session.refresh(channel) assert channel.subscribed is False def test_unsubscribe_without_subscription_id_returns_400(client, db_session): channel = _seed_channel(db_session, youtube_subscription_id=None) resp = client.post(f"/api/channels/{channel.id}/unsubscribe") assert resp.status_code == 400 def test_unsubscribe_insufficient_scope_returns_403(client, db_session, monkeypatch): channel = _seed_channel(db_session) monkeypatch.setattr(sync.google_oauth, "get_credentials", lambda db: object()) def raise_insufficient(creds, sub_id): raise YouTubeInsufficientScope("Request had insufficient authentication scopes.") monkeypatch.setattr(sync.youtube_client, "unsubscribe", raise_insufficient) resp = client.post(f"/api/channels/{channel.id}/unsubscribe") assert resp.status_code == 403 db_session.refresh(channel) assert channel.subscribed is True def test_unsubscribe_channel_not_found(client): resp = client.post("/api/channels/9999/unsubscribe") assert resp.status_code == 404