|
14 | 14 |
|
15 | 15 | import os
|
16 | 16 | import shutil
|
| 17 | +import sys |
17 | 18 | import tempfile
|
18 | 19 |
|
19 | 20 | from qgis.core import QgsVectorLayer, QgsVectorDataProvider
|
|
29 | 30 | # Note - doesn't implement ProviderTestCase as most OGR provider is tested by the shapefile provider test
|
30 | 31 |
|
31 | 32 |
|
| 33 | +def count_opened_filedescriptors(filename_to_test): |
| 34 | + count = -1 |
| 35 | + if sys.platform.startswith('linux'): |
| 36 | + count = 0 |
| 37 | + open_files_dirname = '/proc/%d/fd' % os.getpid() |
| 38 | + filenames = os.listdir(open_files_dirname) |
| 39 | + for filename in filenames: |
| 40 | + full_filename = open_files_dirname + '/' + filename |
| 41 | + if os.path.exists(full_filename): |
| 42 | + link = os.readlink(full_filename) |
| 43 | + if os.path.basename(link) == os.path.basename(filename_to_test): |
| 44 | + count += 1 |
| 45 | + return count |
| 46 | + |
| 47 | + |
32 | 48 | class PyQgsOGRProvider(unittest.TestCase):
|
33 | 49 |
|
34 | 50 | @classmethod
|
@@ -66,6 +82,76 @@ def testUpdateMode(self):
|
66 | 82 | self.assertTrue(vl.dataProvider().leaveUpdateMode())
|
67 | 83 | self.assertEqual(vl.dataProvider().property("_debug_open_mode"), "read-write")
|
68 | 84 |
|
| 85 | + def testNoDanglingFileDescriptorAfterCloseVariant1(self): |
| 86 | + ''' Test that when closing the provider all file handles are released ''' |
| 87 | + |
| 88 | + datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant1.csv') |
| 89 | + with open(datasource, 'wt') as f: |
| 90 | + f.write('id,WKT\n') |
| 91 | + f.write('1,\n') |
| 92 | + f.write('2,POINT(2 49)\n') |
| 93 | + |
| 94 | + vl = QgsVectorLayer(u'{}|layerid=0'.format(datasource), u'test', u'ogr') |
| 95 | + self.assertTrue(vl.isValid()) |
| 96 | + # The iterator will take one extra connection |
| 97 | + myiter = vl.getFeatures() |
| 98 | + # Consume one feature but the iterator is still opened |
| 99 | + f = next(myiter) |
| 100 | + self.assertTrue(f.isValid()) |
| 101 | + |
| 102 | + if sys.platform.startswith('linux'): |
| 103 | + self.assertEqual(count_opened_filedescriptors(datasource), 2) |
| 104 | + |
| 105 | + # Should release one file descriptor |
| 106 | + del vl |
| 107 | + |
| 108 | + # Non portable, but Windows testing is done with trying to unlink |
| 109 | + if sys.platform.startswith('linux'): |
| 110 | + self.assertEqual(count_opened_filedescriptors(datasource), 1) |
| 111 | + |
| 112 | + f = next(myiter) |
| 113 | + self.assertTrue(f.isValid()) |
| 114 | + |
| 115 | + # Should release one file descriptor |
| 116 | + del myiter |
| 117 | + |
| 118 | + # Non portable, but Windows testing is done with trying to unlink |
| 119 | + if sys.platform.startswith('linux'): |
| 120 | + self.assertEqual(count_opened_filedescriptors(datasource), 0) |
| 121 | + |
| 122 | + # Check that deletion works well (can only fail on Windows) |
| 123 | + os.unlink(datasource) |
| 124 | + self.assertFalse(os.path.exists(datasource)) |
| 125 | + |
| 126 | + def testNoDanglingFileDescriptorAfterCloseVariant2(self): |
| 127 | + ''' Test that when closing the provider all file handles are released ''' |
| 128 | + |
| 129 | + datasource = os.path.join(self.basetestpath, 'testNoDanglingFileDescriptorAfterCloseVariant2.csv') |
| 130 | + with open(datasource, 'wt') as f: |
| 131 | + f.write('id,WKT\n') |
| 132 | + f.write('1,\n') |
| 133 | + f.write('2,POINT(2 49)\n') |
| 134 | + |
| 135 | + vl = QgsVectorLayer(u'{}|layerid=0'.format(datasource), u'test', u'ogr') |
| 136 | + self.assertTrue(vl.isValid()) |
| 137 | + # Consume all features. |
| 138 | + myiter = vl.getFeatures() |
| 139 | + for feature in myiter: |
| 140 | + pass |
| 141 | + # The iterator is closed, but the corresponding connection still not closed |
| 142 | + if sys.platform.startswith('linux'): |
| 143 | + self.assertEqual(count_opened_filedescriptors(datasource), 2) |
| 144 | + |
| 145 | + # Should release one file descriptor |
| 146 | + del vl |
| 147 | + |
| 148 | + # Non portable, but Windows testing is done with trying to unlink |
| 149 | + if sys.platform.startswith('linux'): |
| 150 | + self.assertEqual(count_opened_filedescriptors(datasource), 0) |
| 151 | + |
| 152 | + # Check that deletion works well (can only fail on Windows) |
| 153 | + os.unlink(datasource) |
| 154 | + self.assertFalse(os.path.exists(datasource)) |
69 | 155 |
|
70 | 156 | if __name__ == '__main__':
|
71 | 157 | unittest.main()
|
0 commit comments