From c05a7b29e6ff3e67e5f4144fc2f4a40ae3efd4f7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 9 Feb 2023 11:13:13 -0600 Subject: [PATCH] Terminate stale MySQL connections at the end of test runs (#87794) --- tests/components/recorder/test_init.py | 4 ---- tests/conftest.py | 21 ++++++++++++++++++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index 0358522df25..b332a59d232 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -103,10 +103,6 @@ async def test_shutdown_before_startup_finishes( tmp_path, ): """Test shutdown before recorder starts is clean.""" - if recorder_db_url.startswith("mysql://"): - # Currently this test fails with MySQL - return - if recorder_db_url == "sqlite://": # On-disk database because this test does not play nice with the # MutexPool diff --git a/tests/conftest.py b/tests/conftest.py index 4aeb95c2ee0..1d66380229e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1066,7 +1066,26 @@ def recorder_db_url(pytestconfig): assert not sqlalchemy_utils.database_exists(db_url) sqlalchemy_utils.create_database(db_url, encoding="utf8") yield db_url - if db_url.startswith("mysql://") or db_url.startswith("postgresql://"): + if db_url.startswith("mysql://"): + import sqlalchemy as sa + + made_url = sa.make_url(db_url) + db = made_url.database + engine = sa.create_engine(db_url) + # Kill any open connections to the database before dropping it + # to ensure that InnoDB does not deadlock. + with engine.begin() as connection: + query = sa.text( + "select id FROM information_schema.processlist WHERE db=:db and id != CONNECTION_ID()" + ) + for row in connection.execute(query, parameters={"db": db}).fetchall(): + _LOGGER.warning( + "Killing MySQL connection to temporary database %s", row.id + ) + connection.execute(sa.text("KILL :id"), parameters={"id": row.id}) + engine.dispose() + sqlalchemy_utils.drop_database(db_url) + elif db_url.startswith("postgresql://"): sqlalchemy_utils.drop_database(db_url)