def test_misc(self): """ Tests miscellaneous functions """ service_url = 'http://somehost.com/service' with patch('cadcutils.net.ws.WsCapabilities') as caps_mock: caps_mock.return_value.get_service_host.return_value =\ 'somehost.com' caps_mock.return_value.get_access_url.return_value = service_url client = ws.BaseWsClient("someresourceID", auth.Subject(), 'TestApp') self.assertEqual('{}'.format(service_url), client._get_url(('myfeature', None))) caps_mock.return_value.get_access_url.assert_called_with( 'myfeature') self.assertEqual('{}'.format(service_url), client._get_url(('myfeature', ''))) test_host = 'testhost.com' with patch('cadcutils.net.ws.os.makedirs'): client = ws.BaseWsClient("someresourceID", auth.Subject(), 'TestApp', host=test_host) self.assertEqual(test_host, client.host) # test with resource as url with patch('cadcutils.net.ws.WsCapabilities') as caps_mock: caps_mock.return_value.get_service_host.return_value =\ 'somehost.com' cm = Mock() cm.get_access_url.return_value = "http://host/availability" caps_mock.return_value = cm client = ws.BaseWsClient("someresourceID", auth.Subject(), 'TestApp') resource_url = 'http://someurl.com/path/' self.assertEqual(resource_url, client._get_url(resource_url)) # repeat with overriden host name client = ws.BaseWsClient("someresourceID", auth.Subject(), 'TestApp', host=test_host) # same result self.assertEqual(resource_url, client._get_url(resource_url)) # test exceptions with different status in the response session = ws.RetrySession() response = requests.Response() response.status_code = requests.codes.not_found with self.assertRaises(exceptions.NotFoundException): session.check_status(response) response.status_code = requests.codes.unauthorized with self.assertRaises(exceptions.UnauthorizedException): session.check_status(response) response.status_code = requests.codes.forbidden with self.assertRaises(exceptions.ForbiddenException): session.check_status(response) response.status_code = requests.codes.bad_request with self.assertRaises(exceptions.BadRequestException): session.check_status(response) response.status_code = requests.codes.conflict with self.assertRaises(exceptions.AlreadyExistsException): session.check_status(response) response.status_code = requests.codes.internal_server_error with self.assertRaises(exceptions.InternalServerException): session.check_status(response) response.status_code = requests.codes.unavailable with self.assertRaises(requests.HTTPError): session.check_status(response) response.status_code = requests.codes.not_extended with self.assertRaises(exceptions.UnexpectedException): session.check_status(response)
def test_retry(self, send_mock, time_mock): request = Mock() send_mock.return_value = Mock() rs = ws.RetrySession(False) rs.send(request) send_mock.assert_called_with(request, timeout=30) # retry to user defined timeout send_mock.return_value = Mock() rs = ws.RetrySession(False) rs.send(request, timeout=77) send_mock.assert_called_with(request, timeout=77) # mock delays for the 'Connection reset by peer error' # one connection error delay = DEFAULT_RETRY_DELAY send_mock.reset_mock() rs = ws.RetrySession() # connection error that triggers retries ce = requests.exceptions.ConnectionError() ce.errno = 104 response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [ce, response] rs.send(request) time_mock.assert_called_with(DEFAULT_RETRY_DELAY) # two connection error delay = DEFAULT_RETRY_DELAY send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession() # connection error that triggers retries ce = requests.exceptions.ConnectionError() ce.errno = 104 response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [ce, ce, response] # two connection errors rs.send(request) calls = [call(DEFAULT_RETRY_DELAY), call(DEFAULT_RETRY_DELAY * 2)] time_mock.assert_has_calls(calls) # set the start retry to a large number and see how it is capped # to MAX_RETRY_DELAY send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession(start_delay=MAX_RETRY_DELAY / 2 + 1) # connection error that triggers retries ce = requests.exceptions.ConnectionError() ce.errno = 104 response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [ce, ce, response] # two connection errors rs.send(request) calls = (call(MAX_RETRY_DELAY / 2 + 1), call(MAX_RETRY_DELAY)) time_mock.assert_has_calls(calls) # return the error all the time send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession(start_delay=MAX_RETRY_DELAY / 2 + 1) # connection error that triggers retries ce = requests.exceptions.ConnectionError() ce.errno = 104 # make sure the mock returns more errors than the maximum number # of retries allowed http_errors = [] i = 0 while i <= MAX_NUM_RETRIES: http_errors.append(ce) i += 1 send_mock.side_effect = http_errors with self.assertRaises(exceptions.HttpException): rs.send(request) # return the connection error other than 104 - connection reset by peer send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession(start_delay=MAX_RETRY_DELAY / 2 + 1) # connection error that triggers retries ce = requests.exceptions.ConnectionError() ce.errno = 105 send_mock.side_effect = ce with self.assertRaises(exceptions.HttpException): rs.send(request) # return HttpError 503 with Retry-After send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession() server_delay = 5 # connection error that triggers retries he = requests.exceptions.HTTPError() he.response = requests.Response() he.response.status_code = requests.codes.unavailable he.response.headers[SERVICE_RETRY] = server_delay response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [he, response] rs.send(request) calls = [call(server_delay)] time_mock.assert_has_calls(calls) # return HttpError 503 with Retry-After with an invalid value send_mock.reset_mock() time_mock.reset_mock() start_delay = 66 rs = ws.RetrySession(start_delay=start_delay) server_delay = 'notnumber' # connection error that triggers retries he = requests.exceptions.HTTPError() he.response = requests.Response() he.response.status_code = requests.codes.unavailable he.response.headers[SERVICE_RETRY] = server_delay response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [he, response] rs.send(request) calls = [call(start_delay)] # uses the default delay time_mock.assert_has_calls(calls) # return HttpError 503 with no Retry-After send_mock.reset_mock() time_mock.reset_mock() start_delay = 66 rs = ws.RetrySession(start_delay=start_delay) he = requests.exceptions.HTTPError() he.response = requests.Response() he.response.status_code = requests.codes.unavailable response = requests.Response() response.status_code = requests.codes.ok send_mock.side_effect = [he, response] rs.send(request) calls = [call(start_delay)] # uses the default delay time_mock.assert_has_calls(calls) # tests non-transient errors send_mock.reset_mock() time_mock.reset_mock() rs = ws.RetrySession() he = requests.exceptions.HTTPError() he.response = requests.Response() he.response.status_code = requests.codes.internal_server_error send_mock.side_effect = he with self.assertRaises(exceptions.HttpException): rs.send(request)