def _raise_mysql_error(self, errclass, errno, errmsg): """Raise a MySQL error wrapped by SQLAlchemy.""" error = errclass(errno, errmsg) wrapped = InterfaceError.instance( statement="SELECT COUNT(*) FROM table", params={}, orig=error, dbapi_base_err=MySQLError, ) raise wrapped
def handle_qserv_exception(context): conn = context.connection.connection if hasattr(conn, "error") and context.original_exception.args[0] == -1: # Handle Qserv Errors where we return error codes above those # identified by the MySQLdb driver. # The MySQL driver, by default, returns a "whack" error code # if this is the case with error == -1. from _mysql_exceptions import InterfaceError as MysqlIError old_exc = context.sqlalchemy_exception orig = MysqlIError(conn.errno(), conn.error()) return InterfaceError(old_exc.statement, old_exc.params, orig, old_exc.connection_invalidated) pass
def test_execute_with_session_with_reconnection(self, apply_and_flush_mock): function_mock = Mock() args = () kwargs = {} broken_session = Mock() new_session = Mock() session_class_mock = Mock() session_class_mock.side_effect = [broken_session, new_session] apply_and_flush_mock.side_effect = [ InterfaceError(None, None, None, None), sentinel ] result = db_manager._execute_with_session(session_class_mock, function_mock, args, kwargs) expected_calls = [ call(function_mock, broken_session, args, kwargs), call(function_mock, new_session, args, kwargs), ] self.assertEqual(apply_and_flush_mock.call_args_list, expected_calls) self.assertEqual(result, sentinel)
def test_retriable_exceptions( self, celery, redis, session, db_shared_session, metricsmock, errclass, errno, errmsg, backoff_sleep_mock, ): """Test database exceptions where the task should wait and try again.""" obs = CellObservationFactory.build(radio=Radio.lte) shard = CellShard.shard_model(obs.cellid) cell = CellShardFactory.build( radio=obs.radio, mcc=obs.mcc, mnc=obs.mnc, lac=obs.lac, cid=obs.cid, samples=10, created=datetime(2019, 12, 5, tzinfo=UTC), ) session.add(cell) session.commit() session.begin_nested() # Protect test cell from task rollback error = errclass(errno, errmsg) wrapped = InterfaceError.instance( statement="SELECT COUNT(*) FROM cell_area", params={}, orig=error, dbapi_base_err=MySQLError, ) with mock.patch.object(CellUpdater, "add_area_update", side_effect=[wrapped, None]): self._queue_and_update(celery, [obs], update_cell) assert CellUpdater.add_area_update.call_count == 2 backoff_sleep_mock.assert_called_once() cells = session.query(shard).all() assert len(cells) == 1 self.check_statcounter(redis, StatKey.cell, 1) # The existing cell record was updated cell = cells[0] assert cell.samples == 11 assert cell.created == datetime(2019, 12, 5, tzinfo=UTC) self.check_statcounter(redis, StatKey.unique_cell, 0) # Assert generated metrics are correct metricsmock.assert_incr_once("data.observation.insert", value=1, tags=["type:cell"]) metricsmock.assert_incr_once("data.station.confirm", value=1, tags=["type:cell"]) metricsmock.assert_timing_once("task", tags=["task:data.update_cell"]) metricsmock.assert_incr_once("data.station.dberror", tags=["type:cell", "errno:%s" % errno])
def test_retriable_exceptions(self, celery, redis, session, db, metricsmock, errclass, errno, errmsg): """Test database exceptions where the task should wait and try again.""" obs = CellObservationFactory.build(radio=Radio.lte) shard = CellShard.shard_model(obs.cellid) cell = CellShardFactory.build( radio=obs.radio, mcc=obs.mcc, mnc=obs.mnc, lac=obs.lac, cid=obs.cid, samples=10, created=datetime(2019, 12, 5, tzinfo=UTC), ) session.add(cell) session.commit() # TODO: Find a more elegant way to do this db.tests_task_use_savepoint = True error = errclass(errno, errmsg) wrapped = InterfaceError.instance( statement="SELECT COUNT(*) FROM cell_area", params={}, orig=error, dbapi_base_err=MySQLError, ) with mock.patch.object( CellUpdater, "add_area_update", side_effect=[ wrapped, None ]), mock.patch("ichnaea.data.station.time.sleep") as sleepy: self._queue_and_update(celery, [obs], update_cell) assert CellUpdater.add_area_update.call_count == 2 sleepy.assert_called_once_with(1) del db.tests_task_use_savepoint cells = session.query(shard).all() assert len(cells) == 1 self.check_statcounter(redis, StatKey.cell, 1) # The existing cell record was updated cell = cells[0] assert cell.samples == 11 assert cell.created == datetime(2019, 12, 5, tzinfo=UTC) self.check_statcounter(redis, StatKey.unique_cell, 0) # Assert generated metrics are correct assert metricsmock.has_record("incr", "data.observation.insert", value=1, tags=["type:cell"]) assert metricsmock.has_record("incr", "data.station.confirm", value=1, tags=["type:cell"]) assert metricsmock.has_record("timing", "task", tags=["task:data.update_cell"]) assert metricsmock.has_record( "incr", "data.station.dberror", value=1, tags=["type:cell", "errno:%s" % errno], )