mirror of https://github.com/mitsuhiko/flask.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
5.2 KiB
204 lines
5.2 KiB
# -*- coding: utf-8 -*- |
|
""" |
|
tests.conftest |
|
~~~~~~~~~~~~~~ |
|
|
|
:copyright: © 2010 by the Pallets team. |
|
:license: BSD, see LICENSE for more details. |
|
""" |
|
|
|
import gc |
|
import os |
|
import pkgutil |
|
import sys |
|
import textwrap |
|
|
|
import pytest |
|
from _pytest import monkeypatch |
|
|
|
import flask |
|
from flask import Flask as _Flask |
|
|
|
|
|
@pytest.fixture(scope='session', autouse=True) |
|
def _standard_os_environ(): |
|
"""Set up ``os.environ`` at the start of the test session to have |
|
standard values. Returns a list of operations that is used by |
|
:func:`._reset_os_environ` after each test. |
|
""" |
|
mp = monkeypatch.MonkeyPatch() |
|
out = ( |
|
(os.environ, 'FLASK_APP', monkeypatch.notset), |
|
(os.environ, 'FLASK_ENV', monkeypatch.notset), |
|
(os.environ, 'FLASK_DEBUG', monkeypatch.notset), |
|
(os.environ, 'FLASK_RUN_FROM_CLI', monkeypatch.notset), |
|
(os.environ, 'WERKZEUG_RUN_MAIN', monkeypatch.notset), |
|
) |
|
|
|
for _, key, value in out: |
|
if value is monkeypatch.notset: |
|
mp.delenv(key, False) |
|
else: |
|
mp.setenv(key, value) |
|
|
|
yield out |
|
mp.undo() |
|
|
|
|
|
@pytest.fixture(autouse=True) |
|
def _reset_os_environ(monkeypatch, _standard_os_environ): |
|
"""Reset ``os.environ`` to the standard environ after each test, |
|
in case a test changed something without cleaning up. |
|
""" |
|
monkeypatch._setitem.extend(_standard_os_environ) |
|
|
|
|
|
class Flask(_Flask): |
|
testing = True |
|
secret_key = 'test key' |
|
|
|
|
|
@pytest.fixture |
|
def app(): |
|
yield Flask('flask_test', root_path=os.path.dirname(__file__)) |
|
|
|
|
|
@pytest.fixture |
|
def app_ctx(app): |
|
with app.app_context() as ctx: |
|
yield ctx |
|
|
|
|
|
@pytest.fixture |
|
def req_ctx(app): |
|
with app.test_request_context() as ctx: |
|
yield ctx |
|
|
|
|
|
@pytest.fixture |
|
def client(app): |
|
return app.test_client() |
|
|
|
|
|
@pytest.fixture |
|
def test_apps(monkeypatch): |
|
monkeypatch.syspath_prepend( |
|
os.path.abspath(os.path.join( |
|
os.path.dirname(__file__), 'test_apps')) |
|
) |
|
|
|
|
|
@pytest.fixture(autouse=True) |
|
def leak_detector(): |
|
yield |
|
|
|
# make sure we're not leaking a request context since we are |
|
# testing flask internally in debug mode in a few cases |
|
leaks = [] |
|
while flask._request_ctx_stack.top is not None: |
|
leaks.append(flask._request_ctx_stack.pop()) |
|
assert leaks == [] |
|
|
|
|
|
@pytest.fixture(params=(True, False)) |
|
def limit_loader(request, monkeypatch): |
|
"""Patch pkgutil.get_loader to give loader without get_filename or archive. |
|
|
|
This provides for tests where a system has custom loaders, e.g. Google App |
|
Engine's HardenedModulesHook, which have neither the `get_filename` method |
|
nor the `archive` attribute. |
|
|
|
This fixture will run the testcase twice, once with and once without the |
|
limitation/mock. |
|
""" |
|
if not request.param: |
|
return |
|
|
|
class LimitedLoader(object): |
|
def __init__(self, loader): |
|
self.loader = loader |
|
|
|
def __getattr__(self, name): |
|
if name in ('archive', 'get_filename'): |
|
msg = 'Mocking a loader which does not have `%s.`' % name |
|
raise AttributeError(msg) |
|
return getattr(self.loader, name) |
|
|
|
old_get_loader = pkgutil.get_loader |
|
|
|
def get_loader(*args, **kwargs): |
|
return LimitedLoader(old_get_loader(*args, **kwargs)) |
|
|
|
monkeypatch.setattr(pkgutil, 'get_loader', get_loader) |
|
|
|
|
|
@pytest.fixture |
|
def modules_tmpdir(tmpdir, monkeypatch): |
|
"""A tmpdir added to sys.path.""" |
|
rv = tmpdir.mkdir('modules_tmpdir') |
|
monkeypatch.syspath_prepend(str(rv)) |
|
return rv |
|
|
|
|
|
@pytest.fixture |
|
def modules_tmpdir_prefix(modules_tmpdir, monkeypatch): |
|
monkeypatch.setattr(sys, 'prefix', str(modules_tmpdir)) |
|
return modules_tmpdir |
|
|
|
|
|
@pytest.fixture |
|
def site_packages(modules_tmpdir, monkeypatch): |
|
"""Create a fake site-packages.""" |
|
rv = modules_tmpdir \ |
|
.mkdir('lib') \ |
|
.mkdir('python{x[0]}.{x[1]}'.format(x=sys.version_info)) \ |
|
.mkdir('site-packages') |
|
monkeypatch.syspath_prepend(str(rv)) |
|
return rv |
|
|
|
|
|
@pytest.fixture |
|
def install_egg(modules_tmpdir, monkeypatch): |
|
"""Generate egg from package name inside base and put the egg into |
|
sys.path.""" |
|
|
|
def inner(name, base=modules_tmpdir): |
|
if not isinstance(name, str): |
|
raise ValueError(name) |
|
base.join(name).ensure_dir() |
|
base.join(name).join('__init__.py').ensure() |
|
|
|
egg_setup = base.join('setup.py') |
|
egg_setup.write(textwrap.dedent(""" |
|
from setuptools import setup |
|
setup(name='{0}', |
|
version='1.0', |
|
packages=['site_egg'], |
|
zip_safe=True) |
|
""".format(name))) |
|
|
|
import subprocess |
|
subprocess.check_call( |
|
[sys.executable, 'setup.py', 'bdist_egg'], |
|
cwd=str(modules_tmpdir) |
|
) |
|
egg_path, = modules_tmpdir.join('dist/').listdir() |
|
monkeypatch.syspath_prepend(str(egg_path)) |
|
return egg_path |
|
|
|
return inner |
|
|
|
|
|
@pytest.fixture |
|
def purge_module(request): |
|
def inner(name): |
|
request.addfinalizer(lambda: sys.modules.pop(name, None)) |
|
|
|
return inner |
|
|
|
|
|
@pytest.fixture(autouse=True) |
|
def catch_deprecation_warnings(recwarn): |
|
yield |
|
gc.collect() |
|
assert not recwarn.list, '\n'.join(str(w.message) for w in recwarn.list)
|
|
|