fix(Slack): Fix Slack recipients migration to V2 (#32336)

This commit is contained in:
Vitor Avila
2025-03-06 08:52:15 -03:00
committed by GitHub
parent 05409d51da
commit d2e0e2b79c
11 changed files with 318 additions and 78 deletions

View File

@@ -308,7 +308,10 @@ def create_report_slack_chart():
def create_report_slack_chartv2():
chart = db.session.query(Slice).first()
report_schedule = create_report_notification(
slack_channel="slack_channel_id", chart=chart, name="report_slack_chartv2"
slack_channel="slack_channel_id",
chart=chart,
name="report_slack_chartv2",
use_slack_v2=True,
)
yield report_schedule
@@ -1300,9 +1303,7 @@ def test_email_dashboard_report_schedule_force_screenshot(
assert_log(ReportState.SUCCESS)
@pytest.mark.usefixtures(
"load_birth_names_dashboard_with_slices", "create_report_slack_chart"
)
@pytest.mark.usefixtures("create_report_slack_chart")
@patch("superset.commands.report.execute.get_channels_with_search")
@patch("superset.reports.notifications.slack.should_use_v2_api", return_value=True)
@patch("superset.reports.notifications.slackv2.get_slack_client")
@@ -1316,13 +1317,19 @@ def test_slack_chart_report_schedule_converts_to_v2(
):
"""
ExecuteReport Command: Test chart slack report schedule
while converting the recipients list to SlackV2.
"""
# setup screenshot mock
screenshot_mock.return_value = SCREENSHOT_FILE
channel_id = "slack_channel_id"
get_channels_with_search_mock.return_value = channel_id
get_channels_with_search_mock.return_value = [
{
"id": channel_id,
"name": "slack_channel",
"is_member": True,
"is_private": False,
},
]
with freeze_time("2020-01-01T00:00:00Z"):
with patch.object(current_app.config["STATS_LOGGER"], "gauge") as statsd_mock:
@@ -1357,33 +1364,40 @@ def test_slack_chart_report_schedule_converts_to_v2(
assert statsd_mock.call_args_list[1] == call("reports.slack.send.ok", 1)
@pytest.mark.usefixtures(
"load_birth_names_dashboard_with_slices", "create_report_slack_chartv2"
)
@patch("superset.commands.report.execute.get_channels_with_search")
@patch("superset.reports.notifications.slack.should_use_v2_api", return_value=True)
@patch("superset.reports.notifications.slackv2.get_slack_client")
@patch("superset.utils.screenshots.ChartScreenshot.get_screenshot")
def test_slack_chart_report_schedule_v2(
def test_slack_chart_report_schedule_converts_to_v2_channel_with_hash(
screenshot_mock,
slack_client_mock,
slack_should_use_v2_api_mock,
get_channels_with_search_mock,
create_report_slack_chart,
):
"""
ExecuteReport Command: Test chart slack report schedule
ExecuteReport Command: Test converting a Slack report to v2 when
the channel name includes the leading hash (supported in v1).
"""
# setup screenshot mock
screenshot_mock.return_value = SCREENSHOT_FILE
channel_id = "slack_channel_id"
get_channels_with_search_mock.return_value = channel_id
chart = db.session.query(Slice).first()
report_schedule = create_report_notification(
slack_channel="#slack_channel", chart=chart
)
get_channels_with_search_mock.return_value = [
{
"id": channel_id,
"name": "slack_channel",
"is_member": True,
"is_private": False,
},
]
with freeze_time("2020-01-01T00:00:00Z"):
with patch.object(current_app.config["STATS_LOGGER"], "gauge") as statsd_mock:
AsyncExecuteReportScheduleCommand(
TEST_ID, create_report_slack_chart.id, datetime.utcnow()
TEST_ID, report_schedule.id, datetime.utcnow()
).run()
assert (
@@ -1395,6 +1409,12 @@ def test_slack_chart_report_schedule_v2(
== SCREENSHOT_FILE
)
# Assert that the report recipients were updated
assert report_schedule.recipients[0].recipient_config_json == json.dumps(
{"target": channel_id}
)
assert report_schedule.recipients[0].type == ReportRecipientType.SLACKV2
# Assert logs are correct
assert_log(ReportState.SUCCESS)
# this will send a warning
@@ -1403,6 +1423,94 @@ def test_slack_chart_report_schedule_v2(
)
assert statsd_mock.call_args_list[1] == call("reports.slack.send.ok", 1)
cleanup_report_schedule(report_schedule)
@patch("superset.commands.report.execute.get_channels_with_search")
@patch("superset.reports.notifications.slack.should_use_v2_api", return_value=True)
@patch("superset.reports.notifications.slackv2.get_slack_client")
@patch("superset.utils.screenshots.ChartScreenshot.get_screenshot")
def test_slack_chart_report_schedule_fails_to_converts_to_v2(
screenshot_mock,
slack_client_mock,
slack_should_use_v2_api_mock,
get_channels_with_search_mock,
):
"""
ExecuteReport Command: Test converting a Slack report to v2 fails.
"""
# setup screenshot mock
screenshot_mock.return_value = SCREENSHOT_FILE
channel_id = "slack_channel_id"
chart = db.session.query(Slice).first()
report_schedule = create_report_notification(
slack_channel="#slack_channel,my_member_ID", chart=chart
)
get_channels_with_search_mock.return_value = [
{
"id": channel_id,
"name": "slack_channel",
"is_member": True,
"is_private": False,
},
]
with pytest.raises(ReportScheduleSystemErrorsException):
AsyncExecuteReportScheduleCommand(
TEST_ID, report_schedule.id, datetime.utcnow()
).run()
# Assert failuer with proper log
expected_message = (
"Failed to update slack recipients to v2: "
"Could not find the following channels: my_member_ID"
)
assert_log(ReportState.ERROR, error_message=expected_message)
# Assert that previous configuration was kept for manual correction
assert report_schedule.recipients[0].recipient_config_json == json.dumps(
{"target": "#slack_channel,my_member_ID"}
)
assert report_schedule.recipients[0].type == ReportRecipientType.SLACK
cleanup_report_schedule(report_schedule)
@pytest.mark.usefixtures("create_report_slack_chartv2")
@patch("superset.reports.notifications.slack.should_use_v2_api", return_value=True)
@patch("superset.reports.notifications.slackv2.get_slack_client")
@patch("superset.utils.screenshots.ChartScreenshot.get_screenshot")
def test_slack_chart_report_schedule_v2(
screenshot_mock,
slack_client_mock,
slack_should_use_v2_api_mock,
create_report_slack_chartv2,
):
"""
ExecuteReport Command: Test chart slack report schedule using Slack v2.
"""
# setup screenshot mock
screenshot_mock.return_value = SCREENSHOT_FILE
with freeze_time("2020-01-01T00:00:00Z"):
with patch.object(current_app.config["STATS_LOGGER"], "gauge") as statsd_mock:
AsyncExecuteReportScheduleCommand(
TEST_ID, create_report_slack_chartv2.id, datetime.utcnow()
).run()
assert (
slack_client_mock.return_value.files_upload_v2.call_args[1]["channel"]
== "slack_channel_id"
)
assert (
slack_client_mock.return_value.files_upload_v2.call_args[1]["file"]
== SCREENSHOT_FILE
)
# Assert logs are correct
assert_log(ReportState.SUCCESS)
assert statsd_mock.call_args_list[0] == call("reports.slack.send.ok", 1)
@pytest.mark.usefixtures(
"load_birth_names_dashboard_with_slices", "create_report_slack_chart"

View File

@@ -119,6 +119,7 @@ def create_report_notification(
owners: Optional[list[User]] = None,
ccTarget: Optional[str] = None, # noqa: N803
bccTarget: Optional[str] = None, # noqa: N803
use_slack_v2: bool = False,
) -> ReportSchedule:
if not owners:
owners = [
@@ -130,8 +131,11 @@ def create_report_notification(
]
if slack_channel:
type = (
ReportRecipientType.SLACKV2 if use_slack_v2 else ReportRecipientType.SLACK
)
recipient = ReportRecipients(
type=ReportRecipientType.SLACK,
type=type,
recipient_config_json=json.dumps(
{
"target": slack_channel,

View File

@@ -52,7 +52,7 @@ from superset.utils.core import (
GenericDataType,
get_form_data_token,
as_list,
get_email_address_list,
recipients_string_to_list,
get_stacktrace,
merge_extra_filters,
merge_extra_form_data,
@@ -809,12 +809,12 @@ class TestUtils(SupersetTestCase):
assert expected_filename in path
assert os.path.exists(path)
def test_get_email_address_list(self):
assert get_email_address_list("a@a") == ["a@a"]
assert get_email_address_list(" a@a ") == ["a@a"]
assert get_email_address_list("a@a\n") == ["a@a"]
assert get_email_address_list(",a@a;") == ["a@a"]
assert get_email_address_list(",a@a; b@b c@c a-c@c; d@d, f@f") == [
def test_recipients_string_to_list(self):
assert recipients_string_to_list("a@a") == ["a@a"]
assert recipients_string_to_list(" a@a ") == ["a@a"]
assert recipients_string_to_list("a@a\n") == ["a@a"]
assert recipients_string_to_list(",a@a;") == ["a@a"]
assert recipients_string_to_list(",a@a; b@b c@c a-c@c; d@d, f@f") == [
"a@a",
"b@b",
"c@c",