| # 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 ANY, call, MagicMock, patch |
| |
| import pytest |
| |
| from superset import db, security_manager |
| from superset.commands.dashboard.update import UpdateDashboardCommand |
| from superset.models.dashboard import Dashboard |
| from superset.utils.json import dumps |
| from tests.integration_tests.fixtures.tabbed_dashboard import ( |
| tabbed_dashboard, # noqa: F401 |
| ) |
| from tests.integration_tests.reports.utils import ( |
| cleanup_report_schedule, |
| create_report_notification, |
| ) |
| from tests.integration_tests.test_app import app |
| |
| tab1 = "TAB-L1AA" |
| tab2 = "TAB-L1AB" |
| tab3 = "TAB-L1BB" |
| |
| |
| @pytest.fixture(autouse=True, scope="module") |
| def initial_report_cleanup(): |
| with app.app_context(): |
| cleanup_report_schedule() |
| |
| |
| def remove_tabs_from_dashboard(dashboard: Dashboard, tabs: list[str]): |
| data = dashboard.data.copy() |
| position = data["position_json"] |
| for tab in tabs: |
| del position[tab] |
| data["position_json"] = dumps(position) |
| return data |
| |
| |
| @patch("superset.commands.dashboard.update.send_email_smtp") |
| @patch.dict( |
| "superset.extensions.feature_flag_manager._feature_flags", ALERT_REPORT_TABS=True |
| ) |
| def test_tab_deletion_single_report( |
| send_email_smtp_mock: MagicMock, |
| tabbed_dashboard: Dashboard, # noqa: F811 |
| login_as_admin, |
| ): |
| tab_to_delete = tab1 |
| users = db.session.query(security_manager.user_model).all() |
| report = create_report_notification( |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": tab_to_delete}}, |
| owners=[users[0]], |
| ) |
| assert report.active is True |
| UpdateDashboardCommand( |
| tabbed_dashboard.id, |
| remove_tabs_from_dashboard(tabbed_dashboard, [tab_to_delete]), |
| ).run() |
| |
| assert report.active is False |
| send_email_smtp_mock.assert_called_with( |
| to=users[0].email, |
| subject="[Report: report] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ) |
| cleanup_report_schedule(report) |
| |
| |
| @patch("superset.commands.dashboard.update.send_email_smtp") |
| @patch.dict( |
| "superset.extensions.feature_flag_manager._feature_flags", ALERT_REPORT_TABS=True |
| ) |
| def test_tab_deletion_multiple_reports( |
| send_email_smtp_mock: MagicMock, |
| tabbed_dashboard: Dashboard, # noqa: F811 |
| login_as_admin, |
| ): |
| tab_to_delete = tab1 |
| retained_tab = tab2 |
| users = db.session.query(security_manager.user_model).all() |
| report1 = create_report_notification( |
| name="report 1", |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": tab_to_delete}}, |
| owners=[users[0], users[1]], |
| ) |
| report2 = create_report_notification( |
| name="report 2", |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": tab_to_delete}}, |
| owners=[users[1]], |
| ) |
| report3 = create_report_notification( |
| name="report 3", |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": retained_tab}}, |
| owners=[users[2]], |
| ) |
| |
| assert report1.active is True |
| assert report2.active is True |
| assert report3.active is True |
| |
| UpdateDashboardCommand( |
| tabbed_dashboard.id, |
| remove_tabs_from_dashboard(tabbed_dashboard, [tab_to_delete]), |
| ).run() |
| |
| assert report1.active is False |
| assert report2.active is False |
| assert report3.active is True |
| |
| expected_calls = [ |
| call( |
| to=users[0].email, |
| subject="[Report: report 1] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| call( |
| to=users[1].email, |
| subject="[Report: report 1] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| call( |
| to=users[1].email, |
| subject="[Report: report 2] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| ] |
| |
| assert send_email_smtp_mock.call_count == 3 |
| assert send_email_smtp_mock.call_args_list == expected_calls |
| |
| cleanup_report_schedule(report1) |
| cleanup_report_schedule(report2) |
| cleanup_report_schedule(report3) |
| |
| |
| @patch("superset.commands.dashboard.update.send_email_smtp") |
| @patch.dict( |
| "superset.extensions.feature_flag_manager._feature_flags", ALERT_REPORT_TABS=True |
| ) |
| def test_multitple_tabs_removed( |
| send_email_smtp_mock: MagicMock, |
| tabbed_dashboard: Dashboard, # noqa: F811 |
| login_as_admin, |
| ): |
| tabs_to_delete = [tab1, tab2] |
| users = db.session.query(security_manager.user_model).all() |
| report1 = create_report_notification( |
| name="report 1", |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": tabs_to_delete[0]}}, |
| owners=[users[0], users[1]], |
| ) |
| report2 = create_report_notification( |
| name="report 2", |
| dashboard=tabbed_dashboard, |
| extra={"dashboard": {"anchor": tabs_to_delete[1]}}, |
| owners=[users[2]], |
| ) |
| |
| assert report1.active is True |
| assert report2.active is True |
| |
| UpdateDashboardCommand( |
| tabbed_dashboard.id, |
| remove_tabs_from_dashboard(tabbed_dashboard, tabs_to_delete), |
| ).run() |
| |
| assert report1.active is False |
| assert report2.active is False |
| |
| expected_calls = [ |
| call( |
| to=users[0].email, |
| subject="[Report: report 1] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| call( |
| to=users[1].email, |
| subject="[Report: report 1] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| call( |
| to=users[2].email, |
| subject="[Report: report 2] Deactivated", |
| html_content=ANY, |
| config=ANY, |
| ), |
| ] |
| |
| assert send_email_smtp_mock.call_count == 3 |
| assert send_email_smtp_mock.call_args_list == expected_calls |
| |
| cleanup_report_schedule(report1) |
| cleanup_report_schedule(report2) |