comparison test/rest_common.py @ 7555:451232f83244

test: Modify testRestRateLimit test to report when system is too slow. Add an explicit check on the runtime and an error message that reports that the runtime was exceeded for the test to complete as written. testRestRateLimit requires that it finish within 3 seconds. Otherwise the number of remaining requests in the rate limit does not decrease on every call. If disk I/O is high, the anydbm version of this test can take > 3 seconds and result in a failed test. My other alternative was to measure the runtime and adjust the test to match the values that are returned. This seems like too much work and is unlikely to be an issue outside of a developers under powered system.
author John Rouillard <rouilj@ieee.org>
date Tue, 18 Jul 2023 23:18:09 -0400
parents 613f822f1f24
children 978285986b2c
comparison
equal deleted inserted replaced
7554:27476d1fca9f 7555:451232f83244
1074 # page_size < 0 1074 # page_size < 0
1075 # page_index < 0 1075 # page_index < 0
1076 1076
1077 def testRestRateLimit(self): 1077 def testRestRateLimit(self):
1078 1078
1079 self.db.config['WEB_API_CALLS_PER_INTERVAL'] = 20 1079 calls_per_interval = 20
1080 self.db.config['WEB_API_INTERVAL_IN_SEC'] = 60 1080 interval_sec = 60
1081 wait_time_str = str(int(interval_sec/calls_per_interval))
1082
1083 self.db.config['WEB_API_CALLS_PER_INTERVAL'] = calls_per_interval
1084 self.db.config['WEB_API_INTERVAL_IN_SEC'] = interval_sec
1081 1085
1082 # Otk code never passes through the 1086 # Otk code never passes through the
1083 # retry loop. Not sure why but I can force it 1087 # retry loop. Not sure why but I can force it
1084 # through the loop by setting the internal _db_type 1088 # through the loop by setting the internal _db_type
1085 # setting once the db is created by the previous command. 1089 # setting once the db is created by the previous command.
1088 except AttributeError: 1092 except AttributeError:
1089 # if dir attribute doesn't exist the primary db is not 1093 # if dir attribute doesn't exist the primary db is not
1090 # sqlite or anydbm. So don't need to exercise code. 1094 # sqlite or anydbm. So don't need to exercise code.
1091 pass 1095 pass
1092 1096
1093 print("Now realtime start:", datetime.utcnow()) 1097 start_time = datetime.utcnow()
1094 # don't set an accept header; json should be the default 1098 # don't set an accept header; json should be the default
1095 # use up all our allowed api calls 1099 # use up all our allowed api calls
1096 for i in range(20): 1100 for i in range(calls_per_interval):
1097 # i is 0 ... 19 1101 # i is 0 ... calls_per_interval
1098 self.client_error_message = [] 1102 self.client_error_message = []
1099 self.server.client.env.update({'REQUEST_METHOD': 'GET'}) 1103 self.server.client.env.update({'REQUEST_METHOD': 'GET'})
1100 results = self.server.dispatch('GET', 1104 results = self.server.dispatch('GET',
1101 "/rest/data/user/%s/realname"%self.joeid, 1105 "/rest/data/user/%s/realname"%self.joeid,
1102 self.empty_form) 1106 self.empty_form)
1103 1107
1108 loop_time = datetime.utcnow()
1109 self.assertLess((loop_time-start_time).total_seconds(),
1110 int(wait_time_str),
1111 "Test system is too slow to complete test as configured")
1112
1104 # is successful 1113 # is successful
1105 self.assertEqual(self.server.client.response_code, 200) 1114 self.assertEqual(self.server.client.response_code, 200)
1106 # does not have Retry-After header as we have 1115 # does not have Retry-After header as we have
1107 # suceeded with this query 1116 # suceeded with this query
1108 self.assertFalse("Retry-After" in 1117 self.assertFalse("Retry-After" in
1134 self.assertAlmostEqual( 1143 self.assertAlmostEqual(
1135 float(self.server.client.additional_headers["X-RateLimit-Reset"]), 1144 float(self.server.client.additional_headers["X-RateLimit-Reset"]),
1136 59, delta=5) 1145 59, delta=5)
1137 self.assertEqual( 1146 self.assertEqual(
1138 str(self.server.client.additional_headers["Retry-After"]), 1147 str(self.server.client.additional_headers["Retry-After"]),
1139 "3") # check as string 1148 wait_time_str) # check as string
1140 1149
1141 print("Reset:", self.server.client.additional_headers["X-RateLimit-Reset"]) 1150 print("Reset:", self.server.client.additional_headers["X-RateLimit-Reset"])
1142 print("Now realtime pre-sleep:", datetime.utcnow()) 1151 print("Now realtime pre-sleep:", datetime.utcnow())
1143 sleep(3.1) # sleep as requested so we can do another login 1152 # sleep as requested so we can do another login
1153 sleep(float(wait_time_str) + 0.1)
1144 print("Now realtime post-sleep:", datetime.utcnow()) 1154 print("Now realtime post-sleep:", datetime.utcnow())
1145 1155
1146 # this should succeed 1156 # this should succeed
1147 self.server.client.additional_headers.clear() 1157 self.server.client.additional_headers.clear()
1148 results = self.server.dispatch('GET', 1158 results = self.server.dispatch('GET',
1179 self.empty_form) 1189 self.empty_form)
1180 1190
1181 self.assertEqual(self.server.client.response_code, 429) 1191 self.assertEqual(self.server.client.response_code, 429)
1182 self.assertEqual( 1192 self.assertEqual(
1183 str(self.server.client.additional_headers["Retry-After"]), 1193 str(self.server.client.additional_headers["Retry-After"]),
1184 "3") # check as string 1194 wait_time_str) # check as string
1185 1195
1186 json_dict = json.loads(b2s(results)) 1196 json_dict = json.loads(b2s(results))
1187 self.assertEqual(json_dict['error']['msg'], 1197 self.assertEqual(
1188 "Api rate limits exceeded. Please wait: 3 seconds.") 1198 json_dict['error']['msg'],
1199 "Api rate limits exceeded. Please wait: %s seconds." %
1200 wait_time_str)
1189 1201
1190 # reset rest params 1202 # reset rest params
1191 self.db.config['WEB_API_CALLS_PER_INTERVAL'] = 0 1203 self.db.config['WEB_API_CALLS_PER_INTERVAL'] = 0
1192 self.db.config['WEB_API_INTERVAL_IN_SEC'] = 3600 1204 self.db.config['WEB_API_INTERVAL_IN_SEC'] = 3600
1193 1205

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