# allow: no-sut-import — black-box HTTP test; drives real routes through the Flask test client
"""Tests for research_routes module - Research page and API endpoints."""

from unittest.mock import patch, MagicMock


# Research routes are registered under root level
RESEARCH_PREFIX = ""

# Common patch target prefix for research_routes module
_RR = "local_deep_research.web.routes.research_routes"


class TestProgressPage:
    """Tests for /progress/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/progress/test-id")
        assert response.status_code == 302, response.status_code

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return progress page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Progress</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/progress/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/progress.html")


class TestResearchDetailsPage:
    """Tests for /details/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/details/test-id")
        assert response.status_code == 302, response.status_code

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return details page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Details</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/details/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/details.html")


class TestResultsPage:
    """Tests for /results/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/results/test-id")
        assert response.status_code == 302, response.status_code

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return results page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Results</html>"
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/results/test-id"
            )
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/results.html")


class TestHistoryPage:
    """Tests for /history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/history")
        assert response.status_code == 302, response.status_code

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return history page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>History</html>"
            response = authenticated_client.get(f"{RESEARCH_PREFIX}/history")
            assert response.status_code == 200
            mock_render.assert_called_once_with("pages/history.html")


class TestSettingsPage:
    """Tests for /settings endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings")
        assert response.status_code == 302, response.status_code

    def test_returns_page_when_authenticated(self, authenticated_client):
        """Should return settings page when authenticated."""
        with patch(
            "local_deep_research.web.routes.research_routes.render_template_with_defaults"
        ) as mock_render:
            mock_render.return_value = "<html>Settings</html>"
            response = authenticated_client.get(f"{RESEARCH_PREFIX}/settings")
            assert response.status_code == 200
            mock_render.assert_called_once_with("settings_dashboard.html")


class TestMainConfigPage:
    """Tests for /settings/main endpoint (now redirects via settings blueprint)."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/main")
        assert response.status_code == 302, response.status_code

    def test_redirects_when_authenticated(self, authenticated_client):
        """Should redirect to settings dashboard."""
        response = authenticated_client.get(f"{RESEARCH_PREFIX}/settings/main")
        assert response.status_code == 302


class TestCollectionsConfigPage:
    """Tests for /settings/collections endpoint (now redirects via settings blueprint)."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/collections")
        assert response.status_code == 302, response.status_code

    def test_redirects_when_authenticated(self, authenticated_client):
        """Should redirect to settings dashboard."""
        response = authenticated_client.get(
            f"{RESEARCH_PREFIX}/settings/collections"
        )
        assert response.status_code == 302


class TestApiKeysConfigPage:
    """Tests for /settings/api_keys endpoint (now redirects via settings blueprint)."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/api_keys")
        assert response.status_code == 302, response.status_code

    def test_redirects_when_authenticated(self, authenticated_client):
        """Should redirect to settings dashboard."""
        response = authenticated_client.get(
            f"{RESEARCH_PREFIX}/settings/api_keys"
        )
        assert response.status_code == 302


class TestSearchEnginesConfigPage:
    """Tests for /settings/search_engines endpoint (now redirects via settings blueprint)."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/search_engines")
        assert response.status_code == 302, response.status_code

    def test_redirects_when_authenticated(self, authenticated_client):
        """Should redirect to settings dashboard."""
        response = authenticated_client.get(
            f"{RESEARCH_PREFIX}/settings/search_engines"
        )
        assert response.status_code == 302


class TestLlmConfigPage:
    """Tests for /settings/llm endpoint (now redirects via settings blueprint)."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/settings/llm")
        assert response.status_code == 302, response.status_code

    def test_redirects_when_authenticated(self, authenticated_client):
        """Should redirect to settings dashboard."""
        response = authenticated_client.get(f"{RESEARCH_PREFIX}/settings/llm")
        assert response.status_code == 302


class TestRedirectStatic:
    """Tests for /redirect-static/<path> endpoint."""

    def test_redirects_to_static(self, authenticated_client):
        """Should redirect to static URL."""
        with patch(f"{_RR}.url_for", return_value="/static/js/app.js"):
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/redirect-static/js/app.js"
            )
            # Should return a redirect response
            assert response.status_code == 302


class TestStartResearchApi:
    """Tests for /api/start_research endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            json={"query": "test query"},
        )
        assert response.status_code == 401, response.status_code

    def test_returns_401_without_session(self, authenticated_client):
        """Should return 401 when session has no username."""
        # Clear the session username
        with authenticated_client.session_transaction() as sess:
            sess.pop("username", None)

        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            json={"query": "test query"},
        )
        # Expects 401 since username is not in session
        assert response.status_code == 401

    def test_requires_json_body(self, authenticated_client):
        """Should require JSON body."""
        response = authenticated_client.post(
            f"{RESEARCH_PREFIX}/api/start_research",
            data="not json",
            content_type="text/plain",
        )
        # Should return error for non-JSON body
        assert response.status_code == 400, response.status_code


class TestTerminateResearchApi:
    """Tests for /api/terminate/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(f"{RESEARCH_PREFIX}/api/terminate/test-id")
        assert response.status_code == 401, response.status_code

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle terminate request when authenticated."""
        mock_research = MagicMock()
        mock_research.status = "in_progress"
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.post(
                f"{RESEARCH_PREFIX}/api/terminate/test-id"
            )
            assert response.status_code == 200, response.status_code


class TestDeleteResearchApi:
    """Tests for /api/delete/<research_id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.delete(f"{RESEARCH_PREFIX}/api/delete/test-id")
        assert response.status_code == 401, response.status_code

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle delete request when authenticated."""
        mock_research = MagicMock()
        mock_research.status = "completed"
        mock_research.report_path = None
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = mock_research
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.delete(
                f"{RESEARCH_PREFIX}/api/delete/test-id"
            )
            assert response.status_code == 200, response.status_code


class TestClearHistoryApi:
    """Tests for /api/clear_history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.post(f"{RESEARCH_PREFIX}/api/clear_history")
        assert response.status_code == 401, response.status_code

    def test_returns_success_when_authenticated(self, authenticated_client):
        """Should handle clear history request when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.post(
                f"{RESEARCH_PREFIX}/api/clear_history"
            )
            assert response.status_code == 200, response.status_code


class TestGetHistoryApi:
    """Tests for /api/history endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/history")
        assert response.status_code == 401, response.status_code

    def test_returns_history_when_authenticated(self, authenticated_client):
        """Should return history when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.order_by.return_value.limit.return_value.offset.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/history"
            )
            assert response.status_code == 200, response.status_code

    def test_pagination_is_clamped(self, authenticated_client):
        """/api/history must bound its result set: ?limit=-1 (which SQLite
        treats as "no limit") is clamped to >= 1 and offset to >= 0 so the
        endpoint can't load the whole history into memory (#4560)."""
        mock_session = MagicMock()
        mock_session.query.return_value.order_by.return_value.limit.return_value.offset.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/history?limit=-1&offset=-5"
            )
            assert response.status_code == 200, response.status_code

        records_q = mock_session.query.return_value.order_by.return_value
        records_q.limit.assert_called_once_with(1)
        records_q.limit.return_value.offset.assert_called_once_with(0)

    def test_query_projects_columns_not_full_entity(self, authenticated_client):
        """/api/history must project only metadata columns, never the
        full ResearchHistory entity — querying the entity eagerly loads
        the large report_content Text body into memory. Regression guard
        for #4560 (a revert to query(ResearchHistory) is output-identical
        and would otherwise pass silently)."""
        from local_deep_research.database.models import ResearchHistory

        mock_session = MagicMock()
        mock_session.query.return_value.order_by.return_value.limit.return_value.offset.return_value.all.return_value = []
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/history"
            )
            assert response.status_code == 200, response.status_code

        # Identity checks: a SQLAlchemy column's __eq__ builds a SQL clause,
        # so `in`/`==` membership tests are unsafe here. Inspect EVERY query()
        # call (not a positional index) so the guard stays robust if queries
        # are reordered/added: the listing must never load the full
        # ResearchHistory entity or its report_content body in any of them.
        all_selected = [
            arg
            for call in mock_session.query.call_args_list
            for arg in call.args
        ]
        assert not any(arg is ResearchHistory for arg in all_selected), (
            "get_history must not query the full ResearchHistory entity"
        )
        assert not any(
            arg is ResearchHistory.report_content for arg in all_selected
        ), "get_history must not load the report_content body"


class TestGetResearchDetailsApi:
    """Tests for /api/research/<id> endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id")
        assert response.status_code == 401, response.status_code

    def test_returns_details_when_authenticated(self, authenticated_client):
        """Should return research details when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id"
            )
            assert response.status_code == 404, response.status_code


class TestGetResearchLogsApi:
    """Tests for /api/research/<id>/logs endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id/logs")
        assert response.status_code == 401, response.status_code

    def test_returns_logs_when_authenticated(self, authenticated_client):
        """Should return research logs when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id/logs"
            )
            assert response.status_code == 404, response.status_code

    @staticmethod
    def _seed_real_session(num_logs, same_timestamp=False):
        """Build an in-memory SQLite session with one ResearchHistory row
        (id ``test-rid``) and ``num_logs`` ResearchLog rows (messages
        ``Log 0``..``Log N-1``, inserted oldest-first so the autoincrement
        ``id`` rises with the message index). Returns the live session so the
        route is driven through real SQL — a mocked query chain returns a fixed
        list regardless of ``desc()``/``limit()`` and so cannot prove the
        newest-N ordering.

        Rows are spaced 1 minute apart unless ``same_timestamp`` is set, in
        which case every row shares one timestamp — used to prove the ``id``
        tie-break makes the newest-N selection deterministic.
        """
        from datetime import datetime, timedelta, timezone

        from sqlalchemy import create_engine
        from sqlalchemy.orm import sessionmaker

        from local_deep_research.database.models import (
            Base,
            ResearchHistory,
            ResearchLog,
        )

        engine = create_engine("sqlite:///:memory:")
        Base.metadata.create_all(engine)
        session = sessionmaker(bind=engine)()

        session.add(
            ResearchHistory(
                id="test-rid",
                query="q",
                mode="quick",
                status="completed",
                created_at="2025-01-01T00:00:00+00:00",
            )
        )
        base_time = datetime(2025, 1, 1, tzinfo=timezone.utc)
        for i in range(num_logs):
            offset = timedelta(0) if same_timestamp else timedelta(minutes=i)
            session.add(
                ResearchLog(
                    research_id="test-rid",
                    timestamp=base_time + offset,
                    message=f"Log {i}",
                    module="test",
                    function="test",
                    line_no=i,
                    level="INFO",
                )
            )
        session.commit()
        return session

    @staticmethod
    def _close_session(session):
        """Close the session AND dispose its in-memory engine, so the
        underlying sqlite connection is released (otherwise the pool keeps
        it open and pytest reports a ResourceWarning)."""
        engine = session.get_bind()
        session.close()
        if engine is not None:
            engine.dispose()

    def _get_logs(self, authenticated_client, session, query):
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            return authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-rid/logs{query}"
            )

    def test_no_limit_returns_all_logs_oldest_first(self, authenticated_client):
        """Omitting ?limit preserves the public contract: every row, asc."""
        session = self._seed_real_session(10)
        try:
            resp = self._get_logs(authenticated_client, session, "")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == [f"Log {i}" for i in range(10)]
        finally:
            self._close_session(session)

    def test_limit_returns_newest_n_oldest_first(self, authenticated_client):
        """?limit=N returns the newest N rows, still oldest-first."""
        session = self._seed_real_session(10)
        try:
            resp = self._get_logs(authenticated_client, session, "?limit=3")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == ["Log 7", "Log 8", "Log 9"]
        finally:
            self._close_session(session)

    def test_limit_is_clamped_to_at_least_one(self, authenticated_client):
        """?limit=0 clamps up to 1 -> just the single newest row."""
        session = self._seed_real_session(10)
        try:
            resp = self._get_logs(authenticated_client, session, "?limit=0")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == ["Log 9"]
        finally:
            self._close_session(session)

    def test_malformed_limit_falls_back_to_all_logs(self, authenticated_client):
        """A non-integer ?limit (Flask ``type=int`` yields None) is treated as
        absent, preserving the return-all contract rather than erroring."""
        session = self._seed_real_session(10)
        try:
            resp = self._get_logs(authenticated_client, session, "?limit=abc")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == [f"Log {i}" for i in range(10)]
        finally:
            self._close_session(session)

    def test_negative_limit_clamps_to_one(self, authenticated_client):
        """?limit=-5 clamps to 1 — NOT SQLite's ``LIMIT -1`` (= unbounded).
        The clamp runs before ``.limit()``, so a negative value can never
        reach SQL as a no-op limit."""
        session = self._seed_real_session(10)
        try:
            resp = self._get_logs(authenticated_client, session, "?limit=-5")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == ["Log 9"]
        finally:
            self._close_session(session)

    def test_limit_above_hard_cap_is_clamped(self, authenticated_client):
        """?limit above HISTORY_LOGS_HARD_CAP is clamped to the cap. The cap
        is patched to a small value so the clamp is observable without seeding
        thousands of rows."""
        session = self._seed_real_session(10)
        try:
            with patch(f"{_RR}.HISTORY_LOGS_HARD_CAP", 2):
                resp = self._get_logs(
                    authenticated_client, session, "?limit=999999"
                )
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == ["Log 8", "Log 9"]
        finally:
            self._close_session(session)

    def test_tie_break_on_equal_timestamps_is_deterministic(
        self, authenticated_client
    ):
        """When rows share a timestamp, ``id`` tie-breaks so ?limit selects the
        highest-id (most recently inserted) rows deterministically — without
        the secondary key the surviving rows at the boundary are SQL-undefined.
        Log i has id i+1, so newest-3-by-id is Log 7/8/9, oldest-first."""
        session = self._seed_real_session(10, same_timestamp=True)
        try:
            resp = self._get_logs(authenticated_client, session, "?limit=3")
            assert resp.status_code == 200, resp.status_code
            messages = [r["message"] for r in resp.get_json()]
            assert messages == ["Log 7", "Log 8", "Log 9"]
        finally:
            self._close_session(session)


class TestGetResearchStatusApi:
    """Tests for /api/research/<id>/status endpoint."""

    def test_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/research/test-id/status")
        assert response.status_code == 401, response.status_code

    def test_returns_status_when_authenticated(self, authenticated_client):
        """Should return research status when authenticated."""
        mock_session = MagicMock()
        mock_session.query.return_value.filter_by.return_value.first.return_value = None
        with patch(f"{_RR}.get_user_db_session") as mock_db:
            mock_db.return_value.__enter__ = lambda s: mock_session
            mock_db.return_value.__exit__ = MagicMock(return_value=False)
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/research/test-id/status"
            )
            assert response.status_code == 404, response.status_code

    def test_latest_milestone_tie_breaks_equal_timestamps_by_id(
        self, authenticated_client
    ):
        """The /status latest-milestone ``.first()`` picks the highest-id
        milestone among rows sharing the latest timestamp — deterministic,
        not the SQL-undefined arbitrary row the prior single-key order_by
        allowed. Driven through real SQL so the ``id`` tie-break is exercised
        (a mocked ``.first()`` would ignore the order_by and pass regardless).
        """
        from datetime import datetime, timezone

        from local_deep_research.database.models import ResearchLog

        # Reuse the real-session seeding (research row, no INFO logs), then add
        # 3 MILESTONE rows sharing one timestamp; ids rise with insertion so
        # "Milestone 2" is the highest-id (most recently inserted) one.
        session = TestGetResearchLogsApi._seed_real_session(0)
        shared_time = datetime(2025, 1, 1, tzinfo=timezone.utc)
        for i in range(3):
            session.add(
                ResearchLog(
                    research_id="test-rid",
                    timestamp=shared_time,
                    message=f"Milestone {i}",
                    module="test",
                    function="test",
                    line_no=i,
                    level="MILESTONE",
                )
            )
        session.commit()
        try:
            with patch(f"{_RR}.get_user_db_session") as mock_db:
                mock_db.return_value.__enter__ = lambda s: session
                mock_db.return_value.__exit__ = MagicMock(return_value=False)
                resp = authenticated_client.get(
                    f"{RESEARCH_PREFIX}/api/research/test-rid/status"
                )
            assert resp.status_code == 200, resp.status_code
            assert resp.get_json()["log_entry"]["message"] == "Milestone 2"
        finally:
            TestGetResearchLogsApi._close_session(session)


class TestQueueStatusApi:
    """Tests for queue status API endpoints."""

    def test_get_queue_status_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/queue/status")
        assert response.status_code == 401, response.status_code

    def test_get_queue_status_when_authenticated(self, authenticated_client):
        """Should return queue status when authenticated."""
        with patch("local_deep_research.web.queue.QueueManager") as mock_qm:
            mock_qm.get_user_queue.return_value = []
            response = authenticated_client.get(
                f"{RESEARCH_PREFIX}/api/queue/status"
            )
            assert response.status_code == 200, response.status_code

    def test_get_queue_position_requires_authentication(self, client):
        """Should require authentication."""
        response = client.get(f"{RESEARCH_PREFIX}/api/queue/test-id/position")
        assert response.status_code == 401, response.status_code
