Files
superset2/tests/unit_tests/mcp_service/dashboard/test_permalink.py
T

375 lines
12 KiB
Python

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Tests for MCP dashboard permalink helpers."""
from unittest.mock import patch
import pytest
from flask import g
from superset.commands.dashboard.exceptions import DashboardAccessDeniedError
from superset.mcp_service.dashboard.permalink import (
DashboardLookupResult,
extract_dashboard_permalink_key,
get_dashboard_permalink,
get_matching_dashboard_permalink_state,
lookup_dashboard_reference,
refresh_request_user_for_permalink_access,
)
FOUND = "dashboard"
PERMALINK_URL = "https://example.test/dashboard/p/shared-key/"
def _lookup_finding(*found_identifiers: int | str):
"""Build a ``lookup`` callable that only resolves ``found_identifiers``."""
known = {str(identifier) for identifier in found_identifiers}
def lookup(identifier: int | str) -> str | None:
return FOUND if str(identifier) in known else None
return lookup
def _is_found(result: str | None) -> bool:
return result is not None
@pytest.mark.parametrize(
("value", "expected"),
[
("bare-key", "bare-key"),
("/superset/dashboard/p/shared-key/", "shared-key"),
(
"https://example.test/prefix/dashboard/p/shared-key/?foo=bar#tab",
"shared-key",
),
(
"https://example.test/dashboard/not-p/shared-key/",
"https://example.test/dashboard/not-p/shared-key/",
),
],
)
def test_extract_dashboard_permalink_key(value: str, expected: str) -> None:
assert extract_dashboard_permalink_key(value) == expected
@patch(
"superset.commands.dashboard.permalink.get.GetDashboardPermalinkCommand.run",
side_effect=DashboardAccessDeniedError(),
)
@patch(
"superset.mcp_service.dashboard.permalink.refresh_request_user_for_permalink_access"
)
def test_get_dashboard_permalink_hides_access_denial(mock_refresh, mock_run) -> None:
assert get_dashboard_permalink("inaccessible-key") is None
mock_refresh.assert_called_once_with()
mock_run.assert_called_once_with()
@pytest.mark.parametrize(
("username", "email", "expected_kwargs"),
[
("admin", None, {"username": "admin"}),
(None, "admin@example.com", {"email": "admin@example.com"}),
],
)
def test_refresh_request_user_for_permalink_access(
app, username: str | None, email: str | None, expected_kwargs: dict[str, str]
) -> None:
current_user = type(
"CurrentUser",
(),
{"username": username, "email": email, "is_anonymous": False},
)()
refreshed_user = object()
with (
patch(
"superset.mcp_service.dashboard.permalink.load_user_with_relationships",
return_value=refreshed_user,
) as mock_load,
app.test_request_context("/mcp"),
):
g.user = current_user
refresh_request_user_for_permalink_access()
assert g.user is refreshed_user
mock_load.assert_called_once_with(**expected_kwargs)
@pytest.mark.parametrize(
("username", "email", "is_anonymous"),
[("anonymous", "anonymous@example.com", True), (None, None, False)],
)
def test_refresh_request_user_for_permalink_access_skips_unresolvable_user(
app, username: str | None, email: str | None, is_anonymous: bool
) -> None:
current_user = type(
"CurrentUser",
(),
{"username": username, "email": email, "is_anonymous": is_anonymous},
)()
with (
patch(
"superset.mcp_service.dashboard.permalink.load_user_with_relationships"
) as mock_load,
app.test_request_context("/mcp"),
):
g.user = current_user
refresh_request_user_for_permalink_access()
assert g.user is current_user
mock_load.assert_not_called()
def test_refresh_request_user_for_permalink_access_keeps_user_when_reload_fails(
app,
) -> None:
current_user = type(
"CurrentUser",
(),
{"username": "admin", "email": None, "is_anonymous": False},
)()
with (
patch(
"superset.mcp_service.dashboard.permalink.load_user_with_relationships",
return_value=None,
) as mock_load,
app.test_request_context("/mcp"),
):
g.user = current_user
refresh_request_user_for_permalink_access()
assert g.user is current_user
mock_load.assert_called_once_with(username="admin")
@pytest.mark.parametrize(
("reference", "expected_match"),
[
# CreateDashboardPermalinkCommand stores str(dashboard.uuid).
("3f1a2b6c-9d4e-4f80-9c2a-7b1d5e6f8a90", True),
# Legacy permalinks may hold the numeric id or the slug.
("42", True),
("sales-dashboard", True),
("99", False),
("00000000-0000-0000-0000-000000000000", False),
],
)
def test_get_matching_dashboard_permalink_state_accepts_every_identifier(
app, reference: str, expected_match: bool
) -> None:
lookup_result = DashboardLookupResult(
result=object(),
permalink_key="key-1",
permalink_value={"dashboardId": reference, "state": {"activeTabs": ["TAB-A"]}},
)
with app.test_request_context("/mcp"):
state = get_matching_dashboard_permalink_state(
lookup_result,
42,
"3f1a2b6c-9d4e-4f80-9c2a-7b1d5e6f8a90",
"sales-dashboard",
)
assert (state is not None) is expected_match
def test_get_matching_dashboard_permalink_state_skips_check_when_permalink_resolved(
app,
) -> None:
"""The permalink-only path already selected the dashboard from the permalink,
so its state is never re-verified against the resolved identifiers.
"""
lookup_result = DashboardLookupResult(
result=object(),
permalink_key="key-1",
permalink_value={"dashboardId": "whatever", "state": {"activeTabs": ["TAB-A"]}},
resolved_from_permalink=True,
)
with app.test_request_context("/mcp"):
state = get_matching_dashboard_permalink_state(lookup_result, 42)
assert state is not None
assert state.key == "key-1"
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_identifier_only(mock_get_permalink) -> None:
result = lookup_dashboard_reference(
identifier=42,
permalink_key=None,
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key is None
assert result.permalink_value is None
assert result.resolved_from_permalink is False
mock_get_permalink.assert_not_called()
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_identifier_wins_but_permalink_adds_state(
mock_get_permalink,
) -> None:
"""An explicit identifier selects the dashboard; the permalink only adds state."""
value = {"dashboardId": "42", "state": {"activeTabs": ["TAB-A"]}}
mock_get_permalink.return_value = ("key-1", value)
result = lookup_dashboard_reference(
identifier=42,
permalink_key="key-1",
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key == "key-1"
assert result.permalink_value == value
assert result.resolved_from_permalink is False
@patch(
"superset.mcp_service.dashboard.permalink.get_dashboard_permalink",
return_value=None,
)
def test_lookup_dashboard_reference_keeps_dashboard_when_permalink_unresolvable(
mock_get_permalink,
) -> None:
result = lookup_dashboard_reference(
identifier=42,
permalink_key="expired-key",
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key == "expired-key"
assert result.permalink_value is None
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_numeric_identifier_not_found(
mock_get_permalink,
) -> None:
"""A numeric identifier never falls back to permalink resolution."""
result = lookup_dashboard_reference(
identifier=99,
permalink_key=None,
lookup=_lookup_finding(),
is_found=_is_found,
)
assert result.result is None
assert result.permalink_key is None
mock_get_permalink.assert_not_called()
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_identifier_not_found_with_explicit_permalink(
mock_get_permalink,
) -> None:
"""An explicit permalink_key keeps the identifier's own not-found result."""
result = lookup_dashboard_reference(
identifier="missing-slug",
permalink_key="key-1",
lookup=_lookup_finding(),
is_found=_is_found,
)
assert result.result is None
assert result.permalink_key == "key-1"
mock_get_permalink.assert_not_called()
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_shared_url_identifier(mock_get_permalink) -> None:
value = {"dashboardId": "42", "state": {"activeTabs": ["TAB-A"]}}
mock_get_permalink.return_value = ("shared-key", value)
result = lookup_dashboard_reference(
identifier=PERMALINK_URL,
permalink_key=None,
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key == "shared-key"
assert result.permalink_value == value
assert result.resolved_from_permalink is True
mock_get_permalink.assert_called_once_with("shared-key")
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_permalink_only(mock_get_permalink) -> None:
value = {"dashboardId": "42", "state": {"activeTabs": ["TAB-A"]}}
mock_get_permalink.return_value = ("key-1", value)
result = lookup_dashboard_reference(
identifier=None,
permalink_key="key-1",
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key == "key-1"
assert result.resolved_from_permalink is True
@patch("superset.mcp_service.dashboard.permalink.get_dashboard_permalink")
def test_lookup_dashboard_reference_bare_string_falls_back_to_permalink(
mock_get_permalink,
) -> None:
"""An ambiguous bare string tries identifier lookup before permalink lookup."""
value = {"dashboardId": "42", "state": {"activeTabs": ["TAB-A"]}}
mock_get_permalink.return_value = ("maybe-key", value)
result = lookup_dashboard_reference(
identifier="maybe-key",
permalink_key=None,
lookup=_lookup_finding(42),
is_found=_is_found,
)
assert result.result == FOUND
assert result.permalink_key == "maybe-key"
assert result.resolved_from_permalink is True
mock_get_permalink.assert_called_once_with("maybe-key")
@patch(
"superset.mcp_service.dashboard.permalink.get_dashboard_permalink",
return_value=None,
)
def test_lookup_dashboard_reference_unresolvable_reference(mock_get_permalink) -> None:
result = lookup_dashboard_reference(
identifier="nonexistent",
permalink_key=None,
lookup=_lookup_finding(),
is_found=_is_found,
)
assert result.result is None
assert result.permalink_key == "nonexistent"
assert result.permalink_value is None
assert result.resolved_from_permalink is False