From dd45d5223b3c5640baefcb591782bbcff873b6bf Mon Sep 17 00:00:00 2001
From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Date: Wed, 23 Aug 2023 09:09:23 +0200
Subject: [PATCH] Fixed ResourceWarning from unclosed SQLite connection on
 Python 3.13+.

- backends.sqlite.tests.ThreadSharing.test_database_sharing_in_threads
- backends.tests.ThreadTests.test_default_connection_thread_local:
    on SQLite, close() doesn't explicitly close in-memory connections.
- servers.tests.LiveServerInMemoryDatabaseLockTest
- test_runner.tests.SQLiteInMemoryTestDbs.test_transaction_support

Check out https://github.com/python/cpython/pull/108015.
---
 tests/backends/sqlite/tests.py | 27 +++++++++++++++++++++------
 tests/backends/tests.py        |  3 ++-
 tests/servers/tests.py         |  2 ++
 tests/test_runner/tests.py     | 25 +++++++++++++++----------
 4 files changed, 40 insertions(+), 17 deletions(-)

diff --git a/tests/backends/sqlite/tests.py b/tests/backends/sqlite/tests.py
index 2b728f8409..330ed50488 100644
--- a/tests/backends/sqlite/tests.py
+++ b/tests/backends/sqlite/tests.py
@@ -6,7 +6,13 @@ import unittest
 from pathlib import Path
 from unittest import mock
 
-from django.db import NotSupportedError, connection, transaction
+from django.db import (
+    DEFAULT_DB_ALIAS,
+    NotSupportedError,
+    connection,
+    connections,
+    transaction,
+)
 from django.db.models import Aggregate, Avg, StdDev, Sum, Variance
 from django.db.utils import ConnectionHandler
 from django.test import TestCase, TransactionTestCase, override_settings
@@ -222,11 +228,20 @@ class ThreadSharing(TransactionTestCase):
     available_apps = ["backends"]
 
     def test_database_sharing_in_threads(self):
+        thread_connections = []
+
         def create_object():
             Object.objects.create()
+            thread_connections.append(connections[DEFAULT_DB_ALIAS].connection)
 
-        create_object()
-        thread = threading.Thread(target=create_object)
-        thread.start()
-        thread.join()
-        self.assertEqual(Object.objects.count(), 2)
+        main_connection = connections[DEFAULT_DB_ALIAS].connection
+        try:
+            create_object()
+            thread = threading.Thread(target=create_object)
+            thread.start()
+            thread.join()
+            self.assertEqual(Object.objects.count(), 2)
+        finally:
+            for conn in thread_connections:
+                if conn is not main_connection:
+                    conn.close()
diff --git a/tests/backends/tests.py b/tests/backends/tests.py
index bfdf5ed4b4..5c562682f0 100644
--- a/tests/backends/tests.py
+++ b/tests/backends/tests.py
@@ -792,7 +792,8 @@ class ThreadTests(TransactionTestCase):
             # closed on teardown).
             for conn in connections_dict.values():
                 if conn is not connection and conn.allow_thread_sharing:
-                    conn.close()
+                    conn.validate_thread_sharing()
+                    conn._close()
                     conn.dec_thread_sharing()
 
     def test_connections_thread_local(self):
diff --git a/tests/servers/tests.py b/tests/servers/tests.py
index 4dece98ce9..ea49c11534 100644
--- a/tests/servers/tests.py
+++ b/tests/servers/tests.py
@@ -115,6 +115,7 @@ class LiveServerInMemoryDatabaseLockTest(LiveServerBase):
         connection.
         """
         conn = self.server_thread.connections_override[DEFAULT_DB_ALIAS]
+        source_connection = conn.connection
         # Open a connection to the database.
         conn.connect()
         # Create a transaction to lock the database.
@@ -128,6 +129,7 @@ class LiveServerInMemoryDatabaseLockTest(LiveServerBase):
         finally:
             # Release the transaction.
             cursor.execute("ROLLBACK")
+            source_connection.close()
 
 
 class FailingLiveServerThread(LiveServerThread):
diff --git a/tests/test_runner/tests.py b/tests/test_runner/tests.py
index 28145be3db..0643bf93a1 100644
--- a/tests/test_runner/tests.py
+++ b/tests/test_runner/tests.py
@@ -779,16 +779,21 @@ class SQLiteInMemoryTestDbs(TransactionTestCase):
             )
             with mock.patch("django.test.utils.connections", new=tested_connections):
                 other = tested_connections["other"]
-                DiscoverRunner(verbosity=0).setup_databases()
-                msg = (
-                    "DATABASES setting '%s' option set to sqlite3's ':memory:' value "
-                    "shouldn't interfere with transaction support detection."
-                    % option_key
-                )
-                # Transaction support is properly initialized for the 'other' DB.
-                self.assertTrue(other.features.supports_transactions, msg)
-                # And all the DBs report that they support transactions.
-                self.assertTrue(connections_support_transactions(), msg)
+                try:
+                    new_test_connections = DiscoverRunner(verbosity=0).setup_databases()
+                    msg = (
+                        f"DATABASES setting '{option_key}' option set to sqlite3's "
+                        "':memory:' value shouldn't interfere with transaction support "
+                        "detection."
+                    )
+                    # Transaction support is properly initialized for the
+                    # 'other' DB.
+                    self.assertTrue(other.features.supports_transactions, msg)
+                    # And all the DBs report that they support transactions.
+                    self.assertTrue(connections_support_transactions(), msg)
+                finally:
+                    for test_connection, _, _ in new_test_connections:
+                        test_connection._close()
 
 
 class DummyBackendTest(unittest.TestCase):