test_largefile.py revision 180510d29b369b88b0eb8815086162d2d6ef60a7
1"""Test largefile support on system where this makes sense. 2""" 3 4import os 5import stat 6import sys 7import unittest 8from test.test_support import run_unittest, TESTFN, verbose, requires, \ 9 TestSkipped, unlink 10 11try: 12 import signal 13 # The default handler for SIGXFSZ is to abort the process. 14 # By ignoring it, system calls exceeding the file size resource 15 # limit will raise IOError instead of crashing the interpreter. 16 oldhandler = signal.signal(signal.SIGXFSZ, signal.SIG_IGN) 17except (ImportError, AttributeError): 18 pass 19 20# create >2GB file (2GB = 2147483648 bytes) 21size = 2500000000 22 23 24class TestCase(unittest.TestCase): 25 """Test that each file function works as expected for a large 26 (i.e. > 2GB, do we have to check > 4GB) files. 27 28 NOTE: the order of execution of the test methods is important! test_seek 29 must run first to create the test file. File cleanup must also be handled 30 outside the test instances because of this. 31 32 """ 33 34 def test_seek(self): 35 if verbose: 36 print('create large file via seek (may be sparse file) ...') 37 with open(TESTFN, 'wb') as f: 38 f.write(b'z') 39 f.seek(0) 40 f.seek(size) 41 f.write(b'a') 42 f.flush() 43 if verbose: 44 print('check file size with os.fstat') 45 self.assertEqual(os.fstat(f.fileno())[stat.ST_SIZE], size+1) 46 47 def test_osstat(self): 48 if verbose: 49 print('check file size with os.stat') 50 self.assertEqual(os.stat(TESTFN)[stat.ST_SIZE], size+1) 51 52 def test_seek_read(self): 53 if verbose: 54 print('play around with seek() and read() with the built largefile') 55 with open(TESTFN, 'rb') as f: 56 self.assertEqual(f.tell(), 0) 57 self.assertEqual(f.read(1), b'z') 58 self.assertEqual(f.tell(), 1) 59 f.seek(0) 60 self.assertEqual(f.tell(), 0) 61 f.seek(0, 0) 62 self.assertEqual(f.tell(), 0) 63 f.seek(42) 64 self.assertEqual(f.tell(), 42) 65 f.seek(42, 0) 66 self.assertEqual(f.tell(), 42) 67 f.seek(42, 1) 68 self.assertEqual(f.tell(), 84) 69 f.seek(0, 1) 70 self.assertEqual(f.tell(), 84) 71 f.seek(0, 2) # seek from the end 72 self.assertEqual(f.tell(), size + 1 + 0) 73 f.seek(-10, 2) 74 self.assertEqual(f.tell(), size + 1 - 10) 75 f.seek(-size-1, 2) 76 self.assertEqual(f.tell(), 0) 77 f.seek(size) 78 self.assertEqual(f.tell(), size) 79 # the 'a' that was written at the end of file above 80 self.assertEqual(f.read(1), b'a') 81 f.seek(-size-1, 1) 82 self.assertEqual(f.read(1), b'z') 83 self.assertEqual(f.tell(), 1) 84 85 def test_lseek(self): 86 if verbose: 87 print('play around with os.lseek() with the built largefile') 88 with open(TESTFN, 'rb') as f: 89 self.assertEqual(os.lseek(f.fileno(), 0, 0), 0) 90 self.assertEqual(os.lseek(f.fileno(), 42, 0), 42) 91 self.assertEqual(os.lseek(f.fileno(), 42, 1), 84) 92 self.assertEqual(os.lseek(f.fileno(), 0, 1), 84) 93 self.assertEqual(os.lseek(f.fileno(), 0, 2), size+1+0) 94 self.assertEqual(os.lseek(f.fileno(), -10, 2), size+1-10) 95 self.assertEqual(os.lseek(f.fileno(), -size-1, 2), 0) 96 self.assertEqual(os.lseek(f.fileno(), size, 0), size) 97 # the 'a' that was written at the end of file above 98 self.assertEqual(f.read(1), b'a') 99 100 def test_truncate(self): 101 if verbose: 102 print('try truncate') 103 with open(TESTFN, 'r+b') as f: 104 # this is already decided before start running the test suite 105 # but we do it anyway for extra protection 106 if not hasattr(f, 'truncate'): 107 raise TestSkipped("open().truncate() not available on this system") 108 f.seek(0, 2) 109 # else we've lost track of the true size 110 self.assertEqual(f.tell(), size+1) 111 # Cut it back via seek + truncate with no argument. 112 newsize = size - 10 113 f.seek(newsize) 114 f.truncate() 115 self.assertEqual(f.tell(), newsize) # else pointer moved 116 f.seek(0, 2) 117 self.assertEqual(f.tell(), newsize) # else wasn't truncated 118 # Ensure that truncate(smaller than true size) shrinks 119 # the file. 120 newsize -= 1 121 f.seek(42) 122 f.truncate(newsize) 123 self.assertEqual(f.tell(), 42) # else pointer moved 124 f.seek(0, 2) 125 self.assertEqual(f.tell(), newsize) # else wasn't truncated 126 # XXX truncate(larger than true size) is ill-defined 127 # across platform; cut it waaaaay back 128 f.seek(0) 129 f.truncate(1) 130 self.assertEqual(f.tell(), 0) # else pointer moved 131 self.assertEqual(len(f.read()), 1) # else wasn't truncated 132 133def test_main(): 134 # On Windows and Mac OSX this test comsumes large resources; It 135 # takes a long time to build the >2GB file and takes >2GB of disk 136 # space therefore the resource must be enabled to run this test. 137 # If not, nothing after this line stanza will be executed. 138 if sys.platform[:3] == 'win' or sys.platform == 'darwin': 139 requires('largefile', 140 'test requires %s bytes and a long time to run' % str(size)) 141 else: 142 # Only run if the current filesystem supports large files. 143 # (Skip this test on Windows, since we now always support 144 # large files.) 145 f = open(TESTFN, 'wb') 146 try: 147 # 2**31 == 2147483648 148 f.seek(2147483649) 149 # Seeking is not enough of a test: you must write and 150 # flush, too! 151 f.write(b'x') 152 f.flush() 153 except (IOError, OverflowError): 154 f.close() 155 unlink(TESTFN) 156 raise TestSkipped("filesystem does not have largefile support") 157 else: 158 f.close() 159 suite = unittest.TestSuite() 160 suite.addTest(TestCase('test_seek')) 161 suite.addTest(TestCase('test_osstat')) 162 suite.addTest(TestCase('test_seek_read')) 163 suite.addTest(TestCase('test_lseek')) 164 with open(TESTFN, 'w') as f: 165 if hasattr(f, 'truncate'): 166 suite.addTest(TestCase('test_truncate')) 167 unlink(TESTFN) 168 try: 169 run_unittest(suite) 170 finally: 171 unlink(TESTFN) 172 173if __name__ == '__main__': 174 test_main() 175