Skip to content

Commit de65a3e

Browse files
committed
Add live server test to suite.
Now the testsuite starts an instance of the roundup tracker. It then uses requests to verify the main page is acessible. At some point this will be extended to use selemium or splinter to drive more extensive end to end testing.
1 parent 019b56d commit de65a3e

File tree

4 files changed

+148
-1
lines changed

4 files changed

+148
-1
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ install:
9292
- if [[ $TRAVIS_PYTHON_VERSION == "3.4"* ]]; then pip install mysqlclient==1.3.14; fi
9393
- if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install mysqlclient; fi
9494
- pip install psycopg2
95-
- pip install gpg pytz whoosh pyjwt
95+
- pip install gpg pytz whoosh pyjwt requests
9696
- pip install pytest-cov codecov
9797
- if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install docutils; fi
9898
- if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install mistune; fi

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ Features:
126126
memorydb convenience functions and it may be useful in other tests. Make
127127
the prefix a paramter of the convenience functions to be usable in other
128128
tests.
129+
- pytest suite now starts the server under wsgi and loads the home
130+
page. This test is skipped if the requests module is not installed.
131+
129132

130133
2020-07-13 2.0.0
131134

test/test_liveserver.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import shutil, errno, pytest
2+
3+
from roundup.cgi.wsgi_handler import RequestDispatcher
4+
from .wsgi_liveserver import LiveServerTestCase
5+
from . import db_test_base
6+
7+
try:
8+
import requests
9+
skip_requests = lambda func, *args, **kwargs: func
10+
except ImportError:
11+
from .pytest_patcher import mark_class
12+
skip_requests = mark_class(pytest.mark.skip(
13+
reason='Skipping liveserver tests: requests library not available'))
14+
15+
@skip_requests
16+
class SimpleTest(LiveServerTestCase):
17+
port_range = (9001, 9010) # default is (8080, 8090)
18+
19+
dirname = '_test_instance'
20+
backend = 'anydbm'
21+
22+
@classmethod
23+
def setup_class(cls):
24+
'''All test in this class use the same roundup instance.
25+
This instance persists across all tests.
26+
Create the tracker dir here so that it is ready for the
27+
create_app() method to be called.
28+
'''
29+
# tests in this class.
30+
# set up and open a tracker
31+
cls.instance = db_test_base.setupTracker(cls.dirname, cls.backend)
32+
33+
# open the database
34+
cls.db = cls.instance.open('admin')
35+
36+
cls.db.commit()
37+
cls.db.close()
38+
39+
@classmethod
40+
def teardown_class(cls):
41+
'''Close the database and delete the tracker directory
42+
now that the app should be exiting.
43+
'''
44+
if cls.db:
45+
cls.db.close()
46+
try:
47+
shutil.rmtree(cls.dirname)
48+
except OSError as error:
49+
if error.errno not in (errno.ENOENT, errno.ESRCH): raise
50+
51+
def create_app(self):
52+
'''The wsgi app to start'''
53+
return RequestDispatcher(self.dirname)
54+
55+
def test_start_page(self):
56+
""" simple test that verifies that the server can serve a start page.
57+
"""
58+
f = requests.get(self.url_base())
59+
self.assertTrue(b'Roundup' in f.content)
60+
self.assertTrue(b'Creator' in f.content)

test/wsgi_liveserver.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
wsgi-liveserver provides a simple LiverServerTestCase class that can be used to
4+
help start a web server in the background to serve a WSGI compliant application
5+
for use with testing. Generally it will be used in conjuction with something
6+
like Selenium to perform a series of functional tests using a browser.
7+
8+
Licensed under the GNU GPL v3
9+
10+
Copyright (c) 2013 John Kristensen (unless explicitly stated otherwise).
11+
"""
12+
import threading
13+
import socket
14+
import unittest
15+
from wsgiref.simple_server import make_server, WSGIRequestHandler
16+
17+
__author__ = 'John Kristensen'
18+
__version__ = '0.3.1'
19+
__license__ = 'GPLv3'
20+
21+
22+
class QuietHandler(WSGIRequestHandler):
23+
def log_request(*args, **kwargs):
24+
pass
25+
26+
27+
class LiveServerTestCase(unittest.TestCase):
28+
29+
port_range = (8080, 8090)
30+
31+
def create_app(self):
32+
"""Create your wsgi app and return it."""
33+
raise NotImplementedError
34+
35+
def __call__(self, result=None):
36+
"""
37+
Do some custom setup stuff and then hand off to TestCase to do its
38+
thing.
39+
"""
40+
try:
41+
self._pre_setup()
42+
super(LiveServerTestCase, self).__call__(result)
43+
finally:
44+
self._post_teardown()
45+
46+
def url_base(self):
47+
"""Return the url of the test server."""
48+
return 'http://{0}:{1}'.format(self.host, self.port)
49+
50+
def _pre_setup(self):
51+
"""Setup and start the test server in the background."""
52+
self._server = None
53+
54+
self.host = 'localhost'
55+
self.port = self.port_range[0]
56+
self._thread = None
57+
58+
# Get the app
59+
self.app = self.create_app()
60+
61+
# Cycle through the port range to find a free port
62+
while self._server is None and self.port <= self.port_range[1]:
63+
try:
64+
self._server = make_server(self.host, self.port, self.app,
65+
handler_class=QuietHandler)
66+
except socket.error:
67+
self.port += 1
68+
69+
# No free port, raise an exception
70+
if self._server is None:
71+
raise socket.error('Ports {0}-{1} are all already in use'.format(
72+
*self.port_range))
73+
74+
# Start the test server in the background
75+
self._thread = threading.Thread(target=self._server.serve_forever)
76+
self._thread.start()
77+
78+
def _post_teardown(self):
79+
"""Stop the test server."""
80+
if self._thread is not None:
81+
self._server.shutdown()
82+
self._server.server_close()
83+
self._thread.join()
84+
del self._server

0 commit comments

Comments
 (0)