Skip to content

Commit

Permalink
Create TestWSGI class for testing mod_genshi apps.
Browse files Browse the repository at this point in the history
The TestWSGI class sub classes from unittest.TestCase. Each sub class
will have a new mod_genshi application created for testing.
  • Loading branch information
Aaron Iles committed May 30, 2012
1 parent b0de482 commit 0c58625
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 66 deletions.
97 changes: 97 additions & 0 deletions mod_genshi/wsgitest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
try:
import unittest2 as unittest
except ImportError:
import unittest

import string

import webob

import mod_genshi.wsgi

__all__ = ['TestWSGI']


class TestWSGIType(type):
"""Base type for TestWSGI
To allow sub classes to define a setUpClass method, this type meta class
will rename the setUpClass method on sub classes to a unique name that
is called by the setUpClass method of TestWSGI.
"""

@staticmethod
def unused_name(suffix, names):
"""Create new, unique name with a given suffix."""
for letter in string.letters:
name = "_{0}_{1}".format(letter, suffix)
if name not in names:
break
return name

@classmethod
def rename_method(meta, method, classdict):
"""Rename class method to new, unique name with same suffix."""
if method in classdict:
function = classdict[method]
name = meta.unused_name(method, set(classdict.keys()))
del classdict[method]
classdict[name] = function

def __new__(meta, classname, bases, classdict):
if classname != 'TestWSGI':
meta.rename_method('setUpClass', classdict)
meta.rename_method('tearDownClass', classdict)
return type.__new__(meta, classname, bases, classdict)


class TestWSGI(unittest.TestCase):
"""Subclass of unittest.TestCase for WSGI application testing.
This class also provides the following methods.
- get_request(url), create a new WSGI request object for URL.
- get_response(request), generate the application response for request.
Each sub class of this class will have an APPLICATION attribute. This is a
new mod_genshi WSGI application. The base directory of the application
will default to the current directory. This can be over ridden by creating
a new BASE class attribute.
Sub classes may define a setUpClass and tearDownClass.
"""

__metaclass__ = TestWSGIType

@classmethod
def _call_suffixes(cls, suffix):
for name in dir(cls):
if not name.endswith(suffix) or name == suffix:
continue
attr = getattr(cls, name)
if not hasattr(attr, '__call__'):
continue
attr()

@classmethod
def setUpClass(cls):
"""Create a new mod_genshi WSGI application."""
if not hasattr(cls, 'BASE'):
cls.BASE = '.'
cls.APPLICATION = mod_genshi.wsgi.WSGI(cls.BASE)
cls._call_suffixes('setUpClass')

@classmethod
def tearDownClass(cls):
"""Shutdown the mod_genshi WSGI application."""
if hasattr(cls, 'APPLICATION'):
del cls.APPLICATION
cls._call_suffixes('tearDownClass')

def get_request(self, url):
"""Create a new WSGI request object from the given URL."""
return webob.Request.blank(url)

def get_response(self, request):
"""Generate a WSGI response for the given request."""
return request.get_response(self.APPLICATION)
62 changes: 26 additions & 36 deletions tests/test_requests.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,71 @@
import os
import sys

import unittest2
import mod_genshi.wsgitest

from webob import Request
import mod_genshi.wsgi

class TestRequests(mod_genshi.wsgitest.TestWSGI):

class TestRequests(unittest2.TestCase):

@classmethod
def setUpClass(cls):
cls.App = mod_genshi.wsgi.WSGI('tests/app')

@classmethod
def tearDownClass(cls):
if hasattr(cls, 'App'):
del cls.App
BASE = 'tests/app'

def test_hello_world_html(self):
path = 'templates/hello_world.html'
with open(os.path.join(self.App.config.base, path), 'rt') as template:
with open(os.path.join(self.BASE, path), 'rt') as template:
content = template.read()
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 200)
self.assertEqual(response.content_type, 'text/html')
self.assertEqual(response.body, content)

def test_hello_world_text(self):
path = 'templates/hello_world.txt'
with open(os.path.join(self.App.config.base, path), 'rt') as template:
with open(os.path.join(self.BASE, path), 'rt') as template:
content = template.read()
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 200)
self.assertEqual(response.content_type, 'text/plain')
self.assertEqual(response.body, content)

def test_static_file(self):
path = 'static/logo.png'
with open(os.path.join(self.App.config.base, path), 'rb') as template:
with open(os.path.join(self.BASE, path), 'rb') as template:
content = template.read()
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 200)
self.assertEqual(response.content_type, 'image/png')
self.assertEqual(response.body, content)

def test_forbidden(self):
path = 'static/passwd'
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 403)

def test_not_found_generic(self):
path = 'static/_does_not_exist_'
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 403)

def test_not_found_template(self):
path = 'templates/_does_not_exist_.html'
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 404)

def test_not_found_static(self):
path = 'static/_does_not_exist_.png'
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 404)

def test_server_error(self):
path = 'templates/invalid.html'
request = Request.blank(path)
response = request.get_response(self.App)
request = self.get_request(path)
response = self.get_response(request)
self.assertEqual(response.status_int, 500)

def test_reload_python(self):
Expand All @@ -88,12 +78,12 @@ def set_counter():
# initialise
set_counter()
# request one
request = Request.blank(path)
request.get_response(self.App)
request = self.get_request(path)
self.get_response(request)
self.assertEqual(sys.modules['python.counter'].value, 2)
# initiate reload
os.utime(code, None)
# request two
request = Request.blank(path)
request.get_response(self.App)
request = self.get_request(path)
self.get_response(request)
self.assertEqual(sys.modules['python.counter'].value, 1)
12 changes: 5 additions & 7 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@

class TestBrowserCommnd(unittest2.TestCase):

@classmethod
def setUpClass(cls):
cls.url = "http://{0}:8000".format(socket.gethostname())
URL = "http://{0}:8000".format(socket.gethostname())

def test_nothing(self):
opts = parse_command_line([])
Expand All @@ -18,23 +16,23 @@ def test_nothing(self):
def test_current_window(self):
opts = parse_command_line(['-b'])
cmd = open_browser_cmd(opts)
self.assertEqual(cmd.args, (self.url,))
self.assertEqual(cmd.args, (self.URL,))
self.assertEqual(cmd.keywords, {'new': 0, 'autoraise': False})

def test_raise_current_window(self):
opts = parse_command_line(['-b', '-r'])
cmd = open_browser_cmd(opts)
self.assertEqual(cmd.args, (self.url,))
self.assertEqual(cmd.args, (self.URL,))
self.assertEqual(cmd.keywords, {'new': 0, 'autoraise': True})

def test_new_window(self):
opts = parse_command_line(['-w'])
cmd = open_browser_cmd(opts)
self.assertEqual(cmd.args, (self.url,))
self.assertEqual(cmd.args, (self.URL,))
self.assertEqual(cmd.keywords, {'new': 1, 'autoraise': False})

def test_new_tab(self):
opts = parse_command_line(['-t', '-r'])
cmd = open_browser_cmd(opts)
self.assertEqual(cmd.args, (self.url,))
self.assertEqual(cmd.args, (self.URL,))
self.assertEqual(cmd.keywords, {'new': 2, 'autoraise': True})
41 changes: 18 additions & 23 deletions tests/test_wsgi.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,34 @@
import os
import sys

import unittest2

import mod_genshi.wsgi
import mod_genshi.wsgitest


class ModGenshiApp(mod_genshi.wsgitest.TestWSGI):

class ModGenshiApp(object):
BASE = 'tests/app'

Markup = mod_genshi.wsgi.MarkupTemplate
Text = mod_genshi.wsgi.NewTextTemplate
HTTPForbidden = mod_genshi.wsgi.HTTPForbidden

@classmethod
def setUpClass(cls):
cls.App = mod_genshi.wsgi.WSGI('tests/app')
cls.body = cls.App._body
cls.cwd = cls.App.config.templatedir
cls.get_path = cls.App._get_basic_path
cls.get_style = cls.App._get_template_style
cls.is_blocked = cls.App._is_path_blocked
cls.is_static = cls.App._is_static_path_blocked
cls.set_headers = cls.App._headers

@classmethod
def tearDownClass(cls):
if hasattr(cls, 'App'):
del cls.App
cls.body = cls.APPLICATION._body
cls.cwd = cls.APPLICATION.config.templatedir
cls.get_path = cls.APPLICATION._get_basic_path
cls.get_style = cls.APPLICATION._get_template_style
cls.is_blocked = cls.APPLICATION._is_path_blocked
cls.is_static = cls.APPLICATION._is_static_path_blocked
cls.set_headers = cls.APPLICATION._headers

def setUp(self):
self.request = mod_genshi.wsgi.Request({})
self.response = mod_genshi.wsgi.Response()


class TestTemplatePath(ModGenshiApp, unittest2.TestCase):
class TestTemplatePath(ModGenshiApp):

def test_empty_path(self):
self.assertEqual(self.get_path(''), 'index.html')
Expand All @@ -54,7 +49,7 @@ def test_trailing_slash(self):
self.assertEqual(self.get_path('a/'), 'a/index.html')


class TestStyle(ModGenshiApp, unittest2.TestCase):
class TestStyle(ModGenshiApp):

def test_htm(self):
self.assertIs(self.get_style('file.htm'), self.Markup)
Expand All @@ -81,7 +76,7 @@ def test_unknown(self):
self.assertIs(self.get_style('file.xxx'), None)


class TestSecurity(ModGenshiApp, unittest2.TestCase):
class TestSecurity(ModGenshiApp):

def test_index(self):
path = 'index.html'
Expand Down Expand Up @@ -116,7 +111,7 @@ def test_static_file(self):
self.assertRaises(self.HTTPForbidden, self.is_static, path)


class TestHeaders(ModGenshiApp, unittest2.TestCase):
class TestHeaders(ModGenshiApp):

def test_default(self):
self.set_headers('', self.response)
Expand All @@ -143,17 +138,17 @@ def test_gz(self):
self.assertEqual(self.response.status_code, 200)


class TestBody(ModGenshiApp, unittest2.TestCase):
class TestBody(ModGenshiApp):

def test_hello_world_txt(self):
path = 'templates/hello_world.txt'
content = open(os.path.join(self.App.config.base, path), 'rt').read()
content = open(os.path.join(self.BASE, path), 'rt').read()
self.body(path, self.Text, self.request, self.response)
self.assertEqual(self.response.body, content)

def test_hello_world_html(self):
path = 'templates/hello_world.html'
content = open(os.path.join(self.App.config.base, path), 'rt').read()
content = open(os.path.join(self.BASE, path), 'rt').read()
self.body(path, self.Markup, self.request, self.response)
self.assertEqual(self.response.body, content)

Expand Down

0 comments on commit 0c58625

Please sign in to comment.