comparison test/rest_common.py @ 6311:be8d5a8e090a

Fix uncaught error when parsing rest headers, document Started this work as better docs for rest response format. But I found 406 error response was not being tested. Also there was no error for bad Content-Type. In rest.py fix uncaught exceptions due to invalid Accept or Content-Type headers. If Content-type is valid but not application/json return code 415. Document use of accept header (was only shown in examples) and support for q parameter. Describe using .xml and .json extensions to select return format for testing from browser (where setting accept header is a problem). Document 406 error code return. Document 415 error code return and acceptable content types. Previously only doc was in examples. Set up tests for 406 and 415 error codes.
author John Rouillard <rouilj@ieee.org>
date Fri, 01 Jan 2021 14:14:34 -0500
parents 29c6dc8ed004
children 6ef7b66774b4
comparison
equal deleted inserted replaced
6310:68d83479747b 6311:be8d5a8e090a
1319 self.assertEqual(len(json_dict['data']['attributes']['nosy']), 3) 1319 self.assertEqual(len(json_dict['data']['attributes']['nosy']), 3)
1320 self.assertEqual(json_dict['data']['attributes']\ 1320 self.assertEqual(json_dict['data']['attributes']\
1321 ['assignedto']['link'], 1321 ['assignedto']['link'],
1322 "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/user/2") 1322 "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data/user/2")
1323 1323
1324 def testDispatchBadContent(self):
1325 """
1326 runthrough rest dispatch() with bad content_type patterns.
1327 """
1328
1329 # simulate: /rest/data/issue
1330 body=b'{ "title": "Joe Doe has problems", \
1331 "nosy": [ "1", "3" ], \
1332 "assignedto": "2", \
1333 "abool": true, \
1334 "afloat": 2.3, \
1335 "anint": 567890 \
1336 }'
1337 env = { "CONTENT_TYPE": "application/jzot",
1338 "CONTENT_LENGTH": len(body),
1339 "REQUEST_METHOD": "POST"
1340 }
1341
1342 headers={"accept": "application/json; version=1",
1343 "content-type": env['CONTENT_TYPE'],
1344 "content-length": env['CONTENT_LENGTH'],
1345 }
1346
1347 self.headers=headers
1348 # we need to generate a FieldStorage the looks like
1349 # FieldStorage(None, None, 'string') rather than
1350 # FieldStorage(None, None, [])
1351 body_file=BytesIO(body) # FieldStorage needs a file
1352 form = client.BinaryFieldStorage(body_file,
1353 headers=headers,
1354 environ=env)
1355 self.server.client.request.headers.get=self.get_header
1356 results = self.server.dispatch(env["REQUEST_METHOD"],
1357 "/rest/data/issue",
1358 form)
1359
1360 print(results)
1361 self.assertEqual(self.server.client.response_code, 415)
1362 json_dict = json.loads(b2s(results))
1363 self.assertEqual(json_dict['error']['msg'],
1364 "Unable to process input of type application/jzot")
1365
1366 # Test GET as well. I am not sure if this should pass or not.
1367 # Arguably GET doesn't use any form/json input but....
1368 results = self.server.dispatch('GET',
1369 "/rest/data/issue",
1370 form)
1371 print(results)
1372 self.assertEqual(self.server.client.response_code, 415)
1373
1374
1375
1376 def testDispatchBadAccept(self):
1377 # simulate: /rest/data/issue expect failure unknown accept settings
1378 body=b'{ "title": "Joe Doe has problems", \
1379 "nosy": [ "1", "3" ], \
1380 "assignedto": "2", \
1381 "abool": true, \
1382 "afloat": 2.3, \
1383 "anint": 567890 \
1384 }'
1385 env = { "CONTENT_TYPE": "application/json",
1386 "CONTENT_LENGTH": len(body),
1387 "REQUEST_METHOD": "POST"
1388 }
1389
1390 headers={"accept": "application/zot; version=1; q=0.5",
1391 "content-type": env['CONTENT_TYPE'],
1392 "content-length": env['CONTENT_LENGTH'],
1393 }
1394
1395 self.headers=headers
1396 # we need to generate a FieldStorage the looks like
1397 # FieldStorage(None, None, 'string') rather than
1398 # FieldStorage(None, None, [])
1399 body_file=BytesIO(body) # FieldStorage needs a file
1400 form = client.BinaryFieldStorage(body_file,
1401 headers=headers,
1402 environ=env)
1403 self.server.client.request.headers.get=self.get_header
1404 results = self.server.dispatch(env["REQUEST_METHOD"],
1405 "/rest/data/issue",
1406 form)
1407
1408 print(results)
1409 self.assertEqual(self.server.client.response_code, 406)
1410 self.assertIn(b"Requested content type 'application/zot; version=1; q=0.5' is not available.\nAcceptable types: */*, application/json,", results)
1411
1412 # simulate: /rest/data/issue works, multiple acceptable output, one
1413 # is valid
1414 env = { "CONTENT_TYPE": "application/json",
1415 "CONTENT_LENGTH": len(body),
1416 "REQUEST_METHOD": "POST"
1417 }
1418
1419 headers={"accept": "application/zot; version=1; q=0.75, "
1420 "application/json; version=1; q=0.5",
1421 "content-type": env['CONTENT_TYPE'],
1422 "content-length": env['CONTENT_LENGTH'],
1423 }
1424
1425 self.headers=headers
1426 # we need to generate a FieldStorage the looks like
1427 # FieldStorage(None, None, 'string') rather than
1428 # FieldStorage(None, None, [])
1429 body_file=BytesIO(body) # FieldStorage needs a file
1430 form = client.BinaryFieldStorage(body_file,
1431 headers=headers,
1432 environ=env)
1433 self.server.client.request.headers.get=self.get_header
1434 results = self.server.dispatch(env["REQUEST_METHOD"],
1435 "/rest/data/issue",
1436 form)
1437
1438 print(results)
1439 self.assertEqual(self.server.client.response_code, 201)
1440 json_dict = json.loads(b2s(results))
1441 # ERROR this should be 1. What's happening is that the code
1442 # for handling 406 error code runs through everything and creates
1443 # the item. Then it throws a 406 after the work is done when it
1444 # realizes it can't respond as requested. So the 406 post above
1445 # creates issue 1 and this one creates issue 2.
1446 self.assertEqual(json_dict['data']['id'], "2")
1447
1448
1449 # test 3 accept is empty. This triggers */* so passes
1450 headers={"accept": "",
1451 "content-type": env['CONTENT_TYPE'],
1452 "content-length": env['CONTENT_LENGTH'],
1453 }
1454
1455 self.headers=headers
1456 # we need to generate a FieldStorage the looks like
1457 # FieldStorage(None, None, 'string') rather than
1458 # FieldStorage(None, None, [])
1459 body_file=BytesIO(body) # FieldStorage needs a file
1460 form = client.BinaryFieldStorage(body_file,
1461 headers=headers,
1462 environ=env)
1463 self.server.client.request.headers.get=self.get_header
1464 results = self.server.dispatch(env["REQUEST_METHOD"],
1465 "/rest/data/issue",
1466 form)
1467
1468 print(results)
1469 self.assertEqual(self.server.client.response_code, 201)
1470 json_dict = json.loads(b2s(results))
1471 # This is one more than above. Will need to be fixed
1472 # When error above is fixed.
1473 self.assertEqual(json_dict['data']['id'], "3")
1474
1475 # test 4 accept is random junk.
1476 headers={"accept": "Xyzzy I am not a mime, type;",
1477 "content-type": env['CONTENT_TYPE'],
1478 "content-length": env['CONTENT_LENGTH'],
1479 }
1480
1481 self.headers=headers
1482 # we need to generate a FieldStorage the looks like
1483 # FieldStorage(None, None, 'string') rather than
1484 # FieldStorage(None, None, [])
1485 body_file=BytesIO(body) # FieldStorage needs a file
1486 form = client.BinaryFieldStorage(body_file,
1487 headers=headers,
1488 environ=env)
1489 self.server.client.request.headers.get=self.get_header
1490 results = self.server.dispatch(env["REQUEST_METHOD"],
1491 "/rest/data/issue",
1492 form)
1493
1494 print(results)
1495 self.assertEqual(self.server.client.response_code, 406)
1496 json_dict = json.loads(b2s(results))
1497 self.assertIn('Unable to parse Accept Header. Invalid media type: Xyzzy I am not a mime. Acceptable types: */* application/json', json_dict['error']['msg'])
1498
1499 # test 5 accept mimetype is ok, param is not
1500 headers={"accept": "*/*; foo",
1501 "content-type": env['CONTENT_TYPE'],
1502 "content-length": env['CONTENT_LENGTH'],
1503 }
1504
1505 self.headers=headers
1506 # we need to generate a FieldStorage the looks like
1507 # FieldStorage(None, None, 'string') rather than
1508 # FieldStorage(None, None, [])
1509 body_file=BytesIO(body) # FieldStorage needs a file
1510 form = client.BinaryFieldStorage(body_file,
1511 headers=headers,
1512 environ=env)
1513 self.server.client.request.headers.get=self.get_header
1514 results = self.server.dispatch(env["REQUEST_METHOD"],
1515 "/rest/data/issue",
1516 form)
1517
1518 print(results)
1519 self.assertEqual(self.server.client.response_code, 406)
1520 json_dict = json.loads(b2s(results))
1521 self.assertIn('Unable to parse Accept Header. Invalid param: foo. Acceptable types: */* application/json', json_dict['error']['msg'])
1324 1522
1325 def testStatsGen(self): 1523 def testStatsGen(self):
1326 # check stats being returned by put and get ops 1524 # check stats being returned by put and get ops
1327 # using dispatch which parses the @stats query param 1525 # using dispatch which parses the @stats query param
1328 1526

Roundup Issue Tracker: http://roundup-tracker.org/