testing/mozbase/mozhttpd/tests/api.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/testing/mozbase/mozhttpd/tests/api.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,265 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +# This Source Code Form is subject to the terms of the Mozilla Public
     1.7 +# License, v. 2.0. If a copy of the MPL was not distributed with this file,
     1.8 +# You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 +
    1.10 +import mozhttpd
    1.11 +import urllib2
    1.12 +import os
    1.13 +import unittest
    1.14 +import re
    1.15 +import json
    1.16 +import tempfile
    1.17 +
    1.18 +here = os.path.dirname(os.path.abspath(__file__))
    1.19 +
    1.20 +class ApiTest(unittest.TestCase):
    1.21 +    resource_get_called = 0
    1.22 +    resource_post_called = 0
    1.23 +    resource_del_called = 0
    1.24 +
    1.25 +    @mozhttpd.handlers.json_response
    1.26 +    def resource_get(self, request, objid):
    1.27 +        self.resource_get_called += 1
    1.28 +        return (200, { 'called': self.resource_get_called,
    1.29 +                       'id': objid,
    1.30 +                       'query': request.query })
    1.31 +
    1.32 +    @mozhttpd.handlers.json_response
    1.33 +    def resource_post(self, request):
    1.34 +        self.resource_post_called += 1
    1.35 +        return (201, { 'called': self.resource_post_called,
    1.36 +                       'data': json.loads(request.body),
    1.37 +                       'query': request.query })
    1.38 +
    1.39 +    @mozhttpd.handlers.json_response
    1.40 +    def resource_del(self, request, objid):
    1.41 +        self.resource_del_called += 1
    1.42 +        return (200, { 'called': self.resource_del_called,
    1.43 +                       'id': objid,
    1.44 +                       'query': request.query })
    1.45 +
    1.46 +    def get_url(self, path, server_port, querystr):
    1.47 +        url = "http://127.0.0.1:%s%s" % (server_port, path)
    1.48 +        if querystr:
    1.49 +            url += "?%s" % querystr
    1.50 +        return url
    1.51 +
    1.52 +    def try_get(self, server_port, querystr):
    1.53 +        self.resource_get_called = 0
    1.54 +
    1.55 +        f = urllib2.urlopen(self.get_url('/api/resource/1', server_port, querystr))
    1.56 +        try:
    1.57 +            self.assertEqual(f.getcode(), 200)
    1.58 +        except AttributeError:
    1.59 +            pass  # python 2.4
    1.60 +        self.assertEqual(json.loads(f.read()), { 'called': 1, 'id': str(1), 'query': querystr })
    1.61 +        self.assertEqual(self.resource_get_called, 1)
    1.62 +
    1.63 +    def try_post(self, server_port, querystr):
    1.64 +        self.resource_post_called = 0
    1.65 +
    1.66 +        postdata = { 'hamburgers': '1234' }
    1.67 +        try:
    1.68 +            f = urllib2.urlopen(self.get_url('/api/resource/', server_port, querystr),
    1.69 +                                data=json.dumps(postdata))
    1.70 +        except urllib2.HTTPError, e:
    1.71 +            # python 2.4
    1.72 +            self.assertEqual(e.code, 201)
    1.73 +            body = e.fp.read()
    1.74 +        else:
    1.75 +            self.assertEqual(f.getcode(), 201)
    1.76 +            body = f.read()
    1.77 +        self.assertEqual(json.loads(body), { 'called': 1,
    1.78 +                                             'data': postdata,
    1.79 +                                             'query': querystr })
    1.80 +        self.assertEqual(self.resource_post_called, 1)
    1.81 +
    1.82 +    def try_del(self, server_port, querystr):
    1.83 +        self.resource_del_called = 0
    1.84 +
    1.85 +        opener = urllib2.build_opener(urllib2.HTTPHandler)
    1.86 +        request = urllib2.Request(self.get_url('/api/resource/1', server_port, querystr))
    1.87 +        request.get_method = lambda: 'DEL'
    1.88 +        f = opener.open(request)
    1.89 +
    1.90 +        try:
    1.91 +            self.assertEqual(f.getcode(), 200)
    1.92 +        except AttributeError:
    1.93 +            pass  # python 2.4
    1.94 +        self.assertEqual(json.loads(f.read()), { 'called': 1, 'id': str(1), 'query': querystr })
    1.95 +        self.assertEqual(self.resource_del_called, 1)
    1.96 +
    1.97 +    def test_api(self):
    1.98 +        httpd = mozhttpd.MozHttpd(port=0,
    1.99 +                                  urlhandlers = [ { 'method': 'GET',
   1.100 +                                                    'path': '/api/resource/([^/]+)/?',
   1.101 +                                                    'function': self.resource_get },
   1.102 +                                                  { 'method': 'POST',
   1.103 +                                                    'path': '/api/resource/?',
   1.104 +                                                    'function': self.resource_post },
   1.105 +                                                  { 'method': 'DEL',
   1.106 +                                                    'path': '/api/resource/([^/]+)/?',
   1.107 +                                                    'function': self.resource_del }
   1.108 +                                                  ])
   1.109 +        httpd.start(block=False)
   1.110 +
   1.111 +        server_port = httpd.httpd.server_port
   1.112 +
   1.113 +        # GET
   1.114 +        self.try_get(server_port, '')
   1.115 +        self.try_get(server_port, '?foo=bar')
   1.116 +
   1.117 +        # POST
   1.118 +        self.try_post(server_port, '')
   1.119 +        self.try_post(server_port, '?foo=bar')
   1.120 +
   1.121 +        # DEL
   1.122 +        self.try_del(server_port, '')
   1.123 +        self.try_del(server_port, '?foo=bar')
   1.124 +
   1.125 +        # GET: By default we don't serve any files if we just define an API
   1.126 +        f = None
   1.127 +        exception_thrown = False
   1.128 +        try:
   1.129 +            f = urllib2.urlopen(self.get_url('/', server_port, None))
   1.130 +        except urllib2.HTTPError, e:
   1.131 +            self.assertEqual(e.code, 404)
   1.132 +            exception_thrown = True
   1.133 +        self.assertTrue(exception_thrown)
   1.134 +
   1.135 +    def test_nonexistent_resources(self):
   1.136 +        # Create a server with a placeholder handler so we don't fall back
   1.137 +        # to serving local files
   1.138 +        httpd = mozhttpd.MozHttpd(port=0)
   1.139 +        httpd.start(block=False)
   1.140 +        server_port = httpd.httpd.server_port
   1.141 +
   1.142 +        # GET: Return 404 for non-existent endpoint
   1.143 +        f = None
   1.144 +        exception_thrown = False
   1.145 +        try:
   1.146 +            f = urllib2.urlopen(self.get_url('/api/resource/', server_port, None))
   1.147 +        except urllib2.HTTPError, e:
   1.148 +            self.assertEqual(e.code, 404)
   1.149 +            exception_thrown = True
   1.150 +        self.assertTrue(exception_thrown)
   1.151 +
   1.152 +        # POST: POST should also return 404
   1.153 +        f = None
   1.154 +        exception_thrown = False
   1.155 +        try:
   1.156 +            f = urllib2.urlopen(self.get_url('/api/resource/', server_port, None),
   1.157 +                            data=json.dumps({}))
   1.158 +        except urllib2.HTTPError, e:
   1.159 +            self.assertEqual(e.code, 404)
   1.160 +            exception_thrown = True
   1.161 +        self.assertTrue(exception_thrown)
   1.162 +
   1.163 +        # DEL: DEL should also return 404
   1.164 +        f = None
   1.165 +        exception_thrown = False
   1.166 +        try:
   1.167 +            opener = urllib2.build_opener(urllib2.HTTPHandler)
   1.168 +            request = urllib2.Request(self.get_url('/api/resource/', server_port,
   1.169 +                                                   None))
   1.170 +            request.get_method = lambda: 'DEL'
   1.171 +            f = opener.open(request)
   1.172 +        except urllib2.HTTPError, e:
   1.173 +            self.assertEqual(e.code, 404)
   1.174 +            exception_thrown = True
   1.175 +        self.assertTrue(exception_thrown)
   1.176 +
   1.177 +    def test_api_with_docroot(self):
   1.178 +        httpd = mozhttpd.MozHttpd(port=0, docroot=here,
   1.179 +                                  urlhandlers = [ { 'method': 'GET',
   1.180 +                                                    'path': '/api/resource/([^/]+)/?',
   1.181 +                                                    'function': self.resource_get } ])
   1.182 +        httpd.start(block=False)
   1.183 +        server_port = httpd.httpd.server_port
   1.184 +
   1.185 +        # We defined a docroot, so we expect a directory listing
   1.186 +        f = urllib2.urlopen(self.get_url('/', server_port, None))
   1.187 +        try:
   1.188 +            self.assertEqual(f.getcode(), 200)
   1.189 +        except AttributeError:
   1.190 +            pass  # python 2.4
   1.191 +        self.assertTrue('Directory listing for' in f.read())
   1.192 +
   1.193 +        # Make sure API methods still work
   1.194 +        self.try_get(server_port, '')
   1.195 +        self.try_get(server_port, '?foo=bar')
   1.196 +
   1.197 +class ProxyTest(unittest.TestCase):
   1.198 +
   1.199 +    def tearDown(self):
   1.200 +        # reset proxy opener in case it changed
   1.201 +        urllib2.install_opener(None)
   1.202 +
   1.203 +    def test_proxy(self):
   1.204 +        docroot = tempfile.mkdtemp()
   1.205 +        hosts = ('mozilla.com', 'mozilla.org')
   1.206 +        unproxied_host = 'notmozilla.org'
   1.207 +        def url(host): return 'http://%s/' % host
   1.208 +
   1.209 +        index_filename = 'index.html'
   1.210 +        def index_contents(host): return '%s index' % host
   1.211 +
   1.212 +        index = file(os.path.join(docroot, index_filename), 'w')
   1.213 +        index.write(index_contents('*'))
   1.214 +        index.close()
   1.215 +
   1.216 +        httpd = mozhttpd.MozHttpd(port=0, docroot=docroot)
   1.217 +        httpd.start(block=False)
   1.218 +        server_port = httpd.httpd.server_port
   1.219 +
   1.220 +        proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
   1.221 +                                              server_port})
   1.222 +        urllib2.install_opener(urllib2.build_opener(proxy_support))
   1.223 +
   1.224 +        for host in hosts:
   1.225 +            f = urllib2.urlopen(url(host))
   1.226 +            try:
   1.227 +                self.assertEqual(f.getcode(), 200)
   1.228 +            except AttributeError:
   1.229 +                pass  # python 2.4
   1.230 +            self.assertEqual(f.read(), index_contents('*'))
   1.231 +
   1.232 +        httpd.stop()
   1.233 +
   1.234 +        # test separate directories per host
   1.235 +
   1.236 +        httpd = mozhttpd.MozHttpd(port=0, docroot=docroot, proxy_host_dirs=True)
   1.237 +        httpd.start(block=False)
   1.238 +        server_port = httpd.httpd.server_port
   1.239 +
   1.240 +        proxy_support = urllib2.ProxyHandler({'http': 'http://127.0.0.1:%d' %
   1.241 +                                              server_port})
   1.242 +        urllib2.install_opener(urllib2.build_opener(proxy_support))
   1.243 +
   1.244 +        # set up dirs
   1.245 +        for host in hosts:
   1.246 +            os.mkdir(os.path.join(docroot, host))
   1.247 +            file(os.path.join(docroot, host, index_filename), 'w') \
   1.248 +                .write(index_contents(host))
   1.249 +
   1.250 +        for host in hosts:
   1.251 +            f = urllib2.urlopen(url(host))
   1.252 +            try:
   1.253 +                self.assertEqual(f.getcode(), 200)
   1.254 +            except AttributeError:
   1.255 +                pass  # python 2.4
   1.256 +            self.assertEqual(f.read(), index_contents(host))
   1.257 +
   1.258 +        exc = None
   1.259 +        try:
   1.260 +            urllib2.urlopen(url(unproxied_host))
   1.261 +        except urllib2.HTTPError, e:
   1.262 +            exc = e
   1.263 +        self.assertNotEqual(exc, None)
   1.264 +        self.assertEqual(exc.code, 404)
   1.265 +
   1.266 +
   1.267 +if __name__ == '__main__':
   1.268 +    unittest.main()

mercurial