From 2e6ea766315869215fe788c4dafc49ac4328a8f8 Mon Sep 17 00:00:00 2001 From: Daniel Vaz Gaspar Date: Mon, 15 Feb 2021 17:09:47 +0000 Subject: [PATCH] fix(alerts): void query with numeric comparison (#13090) * fix(alerts): void query with numeric comparison * remove config changes * fix tests * better logic * fix logic * fix logic * Improve test readability --- superset/reports/commands/alert.py | 25 +++++++++++++++++++++---- tests/reports/commands_tests.py | 9 +++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/superset/reports/commands/alert.py b/superset/reports/commands/alert.py index 5ddeb4683b..ccf6d436cd 100644 --- a/superset/reports/commands/alert.py +++ b/superset/reports/commands/alert.py @@ -47,15 +47,16 @@ class AlertCommand(BaseCommand): def run(self) -> bool: self.validate() - if self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL: + if self._is_validator_not_null: self._report_schedule.last_value_row_json = str(self._result) - return self._result not in (0, None, np.nan) + return self._result is not None self._report_schedule.last_value = self._result try: operator = json.loads(self._report_schedule.validator_config_json)["op"] threshold = json.loads(self._report_schedule.validator_config_json)[ "threshold" ] + return OPERATOR_FUNCTIONS[operator](self._result, threshold) except (KeyError, json.JSONDecodeError): raise AlertValidatorConfigError() @@ -95,6 +96,18 @@ class AlertCommand(BaseCommand): except (AssertionError, TypeError, ValueError): raise AlertQueryInvalidTypeError() + @property + def _is_validator_not_null(self) -> bool: + return ( + self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL + ) + + @property + def _is_validator_operator(self) -> bool: + return ( + self._report_schedule.validator_type == ReportScheduleValidatorType.OPERATOR + ) + def validate(self) -> None: """ Validate the query result as a Pandas DataFrame @@ -108,10 +121,14 @@ class AlertCommand(BaseCommand): except Exception as ex: raise AlertQueryError(message=str(ex)) - if df.empty: + if df.empty and self._is_validator_not_null: + self._result = None + return + if df.empty and self._is_validator_operator: + self._result = 0.0 return rows = df.to_records() - if self._report_schedule.validator_type == ReportScheduleValidatorType.NOT_NULL: + if self._is_validator_not_null: self._validate_not_null(rows) return self._validate_operator(rows) diff --git a/tests/reports/commands_tests.py b/tests/reports/commands_tests.py index dac34374da..c61cf21fca 100644 --- a/tests/reports/commands_tests.py +++ b/tests/reports/commands_tests.py @@ -308,7 +308,7 @@ def create_test_table_context(database: Database): @pytest.yield_fixture( - params=["alert1", "alert2", "alert3", "alert4", "alert5", "alert6"] + params=["alert1", "alert2", "alert3", "alert4", "alert5", "alert6", "alert7"] ) def create_no_alert_email_chart(request): param_config = { @@ -338,10 +338,15 @@ def create_no_alert_email_chart(request): "validator_config_json": '{"op": "!=", "threshold": 10}', }, "alert6": { - "sql": "SELECT first from test_table where first=0", + "sql": "SELECT first from test_table where 1=0", "validator_type": ReportScheduleValidatorType.NOT_NULL, "validator_config_json": "{}", }, + "alert7": { + "sql": "SELECT first from test_table where 1=0", + "validator_type": ReportScheduleValidatorType.OPERATOR, + "validator_config_json": '{"op": ">", "threshold": 0}', + }, } with app.app_context(): chart = db.session.query(Slice).first()