mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #25961 -- Removed handling of thread-non-safe GEOS functions.
This commit is contained in:
parent
febe1321da
commit
312fc1af7b
3 changed files with 80 additions and 104 deletions
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
|||
import ctypes
|
||||
import json
|
||||
import random
|
||||
import threading
|
||||
from binascii import a2b_hex, b2a_hex
|
||||
from io import BytesIO
|
||||
from unittest import skipUnless
|
||||
|
@ -12,7 +13,7 @@ from django.contrib.gis.gdal import HAS_GDAL
|
|||
from django.contrib.gis.geos import (
|
||||
HAS_GEOS, GeometryCollection, GEOSException, GEOSGeometry, LinearRing,
|
||||
LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
|
||||
fromfile, fromstr,
|
||||
fromfile, fromstr, libgeos,
|
||||
)
|
||||
from django.contrib.gis.geos.base import GEOSBase
|
||||
from django.contrib.gis.geos.libgeos import geos_version_info
|
||||
|
@ -1232,6 +1233,48 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
|
|||
self.assertEqual(m.group('version'), v_geos)
|
||||
self.assertEqual(m.group('capi_version'), v_capi)
|
||||
|
||||
def test_geos_threads(self):
|
||||
pnt = Point()
|
||||
context_ptrs = []
|
||||
|
||||
geos_init = libgeos.lgeos.initGEOS_r
|
||||
geos_finish = libgeos.lgeos.finishGEOS_r
|
||||
|
||||
def init(*args, **kwargs):
|
||||
result = geos_init(*args, **kwargs)
|
||||
context_ptrs.append(result)
|
||||
return result
|
||||
|
||||
def finish(*args, **kwargs):
|
||||
result = geos_finish(*args, **kwargs)
|
||||
destructor_called.set()
|
||||
return result
|
||||
|
||||
for i in range(2):
|
||||
destructor_called = threading.Event()
|
||||
patch_path = 'django.contrib.gis.geos.libgeos.lgeos'
|
||||
with mock.patch.multiple(patch_path, initGEOS_r=mock.DEFAULT, finishGEOS_r=mock.DEFAULT) as mocked:
|
||||
mocked['initGEOS_r'].side_effect = init
|
||||
mocked['finishGEOS_r'].side_effect = finish
|
||||
with mock.patch('django.contrib.gis.geos.prototypes.predicates.geos_hasz.func') as mocked_hasz:
|
||||
thread = threading.Thread(target=lambda: pnt.hasz)
|
||||
thread.start()
|
||||
thread.join()
|
||||
|
||||
# We can't be sure that members of thread locals are
|
||||
# garbage collected right after `thread.join()` so
|
||||
# we must wait until destructor is actually called.
|
||||
# Fail if destructor wasn't called within a second.
|
||||
self.assertTrue(destructor_called.wait(1))
|
||||
|
||||
context_ptr = context_ptrs[i]
|
||||
self.assertIsInstance(context_ptr, libgeos.CONTEXT_PTR)
|
||||
mocked_hasz.assert_called_once_with(context_ptr, pnt.ptr)
|
||||
mocked['finishGEOS_r'].assert_called_once_with(context_ptr)
|
||||
|
||||
# Check that different contexts were used for the different threads.
|
||||
self.assertNotEqual(context_ptrs[0], context_ptrs[1])
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango20Warning)
|
||||
def test_deprecated_srid_getters_setters(self):
|
||||
p = Point(1, 2, srid=123)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue