Home | History | Annotate | Download | only in test
      1 """Test program for the fcntl C module.
      2 """
      3 import platform
      4 import os
      5 import struct
      6 import sys
      7 import unittest
      8 from test.support import (verbose, TESTFN, unlink, run_unittest, import_module,
      9                           cpython_only)
     10 
     11 # Skip test if no fcntl module.
     12 fcntl = import_module('fcntl')
     13 
     14 
     15 # TODO - Write tests for flock() and lockf().
     16 
     17 def get_lockdata():
     18     try:
     19         os.O_LARGEFILE
     20     except AttributeError:
     21         start_len = "ll"
     22     else:
     23         start_len = "qq"
     24 
     25     if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd', 'bsdos'))
     26         or sys.platform == 'darwin'):
     27         if struct.calcsize('l') == 8:
     28             off_t = 'l'
     29             pid_t = 'i'
     30         else:
     31             off_t = 'lxxxx'
     32             pid_t = 'l'
     33         lockdata = struct.pack(off_t + off_t + pid_t + 'hh', 0, 0, 0,
     34                                fcntl.F_WRLCK, 0)
     35     elif sys.platform.startswith('gnukfreebsd'):
     36         lockdata = struct.pack('qqihhi', 0, 0, 0, fcntl.F_WRLCK, 0, 0)
     37     elif sys.platform in ['aix3', 'aix4', 'hp-uxB', 'unixware7']:
     38         lockdata = struct.pack('hhlllii', fcntl.F_WRLCK, 0, 0, 0, 0, 0, 0)
     39     else:
     40         lockdata = struct.pack('hh'+start_len+'hh', fcntl.F_WRLCK, 0, 0, 0, 0, 0)
     41     if lockdata:
     42         if verbose:
     43             print('struct.pack: ', repr(lockdata))
     44     return lockdata
     45 
     46 lockdata = get_lockdata()
     47 
     48 class BadFile:
     49     def __init__(self, fn):
     50         self.fn = fn
     51     def fileno(self):
     52         return self.fn
     53 
     54 class TestFcntl(unittest.TestCase):
     55 
     56     def setUp(self):
     57         self.f = None
     58 
     59     def tearDown(self):
     60         if self.f and not self.f.closed:
     61             self.f.close()
     62         unlink(TESTFN)
     63 
     64     def test_fcntl_fileno(self):
     65         # the example from the library docs
     66         self.f = open(TESTFN, 'wb')
     67         rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
     68         if verbose:
     69             print('Status from fcntl with O_NONBLOCK: ', rv)
     70         rv = fcntl.fcntl(self.f.fileno(), fcntl.F_SETLKW, lockdata)
     71         if verbose:
     72             print('String from fcntl with F_SETLKW: ', repr(rv))
     73         self.f.close()
     74 
     75     def test_fcntl_file_descriptor(self):
     76         # again, but pass the file rather than numeric descriptor
     77         self.f = open(TESTFN, 'wb')
     78         rv = fcntl.fcntl(self.f, fcntl.F_SETFL, os.O_NONBLOCK)
     79         if verbose:
     80             print('Status from fcntl with O_NONBLOCK: ', rv)
     81         rv = fcntl.fcntl(self.f, fcntl.F_SETLKW, lockdata)
     82         if verbose:
     83             print('String from fcntl with F_SETLKW: ', repr(rv))
     84         self.f.close()
     85 
     86     def test_fcntl_bad_file(self):
     87         with self.assertRaises(ValueError):
     88             fcntl.fcntl(-1, fcntl.F_SETFL, os.O_NONBLOCK)
     89         with self.assertRaises(ValueError):
     90             fcntl.fcntl(BadFile(-1), fcntl.F_SETFL, os.O_NONBLOCK)
     91         with self.assertRaises(TypeError):
     92             fcntl.fcntl('spam', fcntl.F_SETFL, os.O_NONBLOCK)
     93         with self.assertRaises(TypeError):
     94             fcntl.fcntl(BadFile('spam'), fcntl.F_SETFL, os.O_NONBLOCK)
     95 
     96     @cpython_only
     97     def test_fcntl_bad_file_overflow(self):
     98         from _testcapi import INT_MAX, INT_MIN
     99         # Issue 15989
    100         with self.assertRaises(OverflowError):
    101             fcntl.fcntl(INT_MAX + 1, fcntl.F_SETFL, os.O_NONBLOCK)
    102         with self.assertRaises(OverflowError):
    103             fcntl.fcntl(BadFile(INT_MAX + 1), fcntl.F_SETFL, os.O_NONBLOCK)
    104         with self.assertRaises(OverflowError):
    105             fcntl.fcntl(INT_MIN - 1, fcntl.F_SETFL, os.O_NONBLOCK)
    106         with self.assertRaises(OverflowError):
    107             fcntl.fcntl(BadFile(INT_MIN - 1), fcntl.F_SETFL, os.O_NONBLOCK)
    108 
    109     @unittest.skipIf(
    110         platform.machine().startswith('arm') and platform.system() == 'Linux',
    111         "ARM Linux returns EINVAL for F_NOTIFY DN_MULTISHOT")
    112     def test_fcntl_64_bit(self):
    113         # Issue #1309352: fcntl shouldn't fail when the third arg fits in a
    114         # C 'long' but not in a C 'int'.
    115         try:
    116             cmd = fcntl.F_NOTIFY
    117             # This flag is larger than 2**31 in 64-bit builds
    118             flags = fcntl.DN_MULTISHOT
    119         except AttributeError:
    120             self.skipTest("F_NOTIFY or DN_MULTISHOT unavailable")
    121         fd = os.open(os.path.dirname(os.path.abspath(TESTFN)), os.O_RDONLY)
    122         try:
    123             fcntl.fcntl(fd, cmd, flags)
    124         finally:
    125             os.close(fd)
    126 
    127     def test_flock(self):
    128         # Solaris needs readable file for shared lock
    129         self.f = open(TESTFN, 'wb+')
    130         fileno = self.f.fileno()
    131         fcntl.flock(fileno, fcntl.LOCK_SH)
    132         fcntl.flock(fileno, fcntl.LOCK_UN)
    133         fcntl.flock(self.f, fcntl.LOCK_SH | fcntl.LOCK_NB)
    134         fcntl.flock(self.f, fcntl.LOCK_UN)
    135         fcntl.flock(fileno, fcntl.LOCK_EX)
    136         fcntl.flock(fileno, fcntl.LOCK_UN)
    137 
    138         self.assertRaises(ValueError, fcntl.flock, -1, fcntl.LOCK_SH)
    139         self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
    140 
    141     @cpython_only
    142     def test_flock_overflow(self):
    143         import _testcapi
    144         self.assertRaises(OverflowError, fcntl.flock, _testcapi.INT_MAX+1,
    145                           fcntl.LOCK_SH)
    146 
    147 
    148 def test_main():
    149     run_unittest(TestFcntl)
    150 
    151 if __name__ == '__main__':
    152     test_main()
    153