mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
feat: Implement UI-based system theme administration (#34560)
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
f50cbd7958
commit
5309edf3a5
233
tests/unit_tests/daos/test_theme_dao.py
Normal file
233
tests/unit_tests/daos/test_theme_dao.py
Normal file
@@ -0,0 +1,233 @@
|
||||
# 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.
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from superset.daos.theme import ThemeDAO
|
||||
from superset.models.core import Theme
|
||||
|
||||
|
||||
class TestThemeDAO:
|
||||
"""Test ThemeDAO functionality"""
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
def test_find_system_default_single(self, mock_session):
|
||||
"""Test finding system default theme when exactly one exists"""
|
||||
# Create a mock theme
|
||||
mock_theme = MagicMock(spec=Theme)
|
||||
mock_theme.is_system_default = True
|
||||
|
||||
# Mock the query chain
|
||||
mock_query = MagicMock()
|
||||
mock_session.query.return_value = mock_query
|
||||
mock_filter = MagicMock()
|
||||
mock_query.filter.return_value = mock_filter
|
||||
mock_filter.all.return_value = [mock_theme]
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_default()
|
||||
|
||||
# Verify the result
|
||||
assert result == mock_theme
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
@patch("superset.daos.theme.logger")
|
||||
def test_find_system_default_multiple(self, mock_logger, mock_session):
|
||||
"""Test finding system default theme when multiple exist"""
|
||||
# Create mock themes
|
||||
mock_theme1 = MagicMock(spec=Theme)
|
||||
mock_theme1.is_system_default = True
|
||||
mock_theme2 = MagicMock(spec=Theme)
|
||||
mock_theme2.is_system_default = True
|
||||
|
||||
# Create mock fallback theme
|
||||
mock_fallback = MagicMock(spec=Theme)
|
||||
mock_fallback.is_system = True
|
||||
mock_fallback.theme_name = "THEME_DEFAULT"
|
||||
|
||||
# Mock the query chains - need separate mocks for each query call
|
||||
mock_query1 = MagicMock()
|
||||
mock_query2 = MagicMock()
|
||||
mock_session.query.side_effect = [mock_query1, mock_query2]
|
||||
|
||||
# First query returns multiple themes
|
||||
mock_filter1 = MagicMock()
|
||||
mock_query1.filter.return_value = mock_filter1
|
||||
mock_filter1.all.return_value = [mock_theme1, mock_theme2]
|
||||
|
||||
# Second query returns fallback theme
|
||||
mock_filter2 = MagicMock()
|
||||
mock_query2.filter.return_value = mock_filter2
|
||||
mock_filter2.first.return_value = mock_fallback
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_default()
|
||||
|
||||
# Verify warning was logged
|
||||
mock_logger.warning.assert_called_once()
|
||||
assert (
|
||||
"Multiple system default themes found (2)"
|
||||
in mock_logger.warning.call_args[0][0]
|
||||
)
|
||||
|
||||
# Verify the result is the fallback theme
|
||||
assert result == mock_fallback
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
def test_find_system_default_none(self, mock_session):
|
||||
"""Test finding system default theme when none exist"""
|
||||
# Create mock fallback theme
|
||||
mock_fallback = MagicMock(spec=Theme)
|
||||
mock_fallback.is_system = True
|
||||
mock_fallback.theme_name = "THEME_DEFAULT"
|
||||
|
||||
# Mock the query chains - need separate mocks for each query call
|
||||
mock_query1 = MagicMock()
|
||||
mock_query2 = MagicMock()
|
||||
mock_session.query.side_effect = [mock_query1, mock_query2]
|
||||
|
||||
# First query returns no themes
|
||||
mock_filter1 = MagicMock()
|
||||
mock_query1.filter.return_value = mock_filter1
|
||||
mock_filter1.all.return_value = []
|
||||
|
||||
# Second query returns fallback theme
|
||||
mock_filter2 = MagicMock()
|
||||
mock_query2.filter.return_value = mock_filter2
|
||||
mock_filter2.first.return_value = mock_fallback
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_default()
|
||||
|
||||
# Verify the result is the fallback theme
|
||||
assert result == mock_fallback
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
def test_find_system_dark_single(self, mock_session):
|
||||
"""Test finding system dark theme when exactly one exists"""
|
||||
# Create a mock theme
|
||||
mock_theme = MagicMock(spec=Theme)
|
||||
mock_theme.is_system_dark = True
|
||||
|
||||
# Mock the query chain
|
||||
mock_query = MagicMock()
|
||||
mock_session.query.return_value = mock_query
|
||||
mock_filter = MagicMock()
|
||||
mock_query.filter.return_value = mock_filter
|
||||
mock_filter.all.return_value = [mock_theme]
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_dark()
|
||||
|
||||
# Verify the result
|
||||
assert result == mock_theme
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
@patch("superset.daos.theme.logger")
|
||||
def test_find_system_dark_multiple(self, mock_logger, mock_session):
|
||||
"""Test finding system dark theme when multiple exist"""
|
||||
# Create mock themes
|
||||
mock_theme1 = MagicMock(spec=Theme)
|
||||
mock_theme1.is_system_dark = True
|
||||
mock_theme2 = MagicMock(spec=Theme)
|
||||
mock_theme2.is_system_dark = True
|
||||
|
||||
# Create mock fallback theme
|
||||
mock_fallback = MagicMock(spec=Theme)
|
||||
mock_fallback.is_system = True
|
||||
mock_fallback.theme_name = "THEME_DARK"
|
||||
|
||||
# Mock the query chains - need separate mocks for each query call
|
||||
mock_query1 = MagicMock()
|
||||
mock_query2 = MagicMock()
|
||||
mock_session.query.side_effect = [mock_query1, mock_query2]
|
||||
|
||||
# First query returns multiple themes
|
||||
mock_filter1 = MagicMock()
|
||||
mock_query1.filter.return_value = mock_filter1
|
||||
mock_filter1.all.return_value = [mock_theme1, mock_theme2]
|
||||
|
||||
# Second query returns fallback theme
|
||||
mock_filter2 = MagicMock()
|
||||
mock_query2.filter.return_value = mock_filter2
|
||||
mock_filter2.first.return_value = mock_fallback
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_dark()
|
||||
|
||||
# Verify warning was logged
|
||||
mock_logger.warning.assert_called_once()
|
||||
assert (
|
||||
"Multiple system dark themes found (2)"
|
||||
in mock_logger.warning.call_args[0][0]
|
||||
)
|
||||
|
||||
# Verify the result is the fallback theme
|
||||
assert result == mock_fallback
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
def test_find_system_dark_none_with_fallback(self, mock_session):
|
||||
"""Test finding system dark theme when none exist but fallback does"""
|
||||
# Create mock fallback theme
|
||||
mock_fallback = MagicMock(spec=Theme)
|
||||
mock_fallback.is_system = True
|
||||
mock_fallback.theme_name = "THEME_DARK"
|
||||
|
||||
# Mock the query chains - need separate mocks for each query call
|
||||
mock_query1 = MagicMock()
|
||||
mock_query2 = MagicMock()
|
||||
mock_session.query.side_effect = [mock_query1, mock_query2]
|
||||
|
||||
# First query returns no themes
|
||||
mock_filter1 = MagicMock()
|
||||
mock_query1.filter.return_value = mock_filter1
|
||||
mock_filter1.all.return_value = []
|
||||
|
||||
# Second query returns fallback theme
|
||||
mock_filter2 = MagicMock()
|
||||
mock_query2.filter.return_value = mock_filter2
|
||||
mock_filter2.first.return_value = mock_fallback
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_dark()
|
||||
|
||||
# Verify the result is the fallback theme
|
||||
assert result == mock_fallback
|
||||
|
||||
@patch("superset.daos.theme.db.session")
|
||||
def test_find_system_dark_none_without_fallback(self, mock_session):
|
||||
"""Test finding system dark theme when none exist and no fallback"""
|
||||
# Mock the query chains - need separate mocks for each query call
|
||||
mock_query1 = MagicMock()
|
||||
mock_query2 = MagicMock()
|
||||
mock_session.query.side_effect = [mock_query1, mock_query2]
|
||||
|
||||
# First query returns no themes
|
||||
mock_filter1 = MagicMock()
|
||||
mock_query1.filter.return_value = mock_filter1
|
||||
mock_filter1.all.return_value = []
|
||||
|
||||
# Second query returns no fallback
|
||||
mock_filter2 = MagicMock()
|
||||
mock_query2.filter.return_value = mock_filter2
|
||||
mock_filter2.first.return_value = None
|
||||
|
||||
# Call the method
|
||||
result = ThemeDAO.find_system_dark()
|
||||
|
||||
# Verify the result is None
|
||||
assert result is None
|
||||
Reference in New Issue
Block a user