fix: delete chart, dashboards, dbs with assoc reports (#11801)

* fix: delete chart or dashboards with assoc reports

* database constraint to reports and tests

* add tests for dashboards and database

* fix exceptions default text
This commit is contained in:
Daniel Vaz Gaspar
2020-11-26 08:45:49 +00:00
committed by GitHub
parent 13c51d5211
commit bac84a3aac
13 changed files with 304 additions and 4 deletions

View File

@@ -38,6 +38,7 @@ from superset.connectors.connector_registry import ConnectorRegistry
from superset.extensions import db, security_manager
from superset.models.core import Database, FavStar, FavStarClassName
from superset.models.dashboard import Dashboard
from superset.models.reports import ReportSchedule, ReportScheduleType
from superset.models.slice import Slice
from superset.utils import core as utils
from tests.base_api_tests import ApiOwnersTestCaseMixin
@@ -117,6 +118,26 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
db.session.delete(fav_chart)
db.session.commit()
@pytest.fixture()
def create_chart_with_report(self):
with self.create_app().app_context():
admin = self.get_user("admin")
chart = self.insert_chart(f"chart_report", [admin.id], 1)
report_schedule = ReportSchedule(
type=ReportScheduleType.REPORT,
name="report_with_chart",
crontab="* * * * *",
chart=chart,
)
db.session.commit()
yield chart
# rollback changes
db.session.delete(report_schedule)
db.session.delete(chart)
db.session.commit()
def test_delete_chart(self):
"""
Chart API: Test delete
@@ -174,6 +195,26 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
rv = self.delete_assert_metric(uri, "delete")
self.assertEqual(rv.status_code, 404)
@pytest.mark.usefixtures("create_chart_with_report")
def test_delete_chart_with_report(self):
"""
Chart API: Test delete with associated report
"""
self.login(username="admin")
chart = (
db.session.query(Slice)
.filter(Slice.slice_name == "chart_report")
.one_or_none()
)
uri = f"api/v1/chart/{chart.id}"
rv = self.client.delete(uri)
response = json.loads(rv.data.decode("utf-8"))
self.assertEqual(rv.status_code, 422)
expected_response = {
"message": "There are associated alerts or reports: report_with_chart"
}
self.assertEqual(response, expected_response)
def test_delete_bulk_charts_not_found(self):
"""
Chart API: Test delete bulk not found
@@ -181,11 +222,35 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
max_id = db.session.query(func.max(Slice.id)).scalar()
chart_ids = [max_id + 1, max_id + 2]
self.login(username="admin")
argument = chart_ids
uri = f"api/v1/chart/?q={prison.dumps(argument)}"
uri = f"api/v1/chart/?q={prison.dumps(chart_ids)}"
rv = self.delete_assert_metric(uri, "bulk_delete")
self.assertEqual(rv.status_code, 404)
@pytest.mark.usefixtures("create_chart_with_report", "create_charts")
def test_bulk_delete_chart_with_report(self):
"""
Chart API: Test bulk delete with associated report
"""
self.login(username="admin")
chart_with_report = (
db.session.query(Slice.id)
.filter(Slice.slice_name == "chart_report")
.one_or_none()
)
charts = db.session.query(Slice.id).filter(Slice.slice_name.like("name%")).all()
chart_ids = [chart.id for chart in charts]
chart_ids.append(chart_with_report.id)
uri = f"api/v1/chart/?q={prison.dumps(chart_ids)}"
rv = self.client.delete(uri)
response = json.loads(rv.data.decode("utf-8"))
self.assertEqual(rv.status_code, 422)
expected_response = {
"message": "There are associated alerts or reports: report_with_chart"
}
self.assertEqual(response, expected_response)
def test_delete_chart_admin_not_owned(self):
"""
Chart API: Test admin delete not owned

View File

@@ -33,6 +33,7 @@ from sqlalchemy import and_
from superset import db, security_manager
from superset.models.dashboard import Dashboard
from superset.models.core import FavStar, FavStarClassName
from superset.models.reports import ReportSchedule, ReportScheduleType
from superset.models.slice import Slice
from superset.views.base import generate_download_headers
@@ -121,6 +122,28 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin):
db.session.delete(fav_dashboard)
db.session.commit()
@pytest.fixture()
def create_dashboard_with_report(self):
with self.create_app().app_context():
admin = self.get_user("admin")
dashboard = self.insert_dashboard(
f"dashboard_report", "dashboard_report", [admin.id]
)
report_schedule = ReportSchedule(
type=ReportScheduleType.REPORT,
name="report_with_dashboard",
crontab="* * * * *",
dashboard=dashboard,
)
db.session.commit()
yield dashboard
# rollback changes
db.session.delete(report_schedule)
db.session.delete(dashboard)
db.session.commit()
def test_get_dashboard(self):
"""
Dashboard API: Test get dashboard
@@ -493,6 +516,26 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin):
rv = self.client.delete(uri)
self.assertEqual(rv.status_code, 404)
@pytest.mark.usefixtures("create_dashboard_with_report")
def test_delete_dashboard_with_report(self):
"""
Dashboard API: Test delete with associated report
"""
self.login(username="admin")
dashboard = (
db.session.query(Dashboard.id)
.filter(Dashboard.dashboard_title == "dashboard_report")
.one_or_none()
)
uri = f"api/v1/dashboard/{dashboard.id}"
rv = self.client.delete(uri)
response = json.loads(rv.data.decode("utf-8"))
self.assertEqual(rv.status_code, 422)
expected_response = {
"message": "There are associated alerts or reports: report_with_dashboard"
}
self.assertEqual(response, expected_response)
def test_delete_bulk_dashboards_not_found(self):
"""
Dashboard API: Test delete bulk not found
@@ -504,6 +547,34 @@ class TestDashboardApi(SupersetTestCase, ApiOwnersTestCaseMixin):
rv = self.client.delete(uri)
self.assertEqual(rv.status_code, 404)
@pytest.mark.usefixtures("create_dashboard_with_report", "create_dashboards")
def test_bulk_delete_dashboard_with_report(self):
"""
Dashboard API: Test bulk delete with associated report
"""
self.login(username="admin")
dashboard_with_report = (
db.session.query(Dashboard.id)
.filter(Dashboard.dashboard_title == "dashboard_report")
.one_or_none()
)
dashboards = (
db.session.query(Dashboard)
.filter(Dashboard.dashboard_title.like("title%"))
.all()
)
dashboard_ids = [dashboard.id for dashboard in dashboards]
dashboard_ids.append(dashboard_with_report.id)
uri = f"api/v1/dashboard/?q={prison.dumps(dashboard_ids)}"
rv = self.client.delete(uri)
response = json.loads(rv.data.decode("utf-8"))
self.assertEqual(rv.status_code, 422)
expected_response = {
"message": "There are associated alerts or reports: report_with_dashboard"
}
self.assertEqual(response, expected_response)
def test_delete_dashboard_admin_not_owned(self):
"""
Dashboard API: Test admin delete not owned

View File

@@ -30,6 +30,7 @@ from sqlalchemy.sql import func
from superset import db, security_manager
from superset.connectors.sqla.models import SqlaTable
from superset.models.core import Database
from superset.models.reports import ReportSchedule, ReportScheduleType
from superset.utils.core import get_example_database, get_main_database
from tests.base_tests import SupersetTestCase
from tests.fixtures.certificates import ssl_certificate
@@ -66,6 +67,30 @@ class TestDatabaseApi(SupersetTestCase):
db.session.commit()
return database
@pytest.fixture()
def create_database_with_report(self):
with self.create_app().app_context():
example_db = get_example_database()
database = self.insert_database(
"database_with_report",
example_db.sqlalchemy_uri_decrypted,
expose_in_sqllab=True,
)
report_schedule = ReportSchedule(
type=ReportScheduleType.ALERT,
name="report_with_database",
crontab="* * * * *",
database=database,
)
db.session.add(report_schedule)
db.session.commit()
yield database
# rollback changes
db.session.delete(report_schedule)
db.session.delete(database)
db.session.commit()
def test_get_items(self):
"""
Database API: Test get items
@@ -486,6 +511,26 @@ class TestDatabaseApi(SupersetTestCase):
rv = self.delete_assert_metric(uri, "delete")
self.assertEqual(rv.status_code, 422)
@pytest.mark.usefixtures("create_database_with_report")
def test_delete_database_with_report(self):
"""
Database API: Test delete with associated report
"""
self.login(username="admin")
database = (
db.session.query(Database)
.filter(Database.database_name == "database_with_report")
.one_or_none()
)
uri = f"api/v1/database/{database.id}"
rv = self.client.delete(uri)
response = json.loads(rv.data.decode("utf-8"))
self.assertEqual(rv.status_code, 422)
expected_response = {
"message": "There are associated alerts or reports: report_with_database"
}
self.assertEqual(response, expected_response)
def test_get_table_metadata(self):
"""
Database API: Test get table metadata info