Esempio n. 1
0
    def testRsopenBehaviour(self):

        # for ease of use, we just test binary unbuffered files...

        with rsfile.rsopen(TESTFN, "RAEB", buffering=0, locking=False) as f:
            self.assertEqual(f.readable(), True)
            self.assertEqual(f.writable(), True)
            self.assertEqual(f._append, True)
            self.assertEqual(f.size(), 0)
            f.write(b"abcde")

        with rsfile.rsopen(TESTFN, "RAEB", buffering=0) as f:
            self.assertEqual(f.size(), 0)
            f.write(b"abcdef")
            f.seek(0)
            f.write(b"abcdef")
            self.assertEqual(f.size(), 12)
            self.assertEqual(f.tell(), 12)

        self.assertRaises(IOError, rsfile.rsopen, TESTFN, "RB-", buffering=0)

        with rsfile.rsopen(TESTFN, "RAEB", buffering=0) as f:
            os.rename(TESTFN, TESTFN + ".temp")  # for windows platforms...
            os.remove(TESTFN + ".temp")

        self.assertRaises(IOError, rsfile.rsopen, TESTFN, "WB+", buffering=0)
def reopener_via_fileno(name, mode):
    """Ensures that possible emulation of fileno doesn't break the access mode of the stream."""
    f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False)
    _disown_file_descriptor(f)
    fileno = f.fileno()
    assert fileno, fileno
    new_f = rsfile.rsopen(mode=mode, fileno=fileno, closefd=True)
    assert new_f.handle() == f.handle()
    assert new_f.fileno() == fileno
    return new_f
def reopener_via_fileno(name, mode):
    """Ensures that possible emulation of fileno doesn't break the access mode of the stream."""
    f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False)
    _disown_file_descriptor(f)
    fileno = f.fileno()
    assert fileno, fileno
    new_f = rsfile.rsopen(mode=mode, fileno=fileno, closefd=True)
    assert new_f.handle() == f.handle()
    assert new_f.fileno() == fileno
    return new_f
def __BROKEN__reopener_via_handle(name, mode):
    """Ensures that possible emulation of handle doesn't break the access mode of the stream."""
    f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False)
    _disown_file_descriptor(f)
    handle = f.handle()
    assert handle, handle
    new_f = rsfile.rsopen(mode=mode, handle=handle, closefd=True)
    assert new_f.handle() == handle
    if (defs.RSFILE_IMPLEMENTATION == "windows"):
        assert f._fileno is None, f._fileno  # we take care of NOT exhausting these emulated resources here
    else:
        assert new_f.fileno() == f.fileno()
    return new_f
def __BROKEN__reopener_via_handle(name, mode):
    """Ensures that possible emulation of handle doesn't break the access mode of the stream."""
    f = rsfile.rsopen(name, mode=mode, locking=False, thread_safe=False)
    _disown_file_descriptor(f)
    handle = f.handle()
    assert handle, handle
    new_f = rsfile.rsopen(mode=mode, handle=handle, closefd=True)
    assert new_f.handle() == handle
    if (defs.RSFILE_IMPLEMENTATION == "windows"):
        assert f._fileno is None, f._fileno  # we take care of NOT exhausting these emulated resources here
    else:
        assert new_f.fileno() == f.fileno()
    return new_f
Esempio n. 6
0
    def testFileCreationPermissions(self):

        with rsfile.rsopen(TESTFN, "RWB-", buffering=0, locking=False,
                           permissions=0o555) as f:  # creating read-only file

            f.write(b"abc")  # WORKS, because file permissions are only applied on subsequent open()
            f.flush()

            with rsfile.rsopen(TESTFN, "RB+", buffering=0, locking=False) as g:
                pass  # no problem

            self.assertRaises(IOError, rsfile.rsopen, TESTFN, "WB+", buffering=0,
                              locking=False)  # now can't open for writing

            os.chmod(TESTFN, 0o777)
            os.remove(TESTFN)
Esempio n. 7
0
    def test_intraprocess_duplicated_handle_locking(self):

        TESTFN = "mytestfile"
        with rsfile.rsopen(TESTFN, "RWB", locking=False) as f:
            f.lock_file(length=100, offset=0)

            other_fileno = os.dup(
                f.fileno())  # using C compatibility layer on windows

            with rsfile.rsopen(mode="RWB", fileno=other_fileno,
                               locking=False) as g:
                self.assertRaises(defs.LockingException,
                                  g.lock_file,
                                  timeout=0)  # duplicate handle

                g.lock_file(length=100, offset=100,
                            timeout=0)  # chunk locking works

        os.remove(TESTFN)
Esempio n. 8
0
    def testFileDeletions(self):

        TESTFNBIS = TESTFN + "X"
        if os.path.exists(TESTFNBIS):
            os.remove(TESTFNBIS)

        with rsfile.rsopen(TESTFN, "RB", buffering=0, locking=True) as h:
            self.assertTrue(os.path.exists(TESTFN))
            os.rename(TESTFN, TESTFNBIS)
            os.remove(TESTFNBIS)
            self.assertRaises(IOError, rsfile.rsopen, TESTFN, "R+", buffering=0)
            self.assertRaises(IOError, rsfile.rsopen, TESTFNBIS, "R+", buffering=0)

            if (defs.RSFILE_IMPLEMENTATION == "windows"):
                # on windows the file remains but in a weird state, awaiting deletion, so we can't reopen it...
                self.assertRaises(IOError, rsfile.rsopen, TESTFNBIS, "w", buffering=0)
            else:
                with rsfile.rsopen(TESTFN, "wb", buffering=0):
                    pass

        """
Esempio n. 9
0
    def testReturnedStreamTypes(self):

        for forced_mutex in [None, threading.RLock(), multiprocessing.RLock()]:
            with rsfile.rsopen(TESTFN, "RWB", buffering=0, mutex=forced_mutex) as f:  # by default, thread-safe
                self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper))
                self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex)
                f.write(b"abc")
            with rsfile.rsopen(TESTFN, "RWB", buffering=0, thread_safe=False) as f:
                self.assertTrue(isinstance(f, io.RawIOBase))
                f.write(b"abc")

            with rsfile.rsopen(TESTFN, "RWB", mutex=forced_mutex) as f:
                self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper))
                self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex)
                f.write(b"abc")
            with rsfile.rsopen(TESTFN, "RWB", thread_safe=False) as f:
                self.assertTrue(isinstance(f, io.BufferedIOBase))
                f.write(b"abc")

            with rsfile.rsopen(TESTFN, "RWT", mutex=forced_mutex) as f:
                self.assertTrue(isinstance(f, rsfile.RSThreadSafeWrapper))
                self.assertEqual(f.mutex, forced_mutex if forced_mutex else f.mutex)
                f.write("abc")
            with rsfile.rsopen(TESTFN, "RWT", thread_safe=False) as f:
                self.assertTrue(isinstance(f, io.TextIOBase))
                f.write("abc")
Esempio n. 10
0
 def __init__(self, buildout, name, options):
     variables = Variables()
     data = {}
     if options.get('index-file'):
         if os.path.exists(options['index-file']):
             with rsfile.rsopen(options['index-file']) as f:
                 data = json.load(f)
     key = options.get('index-key')
     if key is not None:
         if key not in data:
             data[key] = len(data)
         index_start = int(options.get('index-start', 1))
         variables.lookup['index'] = data[key] + index_start
     if options.get('index-file'):
         with rsfile.rsopen(options['index-file'], 'wb') as f:
             json.dump(data, f, indent=4)
     for k, v in options.items():
         try:
             variables.add(k, v)
         except VariableError:
             continue
     variables.evaluate(buildout, name, options)
Esempio n. 11
0
    def testConflictsBetweenLockingAndOperations(self):

        f = rsfile.rsopen(TESTFN, "RWE", thread_safe=False, locking=False)

        f.lock_file(shared=False)
        f.write("héllo")
        f.flush()
        f.seek(0)
        data = f.read()
        self.assertEqual(data, "héllo")
        f.unlock_file()

        f.lock_file(shared=True)
        self.assertEqual(f.read(), "")
        if (defs.RSFILE_IMPLEMENTATION == "windows"):
            f.write("bye")
            self.assertRaises(IOError, f.flush)
            # data in buffers blocks implicit flush...
            self.assertRaises(IOError, f.unlock_file)
            assert f._buffer._write_buf, f._buffer._write_buf
            del f._buffer._write_buf[:]  # else error on closing flush()
            f.flush()
        else:
            f.write("bye")
            f.flush()
        f.unlock_file()

        # no problem if we write OUTSIDE of the locked area though
        f.lock_file(length=1, offset=100, shared=True)
        f.seek(0)
        f.truncate()
        f.write("twist")
        f.flush()
        f.seek(0)
        data = f.read()
        self.assertEqual(data, "twist")
        f.unlock_file(length=1, offset=100)

        f.close()
Esempio n. 12
0
    def test_intra_process_locking(self):
        """
        We check the behaviour of locks when opening several times the same file from within a process.
        """

        # the locking type must be compatible with the opening mode (enforced by some OSes)
        with rsfile.rsopen(self.dummyFileName,
                           "RB",
                           buffering=0,
                           locking=False) as f:
            self.assertRaises(IOError, f.lock_file, shared=False)
        with rsfile.rsopen(self.dummyFileName,
                           "WB",
                           buffering=0,
                           locking=False) as f:
            self.assertRaises(IOError, f.lock_file, shared=True)

        # Locking from different open files
        with rsfile.rsopen(self.dummyFileName, "RB", buffering=0,
                           timeout=0) as _:
            with rsfile.rsopen(self.dummyFileName,
                               "RB",
                               buffering=0,
                               timeout=0) as _:
                pass  # OK - shared locking

            # Exclusively locking the same disk file twice from different open file objects should fail (or block...)
            self.assertRaises(rsfile.LockingException,
                              rsfile.rsopen,
                              self.dummyFileName,
                              "WB",
                              buffering=0,
                              timeout=0)

        with rsfile.rsopen(self.dummyFileName,
                           "RWB",
                           buffering=0,
                           locking=False) as f:
            assert f.tell() == 0

            f.lock_file(shared=True,
                        timeout=0,
                        length=1,
                        offset=100,
                        whence=os.SEEK_SET)
            f.lock_file(shared=False,
                        timeout=0,
                        length=1,
                        offset=200,
                        whence=os.SEEK_SET)

            assert f.tell() == 0

            f.lock_file(shared=True,
                        timeout=0,
                        length=1,
                        offset=0,
                        whence=os.SEEK_SET)
            f.lock_file(shared=False,
                        timeout=0,
                        length=1,
                        offset=1,
                        whence=os.SEEK_SET)
            f.lock_file(shared=True,
                        timeout=0,
                        length=3,
                        offset=2,
                        whence=os.SEEK_SET)

            assert f.tell() == 0

            f.seek(5)
            f.lock_file(shared=True,
                        timeout=0,
                        length=1,
                        offset=0,
                        whence=os.SEEK_CUR)  # works

            f.seek(0)
            assert f.tell() == 0

            # No double locking !

            self.assertRaises(RuntimeError,
                              f.lock_file,
                              shared=True,
                              timeout=None,
                              length=1,
                              offset=0,
                              whence=os.SEEK_CUR)
            self.assertRaises(RuntimeError,
                              f.lock_file,
                              shared=False,
                              timeout=None,
                              length=1,
                              offset=0,
                              whence=os.SEEK_CUR)

            self.assertRaises(RuntimeError,
                              f.lock_file,
                              shared=True,
                              timeout=0,
                              length=1,
                              offset=1,
                              whence=os.SEEK_SET)
            self.assertRaises(RuntimeError,
                              f.lock_file,
                              shared=False,
                              timeout=0,
                              length=1,
                              offset=1,
                              whence=os.SEEK_CUR)

            self.assertRaises(RuntimeError,
                              f.lock_file,
                              length=2,
                              offset=0,
                              whence=os.SEEK_CUR)  # no lock merging !
            self.assertRaises(RuntimeError,
                              f.lock_file,
                              length=1,
                              offset=3,
                              whence=os.SEEK_CUR)  # no lock splitting !

            f.seek(5)
            self.assertRaises(RuntimeError,
                              f.lock_file,
                              shared=True,
                              timeout=0,
                              length=1,
                              offset=0,
                              whence=os.SEEK_CUR)
            f.seek(0)

            assert f.wrapped_stream.__class__._inner_file_lock
            f.wrapped_stream._inner_file_lock = "<nasty_string>"
            # this properly
            self.assertRaises(TypeError,
                              f.lock_file,
                              length=1,
                              offset=355,
                              whence=os.SEEK_SET)
            del f.wrapped_stream._inner_file_lock
            # IntraProcessLockRegistry was well cleaned up when treating this TypeError:
            f.lock_file(shared=True,
                        timeout=0,
                        length=1,
                        offset=355,
                        whence=os.SEEK_SET)

            # Todo - we test locking on duplicated handles, with os.dup() or DuplicateHandle()... but that's very
            # corner-case actually...
            """                     
                if sys.platform == 'win32':
                    self.fail("Exclusively locking the same disk file twice from different open file objects didn't
                    fail on win32")
               if sys.platform != 'win32':
                    self.fail("Exclusively locking the same disk file twice from different open file objects
                    shouldn't fail on unix")
                """

        # has the FCNTL gotcha disappeared ?
        with rsfile.rsopen(self.dummyFileName,
                           "RWB",
                           buffering=0,
                           locking=True) as f:
            with rsfile.rsopen(self.dummyFileName,
                               "RWB",
                               buffering=0,
                               locking=False) as g:
                pass
            # we close the file -> in normal conditions, we'd lose all fcntl() locks

            target = _worker_process.lock_tester
            lockingKwargs = {'timeout': 0}
            kwargs = {
                'resultQueue': None,
                'targetFileName': self.dummyFileName,
                'multiprocessing_lock': None,
                'lockingKwargs': lockingKwargs,
                'pause': 0,
                'multiprocess': True,
                'res_by_exit_code': True
            }

            process = multiprocessing.Process(name="%s %s" %
                                              (target.__name__, "SEEK_SET"),
                                              target=target,
                                              kwargs=kwargs)
            process.daemon = True
            process.start()
            process.join()
            self.assertEqual(
                process.exitcode, 2,
                "Error, we lost all locks when closing a file descriptor - exitcode %s"
                % process.exitcode)
Esempio n. 13
0
    def testFileMethodForwarding(self):

        def test_new_methods(myfile, raw, char):
            myfile.sync()
            myfile.unique_id()
            times = myfile.times()
            assert times.access_time > 0
            assert times.modification_time > 0
            times_repr = repr(times)
            assert "FileTimes" in times_repr and "access" in times_repr and "modification" in times_repr
            myfile.size()

            myfile.mode
            myfile.name
            myfile.origin
            myfile.closefd

            myfile.write(char)
            self.assertEqual(raw.size(), 0)  # not yet flushed
            myfile.lock_file()
            self.assertEqual(raw.size(), 1)  # has been flushed
            myfile.write(char)
            self.assertEqual(raw.size(), 1)  # not yet flushed
            myfile.unlock_file()
            self.assertEqual(raw.size(), 2)  # has been flushed

            myfile.truncate(0)
            self.assertEqual(myfile.tell(), 2)  # file pointer is unmoved
            myfile.write(char)
            self.assertEqual(raw.size(), 0)  # not yet flushed
            myfile.lock_file()
            self.assertEqual(raw.size(), 3)  # has been flushed, extending file as well
            myfile.write(char)
            self.assertEqual(raw.size(), 3)  # not yet flushed
            myfile.unlock_file()
            self.assertEqual(raw.size(), 4)  # has been flushed

            myfile.seek(0)
            myfile.write(char * 10)
            myfile.seek(0)

            self.assertEqual(myfile.read(1), char)
            self.assertTrue(raw.tell() > 1)  # read ahead buffer full
            myfile.lock_file()

            self.assertEqual(raw.tell(), 1)  # read ahead buffer reset
            self.assertEqual(myfile.read(1), char)

            self.assertTrue(raw.tell() > 2)  # read ahead buffer full
            myfile.unlock_file()
            self.assertEqual(raw.tell(), 2)  # read ahead buffer reset

            myfile.seek(0)

            self.assertEqual(myfile.read(1), char)
            self.assertTrue(raw.tell() > 1)  # read ahead buffer full
            myfile.lock_file()
            self.assertEqual(raw.tell(), 1)  # read ahead buffer reset
            self.assertEqual(myfile.read(1), char)
            self.assertTrue(raw.tell() > 2)  # read ahead buffer full
            myfile.unlock_file()
            self.assertEqual(raw.tell(), 2)  # read ahead buffer reset

        with rsfile.rsopen(TESTFN, "RWEB", buffering=100, locking=False,
                           thread_safe=False) as myfile:  # RW buffered binary stream
            test_new_methods(myfile, myfile.raw, b"x")

        with rsfile.rsopen(TESTFN, "RWET", buffering=100, locking=False, thread_safe=False) as myfile:  # text stream
            test_new_methods(myfile, myfile.buffer.raw, "x")
Esempio n. 14
0
    def testFileSynchronization(self):

        # beware - randomization!
        buffering = random.choice([None, -1, 0, 100])
        synchronized = random.choice((True, False))

        combinations = [dict(metadata=True, full_flush=True),
                        dict(metadata=False, full_flush=True),
                        dict(metadata=True, full_flush=False),
                        dict(metadata=False, full_flush=False)]
        kwargs = dict(name=TESTFN,
                      mode="WB" + ("S" if synchronized else ""),
                      buffering=buffering)

        string = b"abcdefghijklmnopqrstuvwxyz" * 1014 * 1024

        # print("kwargs", kwargs)
        f = rsfile.rsopen(**kwargs)
        self.assertEqual(f._synchronized, synchronized)
        res = f.write(string)
        self.assertEqual(res, len(string))

        for kwargs in combinations:
            f.sync(**kwargs)

        f.close()

        top_level_breakage = random.choice((True, False))

        with rsfile.rsopen(TESTFN, "wt", thread_safe=False) as f:
            for kwargs in combinations:
                f.sync(**kwargs)

            def broken(*args, **kwargs):
                ABCD

            if top_level_breakage:
                f.flush = broken
            else:
                f.buffer.flush = broken

            try:
                # print("-------------->BEFORE", f.flush)
                for kwargs in combinations:
                    self.assertRaises(NameError, f.sync, **kwargs)  # sync implies flush!
            finally:
                if top_level_breakage:
                    del f.flush
                else:
                    del f.buffer.flush
            # print("-------------->AFTER", f.flush)
            pass

        if CHECK_SYNC_PERFS:

            # We have no easy way to check that the stream is REALLY in sync mode, except manually crashing the
            # computer... but we may check if perfs diff, at least

            with rsfile.rsopen(TESTFN, "wb", thread_safe=False) as f:

                N = 10

                # NO SYNC
                a = time.time()
                for i in range(N):
                    f.write(b"a")
                    f.flush()
                b = time.time()
                res1 = b - a

                # LIGHTEST SYNC
                a = time.time()
                for i in range(N):
                    f.write(b"b")
                    f.sync(metadata=False, full_flush=False)
                b = time.time()
                res2 = b - a

                assert res2 > 1.05 * res1, (res1, res2)  # it takes time to datasync()

                # HEAVIEST SYNC
                a = time.time()
                for i in range(N):
                    f.write(b"c")
                    # print("We issue full sync")
                    f.sync(metadata=True, full_flush=True)
                    # print("STOP")
                b = time.time()
                res3 = b - a

                if defs.RSFILE_IMPLEMENTATION == "windows":
                    assert res3 > 1.05 * res1, (res1, res3)  # same as datasync
                else:
                    assert res3 > 1.05 * res2, (res2, res3)  # full sync heavier than datasync, on linux/osx
    def testModeEquivalences(self):

        std_parser = rsfile.parse_standard_args
        adv_parser = rsfile.parse_advanced_args

        file_modes = complete_and_normalize_possible_modes(
            FILE_MODES_CORRELATION)

        stdlib_file_modes = set(file_modes.values()) - set([None])
        # pprint(stdlib_file_modes)

        # Combinations: 4 access modes, "+" or not, and ""/"b"/"t"
        assert len(stdlib_file_modes) == (4 if HAS_X_OPEN_FLAG else
                                          3) * 2 * 3, len(stdlib_file_modes)

        def gen_all_combinations(values):
            for L in range(0, len(values) + 1):
                for subset in itertools.combinations(values, L):
                    yield subset

        adv_flags = list("RAWCNEBT")  # remove deprecated and isolated flags
        for idx, subset in enumerate(gen_all_combinations(adv_flags)):

            selected_adv_flags = "".join(
                subset)  # the sames flags will come in various orders

            #print("-> Testing mode equivalences for", selected_adv_flags)

            _selected_adv_flags_normalized = "".join(
                sorted(selected_adv_flags))
            is_abnormal_mode = _selected_adv_flags_normalized not in file_modes
            selected_stdlib_flags = file_modes.get(
                _selected_adv_flags_normalized, None)
            del _selected_adv_flags_normalized

            if False:  # USEFUL LOGGING when debugging open modes
                print("==--> %r, %r" %
                      (selected_adv_flags, selected_stdlib_flags))

            if is_abnormal_mode:
                assert selected_stdlib_flags is None
                self.assertRaises(ValueError, rsfile.rsopen, TESTFN,
                                  selected_adv_flags)  # NOT an OSError
                continue

            try:
                with rsfile.rsopen(TESTFN, selected_adv_flags):
                    pass
            except EnvironmentError:  # it's certainly due to file existence constraints
                if selected_stdlib_flags:
                    # ALSO fails
                    self.assertRaises(EnvironmentError, rsfile.rsopen, TESTFN,
                                      selected_stdlib_flags)
            else:
                if selected_stdlib_flags:
                    # ALSO succeeds
                    with rsfile.rsopen(TESTFN, selected_stdlib_flags):
                        pass

            adv_res = adv_parser(TESTFN, selected_adv_flags, None, None, True)

            if selected_stdlib_flags:

                # we compare abilities on a THEORETICAL level between stdlib and advanced mode
                stdlib_res = std_parser(TESTFN, selected_stdlib_flags, None,
                                        None, True)

                msg = """
                        %s != %s :
                        %s
                        %s""" % (selected_stdlib_flags, selected_adv_flags,
                                 stdlib_res, adv_res)
                self.assertEqual(stdlib_res, adv_res, msg)

                chosen_flags = random.choice(
                    (selected_stdlib_flags, selected_adv_flags))

            else:

                chosen_flags = selected_adv_flags

            # we compare theoretical abilities with what the stream can ACTUALLY do
            theoretical_abilities = dict(
                read=adv_res[0]["read"],
                write=adv_res[0]["write"],
                append=adv_res[0]["append"],
                must_create=adv_res[0]["must_create"],
                must_not_create=adv_res[0]["must_not_create"],
                truncate=adv_res[1]["truncate"])

            real_abilities = self.determine_stream_capabilities(
                rsfile.rsopen, chosen_flags)

            msg = """
                THEORETICAL: %s
                REAL:         %s""" % (theoretical_abilities, real_abilities)
            self.assertEqual(theoretical_abilities, real_abilities, msg)

            if selected_stdlib_flags:
                legacy_abilities = self.determine_stream_capabilities(
                    io.open, selected_stdlib_flags)

                msg = """
                    THEORETICAL: %s
                    LEGACY:      %s""" % (theoretical_abilities,
                                          legacy_abilities)
                self.assertEqual(theoretical_abilities, legacy_abilities, msg)

            abilities_via_fileno = self.determine_stream_capabilities(
                reopener_via_fileno, chosen_flags)
            msg = """
                THEORETICAL:         %s
                REOPENED_VIA_FILENO: %s""" % (theoretical_abilities,
                                              abilities_via_fileno)
            self.assertEqual(theoretical_abilities, abilities_via_fileno, msg)
            '''
            # no need to test "handle" passing because handles are below-or-equal filenos in our current
            implementations,
            # plus it leads to "too many open files" on windows because filenos can't be released without closing the
            handle too (and blcksize forces fileno creation..)
            abilities_via_handle = self.determine_stream_capabilities(reopener_via_handle, chosen_flags)
            msg = """
                THEORETICAL :        %s
                REOPENED_VIA_HANDLE: %s""" % (theoretical_abilities, abilities_via_handle)
            self.assertEqual(theoretical_abilities, abilities_via_handle, msg)
            '''

        assert idx > 200, idx  # we've well browsed lots of combinations
Esempio n. 16
0
    def test_global_locking_options(self):

        old_options = rsfile.get_rsfile_options()

        try:

            rsfile.set_rsfile_options(enforced_locking_timeout_value=2,
                                      default_spinlock_delay=1)

            with rsfile.rsopen(self.dummyFileName,
                               "RWEB",
                               buffering=100,
                               locking=True) as myfile1:

                with rsfile.rsopen(self.dummyFileName,
                                   "RWEB",
                                   buffering=100,
                                   locking=False) as myfile2:
                    self.assertEqual(myfile2.enforced_locking_timeout_value, 2)
                    self.assertEqual(myfile2.default_spinlock_delay, 1)

                    # this would deadlock the application, if no enforced timeout...
                    self.assertRaises(rsfile.LockingException,
                                      myfile2.lock_file,
                                      timeout=1)

                    self.assertRaises(rsfile.LockingException,
                                      myfile2.lock_file,
                                      timeout=3)

                    self.assertRaises(
                        RuntimeError, myfile2.lock_file,
                        timeout=None)  # blocking mode -> global option applies

                    start = time.time()
                    self.assertRaises(rsfile.LockingException,
                                      myfile2.lock_file,
                                      timeout=0.3)
                    delay = time.time() - start
                    self.assertTrue(
                        0.7 < delay < 1.3, "Delay is %d" %
                        delay)  # we check that the 1 s spinlock works

            target = _worker_process.lock_tester

            lockingKwargs = {'timeout': 0}
            kwargs = {
                'resultQueue': None,
                'targetFileName': self.dummyFileName,
                'multiprocessing_lock': None,
                'lockingKwargs': lockingKwargs,
                'pause': 9,
                'multiprocess': True
            }

            process = multiprocessing.Process(name="%s %s" %
                                              (target.__name__, "SEEK_SET"),
                                              target=target,
                                              kwargs=kwargs)
            process.daemon = True
            process.start()

            time.sleep(4)  # let the child process start
            with rsfile.rsopen(self.dummyFileName,
                               "RWEB",
                               buffering=100,
                               locking=False) as myfile:
                self.assertRaises(rsfile.LockingException,
                                  myfile.lock_file,
                                  timeout=1)
                self.assertRaises(
                    RuntimeError, myfile.lock_file, timeout=None
                )  # global timeout due to interprocess locking conflict

            process.join()
            self.assertEqual(
                process.exitcode, 0,
                "Process '%s' encountered some trouble during execution" %
                process.name)

        finally:
            rsfile.set_rsfile_options(**old_options)
    def testModeEquivalences(self):

        std_parser = rsfile.parse_standard_args
        adv_parser = rsfile.parse_advanced_args

        file_modes = complete_and_normalize_possible_modes(FILE_MODES_CORRELATION)

        stdlib_file_modes = set(file_modes.values()) - set([None])
        # pprint(stdlib_file_modes)

        # Combinations: 4 access modes, "+" or not, and ""/"b"/"t"
        assert len(stdlib_file_modes) == (4 if HAS_X_OPEN_FLAG else 3) * 2 * 3, len(stdlib_file_modes)

        def gen_all_combinations(values):
            for L in range(0, len(values) + 1):
                for subset in itertools.combinations(values, L):
                    yield subset

        adv_flags = list("RAWCNEBT")  # remove deprecated and isolated flags
        for idx, subset in enumerate(gen_all_combinations(adv_flags)):

            selected_adv_flags = "".join(subset)  # the sames flags will come in various orders

            #print("-> Testing mode equivalences for", selected_adv_flags)

            _selected_adv_flags_normalized = "".join(sorted(selected_adv_flags))
            is_abnormal_mode = _selected_adv_flags_normalized not in file_modes
            selected_stdlib_flags = file_modes.get(_selected_adv_flags_normalized, None)
            del _selected_adv_flags_normalized

            if False:  # USEFUL LOGGING when debugging open modes
                print("==--> %r, %r" % (selected_adv_flags, selected_stdlib_flags))

            if is_abnormal_mode:
                assert selected_stdlib_flags is None
                self.assertRaises(ValueError, rsfile.rsopen, TESTFN, selected_adv_flags)  # NOT an OSError
                continue

            try:
                with rsfile.rsopen(TESTFN, selected_adv_flags):
                    pass
            except EnvironmentError:  # it's certainly due to file existence constraints
                if selected_stdlib_flags:
                    # ALSO fails
                    self.assertRaises(EnvironmentError, rsfile.rsopen, TESTFN, selected_stdlib_flags)
            else:
                if selected_stdlib_flags:
                    # ALSO succeeds
                    with rsfile.rsopen(TESTFN, selected_stdlib_flags):
                        pass

            adv_res = adv_parser(TESTFN, selected_adv_flags, None, None, True)

            if selected_stdlib_flags:

                # we compare abilities on a THEORETICAL level between stdlib and advanced mode
                stdlib_res = std_parser(TESTFN, selected_stdlib_flags, None, None, True)

                msg = """
                        %s != %s :
                        %s
                        %s""" % (selected_stdlib_flags, selected_adv_flags, stdlib_res, adv_res)
                self.assertEqual(stdlib_res, adv_res, msg)

                chosen_flags = random.choice((selected_stdlib_flags, selected_adv_flags))

            else:

                chosen_flags = selected_adv_flags

            # we compare theoretical abilities with what the stream can ACTUALLY do
            theoretical_abilities = dict(
                read=adv_res[0]["read"],
                write=adv_res[0]["write"],
                append=adv_res[0]["append"],
                must_create=adv_res[0]["must_create"],
                must_not_create=adv_res[0]["must_not_create"],
                truncate=adv_res[1]["truncate"]
            )

            real_abilities = self.determine_stream_capabilities(rsfile.rsopen, chosen_flags)

            msg = """
                THEORETICAL: %s
                REAL:         %s""" % (theoretical_abilities, real_abilities)
            self.assertEqual(theoretical_abilities, real_abilities, msg)

            if selected_stdlib_flags:
                legacy_abilities = self.determine_stream_capabilities(io.open, selected_stdlib_flags)

                msg = """
                    THEORETICAL: %s
                    LEGACY:      %s""" % (theoretical_abilities, legacy_abilities)
                self.assertEqual(theoretical_abilities, legacy_abilities, msg)

            abilities_via_fileno = self.determine_stream_capabilities(reopener_via_fileno, chosen_flags)
            msg = """
                THEORETICAL:         %s
                REOPENED_VIA_FILENO: %s""" % (theoretical_abilities, abilities_via_fileno)
            self.assertEqual(theoretical_abilities, abilities_via_fileno, msg)

            '''
            # no need to test "handle" passing because handles are below-or-equal filenos in our current
            implementations,
            # plus it leads to "too many open files" on windows because filenos can't be released without closing the
            handle too (and blcksize forces fileno creation..)
            abilities_via_handle = self.determine_stream_capabilities(reopener_via_handle, chosen_flags)
            msg = """
                THEORETICAL :        %s
                REOPENED_VIA_HANDLE: %s""" % (theoretical_abilities, abilities_via_handle)
            self.assertEqual(theoretical_abilities, abilities_via_handle, msg)
            '''

        assert idx > 200, idx  # we've well browsed lots of combinations