示例#1
0
    def test_request_url_method(self):

        @action(urls=[('GET', '/my_action'), ('POST', '/my_action/')],
                spec='''\
action my_action
''')
        def my_action(dummy_ctx, dummy_req):
            pass

        app = Application()
        app.add_request(my_action)

        status, dummy_headers, response = app.request('GET', '/my_action')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{}')

        status, dummy_headers, response = app.request('POST', '/my_action/', wsgi_input=b'{}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{}')

        status, dummy_headers, response = app.request('GET', '/my_action/')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        status, dummy_headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        status, dummy_headers, response = app.request('PUT', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')
示例#2
0
    def test_url_arg(self): # pylint: disable=invalid-name

        @action(method='GET', urls='/my_action/{a}', spec='''\
action my_action
  input
    int a
    int b
  output
    int sum
''')
        def my_action(unused_app, req):
            self.assertEqual(req['a'], 5)
            return {'sum': req['a'] + req['b']}

        app = Application()
        app.add_request(my_action)

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('GET', '/my_action/5', query_string='b=7', environ=environ)
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"sum":12}')
        self.assertEqual(environ['wsgi.errors'].getvalue(), '')

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('GET', '/my_action/5', query_string='a=3&b=7', environ=environ)
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"InvalidInput","message":"Duplicate URL argument member \'a\'"}')
        self.assertRegex(
            environ['wsgi.errors'].getvalue(),
            r"WARNING \[\d+ / \d+\] Duplicate URL argument member 'a' for action 'my_action'"
        )
示例#3
0
    def test_request_url_mix(self):

        @action(urls=[(None, '/action/1')],
                spec='''\
action my_action1
  output
    int number
''')
        def my_action1(dummy_ctx, dummy_req):
            return {'number': 1}

        @action(urls=[('GET', '/action/{dummy_number}')],
                spec='''\
action my_action2
  input
    int dummy_number
  output
    int number
''')
        def my_action2(dummy_ctx, dummy_req):
            return {'number': 2}

        app = Application()
        app.add_request(my_action1)
        app.add_request(my_action2)

        status, dummy_headers, response = app.request('GET', '/action/1')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{"number":2}')

        status, dummy_headers, response = app.request('POST', '/action/1', wsgi_input=b'{}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{"number":1}')
示例#4
0
    def test_error_bad_error(self):

        @action(spec='''\
action my_action
  errors
    MyError
''')
        def my_action(unused_app, unused_req):
            raise ActionError('MyBadError')

        app = Application()
        app.add_request(my_action)

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'),
                         '{"error":"InvalidOutput","member":"error","message":"Invalid value \'MyBadError\' (type \'str\') '
                         'for member \'error\', expected type \'my_action_error\'"}')
        self.assertEqual(environ['wsgi.errors'].getvalue(), '')

        app.validate_output = False
        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"MyBadError"}')
        self.assertEqual(environ['wsgi.errors'].getvalue(), '')
示例#5
0
    def test_log_format_callable(self):

        def my_wsgi(environ, start_response):
            ctx = environ[Environ.CTX]
            ctx.log.warning('Hello log')
            start_response(HTTPStatus.OK, [('Content-Type', 'text/plain')])
            return ['Hello'.encode('utf-8')]

        class MyFormatter:

            def __init__(self, ctx):
                assert ctx is not None

            @staticmethod
            def format(record):
                return record.getMessage()

            @staticmethod
            def formatTime(record, unused_datefmt=None): # pylint: disable=invalid-name
                return record.getMessage()

            @staticmethod
            def formatException(unused_exc_info): # pylint: disable=invalid-name
                return 'Bad'

        app = Application()
        app.add_request(Request(my_wsgi))
        app.log_format = MyFormatter

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('GET', '/my_wsgi', environ=environ)
        self.assertEqual(response, 'Hello'.encode('utf-8'))
        self.assertEqual(status, '200 OK')
        self.assertTrue(('Content-Type', 'text/plain') in headers)
        self.assertEqual(environ['wsgi.errors'].getvalue(), 'Hello log\n')
示例#6
0
    def test_post(self):

        @action(spec='''\
action my_action
  input
    int a
    int b
  output
    int c
''')
        def my_action(dummy_app, req):
            return {'c': req['a'] + req['b']}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{"a": 7, "b": 8}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Length', '8'), ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"c":15}')

        # Mixed content and query string
        status, headers, response = app.request('POST', '/my_action', query_string='a=7', wsgi_input=b'{"b": 8}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Length', '8'), ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"c":15}')

        # Mixed content and query string #2
        status, headers, response = app.request('POST', '/my_action', query_string='a=7&b=8', wsgi_input=b'{}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Length', '8'), ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"c":15}')

        # Mixed content and query string #3
        status, headers, response = app.request('POST', '/my_action', query_string='a=7&b=8')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Length', '8'), ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"c":15}')

        # Duplicate query string argument
        status, headers, response = app.request('POST', '/my_action', query_string='a=7', wsgi_input=b'{"a": 7, "b": 8}')
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Length', '79'), ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"InvalidInput","message":"Duplicate query string argument member \'a\'"}')
示例#7
0
    def test_request_head(self):

        def request(environ, unused_start_response):
            assert environ['REQUEST_METHOD'] == 'GET'
            ctx = environ[Environ.CTX]
            return ctx.response_text(HTTPStatus.OK, 'the response')

        app = Application()
        app.add_request(Request(request, method='GET'))

        status, headers, response = app.request('GET', '/request')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'the response')
        self.assertListEqual(headers, [('Content-Type', 'text/plain')])

        status, headers, response = app.request('HEAD', '/request')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'')
        self.assertListEqual(headers, [('Content-Type', 'text/plain')])
示例#8
0
    def test_request_exception(self):

        def request1(unused_environ, unused_start_response):
            raise Exception('')

        app = Application()
        app.add_request(Request(request1))

        status, headers, response = app.request('GET', '/request1')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertTrue(('Content-Type', 'text/plain') in headers)
        self.assertEqual(response, b'Internal Server Error')
示例#9
0
    def test_request(self):

        def request1(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            return ctx.response_text(HTTPStatus.OK, 'request1')

        def request2(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            return ctx.response_text(HTTPStatus.OK, 'request2 ' + ctx.url_args['arg'] + ' ' + ctx.url_args.get('arg2', '?'))

        app = Application()
        app.add_request(Request(request1, urls=(
            ('GET', '/request1a'),
            (None, '/request1b')
        )))
        app.add_request(Request(request2, urls=(
            ('GET', '/request2a/{arg}'),
            (None, '/request2b/{arg}/bar/{arg2}/bonk')
        )))

        # Exact method and exact URL
        status, _, response = app.request('GET', '/request1a')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'request1')

        # Wrong method and exact URL
        status, _, response = app.request('POST', '/request1a')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        # Any method and exact URL
        status, _, response = app.request('GET', '/request1b')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'request1')

        # Exact method and regex URL
        status, _, response = app.request('GET', '/request2a/foo')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'request2 foo ?')

        # Wrong method and regex URL
        status, _, response = app.request('POST', '/request2a/foo')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        # Any method and regex URL
        status, _, response = app.request('POST', '/request2b/foo/bar/blue/bonk')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'request2 foo blue')

        # URL not found
        status, _, response = app.request('GET', '/request3')
        self.assertEqual(status, '404 Not Found')
        self.assertEqual(response, b'Not Found')
示例#10
0
    def test_request_not_found(self):

        @request(doc='''
This is the request documentation.
''')
        def my_request(unused_environ, unused_start_response):
            pass
        application = Application()
        application.add_request(DocAction())
        application.add_request(my_request)

        status, unused_headers, response = application.request('GET', '/doc', query_string='name=my_unknown_request')
        self.assertEqual(status, '404 Not Found')
        self.assertEqual(response, b'Unknown Request')
示例#11
0
    def test_request_url_method_arg(self):

        @action(urls=[('GET', '/my_action/{a}/{b}'), ('POST', '/my_action/{a}/{b}/')],
                spec='''\
action my_action
  input
    int a
    int b
  output
    int sum
''')
        def my_action(dummy_ctx, req):
            return {'sum': req['a'] + req['b']}

        app = Application()
        app.add_request(my_action)

        status, dummy_headers, response = app.request('GET', '/my_action/3/4')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{"sum":7}')

        status, dummy_headers, response = app.request('POST', '/my_action/3/4/', wsgi_input=b'{}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'{"sum":7}')

        status, dummy_headers, response = app.request('GET', '/my_action/3/4/')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        status, dummy_headers, response = app.request('POST', '/my_action/3/4', wsgi_input=b'{}')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')

        status, dummy_headers, response = app.request('PUT', '/my_action/3/4', wsgi_input=b'{}')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(response, b'Method Not Allowed')
示例#12
0
    def test_request_string_response(self):

        def string_response(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            return ctx.response(HTTPStatus.OK, 'text/plain', 'Hello World')

        app = Application()
        app.add_request(Request(string_response))

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('GET', '/string_response', environ=environ)
        self.assertEqual(status, '500 Internal Server Error')
        self.assertListEqual(headers, [('Content-Type', 'text/plain')])
        self.assertEqual(response, b'Internal Server Error')
        self.assertIn('response content cannot be of type str or bytes', environ['wsgi.errors'].getvalue())
示例#13
0
    def test_error_unexpected_custom(self):

        @action(wsgi_response=True, spec='''\
action my_action
''')
        def my_action(unused_app, unused_req):
            raise Exception('FAIL')

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"UnexpectedError"}')
示例#14
0
    def test_error_none_output(self):

        @action(spec='''\
action my_action
''')
        def my_action(unused_app, unused_req):
            pass

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{}')
示例#15
0
    def test_error_array_output(self):

        @action(spec='''\
action my_action
''')
        def my_action(unused_app, unused_req):
            return []

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'),
                         '{"error":"InvalidOutput","message":"Invalid value [] (type \'list\'), '
                         'expected type \'my_action_output\'"}')
示例#16
0
    def test_error_raised(self):

        @action(spec='''\
action my_action
  errors
    MyError
''')
        def my_action(unused_app, unused_req):
            raise ActionError('MyError')

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"MyError"}')
示例#17
0
    def test_error_invalid_method(self):

        @action(spec='''\
action my_action
  input
    int a
''')
        def my_action(unused_app, unused_req):
            return {}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('FOO', '/my_action', wsgi_input=b'{"a": 7}')
        self.assertEqual(status, '405 Method Not Allowed')
        self.assertEqual(sorted(headers), [('Content-Type', 'text/plain')])
        self.assertEqual(response.decode('utf-8'), 'Method Not Allowed')
示例#18
0
    def test_error_raised_status(self):

        @action(spec='''\
action my_action
  errors
    MyError
''')
        def my_action(unused_app, unused_req):
            raise ActionError('MyError', message='My message', status=HTTPStatus.NOT_FOUND)

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '404 Not Found')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"MyError","message":"My message"}')
示例#19
0
    def test_error_invalid_query_string(self):

        @action(method='GET', spec='''\
action my_action
  input
    int a
''')
        def my_action(unused_app, unused_req):
            return {}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('GET', '/my_action', query_string='a')
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"InvalidInput","message":"Invalid key/value pair \'a\'"}')
示例#20
0
    def test_error_response(self):

        @action(spec='''\
action my_action
  errors
    MyError
''')
        def my_action(unused_app, unused_req):
            return {'error': 'MyError'}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"InvalidOutput","message":"Unknown member \'error\'"}')
示例#21
0
    def test_error_raise_builtin(self):

        @action(spec='''\
action my_action
''')
        def my_action(unused_app, unused_req):
            raise ActionError('UnexpectedError', status=HTTPStatus.INTERNAL_SERVER_ERROR)

        app = Application()
        app.add_request(my_action)

        environ = {'wsgi.errors': StringIO()}
        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}', environ=environ)
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"UnexpectedError"}')
        self.assertEqual(environ['wsgi.errors'].getvalue(), '')
示例#22
0
    def test_request_args(self):

        def request1(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            self.assertEqual(environ['QUERY_STRING'], 'a=1&b=2')
            self.assertEqual(environ['wsgi.input'].read(), b'hello')
            ctx.log.warning('in request1')
            return ctx.response_text(HTTPStatus.OK, 'request1')

        app = Application()
        app.add_request(Request(request1))

        environ = {'wsgi.errors': StringIO()}
        status, _, response = app.request('GET', '/request1', query_string='a=1&b=2', wsgi_input=b'hello', environ=environ)
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'request1')
        self.assertIn('in request1', environ['wsgi.errors'].getvalue())
示例#23
0
    def test_headers(self):

        @action(spec='''\
action my_action
''')
        def my_action(ctx, unused_req):
            ctx.add_header('MyHeader', 'MyInitialValue')
            ctx.add_header('MyHeader', 'MyValue')
            return {}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action')
        self.assertEqual(status, '200 OK')
        self.assertEqual(headers, [('Content-Type', 'application/json'), ('MyHeader', 'MyValue')])
        self.assertEqual(response.decode('utf-8'), '{}')
示例#24
0
    def test_error_raised_message(self):

        @action(spec='''\
action my_action
  errors
    MyError
''')
        def my_action(dummy_app, dummy_req):
            raise ActionError('MyError', 'My message')

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Length', '42'),
                                           ('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'), '{"error":"MyError","message":"My message"}')
示例#25
0
    def test_request_nested(self):

        def request1(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            return ctx.response_text(HTTPStatus.OK, '7')

        def request2(environ, unused_start_response):
            ctx = environ[Environ.CTX]
            unused_status, _, response = ctx.app.request('GET', '/request1')
            return ctx.response_text(HTTPStatus.OK, str(5 + int(response)))

        app = Application()
        app.add_request(Request(request1))
        app.add_request(Request(request2))

        status, _, response = app.request('GET', '/request2')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'12')
示例#26
0
    def test_nested_requests(self):

        def request1(environ, dummy_start_response):
            ctx = environ[ENVIRON_CTX]
            return ctx.response_text('200 OK', '7')

        def request2(environ, dummy_start_response):
            ctx = environ[ENVIRON_CTX]
            dummy_status, dummy_headers, response = ctx.app.request('GET', '/request1')
            return ctx.response_text('200 OK', str(5 + int(response)))

        app = Application()
        app.add_request(Request(request1))
        app.add_request(Request(request2))

        status, dummy_headers, response = app.request('GET', '/request2')
        self.assertEqual(status, '200 OK')
        self.assertEqual(response, b'12')
示例#27
0
    def test_error_invalid_output(self):

        @action(spec='''\
action my_action
  output
    int a
''')
        def my_action(unused_app, unused_req):
            return {'a': 'asdf'}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{}')
        self.assertEqual(status, '500 Internal Server Error')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'),
                         '{"error":"InvalidOutput","member":"a","message":"Invalid value \'asdf\' (type \'str\') '
                         'for member \'a\', expected type \'int\'"}')
示例#28
0
    def test_error_invalid_input(self):

        @action(spec='''\
action my_action
  input
    string a
''')
        def my_action(unused_app, unused_req):
            return {}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{"a": 7}')
        self.assertEqual(status, '400 Bad Request')
        self.assertEqual(sorted(headers), [('Content-Type', 'application/json')])
        self.assertEqual(response.decode('utf-8'),
                         '{"error":"InvalidInput","member":"a","message":"Invalid value 7 (type \'int\') '
                         'for member \'a\', expected type \'string\'"}')
示例#29
0
    def test_error_invalid_json(self):

        @action(spec='''\
action my_action
  input
    int a
''')
        def my_action(dummy_app, dummy_req):
            return {}

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{a: 7}')
        self.assertEqual(status, '400 Bad Request')
        self.assertTrue(any(header for header in headers if header[0] == 'Content-Length'))
        self.assertEqual(sorted(header for header in headers if header[0] != 'Content-Length'),
                         [('Content-Type', 'application/json')])
        self.assertTrue(re.search('{"error":"InvalidInput","message":"Invalid request JSON:', response.decode('utf-8')))
示例#30
0
    def test_custom_response(self):

        @action(wsgi_response=True, spec='''\
action my_action
  input
    string a
  output
    string b
''')
        def my_action(ctx, req):
            return ctx.response_text(HTTPStatus.OK, 'Hello ' + str(req['a'].upper()))

        app = Application()
        app.add_request(my_action)

        status, headers, response = app.request('POST', '/my_action', wsgi_input=b'{"a": "world"}')
        self.assertEqual(status, '200 OK')
        self.assertEqual(sorted(headers), [('Content-Type', 'text/plain')])
        self.assertEqual(response.decode('utf-8'), 'Hello WORLD')