Skip to content
This repository has been archived by the owner on Nov 5, 2019. It is now read-only.

Solidify transport interface #654

Merged
merged 15 commits into from Sep 26, 2016

Conversation

theacodes
Copy link
Contributor

These changes solidify the transport interface.

  • Add a transport compliance test (see note below). This is use to qualify transport implementations work as expected.
  • Bring httplib2 transport into compliance.
  • Make transport._request private.
  • Define the transport._request return value.
  • Remove all usage of transport.request in tests in favor of using authed_http directly, just as users would.

Note about compliance tests:
This is the first test in the module to use pytest fixtures as well as use pytest's test & assertion styles. We eventually want to move toward pytest style tests (I plan to do so as I refactor each module for #597), so I'm hoping this won't be controversial. If it is, I'm happy to switch to unittest-style, but I'll be keeping the extremely useful pytest-localserver fixture.

(Also I'm starting to see the light at the end of the tunnel here)

http, self.server.url + '/basic')

assert response.status == http_client.OK
print(response.headers.keys())

This comment was marked as spam.

This comment was marked as spam.

self.token = '{}{}'.format(self.token, '-new')


class TransportComplianceTests(object):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

def test_connection_error(self):
http = self.transport.get_http_object()

with pytest.raises(Exception):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

def request(http, uri, method='GET', body=None, headers=None,
redirections=httplib2.DEFAULT_MAX_REDIRECTS,
**kwargs):
class _ResponseWrapper(object):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

redirections = 3

def test_with_request_attr(self):
def test_it(self):

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

try:
d = json.loads(_helpers._from_bytes(content))
d = json.loads(_helpers._from_bytes(response.data))

This comment was marked as spam.

This comment was marked as spam.

http, _GCE_METADATA_URI, headers=_GCE_HEADERS)
return (
response.status == http_client.OK and
response.get(_METADATA_FLAVOR_HEADER) == _DESIRED_METADATA_FLAVOR)
response.headers.get(
_METADATA_FLAVOR_HEADER) == _DESIRED_METADATA_FLAVOR)

This comment was marked as spam.

This comment was marked as spam.

if 'error' in d:
# you never know what those providers got to say
error_msg = (str(d['error']) +
str(d.get('error_description', '')))
else:
error_msg = 'Invalid response: {0}.'.format(str(resp.status))
error_msg = 'Invalid response: {0}.'.format(
str(response.status))

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

http = self.credentials.authorize(http)
transport.request(http, 'http://example.com')
authed_http = self.credentials.authorize(http)
authed_http = self.credentials.authorize(http)

This comment was marked as spam.

This comment was marked as spam.


return flask.jsonify({
'authorization': flask.request.headers.get('authorization'),
'user_agent': flask.request.headers.get('user-agent')

This comment was marked as spam.

This comment was marked as spam.

class TransportComplianceTests(object):
"""Test base class to confirm that a transport satisfies the interface
expected by oauth2client."""
transport = None

This comment was marked as spam.

@pytest.fixture(autouse=True)
def testserver(self):
"""Provides a test HTTP server that is automatically created before
a test and destoryed at the end. This server is running the test

This comment was marked as spam.

This comment was marked as spam.

response = self.transport._request(
authed_http, self.server.url + '/authorized')

content = json.loads(response.data.decode('utf-8'))

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

content = json.loads(response.data.decode('utf-8'))

assert credentials.token == 'token'
assert content['authorization'] == 'Bearer {}'.format(

This comment was marked as spam.

This comment was marked as spam.

Copy link
Contributor Author

@theacodes theacodes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, @dhermes.

try:
d = json.loads(_helpers._from_bytes(content))
d = json.loads(_helpers._from_bytes(response.data))

This comment was marked as spam.

http, _GCE_METADATA_URI, headers=_GCE_HEADERS)
return (
response.status == http_client.OK and
response.get(_METADATA_FLAVOR_HEADER) == _DESIRED_METADATA_FLAVOR)
response.headers.get(
_METADATA_FLAVOR_HEADER) == _DESIRED_METADATA_FLAVOR)

This comment was marked as spam.

if 'error' in d:
# you never know what those providers got to say
error_msg = (str(d['error']) +
str(d.get('error_description', '')))
else:
error_msg = 'Invalid response: {0}.'.format(str(resp.status))
error_msg = 'Invalid response: {0}.'.format(
str(response.status))

This comment was marked as spam.

"""Makes an HTTP request.

Args:
http_object: The transport-specific http object to be used to make

This comment was marked as spam.

* headers: dict, the HTTP response headers.
* data: bytes, the HTTP response body.
"""
return get_default_transport()._request(

This comment was marked as spam.

@pytest.fixture(autouse=True)
def testserver(self):
"""Provides a test HTTP server that is automatically created before
a test and destoryed at the end. This server is running the test

This comment was marked as spam.

http, self.server.url + '/basic')

assert response.status == http_client.OK
print(response.headers.keys())

This comment was marked as spam.

def test_connection_error(self):
http = self.transport.get_http_object()

with pytest.raises(Exception):

This comment was marked as spam.

response = self.transport._request(
authed_http, self.server.url + '/authorized')

content = json.loads(response.data.decode('utf-8'))

This comment was marked as spam.

content = json.loads(response.data.decode('utf-8'))

assert credentials.token == 'token'
assert content['authorization'] == 'Bearer {}'.format(

This comment was marked as spam.

http = self.credentials.authorize(http)
transport.request(http, 'http://example.com')
authed_http = self.credentials.authorize(http)
# Double-wrap

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

@theacodes
Copy link
Contributor Author

@dhermes it seems like the remainder of your concerns (save the one about exceptions) can be fixed by making transport.request public again. It's used throughout the package, but I don't not want users to use it directly. Are the concerns you have reason enough to make it public?

@dhermes
Copy link
Contributor

dhermes commented Sep 21, 2016

Are the concerns you have reason enough to make it public?

Not sure.

@theacodes
Copy link
Contributor Author

I'll let @nathanielmanistaatgoogle decide.

@@ -29,6 +29,9 @@
_MAX_REFRESH_ATTEMPTS = 2


exceptions = (httplib2.HttpLib2Error,)

This comment was marked as spam.

This comment was marked as spam.

@theacodes
Copy link
Contributor Author

@nathanielmanistaatgoogle can you weigh in on the contentious topic on making transport.request private?

@theacodes
Copy link
Contributor Author

@dhermes I've made request public again. I'm going to try to make the entire transport module private.

@theacodes theacodes merged commit d4b3c97 into googleapis:transport-refactor Sep 26, 2016
@theacodes theacodes deleted the tr-4-transport-test branch September 26, 2016 17:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants