%PDF- %PDF-
| Direktori : /lib/calibre/calibre/srv/tests/ |
| Current File : //lib/calibre/calibre/srv/tests/base.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import unittest, time, shutil, gc, tempfile, atexit, os
from io import BytesIO
from functools import partial
from threading import Thread
from calibre.srv.utils import ServerLog
from polyglot import http_client
rmtree = partial(shutil.rmtree, ignore_errors=True)
class SimpleTest(unittest.TestCase):
longMessage = True
maxDiff = None
ae = unittest.TestCase.assertEqual
class BaseTest(SimpleTest):
def run(self, result=None):
# we retry failing server tests since they are flaky on CI
if result is None:
result = self.defaultTestResult()
max_retries = 1
for i in range(max_retries + 1):
failures_before = len(result.failures)
errors_before = len(result.errors)
super().run(result=result)
if len(result.failures) == failures_before and len(result.errors) == errors_before:
return
print(f'Retrying test {self._testMethodName} after failure/error')
q = result.failures if len(result.failures) > failures_before else result.errors
q.pop(-1)
time.sleep(1)
class LibraryBaseTest(BaseTest):
def setUp(self):
from calibre.utils.recycle_bin import nuke_recycle
nuke_recycle()
self.library_path = self.mkdtemp()
self.create_db(self.library_path)
def tearDown(self):
from calibre.utils.recycle_bin import restore_recyle
restore_recyle()
gc.collect(), gc.collect()
try:
shutil.rmtree(self.library_path)
except OSError:
# Try again in case something transient has a file lock on windows
gc.collect(), gc.collect()
time.sleep(2)
shutil.rmtree(self.library_path)
def mkdtemp(self):
ans = tempfile.mkdtemp(prefix='db_test_')
atexit.register(rmtree, ans)
return ans
def create_db(self, library_path):
from calibre.db.legacy import create_backend
from calibre.db.cache import Cache
d = os.path.dirname
src = os.path.join(d(d(d(os.path.abspath(__file__)))), 'db', 'tests', 'metadata.db')
dest = os.path.join(library_path, 'metadata.db')
shutil.copy2(src, dest)
db = Cache(create_backend(library_path))
db.init()
db.set_cover({1:I('lt.png', data=True), 2:I('polish.png', data=True)})
db.add_format(1, 'FMT1', BytesIO(b'book1fmt1'), run_hooks=False)
db.add_format(1, 'EPUB', open(P('quick_start/eng.epub'), 'rb'), run_hooks=False)
db.add_format(1, 'FMT2', BytesIO(b'book1fmt2'), run_hooks=False)
db.add_format(2, 'FMT1', BytesIO(b'book2fmt1'), run_hooks=False)
db.backend.conn.close()
return dest
def create_server(self, *args, **kwargs):
args = (self.library_path ,) + args
return LibraryServer(*args, **kwargs)
class TestServer(Thread):
daemon = True
def __init__(self, handler, plugins=(), **kwargs):
Thread.__init__(self, name='ServerMain')
from calibre.srv.opts import Options
from calibre.srv.loop import ServerLoop
from calibre.srv.http_response import create_http_handler
self.setup_defaults(kwargs)
self.loop = ServerLoop(
create_http_handler(handler),
opts=Options(**kwargs),
plugins=plugins,
log=ServerLog(level=ServerLog.DEBUG),
)
self.log = self.loop.log
def setup_defaults(self, kwargs):
kwargs['shutdown_timeout'] = kwargs.get('shutdown_timeout', 10)
kwargs['listen_on'] = kwargs.get('listen_on', 'localhost')
kwargs['port'] = kwargs.get('port', 0)
kwargs['userdb'] = kwargs.get('userdb', ':memory:')
def run(self):
try:
self.loop.serve_forever()
except KeyboardInterrupt:
pass
def __enter__(self):
self.start()
while not self.loop.ready and self.is_alive():
time.sleep(0.01)
self.address = self.loop.bound_address[:2]
return self
def __exit__(self, *args):
try:
self.loop.stop()
except Exception as e:
self.log.error('Failed to stop server with error:', e)
self.join(self.loop.opts.shutdown_timeout)
self.loop.close_control_connection()
def connect(self, timeout=None, interface=None):
if timeout is None:
timeout = self.loop.opts.timeout
if interface is None:
interface = self.address[0]
ans = http_client.HTTPConnection(interface, self.address[1], timeout=timeout)
ans.connect()
return ans
def change_handler(self, handler):
from calibre.srv.http_response import create_http_handler
self.loop.handler = create_http_handler(handler)
class LibraryServer(TestServer):
def __init__(self, library_path, libraries=(), plugins=(), **kwargs):
Thread.__init__(self, name='ServerMain')
from calibre.srv.opts import Options
from calibre.srv.loop import ServerLoop
from calibre.srv.handler import Handler
from calibre.srv.http_response import create_http_handler
self.setup_defaults(kwargs)
opts = Options(**kwargs)
self.libraries = libraries or (library_path,)
self.handler = Handler(self.libraries, opts, testing=True)
self.loop = ServerLoop(
create_http_handler(self.handler.dispatch),
opts=opts,
plugins=plugins,
log=ServerLog(level=ServerLog.DEBUG),
)
self.log = self.loop.log
self.handler.set_log(self.log)
def __exit__(self, *args):
try:
self.loop.stop()
except Exception as e:
self.log.error('Failed to stop server with error:', e)
self.handler.close()
self.join(self.loop.opts.shutdown_timeout)
self.loop.close_control_connection()