Skip to content

Commit 99798ec

Browse files
committed
Added some more rest testing and make sure api version is valid.
1 parent 20f9359 commit 99798ec

File tree

2 files changed

+131
-17
lines changed

2 files changed

+131
-17
lines changed

roundup/rest.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,27 +1730,34 @@ def dispatch(self, method, uri, input):
17301730
pretty_output = True
17311731

17321732
# check for @apiver in query string
1733+
msg=( "Unrecognized version: %s. "
1734+
"See /rest without specifying version "
1735+
"for supported versions." )
17331736
try:
17341737
if not self.api_version:
17351738
self.api_version = int(input['@apiver'].value)
17361739
except KeyError:
17371740
self.api_version = None
17381741
except ValueError:
1739-
msg=( "Unrecognized version: %s. "
1740-
"See /rest without specifying version "
1741-
"for supported versions."%(
1742-
input['@apiver'].value))
1743-
output = self.error_obj(400, msg)
1742+
output = self.error_obj(400, msg%input['@apiver'].value)
1743+
1744+
# by this time the API version is set. Error if we don't
1745+
# support it?
1746+
if self.api_version is None:
1747+
# FIXME: do we need to raise an error if client did not specify
1748+
# version? This may be a good thing to require. Note that:
1749+
# Accept: application/json; version=1 may not be legal but....
1750+
# Use default if not specified for now.
1751+
self.api_version = self.__default_api_version
1752+
elif self.api_version not in self.__supported_api_versions:
1753+
raise UsageError(msg%self.api_version)
1754+
17441755
# sadly del doesn't work on FieldStorage which can be the type of
1745-
# input. So I have to ignore keys starting with @ at other
1756+
# input. So we have to ignore keys starting with @ at other
17461757
# places in the code.
17471758
# else:
17481759
# del(input['@apiver'])
17491760

1750-
# FIXME: do we need to raise an error if client did not specify
1751-
# version? This may be a good thing to require. Note that:
1752-
# Accept: application/json; version=1 may not be legal but....
1753-
17541761
# Call the appropriate method
17551762
try:
17561763
# If output was defined by a prior error

test/rest_common.py

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -954,9 +954,6 @@ def testDispatch(self):
954954
# TEST #5
955955
# POST: create new issue
956956
# no etag needed
957-
# FIXME at some point we probably want to implement
958-
# Post Once Only, so we need to add a Post Once Exactly
959-
# test and a resubmit as well.
960957
etag = "not needed"
961958
body=b'{ "title": "foo bar", "priority": "critical" }'
962959
env = { "CONTENT_TYPE": "application/json",
@@ -986,6 +983,101 @@ def testDispatch(self):
986983
self.assertEqual(self.dummy_client.response_code, 200)
987984
self.assertEqual(results['data']['attributes']['title'],
988985
'foo bar')
986+
987+
# TEST #6
988+
# POST: an invalid class
989+
# no etag needed
990+
etag = "not needed"
991+
body=b'{ "title": "foo bar", "priority": "critical" }'
992+
env = { "CONTENT_TYPE": "application/json",
993+
"CONTENT_LENGTH": len(body),
994+
"REQUEST_METHOD": "POST"
995+
}
996+
headers={"accept": "application/json",
997+
"content-type": env['CONTENT_TYPE'],
998+
"content-length": len(body)
999+
}
1000+
self.headers=headers
1001+
body_file=BytesIO(body) # FieldStorage needs a file
1002+
form = client.BinaryFieldStorage(body_file,
1003+
headers=headers,
1004+
environ=env)
1005+
self.server.client.request.headers.get=self.get_header
1006+
results = self.server.dispatch('POST',
1007+
"/rest/data/nonissue",
1008+
form)
1009+
1010+
self.assertEqual(self.server.client.response_code, 404)
1011+
json_dict = json.loads(b2s(results))
1012+
status=json_dict['error']['status']
1013+
msg=json_dict['error']['msg']
1014+
self.assertEqual(status, 404)
1015+
self.assertEqual(msg, 'Class nonissue not found')
1016+
1017+
# TEST #7
1018+
# POST: status without key field of name
1019+
# also test that version spec in accept header is accepted
1020+
# no etag needed
1021+
etag = "not needed"
1022+
body=b'{ "order": 5 }'
1023+
env = { "CONTENT_TYPE": "application/json",
1024+
"CONTENT_LENGTH": len(body),
1025+
"REQUEST_METHOD": "POST"
1026+
}
1027+
headers={"accept": "application/json; version=1",
1028+
"content-type": env['CONTENT_TYPE'],
1029+
"content-length": len(body)
1030+
}
1031+
self.headers=headers
1032+
body_file=BytesIO(body) # FieldStorage needs a file
1033+
form = client.BinaryFieldStorage(body_file,
1034+
headers=headers,
1035+
environ=env)
1036+
self.server.client.request.headers.get=self.get_header
1037+
self.db.setCurrentUser('admin') # must be admin to create status
1038+
results = self.server.dispatch('POST',
1039+
"/rest/data/status",
1040+
form)
1041+
1042+
self.assertEqual(self.server.client.response_code, 400)
1043+
json_dict = json.loads(b2s(results))
1044+
status=json_dict['error']['status']
1045+
msg=json_dict['error']['msg']
1046+
self.assertEqual(status, 400)
1047+
self.assertEqual(msg, "Must provide the 'name' property.")
1048+
1049+
1050+
# TEST #8
1051+
# DELETE: delete issue 1
1052+
etag = calculate_etag(self.db.issue.getnode("1"))
1053+
etagb = etag.strip ('"')
1054+
env = {"CONTENT_TYPE": "application/json",
1055+
"CONTENT_LEN": 0,
1056+
"REQUEST_METHOD": "DELETE" }
1057+
# use text/plain header and request json output by appending
1058+
# .json to the url.
1059+
headers={"accept": "text/plain",
1060+
"content-type": env['CONTENT_TYPE'],
1061+
"if-match": '"%s"'%etagb,
1062+
"content-length": 0,
1063+
}
1064+
self.headers=headers
1065+
body_file=BytesIO(b'') # FieldStorage needs a file
1066+
form = client.BinaryFieldStorage(body_file,
1067+
headers=headers,
1068+
environ=env)
1069+
self.server.client.request.headers.get=self.get_header
1070+
self.db.setCurrentUser('admin') # must be admin to delete issue
1071+
results = self.server.dispatch('DELETE',
1072+
"/rest/data/issue/1.json",
1073+
form)
1074+
self.assertEqual(self.server.client.response_code, 200)
1075+
json_dict = json.loads(b2s(results))
1076+
print(results)
1077+
status=json_dict['data']['status']
1078+
status=json_dict['data']['status']
1079+
self.assertEqual(status, 'ok')
1080+
9891081
del(self.headers)
9901082

9911083
def testPostPOE(self):
@@ -995,17 +1087,18 @@ def testPostPOE(self):
9951087
import time
9961088
# setup environment
9971089
etag = "not needed"
998-
body=b'{ "title": "foo bar", "priority": "critical" }'
1090+
empty_body=b''
9991091
env = { "CONTENT_TYPE": "application/json",
1000-
"CONTENT_LENGTH": len(body),
1092+
"CONTENT_LENGTH": len(empty_body),
10011093
"REQUEST_METHOD": "POST"
10021094
}
10031095
headers={"accept": "application/json",
10041096
"content-type": env['CONTENT_TYPE'],
1005-
"content-length": len(body)
1097+
"content-length": len(empty_body)
10061098
}
10071099
self.headers=headers
1008-
body_file=BytesIO(body) # FieldStorage needs a file
1100+
# use empty_body to test code path for missing/empty json
1101+
body_file=BytesIO(empty_body) # FieldStorage needs a file
10091102
form = client.BinaryFieldStorage(body_file,
10101103
headers=headers,
10111104
environ=env)
@@ -1024,6 +1117,20 @@ def testPostPOE(self):
10241117
url = url[len(self.db.config['TRACKER_WEB'])-1:]
10251118

10261119
## create an issue using poe url.
1120+
body=b'{ "title": "foo bar", "priority": "critical" }'
1121+
env = { "CONTENT_TYPE": "application/json",
1122+
"CONTENT_LENGTH": len(body),
1123+
"REQUEST_METHOD": "POST"
1124+
}
1125+
headers={"accept": "application/json",
1126+
"content-type": env['CONTENT_TYPE'],
1127+
"content-length": len(body)
1128+
}
1129+
self.headers=headers
1130+
body_file=BytesIO(body) # FieldStorage needs a file
1131+
form = client.BinaryFieldStorage(body_file,
1132+
headers=headers,
1133+
environ=env)
10271134
self.server.client.request.headers.get=self.get_header
10281135
results = self.server.dispatch('POST',
10291136
url,

0 commit comments

Comments
 (0)