bpo-37096: Add large-file tests for modules using sendfile(2) (GH-13676) · python/cpython@5bcc6d8 (original) (raw)

`@@ -5,17 +5,19 @@

`

5

5

`import stat

`

6

6

`import sys

`

7

7

`import unittest

`

8

``

`-

from test.support import TESTFN, requires, unlink, bigmemtest

`

``

8

`+

import socket

`

``

9

`+

import shutil

`

``

10

`+

import threading

`

``

11

`+

from test.support import TESTFN, requires, unlink, bigmemtest, find_unused_port

`

9

12

`import io # C implementation of io

`

10

13

`import _pyio as pyio # Python implementation of io

`

11

14

``

12

15

`# size of file to create (>2 GiB; 2 GiB == 2,147,483,648 bytes)

`

13

16

`size = 2_500_000_000

`

``

17

`+

TESTFN2 = TESTFN + '2'

`

``

18

+

14

19

``

15

20

`class LargeFileTest:

`

16

``

`-

"""Test that each file function works as expected for large

`

17

``

`-

(i.e. > 2 GiB) files.

`

18

``

`-

"""

`

19

21

``

20

22

`def setUp(self):

`

21

23

`if os.path.exists(TESTFN):

`

`@@ -44,6 +46,13 @@ def tearDownClass(cls):

`

44

46

`if not os.stat(TESTFN)[stat.ST_SIZE] == 0:

`

45

47

`raise cls.failureException('File was not truncated by opening '

`

46

48

`'with mode "wb"')

`

``

49

`+

unlink(TESTFN2)

`

``

50

+

``

51

+

``

52

`+

class TestFileMethods(LargeFileTest):

`

``

53

`+

"""Test that each file function works as expected for large

`

``

54

`+

(i.e. > 2 GiB) files.

`

``

55

`+

"""

`

47

56

``

48

57

`# _pyio.FileIO.readall() uses a temporary bytearray then casted to bytes,

`

49

58

`# so memuse=2 is needed

`

`@@ -140,6 +149,72 @@ def test_seekable(self):

`

140

149

`f.seek(pos)

`

141

150

`self.assertTrue(f.seekable())

`

142

151

``

``

152

+

``

153

`+

class TestCopyfile(LargeFileTest, unittest.TestCase):

`

``

154

`+

open = staticmethod(io.open)

`

``

155

+

``

156

`+

def test_it(self):

`

``

157

`+

Internally shutil.copyfile() can use "fast copy" methods like

`

``

158

`+

os.sendfile().

`

``

159

`+

size = os.path.getsize(TESTFN)

`

``

160

`+

shutil.copyfile(TESTFN, TESTFN2)

`

``

161

`+

self.assertEqual(os.path.getsize(TESTFN2), size)

`

``

162

`+

with open(TESTFN2, 'rb') as f:

`

``

163

`+

self.assertEqual(f.read(5), b'z\x00\x00\x00\x00')

`

``

164

`+

f.seek(size - 5)

`

``

165

`+

self.assertEqual(f.read(), b'\x00\x00\x00\x00a')

`

``

166

+

``

167

+

``

168

`+

@unittest.skipIf(not hasattr(os, 'sendfile'), 'sendfile not supported')

`

``

169

`+

class TestSocketSendfile(LargeFileTest, unittest.TestCase):

`

``

170

`+

open = staticmethod(io.open)

`

``

171

`+

timeout = 3

`

``

172

+

``

173

`+

def setUp(self):

`

``

174

`+

super().setUp()

`

``

175

`+

self.thread = None

`

``

176

+

``

177

`+

def tearDown(self):

`

``

178

`+

super().tearDown()

`

``

179

`+

if self.thread is not None:

`

``

180

`+

self.thread.join(self.timeout)

`

``

181

`+

self.thread = None

`

``

182

+

``

183

`+

def tcp_server(self, sock):

`

``

184

`+

def run(sock):

`

``

185

`+

with sock:

`

``

186

`+

conn, _ = sock.accept()

`

``

187

`+

with conn, open(TESTFN2, 'wb') as f:

`

``

188

`+

event.wait(self.timeout)

`

``

189

`+

while True:

`

``

190

`+

chunk = conn.recv(65536)

`

``

191

`+

if not chunk:

`

``

192

`+

return

`

``

193

`+

f.write(chunk)

`

``

194

+

``

195

`+

event = threading.Event()

`

``

196

`+

sock.settimeout(self.timeout)

`

``

197

`+

self.thread = threading.Thread(target=run, args=(sock, ))

`

``

198

`+

self.thread.start()

`

``

199

`+

event.set()

`

``

200

+

``

201

`+

def test_it(self):

`

``

202

`+

port = find_unused_port()

`

``

203

`+

with socket.create_server(("", port)) as sock:

`

``

204

`+

self.tcp_server(sock)

`

``

205

`+

with socket.create_connection(("127.0.0.1", port)) as client:

`

``

206

`+

with open(TESTFN, 'rb') as f:

`

``

207

`+

client.sendfile(f)

`

``

208

`+

self.tearDown()

`

``

209

+

``

210

`+

size = os.path.getsize(TESTFN)

`

``

211

`+

self.assertEqual(os.path.getsize(TESTFN2), size)

`

``

212

`+

with open(TESTFN2, 'rb') as f:

`

``

213

`+

self.assertEqual(f.read(5), b'z\x00\x00\x00\x00')

`

``

214

`+

f.seek(size - 5)

`

``

215

`+

self.assertEqual(f.read(), b'\x00\x00\x00\x00a')

`

``

216

+

``

217

+

143

218

`def setUpModule():

`

144

219

`try:

`

145

220

`import signal

`

`@@ -176,14 +251,18 @@ def setUpModule():

`

176

251

`unlink(TESTFN)

`

177

252

``

178

253

``

179

``

`-

class CLargeFileTest(LargeFileTest, unittest.TestCase):

`

``

254

`+

class CLargeFileTest(TestFileMethods, unittest.TestCase):

`

180

255

`open = staticmethod(io.open)

`

181

256

``

182

``

`-

class PyLargeFileTest(LargeFileTest, unittest.TestCase):

`

``

257

+

``

258

`+

class PyLargeFileTest(TestFileMethods, unittest.TestCase):

`

183

259

`open = staticmethod(pyio.open)

`

184

260

``

``

261

+

185

262

`def tearDownModule():

`

186

263

`unlink(TESTFN)

`

``

264

`+

unlink(TESTFN2)

`

``

265

+

187

266

``

188

267

`if name == 'main':

`

189

268

`unittest.main()

`