]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | # -*- coding: utf-8 -*- |
2 | from __future__ import absolute_import | |
3 | ||
4 | import unittest | |
5 | ||
6 | import cherrypy | |
7 | from cherrypy.lib.sessions import RamSession | |
8 | from mock import patch | |
9 | ||
10 | from . import ControllerTestCase | |
11 | from ..services.exception import handle_rados_error | |
12 | from ..controllers import RESTController, ApiController, Controller, \ | |
13 | BaseController, Proxy | |
14 | from ..tools import is_valid_ipv6_address, dict_contains_path, \ | |
15 | RequestLoggingTool | |
16 | ||
17 | ||
18 | # pylint: disable=W0613 | |
19 | @Controller('/foo', secure=False) | |
20 | class FooResource(RESTController): | |
21 | elems = [] | |
22 | ||
23 | def list(self): | |
24 | return FooResource.elems | |
25 | ||
26 | def create(self, a): | |
27 | FooResource.elems.append({'a': a}) | |
28 | return {'a': a} | |
29 | ||
30 | def get(self, key): | |
31 | return {'detail': (key, [])} | |
32 | ||
33 | def delete(self, key): | |
34 | del FooResource.elems[int(key)] | |
35 | ||
36 | def bulk_delete(self): | |
37 | FooResource.elems = [] | |
38 | ||
39 | def set(self, key, newdata): | |
40 | FooResource.elems[int(key)] = {'newdata': newdata} | |
41 | return dict(key=key, newdata=newdata) | |
42 | ||
43 | ||
44 | @Controller('/foo/:key/:method', secure=False) | |
45 | class FooResourceDetail(RESTController): | |
46 | def list(self, key, method): | |
47 | return {'detail': (key, [method])} | |
48 | ||
49 | ||
50 | @ApiController('/rgw/proxy', secure=False) | |
51 | class GenerateControllerRoutesController(BaseController): | |
52 | @Proxy() | |
53 | def __call__(self, path, **params): | |
54 | pass | |
55 | ||
56 | ||
57 | @ApiController('/fooargs', secure=False) | |
58 | class FooArgs(RESTController): | |
59 | def set(self, code, name=None, opt1=None, opt2=None): | |
60 | return {'code': code, 'name': name, 'opt1': opt1, 'opt2': opt2} | |
61 | ||
62 | @handle_rados_error('foo') | |
63 | def create(self, my_arg_name): | |
64 | return my_arg_name | |
65 | ||
66 | def list(self): | |
67 | raise cherrypy.NotFound() | |
68 | ||
69 | ||
70 | # pylint: disable=blacklisted-name | |
71 | class Root(object): | |
72 | foo = FooResource() | |
73 | fooargs = FooArgs() | |
74 | ||
75 | ||
76 | class RESTControllerTest(ControllerTestCase): | |
77 | ||
78 | @classmethod | |
79 | def setup_server(cls): | |
80 | cls.setup_controllers( | |
81 | [FooResource, FooResourceDetail, FooArgs, GenerateControllerRoutesController]) | |
82 | ||
83 | def test_empty(self): | |
84 | self._delete("/foo") | |
85 | self.assertStatus(204) | |
86 | self._get("/foo") | |
87 | self.assertStatus('200 OK') | |
88 | self.assertHeader('Content-Type', 'application/json') | |
89 | self.assertBody('[]') | |
90 | ||
91 | def test_fill(self): | |
92 | sess_mock = RamSession() | |
93 | with patch('cherrypy.session', sess_mock, create=True): | |
94 | data = {'a': 'b'} | |
95 | for _ in range(5): | |
96 | self._post("/foo", data) | |
97 | self.assertJsonBody(data) | |
98 | self.assertStatus(201) | |
99 | self.assertHeader('Content-Type', 'application/json') | |
100 | ||
101 | self._get("/foo") | |
102 | self.assertStatus('200 OK') | |
103 | self.assertHeader('Content-Type', 'application/json') | |
104 | self.assertJsonBody([data] * 5) | |
105 | ||
106 | self._put('/foo/0', {'newdata': 'newdata'}) | |
107 | self.assertStatus('200 OK') | |
108 | self.assertHeader('Content-Type', 'application/json') | |
109 | self.assertJsonBody({'newdata': 'newdata', 'key': '0'}) | |
110 | ||
111 | def test_not_implemented(self): | |
112 | self._put("/foo") | |
113 | self.assertStatus(404) | |
114 | body = self.jsonBody() | |
115 | self.assertIsInstance(body, dict) | |
116 | assert body['detail'] == "The path '/foo' was not found." | |
117 | assert '404' in body['status'] | |
11fdf7f2 TL |
118 | |
119 | def test_args_from_json(self): | |
120 | self._put("/api/fooargs/hello", {'name': 'world'}) | |
121 | self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': None, 'opt2': None}) | |
122 | ||
123 | self._put("/api/fooargs/hello", {'name': 'world', 'opt1': 'opt1'}) | |
124 | self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': 'opt1', 'opt2': None}) | |
125 | ||
126 | self._put("/api/fooargs/hello", {'name': 'world', 'opt2': 'opt2'}) | |
127 | self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': None, 'opt2': 'opt2'}) | |
128 | ||
129 | def test_detail_route(self): | |
130 | self._get('/foo/default') | |
131 | self.assertJsonBody({'detail': ['default', []]}) | |
132 | ||
133 | self._get('/foo/default/default') | |
134 | self.assertJsonBody({'detail': ['default', ['default']]}) | |
135 | ||
136 | self._get('/foo/1/detail') | |
137 | self.assertJsonBody({'detail': ['1', ['detail']]}) | |
138 | ||
139 | self._post('/foo/1/detail', 'post-data') | |
140 | self.assertStatus(404) | |
141 | ||
142 | def test_generate_controller_routes(self): | |
143 | # We just need to add this controller in setup_server(): | |
144 | # noinspection PyStatementEffect | |
145 | # pylint: disable=pointless-statement | |
146 | GenerateControllerRoutesController | |
147 | ||
148 | ||
149 | class RequestLoggingToolTest(ControllerTestCase): | |
150 | ||
151 | def __init__(self, *args, **kwargs): | |
152 | cherrypy.tools.request_logging = RequestLoggingTool() | |
153 | cherrypy.config.update({'tools.request_logging.on': True}) | |
154 | super(RequestLoggingToolTest, self).__init__(*args, **kwargs) | |
155 | ||
156 | @classmethod | |
157 | def setup_server(cls): | |
158 | cls.setup_controllers([FooResource]) | |
159 | ||
160 | def test_is_logged(self): | |
161 | with patch('logging.Logger.debug') as mock_logger_debug: | |
162 | self._put('/foo/0', {'newdata': 'xyz'}) | |
163 | self.assertStatus(200) | |
164 | call_args_list = mock_logger_debug.call_args_list | |
165 | _, host, _, method, user, path = call_args_list[0][0] | |
166 | self.assertEqual(host, '127.0.0.1') | |
167 | self.assertEqual(method, 'PUT') | |
168 | self.assertIsNone(user) | |
169 | self.assertEqual(path, '/foo/0') | |
170 | ||
171 | ||
172 | class TestFunctions(unittest.TestCase): | |
173 | ||
174 | def test_is_valid_ipv6_address(self): | |
175 | self.assertTrue(is_valid_ipv6_address('::')) | |
176 | self.assertTrue(is_valid_ipv6_address('::1')) | |
177 | self.assertFalse(is_valid_ipv6_address('127.0.0.1')) | |
178 | self.assertFalse(is_valid_ipv6_address('localhost')) | |
179 | self.assertTrue(is_valid_ipv6_address('1200:0000:AB00:1234:0000:2552:7777:1313')) | |
180 | self.assertFalse(is_valid_ipv6_address('1200::AB00:1234::2552:7777:1313')) | |
181 | ||
182 | def test_dict_contains_path(self): | |
183 | x = {'a': {'b': {'c': 'foo'}}} | |
184 | self.assertTrue(dict_contains_path(x, ['a', 'b', 'c'])) | |
185 | self.assertTrue(dict_contains_path(x, ['a', 'b', 'c'])) | |
186 | self.assertTrue(dict_contains_path(x, ['a'])) | |
187 | self.assertFalse(dict_contains_path(x, ['a', 'c'])) | |
188 | self.assertTrue(dict_contains_path(x, [])) |