]> git.proxmox.com Git - ceph.git/blame - ceph/src/pybind/mgr/dashboard/tests/test_tools.py
import quincy beta 17.1.0
[ceph.git] / ceph / src / pybind / mgr / dashboard / tests / test_tools.py
CommitLineData
11fdf7f2 1# -*- coding: utf-8 -*-
11fdf7f2
TL
2
3import unittest
4
5import cherrypy
6from cherrypy.lib.sessions import RamSession
f67539c2 7
9f95a23c
TL
8try:
9 from mock import patch
10except ImportError:
11 from unittest.mock import patch
11fdf7f2 12
a4b75251
TL
13from ..controllers import APIRouter, BaseController, Proxy, RESTController, Router
14from ..controllers._version import APIVersion
11fdf7f2 15from ..services.exception import handle_rados_error
a4b75251
TL
16from ..tests import ControllerTestCase
17from ..tools import dict_contains_path, dict_get, json_str_to_object, \
18 merge_list_of_dicts_by_key, partial_dict
11fdf7f2
TL
19
20
21# pylint: disable=W0613
a4b75251 22@Router('/foo', secure=False)
11fdf7f2
TL
23class FooResource(RESTController):
24 elems = []
25
26 def list(self):
27 return FooResource.elems
28
29 def create(self, a):
30 FooResource.elems.append({'a': a})
31 return {'a': a}
32
33 def get(self, key):
34 return {'detail': (key, [])}
35
36 def delete(self, key):
37 del FooResource.elems[int(key)]
38
39 def bulk_delete(self):
40 FooResource.elems = []
41
42 def set(self, key, newdata):
43 FooResource.elems[int(key)] = {'newdata': newdata}
44 return dict(key=key, newdata=newdata)
45
46
a4b75251 47@Router('/foo/:key/:method', secure=False)
11fdf7f2
TL
48class FooResourceDetail(RESTController):
49 def list(self, key, method):
50 return {'detail': (key, [method])}
51
52
a4b75251 53@APIRouter('/rgw/proxy', secure=False)
11fdf7f2
TL
54class GenerateControllerRoutesController(BaseController):
55 @Proxy()
56 def __call__(self, path, **params):
57 pass
58
59
a4b75251 60@APIRouter('/fooargs', secure=False)
11fdf7f2
TL
61class FooArgs(RESTController):
62 def set(self, code, name=None, opt1=None, opt2=None):
63 return {'code': code, 'name': name, 'opt1': opt1, 'opt2': opt2}
64
65 @handle_rados_error('foo')
66 def create(self, my_arg_name):
67 return my_arg_name
68
69 def list(self):
70 raise cherrypy.NotFound()
71
72
11fdf7f2 73class Root(object):
f67539c2 74 foo_resource = FooResource()
11fdf7f2
TL
75 fooargs = FooArgs()
76
77
78class RESTControllerTest(ControllerTestCase):
79
80 @classmethod
81 def setup_server(cls):
82 cls.setup_controllers(
83 [FooResource, FooResourceDetail, FooArgs, GenerateControllerRoutesController])
84
85 def test_empty(self):
86 self._delete("/foo")
87 self.assertStatus(204)
88 self._get("/foo")
89 self.assertStatus('200 OK')
a4b75251 90 self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
11fdf7f2
TL
91 self.assertBody('[]')
92
93 def test_fill(self):
94 sess_mock = RamSession()
95 with patch('cherrypy.session', sess_mock, create=True):
96 data = {'a': 'b'}
97 for _ in range(5):
98 self._post("/foo", data)
99 self.assertJsonBody(data)
100 self.assertStatus(201)
a4b75251 101 self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
11fdf7f2
TL
102
103 self._get("/foo")
104 self.assertStatus('200 OK')
a4b75251 105 self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
11fdf7f2
TL
106 self.assertJsonBody([data] * 5)
107
108 self._put('/foo/0', {'newdata': 'newdata'})
109 self.assertStatus('200 OK')
a4b75251 110 self.assertHeader('Content-Type', APIVersion.DEFAULT.to_mime_type())
11fdf7f2
TL
111 self.assertJsonBody({'newdata': 'newdata', 'key': '0'})
112
113 def test_not_implemented(self):
114 self._put("/foo")
115 self.assertStatus(404)
9f95a23c 116 body = self.json_body()
11fdf7f2
TL
117 self.assertIsInstance(body, dict)
118 assert body['detail'] == "The path '/foo' was not found."
119 assert '404' in body['status']
11fdf7f2
TL
120
121 def test_args_from_json(self):
122 self._put("/api/fooargs/hello", {'name': 'world'})
123 self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': None, 'opt2': None})
124
125 self._put("/api/fooargs/hello", {'name': 'world', 'opt1': 'opt1'})
126 self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': 'opt1', 'opt2': None})
127
128 self._put("/api/fooargs/hello", {'name': 'world', 'opt2': 'opt2'})
129 self.assertJsonBody({'code': 'hello', 'name': 'world', 'opt1': None, 'opt2': 'opt2'})
130
131 def test_detail_route(self):
132 self._get('/foo/default')
133 self.assertJsonBody({'detail': ['default', []]})
134
135 self._get('/foo/default/default')
136 self.assertJsonBody({'detail': ['default', ['default']]})
137
138 self._get('/foo/1/detail')
139 self.assertJsonBody({'detail': ['1', ['detail']]})
140
141 self._post('/foo/1/detail', 'post-data')
142 self.assertStatus(404)
143
144 def test_generate_controller_routes(self):
145 # We just need to add this controller in setup_server():
146 # noinspection PyStatementEffect
147 # pylint: disable=pointless-statement
148 GenerateControllerRoutesController
149
150
151class RequestLoggingToolTest(ControllerTestCase):
152
f67539c2 153 _request_logging = True
11fdf7f2
TL
154
155 @classmethod
156 def setup_server(cls):
157 cls.setup_controllers([FooResource])
158
159 def test_is_logged(self):
160 with patch('logging.Logger.debug') as mock_logger_debug:
161 self._put('/foo/0', {'newdata': 'xyz'})
162 self.assertStatus(200)
163 call_args_list = mock_logger_debug.call_args_list
164 _, host, _, method, user, path = call_args_list[0][0]
165 self.assertEqual(host, '127.0.0.1')
166 self.assertEqual(method, 'PUT')
167 self.assertIsNone(user)
168 self.assertEqual(path, '/foo/0')
169
170
171class TestFunctions(unittest.TestCase):
172
11fdf7f2
TL
173 def test_dict_contains_path(self):
174 x = {'a': {'b': {'c': 'foo'}}}
175 self.assertTrue(dict_contains_path(x, ['a', 'b', 'c']))
176 self.assertTrue(dict_contains_path(x, ['a', 'b', 'c']))
177 self.assertTrue(dict_contains_path(x, ['a']))
178 self.assertFalse(dict_contains_path(x, ['a', 'c']))
179 self.assertTrue(dict_contains_path(x, []))
9f95a23c
TL
180
181 def test_json_str_to_object(self):
182 expected_result = {'a': 1, 'b': 'bbb'}
183 self.assertEqual(expected_result, json_str_to_object('{"a": 1, "b": "bbb"}'))
184 self.assertEqual(expected_result, json_str_to_object(b'{"a": 1, "b": "bbb"}'))
185 self.assertEqual('', json_str_to_object(''))
186 self.assertRaises(TypeError, json_str_to_object, None)
187
188 def test_partial_dict(self):
189 expected_result = {'a': 1, 'c': 3}
190 self.assertEqual(expected_result, partial_dict({'a': 1, 'b': 2, 'c': 3}, ['a', 'c']))
191 self.assertEqual({}, partial_dict({'a': 1, 'b': 2, 'c': 3}, []))
192 self.assertEqual({}, partial_dict({}, []))
193 self.assertRaises(KeyError, partial_dict, {'a': 1, 'b': 2, 'c': 3}, ['d'])
194 self.assertRaises(TypeError, partial_dict, None, ['a'])
195 self.assertRaises(TypeError, partial_dict, {'a': 1, 'b': 2, 'c': 3}, None)
196
197 def test_dict_get(self):
198 self.assertFalse(dict_get({'foo': {'bar': False}}, 'foo.bar'))
199 self.assertIsNone(dict_get({'foo': {'bar': False}}, 'foo.bar.baz'))
200 self.assertEqual(dict_get({'foo': {'bar': False}, 'baz': 'xyz'}, 'baz'), 'xyz')
a4b75251
TL
201
202 def test_merge_list_of_dicts_by_key(self):
203 expected_result = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 5, 'c': 6}]
204 self.assertEqual(expected_result, merge_list_of_dicts_by_key(
205 [{'a': 1, 'b': 2}, {'a': 4, 'b': 5}], [{'a': 1, 'c': 3}, {'a': 4, 'c': 6}], 'a'))
206
207 expected_result = [{'a': 1, 'b': 2}, {'a': 4, 'b': 5, 'c': 6}]
208 self.assertEqual(expected_result, merge_list_of_dicts_by_key(
209 [{'a': 1, 'b': 2}, {'a': 4, 'b': 5}], [{}, {'a': 4, 'c': 6}], 'a'))
210 self.assertRaises(TypeError, merge_list_of_dicts_by_key, None)