blob: 43448df64d31ef6096e02a713d07c22446f305ca [file] [log] [blame]
#!/usr/bin/env python
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import mozfile
import mozhttpd
import urllib2
import os
import unittest
import json
import tempfile
here = os.path.dirname(os.path.abspath(__file__))
class ApiTest(unittest.TestCase):
resource_get_called = 0
resource_post_called = 0
resource_del_called = 0
@mozhttpd.handlers.json_response
def resource_get(self, request, objid):
self.resource_get_called += 1
return (200, { 'called': self.resource_get_called,
'id': objid,
'query': request.query })
@mozhttpd.handlers.json_response
def resource_post(self, request):
self.resource_post_called += 1
return (201, { 'called': self.resource_post_called,
'data': json.loads(request.body),
'query': request.query })
@mozhttpd.handlers.json_response
def resource_del(self, request, objid):
self.resource_del_called += 1
return (200, { 'called': self.resource_del_called,
'id': objid,
'query': request.query })
def get_url(self, path, server_port, querystr):
url = "http://127.0.0.1:%s%s" % (server_port, path)
if querystr:
url += "?%s" % querystr
return url
def try_get(self, server_port, querystr):
self.resource_get_called = 0
f = urllib2.urlopen(self.get_url('/api/resource/1', server_port, querystr))
try:
self.assertEqual(f.getcode(), 200)
except AttributeError:
pass # python 2.4
self.assertEqual(json.loads(f.read()), { 'called': 1, 'id': str(1), 'query': querystr })
self.assertEqual(self.resource_get_called, 1)
def try_post(self, server_port, querystr):
self.resource_post_called = 0
postdata = { 'hamburgers': '1234' }
try:
f = urllib2.urlopen(self.get_url('/api/resource/', server_port, querystr),
data=json.dumps(postdata))
except urllib2.HTTPError, e:
# python 2.4
self.assertEqual(e.code, 201)
body = e.fp.read()
else:
self.assertEqual(f.getcode(), 201)
body = f.read()
self.assertEqual(json.loads(body), { 'called': 1,
'data': postdata,
'query': querystr })
self.assertEqual(self.resource_post_called, 1)
def try_del(self, server_port, querystr):
self.resource_del_called = 0
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(self.get_url('/api/resource/1', server_port, querystr))
request.get_method = lambda: 'DEL'
f = opener.open(request)
try:
self.assertEqual(f.getcode(), 200)
except AttributeError:
pass # python 2.4
self.assertEqual(json.loads(f.read()), { 'called': 1, 'id': str(1), 'query': querystr })
self.assertEqual(self.resource_del_called, 1)
def test_api(self):
httpd = mozhttpd.MozHttpd(port=0,
urlhandlers = [ { 'method': 'GET',
'path': '/api/resource/([^/]+)/?',
'function': self.resource_get },
{ 'method': 'POST',
'path': '/api/resource/?',
'function': self.resource_post },
{ 'method': 'DEL',
'path': '/api/resource/([^/]+)/?',
'function': self.resource_del }
])
httpd.start(block=False)
server_port = httpd.httpd.server_port
# GET
self.try_get(server_port, '')
self.try_get(server_port, '?foo=bar')
# POST
self.try_post(server_port, '')
self.try_post(server_port, '?foo=bar')
# DEL
self.try_del(server_port, '')
self.try_del(server_port, '?foo=bar')
# GET: By default we don't serve any files if we just define an API
exception_thrown = False
try:
urllib2.urlopen(self.get_url('/', server_port, None))
except urllib2.HTTPError, e:
self.assertEqual(e.code, 404)
exception_thrown = True
self.assertTrue(exception_thrown)
def test_nonexistent_resources(self):
# Create a server with a placeholder handler so we don't fall back
# to serving local files
httpd = mozhttpd.MozHttpd(port=0)
httpd.start(block=False)
server_port = httpd.httpd.server_port
# GET: Return 404 for non-existent endpoint
exception_thrown = False
try:
urllib2.urlopen(self.get_url('/api/resource/', server_port, None))
except urllib2.HTTPError, e:
self.assertEqual(e.code, 404)
exception_thrown = True
self.assertTrue(exception_thrown)
# POST: POST should also return 404
exception_thrown = False
try:
urllib2.urlopen(self.get_url('/api/resource/', server_port, None),
data=json.dumps({}))
except urllib2.HTTPError, e:
self.assertEqual(e.code, 404)
exception_thrown = True
self.assertTrue(exception_thrown)
# DEL: DEL should also return 404
exception_thrown = False
try:
opener = urllib2.build_opener(urllib2.HTTPHandler)
request = urllib2.Request(self.get_url('/api/resource/', server_port,
None))
request.get_method = lambda: 'DEL'
opener.open(request)
except urllib2.HTTPError:
self.assertEqual(e.code, 404)
exception_thrown = True
self.assertTrue(exception_thrown)
def test_api_with_docroot(self):
httpd = mozhttpd.MozHttpd(port=0, docroot=here,
urlhandlers = [ { 'method': 'GET',
'path': '/api/resource/([^/]+)/?',
'function': self.resource_get } ])
httpd.start(block=False)
server_port = httpd.httpd.server_port
# We defined a docroot, so we expect a directory listing
f = urllib2.urlopen(self.get_url('/', server_port, None))
try:
self.assertEqual(f.getcode(), 200)
except AttributeError:
pass # python 2.4
self.assertTrue('Directory listing for' in f.read())
# Make sure API methods still work
self.try_get(server_port, '')
self.try_get(server_port, '?foo=bar')
class ProxyTest(unittest.TestCase):
def tearDown(self):
# reset proxy opener in case it changed
urllib2.install_opener(None)
def test_proxy(self):
docroot = tempfile.mkdtemp()
self.addCleanup(mozfile.remove, docroot)
hosts = ('mozilla.com', 'mozilla.org')
unproxied_host = 'notmozilla.org'
def url(host): return 'http://%s/' % host
index_filename = 'index.html'
def index_contents(host): return '%s index' % host
index = file(os.path.join(docroot, index_filename), 'w')
index.write(index_contents('*'))
index.close()
httpd = mozhttpd.MozHttpd(port=0, docroot=docroot)
httpd.start(block=False)
server_port = httpd.httpd.server_port
proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
server_port})
urllib2.install_opener(urllib2.build_opener(proxy_support))
for host in hosts:
f = urllib2.urlopen(url(host))
try:
self.assertEqual(f.getcode(), 200)
except AttributeError:
pass # python 2.4
self.assertEqual(f.read(), index_contents('*'))
httpd.stop()
# test separate directories per host
httpd = mozhttpd.MozHttpd(port=0, docroot=docroot, proxy_host_dirs=True)
httpd.start(block=False)
server_port = httpd.httpd.server_port
proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
server_port})
urllib2.install_opener(urllib2.build_opener(proxy_support))
# set up dirs
for host in hosts:
os.mkdir(os.path.join(docroot, host))
file(os.path.join(docroot, host, index_filename), 'w') \
.write(index_contents(host))
for host in hosts:
f = urllib2.urlopen(url(host))
try:
self.assertEqual(f.getcode(), 200)
except AttributeError:
pass # python 2.4
self.assertEqual(f.read(), index_contents(host))
exc = None
try:
urllib2.urlopen(url(unproxied_host))
except urllib2.HTTPError, e:
exc = e
self.assertNotEqual(exc, None)
self.assertEqual(exc.code, 404)
if __name__ == '__main__':
unittest.main()