Mercurial > p > roundup > code
comparison test/rest_common.py @ 5606:5fc476d4e34c
Merge REST API changes
| author | Ralf Schlatterbeck <rsc@runtux.com> |
|---|---|
| date | Wed, 30 Jan 2019 18:11:02 +0100 |
| parents | ed02a1e0aa5d |
| children | 1c4adab65faf |
comparison
equal
deleted
inserted
replaced
| 5553:a75285092156 | 5606:5fc476d4e34c |
|---|---|
| 1 import unittest | |
| 2 import os | |
| 3 import shutil | |
| 4 import errno | |
| 5 | |
| 6 from roundup.cgi.exceptions import * | |
| 7 from roundup import password, hyperdb | |
| 8 from roundup.rest import RestfulInstance | |
| 9 from roundup.backends import list_backends | |
| 10 from roundup.cgi import client | |
| 11 import random | |
| 12 | |
| 13 from .db_test_base import setupTracker | |
| 14 | |
| 15 NEEDS_INSTANCE = 1 | |
| 16 | |
| 17 | |
| 18 class TestCase(): | |
| 19 | |
| 20 backend = None | |
| 21 | |
| 22 def setUp(self): | |
| 23 self.dirname = '_test_rest' | |
| 24 # set up and open a tracker | |
| 25 self.instance = setupTracker(self.dirname, self.backend) | |
| 26 | |
| 27 # open the database | |
| 28 self.db = self.instance.open('admin') | |
| 29 | |
| 30 # Get user id (user4 maybe). Used later to get data from db. | |
| 31 self.joeid = self.db.user.create( | |
| 32 username='joe', | |
| 33 password=password.Password('random'), | |
| 34 address='random@home.org', | |
| 35 realname='Joe Random', | |
| 36 roles='User' | |
| 37 ) | |
| 38 | |
| 39 self.db.commit() | |
| 40 self.db.close() | |
| 41 self.db = self.instance.open('joe') | |
| 42 # Allow joe to retire | |
| 43 p = self.db.security.addPermission(name='Retire', klass='issue') | |
| 44 self.db.security.addPermissionToRole('User', p) | |
| 45 | |
| 46 self.db.tx_Source = 'web' | |
| 47 | |
| 48 self.db.issue.addprop(tx_Source=hyperdb.String()) | |
| 49 self.db.msg.addprop(tx_Source=hyperdb.String()) | |
| 50 | |
| 51 self.db.post_init() | |
| 52 | |
| 53 thisdir = os.path.dirname(__file__) | |
| 54 vars = {} | |
| 55 with open(os.path.join(thisdir, "tx_Source_detector.py")) as f: | |
| 56 code = compile(f.read(), "tx_Source_detector.py", "exec") | |
| 57 exec(code, vars) | |
| 58 vars['init'](self.db) | |
| 59 | |
| 60 env = { | |
| 61 'PATH_INFO': 'http://localhost/rounduptest/rest/', | |
| 62 'HTTP_HOST': 'localhost', | |
| 63 'TRACKER_NAME': 'rounduptest' | |
| 64 } | |
| 65 self.dummy_client = client.Client(self.instance, None, env, [], None) | |
| 66 self.empty_form = cgi.FieldStorage() | |
| 67 | |
| 68 self.server = RestfulInstance(self.dummy_client, self.db) | |
| 69 | |
| 70 def tearDown(self): | |
| 71 self.db.close() | |
| 72 try: | |
| 73 shutil.rmtree(self.dirname) | |
| 74 except OSError as error: | |
| 75 if error.errno not in (errno.ENOENT, errno.ESRCH): | |
| 76 raise | |
| 77 | |
| 78 def testGet(self): | |
| 79 """ | |
| 80 Retrieve all three users | |
| 81 obtain data for 'joe' | |
| 82 """ | |
| 83 # Retrieve all three users. | |
| 84 results = self.server.get_collection('user', self.empty_form) | |
| 85 self.assertEqual(self.dummy_client.response_code, 200) | |
| 86 self.assertEqual(len(results['data']), 3) | |
| 87 | |
| 88 # Obtain data for 'joe'. | |
| 89 results = self.server.get_element('user', self.joeid, self.empty_form) | |
| 90 results = results['data'] | |
| 91 self.assertEqual(self.dummy_client.response_code, 200) | |
| 92 self.assertEqual(results['attributes']['username'], 'joe') | |
| 93 self.assertEqual(results['attributes']['realname'], 'Joe Random') | |
| 94 | |
| 95 # Obtain data for 'joe'. | |
| 96 results = self.server.get_attribute( | |
| 97 'user', self.joeid, 'username', self.empty_form | |
| 98 ) | |
| 99 self.assertEqual(self.dummy_client.response_code, 200) | |
| 100 self.assertEqual(results['data']['data'], 'joe') | |
| 101 | |
| 102 def testFilter(self): | |
| 103 """ | |
| 104 Retrieve all three users | |
| 105 obtain data for 'joe' | |
| 106 """ | |
| 107 # create sample data | |
| 108 try: | |
| 109 self.db.status.create(name='open') | |
| 110 except ValueError: | |
| 111 pass | |
| 112 try: | |
| 113 self.db.status.create(name='closed') | |
| 114 except ValueError: | |
| 115 pass | |
| 116 try: | |
| 117 self.db.priority.create(name='normal') | |
| 118 except ValueError: | |
| 119 pass | |
| 120 try: | |
| 121 self.db.priority.create(name='critical') | |
| 122 except ValueError: | |
| 123 pass | |
| 124 self.db.issue.create( | |
| 125 title='foo4', | |
| 126 status=self.db.status.lookup('closed'), | |
| 127 priority=self.db.priority.lookup('critical') | |
| 128 ) | |
| 129 self.db.issue.create( | |
| 130 title='foo1', | |
| 131 status=self.db.status.lookup('open'), | |
| 132 priority=self.db.priority.lookup('normal') | |
| 133 ) | |
| 134 issue_open_norm = self.db.issue.create( | |
| 135 title='foo2', | |
| 136 status=self.db.status.lookup('open'), | |
| 137 priority=self.db.priority.lookup('normal') | |
| 138 ) | |
| 139 issue_closed_norm = self.db.issue.create( | |
| 140 title='foo3', | |
| 141 status=self.db.status.lookup('closed'), | |
| 142 priority=self.db.priority.lookup('normal') | |
| 143 ) | |
| 144 issue_closed_crit = self.db.issue.create( | |
| 145 title='foo4', | |
| 146 status=self.db.status.lookup('closed'), | |
| 147 priority=self.db.priority.lookup('critical') | |
| 148 ) | |
| 149 issue_open_crit = self.db.issue.create( | |
| 150 title='foo5', | |
| 151 status=self.db.status.lookup('open'), | |
| 152 priority=self.db.priority.lookup('critical') | |
| 153 ) | |
| 154 base_path = self.dummy_client.env['PATH_INFO'] + 'data/issue/' | |
| 155 | |
| 156 # Retrieve all issue status=open | |
| 157 form = cgi.FieldStorage() | |
| 158 form.list = [ | |
| 159 cgi.MiniFieldStorage('where_status', 'open') | |
| 160 ] | |
| 161 results = self.server.get_collection('issue', form) | |
| 162 self.assertEqual(self.dummy_client.response_code, 200) | |
| 163 self.assertIn(get_obj(base_path, issue_open_norm), results['data']) | |
| 164 self.assertIn(get_obj(base_path, issue_open_crit), results['data']) | |
| 165 self.assertNotIn( | |
| 166 get_obj(base_path, issue_closed_norm), results['data'] | |
| 167 ) | |
| 168 | |
| 169 # Retrieve all issue status=closed and priority=critical | |
| 170 form = cgi.FieldStorage() | |
| 171 form.list = [ | |
| 172 cgi.MiniFieldStorage('where_status', 'closed'), | |
| 173 cgi.MiniFieldStorage('where_priority', 'critical') | |
| 174 ] | |
| 175 results = self.server.get_collection('issue', form) | |
| 176 self.assertEqual(self.dummy_client.response_code, 200) | |
| 177 self.assertIn(get_obj(base_path, issue_closed_crit), results['data']) | |
| 178 self.assertNotIn(get_obj(base_path, issue_open_crit), results['data']) | |
| 179 self.assertNotIn( | |
| 180 get_obj(base_path, issue_closed_norm), results['data'] | |
| 181 ) | |
| 182 | |
| 183 # Retrieve all issue status=closed and priority=normal,critical | |
| 184 form = cgi.FieldStorage() | |
| 185 form.list = [ | |
| 186 cgi.MiniFieldStorage('where_status', 'closed'), | |
| 187 cgi.MiniFieldStorage('where_priority', 'normal,critical') | |
| 188 ] | |
| 189 results = self.server.get_collection('issue', form) | |
| 190 self.assertEqual(self.dummy_client.response_code, 200) | |
| 191 self.assertIn(get_obj(base_path, issue_closed_crit), results['data']) | |
| 192 self.assertIn(get_obj(base_path, issue_closed_norm), results['data']) | |
| 193 self.assertNotIn(get_obj(base_path, issue_open_crit), results['data']) | |
| 194 self.assertNotIn(get_obj(base_path, issue_open_norm), results['data']) | |
| 195 | |
| 196 def testPagination(self): | |
| 197 """ | |
| 198 Retrieve all three users | |
| 199 obtain data for 'joe' | |
| 200 """ | |
| 201 # create sample data | |
| 202 for i in range(0, random.randint(5, 10)): | |
| 203 self.db.issue.create(title='foo' + str(i)) | |
| 204 | |
| 205 # Retrieving all the issues | |
| 206 results = self.server.get_collection('issue', self.empty_form) | |
| 207 self.assertEqual(self.dummy_client.response_code, 200) | |
| 208 total_length = len(results['data']) | |
| 209 | |
| 210 # Pagination will be 70% of the total result | |
| 211 page_size = total_length * 70 // 100 | |
| 212 page_zero_expected = page_size | |
| 213 page_one_expected = total_length - page_zero_expected | |
| 214 | |
| 215 # Retrieve page 0 | |
| 216 form = cgi.FieldStorage() | |
| 217 form.list = [ | |
| 218 cgi.MiniFieldStorage('page_size', page_size), | |
| 219 cgi.MiniFieldStorage('page_index', 0) | |
| 220 ] | |
| 221 results = self.server.get_collection('issue', form) | |
| 222 self.assertEqual(self.dummy_client.response_code, 200) | |
| 223 self.assertEqual(len(results['data']), page_zero_expected) | |
| 224 | |
| 225 # Retrieve page 1 | |
| 226 form = cgi.FieldStorage() | |
| 227 form.list = [ | |
| 228 cgi.MiniFieldStorage('page_size', page_size), | |
| 229 cgi.MiniFieldStorage('page_index', 1) | |
| 230 ] | |
| 231 results = self.server.get_collection('issue', form) | |
| 232 self.assertEqual(self.dummy_client.response_code, 200) | |
| 233 self.assertEqual(len(results['data']), page_one_expected) | |
| 234 | |
| 235 # Retrieve page 2 | |
| 236 form = cgi.FieldStorage() | |
| 237 form.list = [ | |
| 238 cgi.MiniFieldStorage('page_size', page_size), | |
| 239 cgi.MiniFieldStorage('page_index', 2) | |
| 240 ] | |
| 241 results = self.server.get_collection('issue', form) | |
| 242 self.assertEqual(self.dummy_client.response_code, 200) | |
| 243 self.assertEqual(len(results['data']), 0) | |
| 244 | |
| 245 def testPut(self): | |
| 246 """ | |
| 247 Change joe's 'realname' | |
| 248 Check if we can't change admin's detail | |
| 249 """ | |
| 250 # change Joe's realname via attribute uri | |
| 251 form = cgi.FieldStorage() | |
| 252 form.list = [ | |
| 253 cgi.MiniFieldStorage('data', 'Joe Doe Doe') | |
| 254 ] | |
| 255 results = self.server.put_attribute( | |
| 256 'user', self.joeid, 'realname', form | |
| 257 ) | |
| 258 results = self.server.get_attribute( | |
| 259 'user', self.joeid, 'realname', self.empty_form | |
| 260 ) | |
| 261 self.assertEqual(self.dummy_client.response_code, 200) | |
| 262 self.assertEqual(results['data']['data'], 'Joe Doe Doe') | |
| 263 | |
| 264 # Reset joe's 'realname'. | |
| 265 form = cgi.FieldStorage() | |
| 266 form.list = [ | |
| 267 cgi.MiniFieldStorage('realname', 'Joe Doe') | |
| 268 ] | |
| 269 results = self.server.put_element('user', self.joeid, form) | |
| 270 results = self.server.get_element('user', self.joeid, self.empty_form) | |
| 271 self.assertEqual(self.dummy_client.response_code, 200) | |
| 272 self.assertEqual(results['data']['attributes']['realname'], 'Joe Doe') | |
| 273 | |
| 274 # check we can't change admin's details | |
| 275 results = self.server.put_element('user', '1', form) | |
| 276 self.assertEqual(self.dummy_client.response_code, 403) | |
| 277 self.assertEqual(results['error']['status'], 403) | |
| 278 | |
| 279 def testPost(self): | |
| 280 """ | |
| 281 Post a new issue with title: foo | |
| 282 Verify the information of the created issue | |
| 283 """ | |
| 284 form = cgi.FieldStorage() | |
| 285 form.list = [ | |
| 286 cgi.MiniFieldStorage('title', 'foo') | |
| 287 ] | |
| 288 results = self.server.post_collection('issue', form) | |
| 289 self.assertEqual(self.dummy_client.response_code, 201) | |
| 290 issueid = results['data']['id'] | |
| 291 results = self.server.get_element('issue', issueid, self.empty_form) | |
| 292 self.assertEqual(self.dummy_client.response_code, 200) | |
| 293 self.assertEqual(results['data']['attributes']['title'], 'foo') | |
| 294 self.assertEqual(self.db.issue.get(issueid, "tx_Source"), 'web') | |
| 295 | |
| 296 def testPostFile(self): | |
| 297 """ | |
| 298 Post a new file with content: hello\r\nthere | |
| 299 Verify the information of the created file | |
| 300 """ | |
| 301 form = cgi.FieldStorage() | |
| 302 form.list = [ | |
| 303 cgi.MiniFieldStorage('content', 'hello\r\nthere') | |
| 304 ] | |
| 305 results = self.server.post_collection('file', form) | |
| 306 self.assertEqual(self.dummy_client.response_code, 201) | |
| 307 fileid = results['data']['id'] | |
| 308 results = self.server.get_element('file', fileid, self.empty_form) | |
| 309 results = results['data'] | |
| 310 self.assertEqual(self.dummy_client.response_code, 200) | |
| 311 self.assertEqual(results['attributes']['content'], 'hello\r\nthere') | |
| 312 | |
| 313 def testAuthDeniedPut(self): | |
| 314 """ | |
| 315 Test unauthorized PUT request | |
| 316 """ | |
| 317 # Wrong permissions (caught by roundup security module). | |
| 318 form = cgi.FieldStorage() | |
| 319 form.list = [ | |
| 320 cgi.MiniFieldStorage('realname', 'someone') | |
| 321 ] | |
| 322 results = self.server.put_element('user', '1', form) | |
| 323 self.assertEqual(self.dummy_client.response_code, 403) | |
| 324 self.assertEqual(results['error']['status'], 403) | |
| 325 | |
| 326 def testAuthDeniedPost(self): | |
| 327 """ | |
| 328 Test unauthorized POST request | |
| 329 """ | |
| 330 form = cgi.FieldStorage() | |
| 331 form.list = [ | |
| 332 cgi.MiniFieldStorage('username', 'blah') | |
| 333 ] | |
| 334 results = self.server.post_collection('user', form) | |
| 335 self.assertEqual(self.dummy_client.response_code, 403) | |
| 336 self.assertEqual(results['error']['status'], 403) | |
| 337 | |
| 338 def testAuthAllowedPut(self): | |
| 339 """ | |
| 340 Test authorized PUT request | |
| 341 """ | |
| 342 self.db.setCurrentUser('admin') | |
| 343 form = cgi.FieldStorage() | |
| 344 form.list = [ | |
| 345 cgi.MiniFieldStorage('realname', 'someone') | |
| 346 ] | |
| 347 try: | |
| 348 self.server.put_element('user', '2', form) | |
| 349 except Unauthorised as err: | |
| 350 self.fail('raised %s' % err) | |
| 351 finally: | |
| 352 self.db.setCurrentUser('joe') | |
| 353 | |
| 354 def testAuthAllowedPost(self): | |
| 355 """ | |
| 356 Test authorized POST request | |
| 357 """ | |
| 358 self.db.setCurrentUser('admin') | |
| 359 form = cgi.FieldStorage() | |
| 360 form.list = [ | |
| 361 cgi.MiniFieldStorage('username', 'blah') | |
| 362 ] | |
| 363 try: | |
| 364 self.server.post_collection('user', form) | |
| 365 except Unauthorised as err: | |
| 366 self.fail('raised %s' % err) | |
| 367 finally: | |
| 368 self.db.setCurrentUser('joe') | |
| 369 | |
| 370 def testDeleteAttributeUri(self): | |
| 371 """ | |
| 372 Test Delete an attribute | |
| 373 """ | |
| 374 # create a new issue with userid 1 in the nosy list | |
| 375 issue_id = self.db.issue.create(title='foo', nosy=['1']) | |
| 376 | |
| 377 # remove the title and nosy | |
| 378 results = self.server.delete_attribute( | |
| 379 'issue', issue_id, 'title', self.empty_form | |
| 380 ) | |
| 381 self.assertEqual(self.dummy_client.response_code, 200) | |
| 382 | |
| 383 results = self.server.delete_attribute( | |
| 384 'issue', issue_id, 'nosy', self.empty_form | |
| 385 ) | |
| 386 self.assertEqual(self.dummy_client.response_code, 200) | |
| 387 | |
| 388 # verify the result | |
| 389 results = self.server.get_element('issue', issue_id, self.empty_form) | |
| 390 results = results['data'] | |
| 391 self.assertEqual(self.dummy_client.response_code, 200) | |
| 392 self.assertEqual(len(results['attributes']['nosy']), 0) | |
| 393 self.assertListEqual(results['attributes']['nosy'], []) | |
| 394 self.assertEqual(results['attributes']['title'], None) | |
| 395 | |
| 396 def testPatchAdd(self): | |
| 397 """ | |
| 398 Test Patch op 'Add' | |
| 399 """ | |
| 400 # create a new issue with userid 1 in the nosy list | |
| 401 issue_id = self.db.issue.create(title='foo', nosy=['1']) | |
| 402 | |
| 403 # add userid 2 to the nosy list | |
| 404 form = cgi.FieldStorage() | |
| 405 form.list = [ | |
| 406 cgi.MiniFieldStorage('op', 'add'), | |
| 407 cgi.MiniFieldStorage('nosy', '2') | |
| 408 ] | |
| 409 results = self.server.patch_element('issue', issue_id, form) | |
| 410 self.assertEqual(self.dummy_client.response_code, 200) | |
| 411 | |
| 412 # verify the result | |
| 413 results = self.server.get_element('issue', issue_id, self.empty_form) | |
| 414 results = results['data'] | |
| 415 self.assertEqual(self.dummy_client.response_code, 200) | |
| 416 self.assertEqual(len(results['attributes']['nosy']), 2) | |
| 417 self.assertListEqual(results['attributes']['nosy'], ['1', '2']) | |
| 418 | |
| 419 def testPatchReplace(self): | |
| 420 """ | |
| 421 Test Patch op 'Replace' | |
| 422 """ | |
| 423 # create a new issue with userid 1 in the nosy list and status = 1 | |
| 424 issue_id = self.db.issue.create(title='foo', nosy=['1'], status='1') | |
| 425 | |
| 426 # replace userid 2 to the nosy list and status = 3 | |
| 427 form = cgi.FieldStorage() | |
| 428 form.list = [ | |
| 429 cgi.MiniFieldStorage('op', 'replace'), | |
| 430 cgi.MiniFieldStorage('nosy', '2'), | |
| 431 cgi.MiniFieldStorage('status', '3') | |
| 432 ] | |
| 433 results = self.server.patch_element('issue', issue_id, form) | |
| 434 self.assertEqual(self.dummy_client.response_code, 200) | |
| 435 | |
| 436 # verify the result | |
| 437 results = self.server.get_element('issue', issue_id, self.empty_form) | |
| 438 results = results['data'] | |
| 439 self.assertEqual(self.dummy_client.response_code, 200) | |
| 440 self.assertEqual(results['attributes']['status'], '3') | |
| 441 self.assertEqual(len(results['attributes']['nosy']), 1) | |
| 442 self.assertListEqual(results['attributes']['nosy'], ['2']) | |
| 443 | |
| 444 def testPatchRemoveAll(self): | |
| 445 """ | |
| 446 Test Patch Action 'Remove' | |
| 447 """ | |
| 448 # create a new issue with userid 1 and 2 in the nosy list | |
| 449 issue_id = self.db.issue.create(title='foo', nosy=['1', '2']) | |
| 450 | |
| 451 # remove the nosy list and the title | |
| 452 form = cgi.FieldStorage() | |
| 453 form.list = [ | |
| 454 cgi.MiniFieldStorage('op', 'remove'), | |
| 455 cgi.MiniFieldStorage('nosy', ''), | |
| 456 cgi.MiniFieldStorage('title', '') | |
| 457 ] | |
| 458 results = self.server.patch_element('issue', issue_id, form) | |
| 459 self.assertEqual(self.dummy_client.response_code, 200) | |
| 460 | |
| 461 # verify the result | |
| 462 results = self.server.get_element('issue', issue_id, self.empty_form) | |
| 463 results = results['data'] | |
| 464 self.assertEqual(self.dummy_client.response_code, 200) | |
| 465 self.assertEqual(results['attributes']['title'], None) | |
| 466 self.assertEqual(len(results['attributes']['nosy']), 0) | |
| 467 self.assertEqual(results['attributes']['nosy'], []) | |
| 468 | |
| 469 def testPatchAction(self): | |
| 470 """ | |
| 471 Test Patch Action 'Action' | |
| 472 """ | |
| 473 # create a new issue with userid 1 and 2 in the nosy list | |
| 474 issue_id = self.db.issue.create(title='foo') | |
| 475 | |
| 476 # execute action retire | |
| 477 form = cgi.FieldStorage() | |
| 478 form.list = [ | |
| 479 cgi.MiniFieldStorage('op', 'action'), | |
| 480 cgi.MiniFieldStorage('action_name', 'retire') | |
| 481 ] | |
| 482 results = self.server.patch_element('issue', issue_id, form) | |
| 483 self.assertEqual(self.dummy_client.response_code, 200) | |
| 484 | |
| 485 # verify the result | |
| 486 self.assertTrue(self.db.issue.is_retired(issue_id)) | |
| 487 | |
| 488 def testPatchRemove(self): | |
| 489 """ | |
| 490 Test Patch Action 'Remove' only some element from a list | |
| 491 """ | |
| 492 # create a new issue with userid 1, 2, 3 in the nosy list | |
| 493 issue_id = self.db.issue.create(title='foo', nosy=['1', '2', '3']) | |
| 494 | |
| 495 # remove the nosy list and the title | |
| 496 form = cgi.FieldStorage() | |
| 497 form.list = [ | |
| 498 cgi.MiniFieldStorage('op', 'remove'), | |
| 499 cgi.MiniFieldStorage('nosy', '1, 2'), | |
| 500 ] | |
| 501 results = self.server.patch_element('issue', issue_id, form) | |
| 502 self.assertEqual(self.dummy_client.response_code, 200) | |
| 503 | |
| 504 # verify the result | |
| 505 results = self.server.get_element('issue', issue_id, self.empty_form) | |
| 506 results = results['data'] | |
| 507 self.assertEqual(self.dummy_client.response_code, 200) | |
| 508 self.assertEqual(len(results['attributes']['nosy']), 1) | |
| 509 self.assertEqual(results['attributes']['nosy'], ['3']) | |
| 510 | |
| 511 | |
| 512 def get_obj(path, id): | |
| 513 return { | |
| 514 'id': id, | |
| 515 'link': path + id | |
| 516 } | |
| 517 | |
| 518 if __name__ == '__main__': | |
| 519 runner = unittest.TextTestRunner() | |
| 520 unittest.main(testRunner=runner) |
