Mercurial > p > roundup > code
diff test/test_liveserver.py @ 6525:c505c774a94d
Mutiple changes to REST code.
Requesting an invalid attribut via rest/data/class/id/attrib used to
return a 405, it now returns a 400 and a better error message.
/rest/ response scans the registered endpoints rather than using a
hard coded description. So new endpoints added in interfaces.py are
listed.
Fix a number of Allow headers that were listing invalid methods. Also
when invalid method is used, report valid methods in response. Extract
methods from Route list.
Fix Access-Control-Allow-Methods. Add X-Requested-With to
Access-Control-Allow-Headers.
Add decorator openapi_doc to add openapi annotations for the rest
endpoints. Added a couple of examples. Returning this info to a
client is still a work in progress.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Sun, 07 Nov 2021 01:04:43 -0500 |
| parents | 1fc765ef6379 |
| children | 3c8322e3fe25 |
line wrap: on
line diff
--- a/test/test_liveserver.py Sun Nov 07 01:49:03 2021 -0400 +++ b/test/test_liveserver.py Sun Nov 07 01:04:43 2021 -0500 @@ -95,6 +95,34 @@ self.assertTrue(b'Creator' in f.content) + def test_rest_invalid_method_collection(self): + # use basic auth for rest endpoint + f = requests.put(self.url_base() + '/rest/data/user', + auth=('admin', 'sekrit'), + headers = {'content-type': "", + 'x-requested-with': "rest"}) + import pdb; pdb.set_trace() + print(f.status_code) + print(f.headers) + print(f.content) + + self.assertEqual(f.status_code, 405) + expected = { 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', + 'Allow': 'DELETE, GET, OPTIONS, POST', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', + } + + print(f.headers) + # use dict comprehension to remove fields like date, + # content-length etc. from f.headers. + self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected) + + content = json.loads(f.content) + + exp_content = "Method PUT not allowed. Allowed: DELETE, GET, OPTIONS, POST" + self.assertEqual(exp_content, content['error']['msg']) + def test_http_options(self): """ options returns an unimplemented error for this case.""" @@ -114,9 +142,9 @@ self.assertEqual(f.status_code, 204) expected = { 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } # use dict comprehension to remove fields like date, @@ -134,9 +162,9 @@ self.assertEqual(f.status_code, 204) expected = { 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } # use dict comprehension to remove fields like date, @@ -153,9 +181,9 @@ self.assertEqual(f.status_code, 204) expected = { 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } # use dict comprehension to remove fields like date, @@ -173,9 +201,9 @@ self.assertEqual(f.status_code, 204) expected = { 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } # use dict comprehension to remove fields like date, @@ -192,9 +220,9 @@ self.assertEqual(f.status_code, 204) expected = { 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } # use dict comprehension to remove fields like date, @@ -382,9 +410,9 @@ self.assertEqual(f.status_code, 200) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', 'Content-Encoding': 'gzip', 'Vary': 'Accept-Encoding', } @@ -427,20 +455,19 @@ print(f.status_code) print(f.headers) - # ERROR: attribute error turns into 405, not sure that's right. # NOTE: not compressed payload too small - self.assertEqual(f.status_code, 405) + self.assertEqual(f.status_code, 400) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } content = { "error": { - "status": 405, - "msg": "'foo'" + "status": 400, + "msg": "Invalid attribute foo" } } @@ -509,9 +536,9 @@ self.assertEqual(f.status_code, 200) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', 'Content-Encoding': 'br', 'Vary': 'Accept-Encoding', } @@ -555,20 +582,20 @@ 'Accept': '*/*'}) print(f.status_code) print(f.headers) - # ERROR: attribute error turns into 405, not sure that's right. + # Note: not compressed payload too small - self.assertEqual(f.status_code, 405) + self.assertEqual(f.status_code, 400) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } content = { "error": { - "status": 405, - "msg": "'foo'" + "status": 400, + "msg": "Invalid attribute foo" } } json_dict = json.loads(b2s(f.content)) @@ -655,9 +682,9 @@ self.assertEqual(f.status_code, 200) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', 'Content-Encoding': 'zstd', 'Vary': 'Accept-Encoding', } @@ -703,20 +730,19 @@ print(f.status_code) print(f.headers) - # ERROR: attribute error turns into 405, not sure that's right. # Note: not compressed, payload too small - self.assertEqual(f.status_code, 405) + self.assertEqual(f.status_code, 400) expected = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override', 'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH', - 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH', + 'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH', } content = { "error": { - "status": 405, - "msg": "'foo'" + "status": 400, + "msg": "Invalid attribute foo" } }
