def test_extract_error_message(self): from MySQLdb._exceptions import OperationalError message = "Unknown table 'BIRTH_NAMES1' in information_schema" exception = OperationalError(message) extracted_message = MySQLEngineSpec._extract_error_message(exception) assert extracted_message == message exception = OperationalError(123, message) extracted_message = MySQLEngineSpec._extract_error_message(exception) assert extracted_message == message
def test_convert_dttm(self): dttm = self.get_dttm() self.assertEqual( MySQLEngineSpec.convert_dttm("DATE", dttm), "STR_TO_DATE('2019-01-02', '%Y-%m-%d')", ) self.assertEqual( MySQLEngineSpec.convert_dttm("DATETIME", dttm), "STR_TO_DATE('2019-01-02 03:04:05.678900', '%Y-%m-%d %H:%i:%s.%f')", )
def test_is_db_column_type_match(self): type_expectations = ( # Numeric ("TINYINT", GenericDataType.NUMERIC), ("SMALLINT", GenericDataType.NUMERIC), ("MEDIUMINT", GenericDataType.NUMERIC), ("INT", GenericDataType.NUMERIC), ("BIGINT", GenericDataType.NUMERIC), ("DECIMAL", GenericDataType.NUMERIC), ("FLOAT", GenericDataType.NUMERIC), ("DOUBLE", GenericDataType.NUMERIC), ("BIT", GenericDataType.NUMERIC), # String ("CHAR", GenericDataType.STRING), ("VARCHAR", GenericDataType.STRING), ("TINYTEXT", GenericDataType.STRING), ("MEDIUMTEXT", GenericDataType.STRING), ("LONGTEXT", GenericDataType.STRING), # Temporal ("DATE", GenericDataType.TEMPORAL), ("DATETIME", GenericDataType.TEMPORAL), ("TIMESTAMP", GenericDataType.TEMPORAL), ("TIME", GenericDataType.TEMPORAL), ) for type_str, col_type in type_expectations: column_spec = MySQLEngineSpec.get_column_spec(type_str) assert column_spec.generic_type == col_type
def test_is_db_column_type_match(self): type_expectations = ( # Numeric ("TINYINT", DbColumnType.NUMERIC), ("SMALLINT", DbColumnType.NUMERIC), ("MEDIUMINT", DbColumnType.NUMERIC), ("INT", DbColumnType.NUMERIC), ("BIGINT", DbColumnType.NUMERIC), ("DECIMAL", DbColumnType.NUMERIC), ("FLOAT", DbColumnType.NUMERIC), ("DOUBLE", DbColumnType.NUMERIC), ("BIT", DbColumnType.NUMERIC), # String ("CHAR", DbColumnType.STRING), ("VARCHAR", DbColumnType.STRING), ("TINYTEXT", DbColumnType.STRING), ("MEDIUMTEXT", DbColumnType.STRING), ("LONGTEXT", DbColumnType.STRING), # Temporal ("DATE", DbColumnType.TEMPORAL), ("DATETIME", DbColumnType.TEMPORAL), ("TIMESTAMP", DbColumnType.TEMPORAL), ("TIME", DbColumnType.TEMPORAL), ) for type_expectation in type_expectations: type_str = type_expectation[0] col_type = type_expectation[1] assert MySQLEngineSpec.is_db_column_type_match( type_str, DbColumnType.NUMERIC) is (col_type == DbColumnType.NUMERIC) assert MySQLEngineSpec.is_db_column_type_match( type_str, DbColumnType.STRING) is (col_type == DbColumnType.STRING) assert MySQLEngineSpec.is_db_column_type_match( type_str, DbColumnType.TEMPORAL) is (col_type == DbColumnType.TEMPORAL)
def test_get_time_grain_with_unkown_values(self): """ Should concatenate from configs and then sort in the proper order putting unknown patterns at the end """ app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = { "mysql": { "PT2H": "foo", "weird": "foo", "PT12H": "foo", } } time_grains = MySQLEngineSpec.get_time_grain_expressions() self.assertEqual( list(time_grains)[-1], "weird", ) app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = {}
def test_column_datatype_to_string(self): test_cases = ( (DATE(), "DATE"), (VARCHAR(length=255), "VARCHAR(255)"), ( VARCHAR(length=255, charset="latin1", collation="utf8mb4_general_ci"), "VARCHAR(255)", ), (NVARCHAR(length=128), "NATIONAL VARCHAR(128)"), (TEXT(), "TEXT"), ) for original, expected in test_cases: actual = MySQLEngineSpec.column_datatype_to_string( original, mysql.dialect() ) self.assertEqual(actual, expected)
def test_get_time_grain_expressions(self): time_grains = MySQLEngineSpec.get_time_grain_expressions() self.assertEqual( list(time_grains.keys()), [ None, "PT1S", "PT1M", "PT1H", "P1D", "P1W", "P1M", "P3M", "P1Y", "1969-12-29T00:00:00Z/P1W", ], )
def test_get_time_grain_with_unkown_values(): """Should concatenate from configs and then sort in the proper order putting unknown patterns at the end""" config = app.config.copy() app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = { "mysql": { "PT2H": "foo", "weird": "foo", "PT12H": "foo", } } with app.app_context(): time_grains = MySQLEngineSpec.get_time_grain_expressions() assert list(time_grains)[-1] == "weird" app.config = config
def test_get_time_grain_with_config(): """Should concatenate from configs and then sort in the proper order""" config = app.config.copy() app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = { "mysql": { "PT2H": "foo", "PT4H": "foo", "PT6H": "foo", "PT8H": "foo", "PT10H": "foo", "PT12H": "foo", "PT1S": "foo", } } with app.app_context(): time_grains = MySQLEngineSpec.get_time_grain_expressions() assert set(time_grains.keys()) == { None, "PT1S", "PT1M", "PT1H", "PT2H", "PT4H", "PT6H", "PT8H", "PT10H", "PT12H", "P1D", "P1W", "P1M", "P3M", "P1Y", "1969-12-29T00:00:00Z/P1W", } app.config = config
def test_get_time_grain_with_config(self): """ Should concatenate from configs and then sort in the proper order """ app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = { "mysql": { "PT2H": "foo", "PT4H": "foo", "PT6H": "foo", "PT8H": "foo", "PT10H": "foo", "PT12H": "foo", "PT1S": "foo", } } time_grains = MySQLEngineSpec.get_time_grain_expressions() self.assertEqual( list(time_grains.keys()), [ None, "PT1S", "PT1M", "PT1H", "PT2H", "PT4H", "PT6H", "PT8H", "PT10H", "PT12H", "P1D", "P1W", "P1M", "P0.25Y", "P1Y", "1969-12-29T00:00:00Z/P1W", ], ) app.config["TIME_GRAIN_ADDON_EXPRESSIONS"] = {}
def test_get_datatype_mysql(self): """Tests related to datatype mapping for MySQL""" self.assertEqual("TINY", MySQLEngineSpec.get_datatype(1)) self.assertEqual("VARCHAR", MySQLEngineSpec.get_datatype(15))
def test_extract_errors(self): """ Test that custom error messages are extracted correctly. """ msg = "mysql: Access denied for user 'test'@'testuser.com'" result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.CONNECTION_ACCESS_DENIED_ERROR, message= 'Either the username "test" or the password is incorrect.', level=ErrorLevel.ERROR, extra={ "invalid": ["username", "password"], "engine_name": "MySQL", "issue_codes": [ { "code": 1014, "message": "Issue 1014 - Either the" " username or the password is wrong.", }, { "code": 1015, "message": "Issue 1015 - Either the database is " "spelled incorrectly or does not exist.", }, ], }, ) ] msg = "mysql: Unknown MySQL server host 'badhostname.com'" result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.CONNECTION_INVALID_HOSTNAME_ERROR, message='Unknown MySQL server host "badhostname.com".', level=ErrorLevel.ERROR, extra={ "invalid": ["host"], "engine_name": "MySQL", "issue_codes": [{ "code": 1007, "message": "Issue 1007 - The hostname" " provided can't be resolved.", }], }, ) ] msg = "mysql: Can't connect to MySQL server on 'badconnection.com'" result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.CONNECTION_HOST_DOWN_ERROR, message='The host "badconnection.com" might be ' "down and can't be reached.", level=ErrorLevel.ERROR, extra={ "invalid": ["host", "port"], "engine_name": "MySQL", "issue_codes": [{ "code": 1007, "message": "Issue 1007 - The hostname provided" " can't be resolved.", }], }, ) ] msg = "mysql: Can't connect to MySQL server on '93.184.216.34'" result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.CONNECTION_HOST_DOWN_ERROR, message= 'The host "93.184.216.34" might be down and can\'t be reached.', level=ErrorLevel.ERROR, extra={ "invalid": ["host", "port"], "engine_name": "MySQL", "issue_codes": [{ "code": 10007, "message": "Issue 1007 - The hostname provided " "can't be resolved.", }], }, ) ] msg = "mysql: Unknown database 'badDB'" result = MySQLEngineSpec.extract_errors(Exception(msg)) print(result) assert result == [ SupersetError( message='Unable to connect to database "badDB".', error_type=SupersetErrorType.CONNECTION_UNKNOWN_DATABASE_ERROR, level=ErrorLevel.ERROR, extra={ "invalid": ["database"], "engine_name": "MySQL", "issue_codes": [{ "code": 1015, "message": "Issue 1015 - Either the database is spelled incorrectly or does not exist.", }], }, ) ]
def test_cancel_query(self, engine_mock): query = Query() cursor_mock = engine_mock.return_value.__enter__.return_value assert MySQLEngineSpec.cancel_query(cursor_mock, query, 123) is True
def test_extract_errors(self): """ Test that custom error messages are extracted correctly. """ msg = "mysql: Access denied for user 'test'@'testuser.com'. " result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType. TEST_CONNECTION_ACCESS_DENIED_ERROR, message= 'Either the username "test" or the password is incorrect.', level=ErrorLevel.ERROR, extra={ "engine_name": "MySQL", "issue_codes": [{ "code": 1014, "message": "Issue 1014 - Either the username or the password is wrong.", }], }, ) ] msg = "mysql: Unknown MySQL server host 'badhostname.com'. " result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType. TEST_CONNECTION_INVALID_HOSTNAME_ERROR, message='Unknown MySQL server host "badhostname.com".', level=ErrorLevel.ERROR, extra={ "engine_name": "MySQL", "issue_codes": [{ "code": 1007, "message": "Issue 1007 - The hostname provided can't be resolved.", }], }, ) ] msg = "mysql: Can't connect to MySQL server on 'badconnection.com'." result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.TEST_CONNECTION_HOST_DOWN_ERROR, message= 'The host "badconnection.com" might be down and can\'t be reached.', level=ErrorLevel.ERROR, extra={ "engine_name": "MySQL", "issue_codes": [{ "code": 1007, "message": "Issue 1007 - The hostname provided can't be resolved.", }], }, ) ] msg = "mysql: Can't connect to MySQL server on '93.184.216.34'." result = MySQLEngineSpec.extract_errors(Exception(msg)) assert result == [ SupersetError( error_type=SupersetErrorType.TEST_CONNECTION_HOST_DOWN_ERROR, message= 'The host "93.184.216.34" might be down and can\'t be reached.', level=ErrorLevel.ERROR, extra={ "engine_name": "MySQL", "issue_codes": [{ "code": 10007, "message": "Issue 1007 - The hostname provided can't be resolved.", }], }, ) ]
def test_get_datatype(self): self.assertEquals('STRING', PrestoEngineSpec.get_datatype('string')) self.assertEquals('TINY', MySQLEngineSpec.get_datatype(1)) self.assertEquals('VARCHAR', MySQLEngineSpec.get_datatype(15)) self.assertEquals('VARCHAR', BaseEngineSpec.get_datatype('VARCHAR'))
def test_cancel_query_failed(self, engine_mock): query = Query() cursor_mock = engine_mock.raiseError.side_effect = Exception() assert MySQLEngineSpec.cancel_query(cursor_mock, query, 123) is False
def test_get_datatype_mysql(self): self.assertEquals("TINY", MySQLEngineSpec.get_datatype(1)) self.assertEquals("VARCHAR", MySQLEngineSpec.get_datatype(15))
def test_get_cancel_query_id(self, engine_mock): query = Query() cursor_mock = engine_mock.return_value.__enter__.return_value cursor_mock.fetchone.return_value = [123] assert MySQLEngineSpec.get_cancel_query_id(cursor_mock, query) == 123