PageRenderTime 82ms CodeModel.GetById 67ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/lib/python/indra/ipc/siesta_test.py

https://bitbucket.org/lindenlab/viewer-beta/
Python | 235 lines | 205 code | 9 blank | 21 comment | 1 complexity | d32ae4c94f2f78f207bc1d3b4aceabdd MD5 | raw file
  1#!/usr/bin/python
  2## $LicenseInfo:firstyear=2011&license=viewerlgpl$
  3## Second Life Viewer Source Code
  4## Copyright (C) 2011, Linden Research, Inc.
  5## 
  6## This library is free software; you can redistribute it and/or
  7## modify it under the terms of the GNU Lesser General Public
  8## License as published by the Free Software Foundation;
  9## version 2.1 of the License only.
 10## 
 11## This library is distributed in the hope that it will be useful,
 12## but WITHOUT ANY WARRANTY; without even the implied warranty of
 13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14## Lesser General Public License for more details.
 15## 
 16## You should have received a copy of the GNU Lesser General Public
 17## License along with this library; if not, write to the Free Software
 18## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 19## 
 20## Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 21## $/LicenseInfo$
 22from indra.base import llsd, lluuid
 23from indra.ipc import siesta
 24import datetime, math, unittest
 25from webob import exc
 26
 27
 28class ClassApp(object):
 29    def handle_get(self, req):
 30        pass
 31
 32    def handle_post(self, req):
 33        return req.llsd
 34    
 35
 36def callable_app(req):
 37    if req.method == 'UNDERPANTS':
 38        raise exc.HTTPMethodNotAllowed()
 39    elif req.method == 'GET':
 40        return None
 41    return req.llsd
 42
 43
 44class TestBase:
 45    def test_basic_get(self):
 46        req = siesta.Request.blank('/')
 47        self.assertEquals(req.get_response(self.server).body,
 48                          llsd.format_xml(None))
 49        
 50    def test_bad_method(self):
 51        req = siesta.Request.blank('/')
 52        req.environ['REQUEST_METHOD'] = 'UNDERPANTS'
 53        self.assertEquals(req.get_response(self.server).status_int,
 54                          exc.HTTPMethodNotAllowed.code)
 55        
 56    json_safe = {
 57        'none': None,
 58        'bool_true': True,
 59        'bool_false': False,
 60        'int_zero': 0,
 61        'int_max': 2147483647,
 62        'int_min': -2147483648,
 63        'long_zero': 0,
 64        'long_max': 2147483647L,
 65        'long_min': -2147483648L,
 66        'float_zero': 0,
 67        'float': math.pi,
 68        'float_huge': 3.14159265358979323846e299,
 69        'str_empty': '',
 70        'str': 'foo',
 71        u'unic\u1e51de_empty': u'',
 72        u'unic\u1e51de': u'\u1e4exx\u10480',
 73        }
 74    json_safe['array'] = json_safe.values()
 75    json_safe['tuple'] = tuple(json_safe.values())
 76    json_safe['dict'] = json_safe.copy()
 77
 78    json_unsafe = {
 79        'uuid_empty': lluuid.UUID(),
 80        'uuid_full': lluuid.UUID('dc61ab0530200d7554d23510559102c1a98aab1b'),
 81        'binary_empty': llsd.binary(),
 82        'binary': llsd.binary('f\0\xff'),
 83        'uri_empty': llsd.uri(),
 84        'uri': llsd.uri('http://www.secondlife.com/'),
 85        'datetime_empty': datetime.datetime(1970,1,1),
 86        'datetime': datetime.datetime(1999,9,9,9,9,9),
 87        }
 88    json_unsafe.update(json_safe)
 89    json_unsafe['array'] = json_unsafe.values()
 90    json_unsafe['tuple'] = tuple(json_unsafe.values())
 91    json_unsafe['dict'] = json_unsafe.copy()
 92    json_unsafe['iter'] = iter(json_unsafe.values())
 93
 94    def _test_client_content_type_good(self, content_type, ll):
 95        def run(ll):
 96            req = siesta.Request.blank('/')
 97            req.environ['REQUEST_METHOD'] = 'POST'
 98            req.content_type = content_type
 99            req.llsd = ll
100            req.accept = content_type
101            resp = req.get_response(self.server)
102            self.assertEquals(resp.status_int, 200)
103            return req, resp
104        
105        if False and isinstance(ll, dict):
106            def fixup(v):
107                if isinstance(v, float):
108                    return '%.5f' % v
109                if isinstance(v, long):
110                    return int(v)
111                if isinstance(v, (llsd.binary, llsd.uri)):
112                    return v
113                if isinstance(v, (tuple, list)):
114                    return [fixup(i) for i in v]
115                if isinstance(v, dict):
116                    return dict([(k, fixup(i)) for k, i in v.iteritems()])
117                return v
118            for k, v in ll.iteritems():
119                l = [k, v]
120                req, resp = run(l)
121                self.assertEquals(fixup(resp.llsd), fixup(l))
122
123        run(ll)
124
125    def test_client_content_type_json_good(self):
126        self._test_client_content_type_good('application/json', self.json_safe)
127
128    def test_client_content_type_llsd_xml_good(self):
129        self._test_client_content_type_good('application/llsd+xml',
130                                            self.json_unsafe)
131
132    def test_client_content_type_llsd_notation_good(self):
133        self._test_client_content_type_good('application/llsd+notation',
134                                            self.json_unsafe)
135
136    def test_client_content_type_llsd_binary_good(self):
137        self._test_client_content_type_good('application/llsd+binary',
138                                            self.json_unsafe)
139
140    def test_client_content_type_xml_good(self):
141        self._test_client_content_type_good('application/xml',
142                                            self.json_unsafe)
143
144    def _test_client_content_type_bad(self, content_type):
145        req = siesta.Request.blank('/')
146        req.environ['REQUEST_METHOD'] = 'POST'
147        req.body = '\0invalid nonsense under all encodings'
148        req.content_type = content_type
149        self.assertEquals(req.get_response(self.server).status_int,
150                          exc.HTTPBadRequest.code)
151        
152    def test_client_content_type_json_bad(self):
153        self._test_client_content_type_bad('application/json')
154
155    def test_client_content_type_llsd_xml_bad(self):
156        self._test_client_content_type_bad('application/llsd+xml')
157
158    def test_client_content_type_llsd_notation_bad(self):
159        self._test_client_content_type_bad('application/llsd+notation')
160
161    def test_client_content_type_llsd_binary_bad(self):
162        self._test_client_content_type_bad('application/llsd+binary')
163
164    def test_client_content_type_xml_bad(self):
165        self._test_client_content_type_bad('application/xml')
166
167    def test_client_content_type_bad(self):
168        req = siesta.Request.blank('/')
169        req.environ['REQUEST_METHOD'] = 'POST'
170        req.body = 'XXX'
171        req.content_type = 'application/nonsense'
172        self.assertEquals(req.get_response(self.server).status_int,
173                          exc.HTTPUnsupportedMediaType.code)
174
175    def test_request_default_content_type(self):
176        req = siesta.Request.blank('/')
177        self.assertEquals(req.content_type, req.default_content_type)
178
179    def test_request_default_accept(self):
180        req = siesta.Request.blank('/')
181        from webob import acceptparse
182        self.assertEquals(str(req.accept).replace(' ', ''),
183                          req.default_accept.replace(' ', ''))
184
185    def test_request_llsd_auto_body(self):
186        req = siesta.Request.blank('/')
187        req.llsd = {'a': 2}
188        self.assertEquals(req.body, '<?xml version="1.0" ?><llsd><map>'
189                          '<key>a</key><integer>2</integer></map></llsd>')
190
191    def test_request_llsd_mod_body_changes_llsd(self):
192        req = siesta.Request.blank('/')
193        req.llsd = {'a': 2}
194        req.body = '<?xml version="1.0" ?><llsd><integer>1337</integer></llsd>'
195        self.assertEquals(req.llsd, 1337)
196
197    def test_request_bad_llsd_fails(self):
198        def crashme(ctype):
199            def boom():
200                class foo(object): pass
201                req = siesta.Request.blank('/')
202                req.content_type = ctype
203                req.llsd = foo()
204        for mime_type in siesta.llsd_parsers:
205            self.assertRaises(TypeError, crashme(mime_type))
206
207
208class ClassServer(TestBase, unittest.TestCase):
209    def __init__(self, *args, **kwargs):
210        unittest.TestCase.__init__(self, *args, **kwargs)
211        self.server = siesta.llsd_class(ClassApp)
212
213
214class CallableServer(TestBase, unittest.TestCase):
215    def __init__(self, *args, **kwargs):
216        unittest.TestCase.__init__(self, *args, **kwargs)
217        self.server = siesta.llsd_callable(callable_app)
218
219
220class RouterServer(unittest.TestCase):
221    def test_router(self):
222        def foo(req, quux):
223            print quux
224
225        r = siesta.Router()
226        r.add('/foo/{quux:int}', siesta.llsd_callable(foo), methods=['GET'])
227        req = siesta.Request.blank('/foo/33')
228        req.get_response(r)
229
230        req = siesta.Request.blank('/foo/bar')
231        self.assertEquals(req.get_response(r).status_int,
232                          exc.HTTPNotFound.code)
233    
234if __name__ == '__main__':
235    unittest.main()