Skip to content

Commit 4c7b3be

Browse files
authored
Merge pull request googleapis#612 from dhermes/fix-599
Use transport module for GCE environment check.
2 parents 547d600 + e332a51 commit 4c7b3be

File tree

2 files changed

+41
-60
lines changed

2 files changed

+41
-60
lines changed

oauth2client/client.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,10 @@
108108
GCE_METADATA_TIMEOUT = 3
109109

110110
_SERVER_SOFTWARE = 'SERVER_SOFTWARE'
111-
_GCE_METADATA_HOST = '169.254.169.254'
112-
_METADATA_FLAVOR_HEADER = 'Metadata-Flavor'
111+
_GCE_METADATA_URI = 'http://169.254.169.254'
112+
_METADATA_FLAVOR_HEADER = 'metadata-flavor' # lowercase header
113113
_DESIRED_METADATA_FLAVOR = 'Google'
114+
_GCE_HEADERS = {_METADATA_FLAVOR_HEADER: _DESIRED_METADATA_FLAVOR}
114115

115116
# Expose utcnow() at module level to allow for
116117
# easier testing (by replacing with a stub).
@@ -997,21 +998,16 @@ def _detect_gce_environment():
997998
# could lead to false negatives in the event that we are on GCE, but
998999
# the metadata resolution was particularly slow. The latter case is
9991000
# "unlikely".
1000-
connection = six.moves.http_client.HTTPConnection(
1001-
_GCE_METADATA_HOST, timeout=GCE_METADATA_TIMEOUT)
1002-
1001+
http = transport.get_http_object(timeout=GCE_METADATA_TIMEOUT)
10031002
try:
1004-
headers = {_METADATA_FLAVOR_HEADER: _DESIRED_METADATA_FLAVOR}
1005-
connection.request('GET', '/', headers=headers)
1006-
response = connection.getresponse()
1007-
if response.status == http_client.OK:
1008-
return (response.getheader(_METADATA_FLAVOR_HEADER) ==
1009-
_DESIRED_METADATA_FLAVOR)
1003+
response, _ = transport.request(
1004+
http, _GCE_METADATA_URI, headers=_GCE_HEADERS)
1005+
return (
1006+
response.status == http_client.OK and
1007+
response.get(_METADATA_FLAVOR_HEADER) == _DESIRED_METADATA_FLAVOR)
10101008
except socket.error: # socket.timeout or socket.error(64, 'Host is down')
10111009
logger.info('Timeout attempting to reach GCE metadata service.')
10121010
return False
1013-
finally:
1014-
connection.close()
10151011

10161012

10171013
def _in_gae_environment():

tests/test_client.py

Lines changed: 32 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@
4242
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
4343

4444

45-
# TODO(craigcitro): This is duplicated from
46-
# googleapiclient.test_discovery; consolidate these definitions.
4745
def assertUrisEqual(testcase, expected, actual):
4846
"""Test that URIs are the same, up to reordering of query parameters."""
4947
expected = urllib.parse.urlparse(expected)
@@ -357,67 +355,41 @@ def test_environment_caching(self):
357355
# is cached.
358356
self.assertTrue(client._in_gae_environment())
359357

360-
def _environment_check_gce_helper(self, status_ok=True, socket_error=False,
358+
def _environment_check_gce_helper(self, status_ok=True,
361359
server_software=''):
362-
response = mock.Mock()
363360
if status_ok:
364-
response.status = http_client.OK
365-
response.getheader = mock.Mock(
366-
name='getheader',
367-
return_value=client._DESIRED_METADATA_FLAVOR)
361+
headers = {'status': http_client.OK}
362+
headers.update(client._GCE_HEADERS)
368363
else:
369-
response.status = http_client.NOT_FOUND
370-
371-
connection = mock.Mock()
372-
connection.getresponse = mock.Mock(name='getresponse',
373-
return_value=response)
374-
if socket_error:
375-
connection.getresponse.side_effect = socket.error()
364+
headers = {'status': http_client.NOT_FOUND}
376365

366+
http = http_mock.HttpMock(headers=headers)
377367
with mock.patch('oauth2client.client.os') as os_module:
378368
os_module.environ = {client._SERVER_SOFTWARE: server_software}
379-
with mock.patch('oauth2client.client.six') as six_module:
380-
http_client_module = six_module.moves.http_client
381-
http_client_module.HTTPConnection = mock.Mock(
382-
name='HTTPConnection', return_value=connection)
383-
369+
with mock.patch('oauth2client.transport.get_http_object',
370+
return_value=http) as new_http:
384371
if server_software == '':
385372
self.assertFalse(client._in_gae_environment())
386373
else:
387374
self.assertTrue(client._in_gae_environment())
388375

389-
if status_ok and not socket_error and server_software == '':
376+
if status_ok and server_software == '':
390377
self.assertTrue(client._in_gce_environment())
391378
else:
392379
self.assertFalse(client._in_gce_environment())
393380

381+
# Verify mocks.
394382
if server_software == '':
395-
http_client_module.HTTPConnection.assert_called_once_with(
396-
client._GCE_METADATA_HOST,
383+
new_http.assert_called_once_with(
397384
timeout=client.GCE_METADATA_TIMEOUT)
398-
connection.getresponse.assert_called_once_with()
399-
# Remaining calls are not "getresponse"
400-
headers = {
401-
client._METADATA_FLAVOR_HEADER: (
402-
client._DESIRED_METADATA_FLAVOR),
403-
}
404-
self.assertEqual(connection.method_calls, [
405-
mock.call.request('GET', '/',
406-
headers=headers),
407-
mock.call.close(),
408-
])
409-
self.assertEqual(response.method_calls, [])
410-
if status_ok and not socket_error:
411-
response.getheader.assert_called_once_with(
412-
client._METADATA_FLAVOR_HEADER)
385+
self.assertEqual(http.requests, 1)
386+
self.assertEqual(http.uri, client._GCE_METADATA_URI)
387+
self.assertEqual(http.method, 'GET')
388+
self.assertIsNone(http.body)
389+
self.assertEqual(http.headers, client._GCE_HEADERS)
413390
else:
414-
self.assertEqual(
415-
http_client_module.HTTPConnection.mock_calls, [])
416-
self.assertEqual(connection.getresponse.mock_calls, [])
417-
# Remaining calls are not "getresponse"
418-
self.assertEqual(connection.method_calls, [])
419-
self.assertEqual(response.method_calls, [])
420-
self.assertEqual(response.getheader.mock_calls, [])
391+
new_http.assert_not_called()
392+
self.assertEqual(http.requests, 0)
421393

422394
def test_environment_check_gce_production(self):
423395
self._environment_check_gce_helper(status_ok=True)
@@ -426,8 +398,21 @@ def test_environment_check_gce_prod_with_working_gae_imports(self):
426398
with mock_module_import('google.appengine'):
427399
self._environment_check_gce_helper(status_ok=True)
428400

429-
def test_environment_check_gce_timeout(self):
430-
self._environment_check_gce_helper(socket_error=True)
401+
@mock.patch('oauth2client.client.os.environ',
402+
new={client._SERVER_SOFTWARE: ''})
403+
@mock.patch('oauth2client.transport.get_http_object',
404+
return_value=object())
405+
@mock.patch('oauth2client.transport.request',
406+
side_effect=socket.timeout())
407+
def test_environment_check_gce_timeout(self, mock_request, new_http):
408+
self.assertFalse(client._in_gae_environment())
409+
self.assertFalse(client._in_gce_environment())
410+
411+
# Verify mocks.
412+
new_http.assert_called_once_with(timeout=client.GCE_METADATA_TIMEOUT)
413+
mock_request.assert_called_once_with(
414+
new_http.return_value, client._GCE_METADATA_URI,
415+
headers=client._GCE_HEADERS)
431416

432417
def test_environ_check_gae_module_unknown(self):
433418
with mock_module_import('google.appengine'):

0 commit comments

Comments
 (0)