mirror of
https://github.com/frappe/gunicorn.git
synced 2026-01-14 11:09:11 +08:00
Added unit tests for new Config code.
This commit is contained in:
parent
f738d82bb7
commit
6ffbe54734
65
examples/pylonstest/nose.ini
Normal file
65
examples/pylonstest/nose.ini
Normal file
@ -0,0 +1,65 @@
|
||||
#
|
||||
# pylonstest - Pylons testing environment configuration
|
||||
#
|
||||
# The %(here)s variable will be replaced with the parent directory of this file
|
||||
#
|
||||
[DEFAULT]
|
||||
debug = false
|
||||
# Uncomment and replace with the address which should receive any error reports
|
||||
#email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[server:main]
|
||||
use = egg:gunicorn#main
|
||||
host = 192.168.0.1
|
||||
port = 80
|
||||
workers = 2
|
||||
proc_name = brim
|
||||
ignore_this = True
|
||||
|
||||
[app:main]
|
||||
use = egg:pylonstest
|
||||
full_stack = true
|
||||
static_files = true
|
||||
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = pylonstest
|
||||
beaker.session.secret = somesecret
|
||||
|
||||
# Add additional test specific configuration options as necessary.
|
||||
# Logging configuration
|
||||
[loggers]
|
||||
keys = root, routes, pylonstest
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[logger_routes]
|
||||
level = INFO
|
||||
handlers =
|
||||
qualname = routes.middleware
|
||||
# "level = DEBUG" logs the route matched and routing variables.
|
||||
|
||||
[logger_pylonstest]
|
||||
level = DEBUG
|
||||
handlers =
|
||||
qualname = pylonstest
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
|
||||
datefmt = %H:%M:%S
|
||||
|
||||
@ -33,7 +33,13 @@ class Application(object):
|
||||
|
||||
# Load up the config file if its found.
|
||||
if opts.config and os.path.exists(opts.config):
|
||||
cfg = globals().copy()
|
||||
cfg = {
|
||||
"__builtins__": __builtins__,
|
||||
"__name__": "__config__",
|
||||
"__file__": opts.config,
|
||||
"__doc__": None,
|
||||
"__package__": None
|
||||
}
|
||||
try:
|
||||
execfile(opts.config, cfg, cfg)
|
||||
except Exception, e:
|
||||
@ -42,6 +48,9 @@ class Application(object):
|
||||
sys.exit(1)
|
||||
|
||||
for k, v in list(cfg.items()):
|
||||
# Ignore unknown names
|
||||
if k not in self.cfg.settings:
|
||||
continue
|
||||
self.cfg.set(k.lower(), v)
|
||||
|
||||
# Lastly, update the configuration with any command line
|
||||
|
||||
@ -47,7 +47,12 @@ class PasterApplication(Application):
|
||||
cfg['workers'] = int(lc.get('workers', 1))
|
||||
cfg['umask'] = int(lc.get('umask', 0))
|
||||
cfg['default_proc_name'] = gc.get('__file__')
|
||||
cfg.update(dict((k,v) for (k,v) in lc.items() if k not in cfg))
|
||||
|
||||
for k, v in lc.items():
|
||||
if k not in self.cfg.settings:
|
||||
continue
|
||||
cfg[k] = v
|
||||
|
||||
return cfg
|
||||
|
||||
def load(self):
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
from __future__ import with_statement
|
||||
|
||||
import ConfigParser
|
||||
import copy
|
||||
import grp
|
||||
import inspect
|
||||
import optparse
|
||||
@ -23,7 +23,7 @@ KNOWN_SETTINGS = []
|
||||
class Config(object):
|
||||
|
||||
def __init__(self, usage=None):
|
||||
self.settings = dict((s.name, s) for s in KNOWN_SETTINGS)
|
||||
self.settings = dict((s.name, s.copy()) for s in KNOWN_SETTINGS)
|
||||
self.usage = usage
|
||||
|
||||
def __getattr__(self, name):
|
||||
@ -78,7 +78,6 @@ class Config(object):
|
||||
@property
|
||||
def uid(self):
|
||||
user = self.settings['user'].get()
|
||||
|
||||
if not user:
|
||||
return os.geteuid()
|
||||
elif user.isdigit() or isinstance(user, int):
|
||||
@ -89,7 +88,6 @@ class Config(object):
|
||||
@property
|
||||
def gid(self):
|
||||
group = self.settings['group'].get()
|
||||
|
||||
if not group:
|
||||
return os.getegid()
|
||||
elif group.isdigit() or isinstance(user, int):
|
||||
@ -105,18 +103,6 @@ class Config(object):
|
||||
else:
|
||||
return self.settings['default_proc_name']
|
||||
|
||||
@property
|
||||
def pre_fork(self):
|
||||
return self.settings['pre_fork'].get()
|
||||
|
||||
@property
|
||||
def post_fork(self):
|
||||
return self.settings['post_fork'].get()
|
||||
|
||||
@property
|
||||
def pre_exec(self):
|
||||
return self.settings['pre_exec'].get()
|
||||
|
||||
class Setting(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@ -162,6 +148,9 @@ class Setting(object):
|
||||
kwargs.pop("type")
|
||||
parser.add_option(*args, **kwargs)
|
||||
|
||||
def copy(self):
|
||||
return copy.copy(self)
|
||||
|
||||
def get(self):
|
||||
return self.value
|
||||
|
||||
@ -172,6 +161,8 @@ class Setting(object):
|
||||
def validate_bool(val):
|
||||
if isinstance(val, types.BooleanType):
|
||||
return val
|
||||
if not isinstance(val, basestring):
|
||||
raise TypeError("Invalid type for casting: %s" % val)
|
||||
if val.lower().strip() == "true":
|
||||
return True
|
||||
elif val.lower().strip() == "false":
|
||||
@ -182,11 +173,17 @@ def validate_bool(val):
|
||||
def validate_pos_int(val):
|
||||
if not isinstance(val, (types.IntType, types.LongType)):
|
||||
val = int(val, 0)
|
||||
else:
|
||||
# Booleans are ints!
|
||||
val = int(val)
|
||||
print "Setting: %s" % val
|
||||
if val < 0:
|
||||
raise ValueError("Value must be positive: %s" % val)
|
||||
return val
|
||||
|
||||
def validate_string(val):
|
||||
if not isinstance(val, basestring):
|
||||
raise TypeError("Not a string: %s" % val)
|
||||
return val.strip()
|
||||
|
||||
def validate_callable(arity):
|
||||
@ -203,7 +200,7 @@ with Setting("config") as s:
|
||||
s.cli = ["-c", "--config"]
|
||||
s.meta = "FILE"
|
||||
s.validator = validate_string
|
||||
s.default = "gunicorn.conf.py"
|
||||
s.default = None
|
||||
s.fmt_desc("""\
|
||||
The path to a Gunicorn config file.
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ class TeeInput(object):
|
||||
elif self._len and self._len < util.MAX_BODY:
|
||||
self.tmp = StringIO()
|
||||
else:
|
||||
self.tmp = tempfile.TemporaryFile(dir=self.cfg['tmp_upload_dir'])
|
||||
self.tmp = tempfile.TemporaryFile(dir=self.cfg.tmp_upload_dir)
|
||||
|
||||
if len(buf.getvalue()) > 0:
|
||||
chunk, self.buf = parser.filter_body(buf)
|
||||
|
||||
@ -167,7 +167,7 @@ def test_010(buf, p):
|
||||
body = ""
|
||||
while not p.body_eof():
|
||||
chunk, buf2 = p.filter_body(buf2)
|
||||
print chunk
|
||||
#print chunk
|
||||
if chunk:
|
||||
body += chunk
|
||||
t.eq(body, "all your base are belong to us")
|
||||
|
||||
186
tests/003-test-config.py
Normal file
186
tests/003-test-config.py
Normal file
@ -0,0 +1,186 @@
|
||||
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
import t
|
||||
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
|
||||
from gunicorn import config
|
||||
from gunicorn.app.base import Application
|
||||
from gunicorn.workers.sync import SyncWorker
|
||||
|
||||
dirname = os.path.dirname(__file__)
|
||||
def cfg_file():
|
||||
return os.path.join(dirname, "config", "test_cfg.py")
|
||||
def paster_ini():
|
||||
return os.path.join(dirname, "..", "examples", "pylonstest", "nose.ini")
|
||||
|
||||
def PasterApp():
|
||||
try:
|
||||
from paste.deploy import loadapp, loadwsgi
|
||||
except ImportError:
|
||||
raise SkipTest()
|
||||
from gunicorn.app.pasterapp import PasterApplication
|
||||
return PasterApplication("no_usage")
|
||||
|
||||
class AltArgs(object):
|
||||
def __init__(self, args=None):
|
||||
self.args = args or []
|
||||
self.orig = sys.argv
|
||||
|
||||
def __enter__(self):
|
||||
sys.argv = self.args
|
||||
|
||||
def __exit__(self, exc_type, exc_inst, traceback):
|
||||
sys.argv = self.orig
|
||||
|
||||
class NoConfigApp(Application):
|
||||
def __init__(self):
|
||||
super(NoConfigApp, self).__init__("no_usage")
|
||||
|
||||
def init(self, parser, opts, args):
|
||||
pass
|
||||
|
||||
def load(self):
|
||||
pass
|
||||
|
||||
|
||||
def test_defaults():
|
||||
c = config.Config()
|
||||
for s in config.KNOWN_SETTINGS:
|
||||
t.eq(s.default, c.settings[s.name].get())
|
||||
|
||||
def test_property_access():
|
||||
c = config.Config()
|
||||
for s in config.KNOWN_SETTINGS:
|
||||
getattr(c, s.name)
|
||||
|
||||
# Class was loaded
|
||||
t.eq(c.worker_class, SyncWorker)
|
||||
|
||||
# Debug affects workers
|
||||
t.eq(c.workers, 1)
|
||||
c.set("workers", 3)
|
||||
t.eq(c.workers, 3)
|
||||
c.set("debug", True)
|
||||
t.eq(c.workers, 1)
|
||||
|
||||
# Address is parsed
|
||||
t.eq(c.address, ("127.0.0.1", 8000))
|
||||
|
||||
# User and group defaults
|
||||
t.eq(os.geteuid(), c.uid)
|
||||
t.eq(os.getegid(), c.gid)
|
||||
|
||||
# Proc name
|
||||
t.eq("gunicorn", c.proc_name)
|
||||
|
||||
# Not a config property
|
||||
t.raises(AttributeError, getattr, c, "foo")
|
||||
# Force to be not an error
|
||||
class Baz(object):
|
||||
def get(self):
|
||||
return 3.14
|
||||
c.settings["foo"] = Baz()
|
||||
t.eq(c.foo, 3.14)
|
||||
|
||||
# Attempt to set a cfg not via c.set
|
||||
t.raises(AttributeError, setattr, c, "proc_name", "baz")
|
||||
|
||||
# No setting for name
|
||||
t.raises(AttributeError, c.set, "baz", "bar")
|
||||
|
||||
def test_bool_validation():
|
||||
c = config.Config()
|
||||
t.eq(c.debug, False)
|
||||
c.set("debug", True)
|
||||
t.eq(c.debug, True)
|
||||
c.set("debug", "true")
|
||||
t.eq(c.debug, True)
|
||||
c.set("debug", "false")
|
||||
t.eq(c.debug, False)
|
||||
t.raises(ValueError, c.set, "debug", "zilch")
|
||||
t.raises(TypeError, c.set, "debug", 4)
|
||||
|
||||
def test_pos_int_validation():
|
||||
c = config.Config()
|
||||
t.eq(c.workers, 1)
|
||||
c.set("workers", 4)
|
||||
t.eq(c.workers, 4)
|
||||
c.set("workers", "5")
|
||||
t.eq(c.workers, 5)
|
||||
c.set("workers", "0xFF")
|
||||
t.eq(c.workers, 255)
|
||||
c.set("workers", True)
|
||||
t.eq(c.workers, 1) # Yes. That's right...
|
||||
t.raises(ValueError, c.set, "workers", -21)
|
||||
t.raises(TypeError, c.set, "workers", c)
|
||||
|
||||
def test_str_validation():
|
||||
c = config.Config()
|
||||
t.eq(c.proc_name, "gunicorn")
|
||||
c.set("proc_name", " foo ")
|
||||
t.eq(c.proc_name, "foo")
|
||||
t.raises(TypeError, c.set, "proc_name", 2)
|
||||
|
||||
def test_callable_validation():
|
||||
c = config.Config()
|
||||
def func(a, b):
|
||||
pass
|
||||
c.set("pre_fork", func)
|
||||
t.eq(c.pre_fork, func)
|
||||
t.raises(TypeError, c.set, "pre_fork", 1)
|
||||
t.raises(TypeError, c.set, "pre_fork", lambda x: True)
|
||||
|
||||
def test_cmd_line():
|
||||
with AltArgs(["prog_name", "-b", "blargh"]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.bind, "blargh")
|
||||
with AltArgs(["prog_name", "-w", "3"]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.workers, 3)
|
||||
with AltArgs(["prog_name", "-d"]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.debug, True)
|
||||
|
||||
def test_app_config():
|
||||
with AltArgs():
|
||||
app = NoConfigApp()
|
||||
for s in config.KNOWN_SETTINGS:
|
||||
t.eq(s.default, app.cfg.settings[s.name].get())
|
||||
|
||||
def test_load_config():
|
||||
with AltArgs(["prog_name", "-c", cfg_file()]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.bind, "unix:/tmp/bar/baz")
|
||||
t.eq(app.cfg.workers, 3)
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
|
||||
def test_cli_overrides_config():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), "-b", "blarney"]):
|
||||
app = NoConfigApp()
|
||||
t.eq(app.cfg.bind, "blarney")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
|
||||
def test_paster_config():
|
||||
with AltArgs(["prog_name", paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "192.168.0.1:80")
|
||||
t.eq(app.cfg.proc_name, "brim")
|
||||
t.eq("ignore_me" in app.cfg.settings, False)
|
||||
|
||||
def test_cfg_over_paster():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "unix:/tmp/bar/baz")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
t.eq(app.cfg.default_proc_name, "blurgh")
|
||||
|
||||
def test_cli_cfg_paster():
|
||||
with AltArgs(["prog_name", "-c", cfg_file(), "-b", "whee", paster_ini()]):
|
||||
app = PasterApp()
|
||||
t.eq(app.cfg.bind, "whee")
|
||||
t.eq(app.cfg.proc_name, "fooey")
|
||||
t.eq(app.cfg.default_proc_name, "blurgh")
|
||||
4
tests/config/test_cfg.py
Normal file
4
tests/config/test_cfg.py
Normal file
@ -0,0 +1,4 @@
|
||||
bind = "unix:/tmp/bar/baz"
|
||||
workers = 3
|
||||
proc_name = "fooey"
|
||||
default_proc_name = "blurgh"
|
||||
@ -75,7 +75,7 @@ class http_request(object):
|
||||
def __call__(self, func):
|
||||
def run():
|
||||
fsock = FakeSocket(data_source(self.fname))
|
||||
req = Request(fsock, ('127.0.0.1', 6000), ('127.0.0.1', 8000), Config({}))
|
||||
req = Request(Config(), fsock, ('127.0.0.1', 6000), ('127.0.0.1', 8000))
|
||||
func(req)
|
||||
run.func_name = func.func_name
|
||||
return run
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user