%PDF- %PDF-
| Direktori : /lib/calibre/calibre/utils/ |
| Current File : //lib/calibre/calibre/utils/test_lock.py |
#!/usr/bin/env python3
# License: GPLv3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
import os
import shutil
import subprocess
import sys
import tempfile
import time
import unittest
from threading import Thread
from calibre.constants import cache_dir, iswindows
from calibre.utils.lock import ExclusiveFile, create_single_instance_mutex, unix_open
from calibre.utils.tdir_in_cache import (
clean_tdirs_in, is_tdir_locked, retry_lock_tdir, tdir_in_cache, tdirs_in,
unlock_file
)
from polyglot.builtins import iteritems, native_string_type
def FastFailEF(name):
return ExclusiveFile(name, sleep_time=0.01, timeout=0.05)
class Other(Thread):
daemon = True
locked = None
def run(self):
try:
with FastFailEF('testsp'):
self.locked = True
except OSError:
self.locked = False
def run_worker(mod, func, **kw):
try:
exe = [sys.executable, os.path.join(sys.setup_dir, 'run-calibre-worker.py')]
except AttributeError:
exe = [
os.path.join(
os.path.dirname(os.path.abspath(sys.executable)),
'calibre-parallel' + ('.exe' if iswindows else '')
)
]
env = kw.get('env', os.environ.copy())
env['CALIBRE_SIMPLE_WORKER'] = mod + ':' + func
if iswindows:
kw['creationflags'] = subprocess.CREATE_NO_WINDOW
kw['env'] = {native_string_type(k): native_string_type(v)
for k, v in iteritems(env)} # windows needs bytes in env
return subprocess.Popen(exe, **kw)
class IPCLockTest(unittest.TestCase):
def setUp(self):
self.cwd = os.getcwd()
self.tdir = tempfile.mkdtemp()
os.chdir(self.tdir)
self.original_cache_dir = cache_dir()
cache_dir.ans = self.tdir
def tearDown(self):
cache_dir.ans = self.original_cache_dir
os.chdir(self.cwd)
for i in range(100):
try:
shutil.rmtree(self.tdir)
break
except OSError:
time.sleep(0.1)
def test_exclusive_file_same_process(self):
fname = 'testsp'
with ExclusiveFile(fname):
ef = FastFailEF(fname)
self.assertRaises(EnvironmentError, ef.__enter__)
t = Other()
t.start(), t.join()
self.assertIs(t.locked, False)
if not iswindows:
import fcntl
with unix_open(fname) as f:
self.assertEqual(
1, fcntl.fcntl(f.fileno(), fcntl.F_GETFD) & fcntl.FD_CLOEXEC
)
def run_other_ef_op(self, clean_exit):
child = run_worker('calibre.utils.test_lock', 'other1')
try:
while child.poll() is None:
if os.path.exists('ready'):
break
time.sleep(0.01)
self.assertIsNone(child.poll(), 'child died without creating ready dir')
ef = FastFailEF('test')
self.assertRaises(EnvironmentError, ef.__enter__)
if clean_exit:
os.mkdir('quit')
else:
child.kill()
self.assertIsNotNone(child.wait())
with ExclusiveFile('test', timeout=3):
pass
finally:
if child.poll() is None:
child.kill()
def test_exclusive_file_other_process_clean(self):
self.run_other_ef_op(True)
def test_exclusive_file_other_process_kill(self):
self.run_other_ef_op(False)
def test_single_instance(self):
release_mutex = create_single_instance_mutex('test')
for i in range(5):
child = run_worker('calibre.utils.test_lock', 'other2')
self.assertEqual(child.wait(), 0)
release_mutex()
for i in range(5):
child = run_worker('calibre.utils.test_lock', 'other2')
self.assertEqual(child.wait(), 1)
child = run_worker('calibre.utils.test_lock', 'other3')
while not os.path.exists('ready'):
time.sleep(0.01)
child.kill()
child.wait()
release_mutex = create_single_instance_mutex('test')
self.assertIsNotNone(release_mutex)
release_mutex()
def test_tdir_in_cache_dir(self):
child = run_worker('calibre.utils.test_lock', 'other4')
tdirs = []
while not tdirs:
time.sleep(0.05)
gl = retry_lock_tdir('t', sleep=0.05)
try:
tdirs = list(tdirs_in('t'))
finally:
unlock_file(gl)
self.assertTrue(is_tdir_locked(tdirs[0]))
c2 = run_worker('calibre.utils.test_lock', 'other5')
self.assertEqual(c2.wait(), 0)
self.assertTrue(is_tdir_locked(tdirs[0]))
child.kill(), child.wait()
self.assertTrue(os.path.exists(tdirs[0]))
self.assertFalse(is_tdir_locked(tdirs[0]))
clean_tdirs_in('t')
self.assertFalse(os.path.exists(tdirs[0]))
self.assertEqual(os.listdir('t'), ['tdir-lock'])
def other1():
e = ExclusiveFile('test')
with e:
os.mkdir('ready')
while not os.path.exists('quit'):
time.sleep(0.02)
def other2():
release_mutex = create_single_instance_mutex('test')
if release_mutex is None:
ret = 0
else:
ret = 1
release_mutex()
raise SystemExit(ret)
def other3():
release_mutex = create_single_instance_mutex('test')
try:
os.mkdir('ready')
time.sleep(30)
finally:
if release_mutex is not None:
release_mutex()
def other4():
cache_dir.ans = os.getcwd()
tdir_in_cache('t')
time.sleep(30)
def other5():
cache_dir.ans = os.getcwd()
if not os.path.isdir(tdir_in_cache('t')):
raise SystemExit(1)
def find_tests():
return unittest.defaultTestLoader.loadTestsFromTestCase(IPCLockTest)
def run_tests():
from calibre.utils.run_tests import run_tests
run_tests(find_tests)
if __name__ == '__main__':
run_tests()