2019-01-15 18:53:27 -05:00
|
|
|
# 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.
|
2019-11-20 10:47:06 -05:00
|
|
|
# isort:skip_file
|
2019-10-18 17:44:27 -04:00
|
|
|
from datetime import datetime, timedelta
|
2021-05-21 17:29:52 -04:00
|
|
|
from superset.views.schedules import DashboardEmailScheduleView, SliceEmailScheduleView
|
2019-03-27 17:08:36 -04:00
|
|
|
from unittest.mock import Mock, patch, PropertyMock
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
from flask_babel import gettext as __
|
2020-07-20 12:20:05 -04:00
|
|
|
import pytest
|
2018-12-11 01:29:29 -05:00
|
|
|
from selenium.common.exceptions import WebDriverException
|
2020-07-20 12:20:05 -04:00
|
|
|
from slack import errors, WebClient
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-07-01 11:03:07 -04:00
|
|
|
from tests.integration_tests.fixtures.world_bank_dashboard import (
|
|
|
|
load_world_bank_dashboard_with_slices,
|
|
|
|
)
|
|
|
|
from tests.integration_tests.test_app import app
|
2019-11-20 10:47:06 -05:00
|
|
|
from superset import db
|
2019-12-18 14:40:45 -05:00
|
|
|
from superset.models.dashboard import Dashboard
|
2018-12-11 01:29:29 -05:00
|
|
|
from superset.models.schedules import (
|
|
|
|
DashboardEmailSchedule,
|
|
|
|
EmailDeliveryType,
|
|
|
|
SliceEmailReportFormat,
|
|
|
|
SliceEmailSchedule,
|
|
|
|
)
|
|
|
|
from superset.tasks.schedules import (
|
|
|
|
create_webdriver,
|
|
|
|
deliver_dashboard,
|
|
|
|
deliver_slice,
|
|
|
|
next_schedules,
|
|
|
|
)
|
2019-12-18 14:40:45 -05:00
|
|
|
from superset.models.slice import Slice
|
2021-07-01 11:03:07 -04:00
|
|
|
from tests.integration_tests.base_tests import SupersetTestCase
|
|
|
|
from tests.integration_tests.utils import read_fixture
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
|
2020-06-29 18:36:06 -04:00
|
|
|
class TestSchedules(SupersetTestCase):
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
RECIPIENTS = "recipient1@superset.com, recipient2@superset.com"
|
|
|
|
BCC = "bcc@superset.com"
|
|
|
|
CSV = read_fixture("trends.csv")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.fixture()
|
|
|
|
def add_schedule_slice_and_dashboard(self):
|
2019-11-20 10:47:06 -05:00
|
|
|
with app.app_context():
|
2021-02-23 01:21:19 -05:00
|
|
|
self.common_data = dict(
|
2019-11-20 10:47:06 -05:00
|
|
|
active=True,
|
|
|
|
crontab="* * * * *",
|
2021-02-23 01:21:19 -05:00
|
|
|
recipients=self.RECIPIENTS,
|
2019-11-20 10:47:06 -05:00
|
|
|
deliver_as_group=True,
|
|
|
|
delivery_type=EmailDeliveryType.inline,
|
|
|
|
)
|
2020-07-31 15:05:39 -04:00
|
|
|
# Pick up a sample slice and dashboard
|
2021-02-23 01:21:19 -05:00
|
|
|
slice = db.session.query(Slice).filter_by(slice_name="Region Filter").one()
|
2020-07-31 15:05:39 -04:00
|
|
|
dashboard = (
|
|
|
|
db.session.query(Dashboard)
|
2020-08-10 16:20:19 -04:00
|
|
|
.filter_by(dashboard_title="World Bank's Data")
|
2020-07-31 15:05:39 -04:00
|
|
|
.one()
|
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
dashboard_schedule = DashboardEmailSchedule(**self.common_data)
|
2019-11-20 10:47:06 -05:00
|
|
|
dashboard_schedule.dashboard_id = dashboard.id
|
|
|
|
dashboard_schedule.user_id = 1
|
|
|
|
db.session.add(dashboard_schedule)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
slice_schedule = SliceEmailSchedule(**self.common_data)
|
|
|
|
slice_schedule.slice_id = slice.id
|
2019-11-20 10:47:06 -05:00
|
|
|
slice_schedule.user_id = 1
|
|
|
|
slice_schedule.email_format = SliceEmailReportFormat.data
|
2020-06-17 14:01:25 -04:00
|
|
|
slice_schedule.slack_channel = "#test_channel"
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-11-20 10:47:06 -05:00
|
|
|
db.session.add(slice_schedule)
|
|
|
|
db.session.commit()
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
self.slice_schedule = slice_schedule.id
|
|
|
|
self.dashboard_schedule = dashboard_schedule.id
|
|
|
|
|
|
|
|
yield
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-11-20 10:47:06 -05:00
|
|
|
with app.app_context():
|
|
|
|
db.session.query(SliceEmailSchedule).filter_by(
|
2021-02-23 01:21:19 -05:00
|
|
|
id=self.slice_schedule
|
2019-11-20 10:47:06 -05:00
|
|
|
).delete()
|
|
|
|
db.session.query(DashboardEmailSchedule).filter_by(
|
2021-02-23 01:21:19 -05:00
|
|
|
id=self.dashboard_schedule
|
2019-11-20 10:47:06 -05:00
|
|
|
).delete()
|
|
|
|
db.session.commit()
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
def test_crontab_scheduler(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
crontab = "* * * * *"
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
start_at = datetime.now().replace(microsecond=0, second=0, minute=0)
|
|
|
|
stop_at = start_at + timedelta(seconds=3600)
|
|
|
|
|
|
|
|
# Fire off the task every minute
|
|
|
|
schedules = list(next_schedules(crontab, start_at, stop_at, resolution=0))
|
|
|
|
|
|
|
|
self.assertEqual(schedules[0], start_at)
|
|
|
|
self.assertEqual(schedules[-1], stop_at - timedelta(seconds=60))
|
|
|
|
self.assertEqual(len(schedules), 60)
|
|
|
|
|
|
|
|
# Fire off the task every 10 minutes, controlled via resolution
|
|
|
|
schedules = list(next_schedules(crontab, start_at, stop_at, resolution=10 * 60))
|
|
|
|
|
|
|
|
self.assertEqual(schedules[0], start_at)
|
|
|
|
self.assertEqual(schedules[-1], stop_at - timedelta(seconds=10 * 60))
|
|
|
|
self.assertEqual(len(schedules), 6)
|
|
|
|
|
|
|
|
# Fire off the task every 12 minutes, controlled via resolution
|
|
|
|
schedules = list(next_schedules(crontab, start_at, stop_at, resolution=12 * 60))
|
|
|
|
|
|
|
|
self.assertEqual(schedules[0], start_at)
|
|
|
|
self.assertEqual(schedules[-1], stop_at - timedelta(seconds=12 * 60))
|
|
|
|
self.assertEqual(len(schedules), 5)
|
|
|
|
|
|
|
|
def test_wider_schedules(self):
|
2019-06-25 16:34:48 -04:00
|
|
|
crontab = "*/15 2,10 * * *"
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
for hour in range(0, 24):
|
|
|
|
start_at = datetime.now().replace(
|
2019-06-25 16:34:48 -04:00
|
|
|
microsecond=0, second=0, minute=0, hour=hour
|
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
stop_at = start_at + timedelta(seconds=3600)
|
|
|
|
schedules = list(next_schedules(crontab, start_at, stop_at, resolution=0))
|
|
|
|
|
|
|
|
if hour in (2, 10):
|
|
|
|
self.assertEqual(len(schedules), 4)
|
|
|
|
else:
|
|
|
|
self.assertEqual(len(schedules), 0)
|
|
|
|
|
|
|
|
def test_complex_schedule(self):
|
|
|
|
# Run the job on every Friday of March and May
|
|
|
|
# On these days, run the job at
|
|
|
|
# 5:10 pm
|
|
|
|
# 5:11 pm
|
|
|
|
# 5:12 pm
|
|
|
|
# 5:13 pm
|
|
|
|
# 5:14 pm
|
|
|
|
# 5:15 pm
|
|
|
|
# 5:25 pm
|
|
|
|
# 5:28 pm
|
|
|
|
# 5:31 pm
|
|
|
|
# 5:34 pm
|
|
|
|
# 5:37 pm
|
|
|
|
# 5:40 pm
|
2019-06-25 16:34:48 -04:00
|
|
|
crontab = "10-15,25-40/3 17 * 3,5 5"
|
|
|
|
start_at = datetime.strptime("2018/01/01", "%Y/%m/%d")
|
|
|
|
stop_at = datetime.strptime("2018/12/31", "%Y/%m/%d")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedules = list(next_schedules(crontab, start_at, stop_at, resolution=60))
|
|
|
|
self.assertEqual(len(schedules), 108)
|
2019-06-25 16:34:48 -04:00
|
|
|
fmt = "%Y-%m-%d %H:%M:%S"
|
|
|
|
self.assertEqual(schedules[0], datetime.strptime("2018-03-02 17:10:00", fmt))
|
|
|
|
self.assertEqual(schedules[-1], datetime.strptime("2018-05-25 17:40:00", fmt))
|
|
|
|
self.assertEqual(schedules[59], datetime.strptime("2018-03-30 17:40:00", fmt))
|
|
|
|
self.assertEqual(schedules[60], datetime.strptime("2018-05-04 17:10:00", fmt))
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
2018-12-11 01:29:29 -05:00
|
|
|
def test_create_driver(self, mock_driver_class):
|
|
|
|
mock_driver = Mock()
|
|
|
|
mock_driver_class.return_value = mock_driver
|
|
|
|
mock_driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
|
2020-09-21 13:34:03 -04:00
|
|
|
create_webdriver(db.session)
|
2018-12-11 01:29:29 -05:00
|
|
|
mock_driver.add_cookie.assert_called_once()
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
2018-12-11 01:29:29 -05:00
|
|
|
def test_deliver_dashboard_inline(self, mtime, send_email_smtp, driver_class):
|
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
element.screenshot_as_png = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
|
|
|
db.session.query(DashboardEmailSchedule)
|
|
|
|
.filter_by(id=self.dashboard_schedule)
|
2020-07-31 15:05:39 -04:00
|
|
|
.one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_dashboard(
|
|
|
|
schedule.dashboard_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.deliver_as_group,
|
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_not_called()
|
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
|
|
|
def test_deliver_dashboard_as_attachment(
|
|
|
|
self, mtime, send_email_smtp, driver_class
|
|
|
|
):
|
2018-12-11 01:29:29 -05:00
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_id.return_value = element
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
element.screenshot_as_png = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
|
|
|
db.session.query(DashboardEmailSchedule)
|
|
|
|
.filter_by(id=self.dashboard_schedule)
|
2020-07-31 15:05:39 -04:00
|
|
|
.one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedule.delivery_type = EmailDeliveryType.attachment
|
2020-06-17 14:01:25 -04:00
|
|
|
|
|
|
|
deliver_dashboard(
|
|
|
|
schedule.dashboard_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.deliver_as_group,
|
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_not_called()
|
|
|
|
send_email_smtp.assert_called_once()
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIsNone(send_email_smtp.call_args[1]["images"])
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(
|
2020-07-06 16:12:27 -04:00
|
|
|
send_email_smtp.call_args[1]["data"]["screenshot"],
|
2018-12-11 01:29:29 -05:00
|
|
|
element.screenshot_as_png,
|
|
|
|
)
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
2018-12-11 01:29:29 -05:00
|
|
|
def test_dashboard_chrome_like(self, mtime, send_email_smtp, driver_class):
|
|
|
|
# Test functionality for chrome driver which does not support
|
|
|
|
# element snapshots
|
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
type(element).screenshot_as_png = PropertyMock(side_effect=WebDriverException)
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_id.return_value = element
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
driver.screenshot.return_value = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
|
|
|
db.session.query(DashboardEmailSchedule)
|
|
|
|
.filter_by(id=self.dashboard_schedule)
|
2020-07-31 15:05:39 -04:00
|
|
|
.one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_dashboard(
|
|
|
|
schedule.dashboard_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.deliver_as_group,
|
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_called_once()
|
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(send_email_smtp.call_args[0][0], self.RECIPIENTS)
|
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
list(send_email_smtp.call_args[1]["images"].values())[0],
|
2018-12-11 01:29:29 -05:00
|
|
|
driver.screenshot.return_value,
|
|
|
|
)
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
2018-12-11 01:29:29 -05:00
|
|
|
def test_deliver_email_options(self, mtime, send_email_smtp, driver_class):
|
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
element.screenshot_as_png = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
|
|
|
db.session.query(DashboardEmailSchedule)
|
|
|
|
.filter_by(id=self.dashboard_schedule)
|
2020-07-31 15:05:39 -04:00
|
|
|
.one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
# Send individual mails to the group
|
|
|
|
schedule.deliver_as_group = False
|
|
|
|
|
|
|
|
# Set a bcc email address
|
2019-06-25 16:34:48 -04:00
|
|
|
app.config["EMAIL_REPORT_BCC_ADDRESS"] = self.BCC
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_dashboard(
|
|
|
|
schedule.dashboard_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.deliver_as_group,
|
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_not_called()
|
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(send_email_smtp.call_count, 2)
|
|
|
|
self.assertEqual(send_email_smtp.call_args[1]["bcc"], self.BCC)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2020-06-17 14:01:25 -04:00
|
|
|
@patch("superset.tasks.slack_util.WebClient.files_upload")
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
2020-06-17 14:01:25 -04:00
|
|
|
def test_deliver_slice_inline_image(
|
|
|
|
self, mtime, send_email_smtp, driver_class, files_upload
|
|
|
|
):
|
2018-12-11 01:29:29 -05:00
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
element.screenshot_as_png = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
2020-07-31 15:05:39 -04:00
|
|
|
db.session.query(SliceEmailSchedule).filter_by(id=self.slice_schedule).one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedule.email_format = SliceEmailReportFormat.visualization
|
|
|
|
schedule.delivery_format = EmailDeliveryType.inline
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_slice(
|
|
|
|
schedule.slice_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.email_format,
|
|
|
|
schedule.deliver_as_group,
|
2020-09-10 16:29:57 -04:00
|
|
|
db.session,
|
2020-06-17 14:01:25 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_not_called()
|
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(
|
2019-06-25 16:34:48 -04:00
|
|
|
list(send_email_smtp.call_args[1]["images"].values())[0],
|
2018-12-11 01:29:29 -05:00
|
|
|
element.screenshot_as_png,
|
|
|
|
)
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
self.assertEqual(
|
|
|
|
files_upload.call_args[1],
|
|
|
|
{
|
|
|
|
"channels": "#test_channel",
|
|
|
|
"file": element.screenshot_as_png,
|
2021-02-23 01:21:19 -05:00
|
|
|
"initial_comment": f"\n *Region Filter*\n\n <http://0.0.0.0:8080/superset/slice/{schedule.slice_id}/|Explore in Superset>\n ",
|
|
|
|
"title": "[Report] Region Filter",
|
2020-06-17 14:01:25 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2020-06-17 14:01:25 -04:00
|
|
|
@patch("superset.tasks.slack_util.WebClient.files_upload")
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.firefox.webdriver.WebDriver")
|
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
|
|
|
@patch("superset.tasks.schedules.time")
|
2020-06-17 14:01:25 -04:00
|
|
|
def test_deliver_slice_attachment(
|
|
|
|
self, mtime, send_email_smtp, driver_class, files_upload
|
|
|
|
):
|
2018-12-11 01:29:29 -05:00
|
|
|
element = Mock()
|
|
|
|
driver = Mock()
|
|
|
|
mtime.sleep.return_value = None
|
|
|
|
|
|
|
|
driver_class.return_value = driver
|
|
|
|
|
|
|
|
# Ensure that we are able to login with the driver
|
|
|
|
driver.find_elements_by_id.side_effect = [True, False]
|
|
|
|
driver.find_element_by_class_name.return_value = element
|
2019-06-25 16:34:48 -04:00
|
|
|
element.screenshot_as_png = read_fixture("sample.png")
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
2020-07-31 15:05:39 -04:00
|
|
|
db.session.query(SliceEmailSchedule).filter_by(id=self.slice_schedule).one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedule.email_format = SliceEmailReportFormat.visualization
|
|
|
|
schedule.delivery_type = EmailDeliveryType.attachment
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_slice(
|
|
|
|
schedule.slice_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.email_format,
|
|
|
|
schedule.deliver_as_group,
|
2020-09-10 16:29:57 -04:00
|
|
|
db.session,
|
2020-06-17 14:01:25 -04:00
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
mtime.sleep.assert_called_once()
|
|
|
|
driver.screenshot.assert_not_called()
|
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(
|
2020-07-06 16:12:27 -04:00
|
|
|
send_email_smtp.call_args[1]["data"]["screenshot"],
|
2018-12-11 01:29:29 -05:00
|
|
|
element.screenshot_as_png,
|
|
|
|
)
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
self.assertEqual(
|
|
|
|
files_upload.call_args[1],
|
|
|
|
{
|
|
|
|
"channels": "#test_channel",
|
|
|
|
"file": element.screenshot_as_png,
|
2021-02-23 01:21:19 -05:00
|
|
|
"initial_comment": f"\n *Region Filter*\n\n <http://0.0.0.0:8080/superset/slice/{schedule.slice_id}/|Explore in Superset>\n ",
|
|
|
|
"title": "[Report] Region Filter",
|
2020-06-17 14:01:25 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2020-06-17 14:01:25 -04:00
|
|
|
@patch("superset.tasks.slack_util.WebClient.files_upload")
|
2019-08-02 13:01:28 -04:00
|
|
|
@patch("superset.tasks.schedules.urllib.request.OpenerDirector.open")
|
|
|
|
@patch("superset.tasks.schedules.urllib.request.urlopen")
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
2019-08-02 13:01:28 -04:00
|
|
|
def test_deliver_slice_csv_attachment(
|
2020-06-17 14:01:25 -04:00
|
|
|
self, send_email_smtp, mock_open, mock_urlopen, files_upload
|
2019-08-02 13:01:28 -04:00
|
|
|
):
|
2018-12-11 01:29:29 -05:00
|
|
|
response = Mock()
|
2019-08-02 13:01:28 -04:00
|
|
|
mock_open.return_value = response
|
|
|
|
mock_urlopen.return_value = response
|
|
|
|
mock_urlopen.return_value.getcode.return_value = 200
|
2019-12-07 19:07:09 -05:00
|
|
|
response.read.return_value = self.CSV
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
2020-07-31 15:05:39 -04:00
|
|
|
db.session.query(SliceEmailSchedule).filter_by(id=self.slice_schedule).one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedule.email_format = SliceEmailReportFormat.data
|
|
|
|
schedule.delivery_type = EmailDeliveryType.attachment
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_slice(
|
|
|
|
schedule.slice_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.email_format,
|
|
|
|
schedule.deliver_as_group,
|
2020-09-10 16:29:57 -04:00
|
|
|
db.session,
|
2020-06-17 14:01:25 -04:00
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
file_name = __("%(name)s.csv", name=schedule.slice.slice_name)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2019-10-21 10:49:12 -04:00
|
|
|
self.assertEqual(send_email_smtp.call_args[1]["data"][file_name], self.CSV)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
self.assertEqual(
|
|
|
|
files_upload.call_args[1],
|
|
|
|
{
|
|
|
|
"channels": "#test_channel",
|
|
|
|
"file": self.CSV,
|
2021-02-23 01:21:19 -05:00
|
|
|
"initial_comment": f"\n *Region Filter*\n\n <http://0.0.0.0:8080/superset/slice/{schedule.slice_id}/|Explore in Superset>\n ",
|
|
|
|
"title": "[Report] Region Filter",
|
2020-06-17 14:01:25 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2021-02-23 01:21:19 -05:00
|
|
|
@pytest.mark.usefixtures(
|
|
|
|
"load_world_bank_dashboard_with_slices", "add_schedule_slice_and_dashboard"
|
|
|
|
)
|
2020-06-17 14:01:25 -04:00
|
|
|
@patch("superset.tasks.slack_util.WebClient.files_upload")
|
2019-08-02 13:01:28 -04:00
|
|
|
@patch("superset.tasks.schedules.urllib.request.urlopen")
|
|
|
|
@patch("superset.tasks.schedules.urllib.request.OpenerDirector.open")
|
2019-06-25 16:34:48 -04:00
|
|
|
@patch("superset.tasks.schedules.send_email_smtp")
|
2020-06-17 14:01:25 -04:00
|
|
|
def test_deliver_slice_csv_inline(
|
|
|
|
self, send_email_smtp, mock_open, mock_urlopen, files_upload
|
|
|
|
):
|
2018-12-11 01:29:29 -05:00
|
|
|
response = Mock()
|
2019-08-02 13:01:28 -04:00
|
|
|
mock_open.return_value = response
|
|
|
|
mock_urlopen.return_value = response
|
|
|
|
mock_urlopen.return_value.getcode.return_value = 200
|
2019-12-07 19:07:09 -05:00
|
|
|
response.read.return_value = self.CSV
|
2019-06-25 16:34:48 -04:00
|
|
|
schedule = (
|
2020-07-31 15:05:39 -04:00
|
|
|
db.session.query(SliceEmailSchedule).filter_by(id=self.slice_schedule).one()
|
2019-06-25 16:34:48 -04:00
|
|
|
)
|
2018-12-11 01:29:29 -05:00
|
|
|
|
|
|
|
schedule.email_format = SliceEmailReportFormat.data
|
|
|
|
schedule.delivery_type = EmailDeliveryType.inline
|
|
|
|
|
2020-06-17 14:01:25 -04:00
|
|
|
deliver_slice(
|
|
|
|
schedule.slice_id,
|
|
|
|
schedule.recipients,
|
|
|
|
schedule.slack_channel,
|
|
|
|
schedule.delivery_type,
|
|
|
|
schedule.email_format,
|
|
|
|
schedule.deliver_as_group,
|
2020-09-10 16:29:57 -04:00
|
|
|
db.session,
|
2020-06-17 14:01:25 -04:00
|
|
|
)
|
|
|
|
|
2018-12-11 01:29:29 -05:00
|
|
|
send_email_smtp.assert_called_once()
|
|
|
|
|
2019-06-25 16:34:48 -04:00
|
|
|
self.assertIsNone(send_email_smtp.call_args[1]["data"])
|
|
|
|
self.assertTrue("<table " in send_email_smtp.call_args[0][2])
|
2020-06-17 14:01:25 -04:00
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
files_upload.call_args[1],
|
|
|
|
{
|
|
|
|
"channels": "#test_channel",
|
|
|
|
"file": self.CSV,
|
2021-02-23 01:21:19 -05:00
|
|
|
"initial_comment": f"\n *Region Filter*\n\n <http://0.0.0.0:8080/superset/slice/{schedule.slice_id}/|Explore in Superset>\n ",
|
|
|
|
"title": "[Report] Region Filter",
|
2020-06-17 14:01:25 -04:00
|
|
|
},
|
|
|
|
)
|
2020-07-20 12:20:05 -04:00
|
|
|
|
2021-05-21 17:29:52 -04:00
|
|
|
def test_dashboard_disabled(self):
|
|
|
|
with patch.object(DashboardEmailScheduleView, "is_enabled", return_value=False):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/dashboardemailscheduleview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertEqual(rv.status_code, 404)
|
|
|
|
|
|
|
|
def test_dashboard_enabled(self):
|
|
|
|
with patch.object(DashboardEmailScheduleView, "is_enabled", return_value=True):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/dashboardemailscheduleview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertLess(rv.status_code, 400)
|
|
|
|
|
|
|
|
def test_slice_disabled(self):
|
|
|
|
with patch.object(SliceEmailScheduleView, "is_enabled", return_value=False):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/sliceemailscheduleview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertEqual(rv.status_code, 404)
|
|
|
|
|
|
|
|
def test_slice_enabled(self):
|
|
|
|
with patch.object(SliceEmailScheduleView, "is_enabled", return_value=True):
|
|
|
|
self.login("admin")
|
|
|
|
uri = "/sliceemailscheduleview/list/"
|
|
|
|
rv = self.client.get(uri)
|
|
|
|
self.assertLess(rv.status_code, 400)
|
|
|
|
|
2020-07-20 12:20:05 -04:00
|
|
|
|
|
|
|
def test_slack_client_compatibility():
|
|
|
|
c2 = WebClient()
|
|
|
|
# slackclient >2.5.0 raises TypeError: a bytes-like object is required, not 'str
|
|
|
|
# and requires to path a filepath instead of the bytes directly
|
|
|
|
with pytest.raises(errors.SlackApiError):
|
|
|
|
c2.files_upload(channels="#bogdan-test2", file=b"blabla", title="Test upload")
|