| # Copyright 2014 Google Inc. All rights reserved. | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| """Oauth2client.file tests | |
| Unit tests for oauth2client.file | |
| """ | |
| import copy | |
| import datetime | |
| import json | |
| import os | |
| import pickle | |
| import stat | |
| import tempfile | |
| import six | |
| from six.moves import http_client | |
| import unittest2 | |
| from oauth2client import client | |
| from oauth2client import file | |
| from .http_mock import HttpMockSequence | |
| try: | |
| # Python2 | |
| from future_builtins import oct | |
| except: # pragma: NO COVER | |
| pass | |
| __author__ = 'jcgregorio@google.com (Joe Gregorio)' | |
| _filehandle, FILENAME = tempfile.mkstemp('oauth2client_test.data') | |
| os.close(_filehandle) | |
| class OAuth2ClientFileTests(unittest2.TestCase): | |
| def tearDown(self): | |
| try: | |
| os.unlink(FILENAME) | |
| except OSError: | |
| pass | |
| def setUp(self): | |
| try: | |
| os.unlink(FILENAME) | |
| except OSError: | |
| pass | |
| def _create_test_credentials(self, client_id='some_client_id', | |
| expiration=None): | |
| access_token = 'foo' | |
| client_secret = 'cOuDdkfjxxnv+' | |
| refresh_token = '1/0/a.df219fjls0' | |
| token_expiry = expiration or datetime.datetime.utcnow() | |
| token_uri = 'https://www.google.com/accounts/o8/oauth2/token' | |
| user_agent = 'refresh_checker/1.0' | |
| credentials = client.OAuth2Credentials( | |
| access_token, client_id, client_secret, | |
| refresh_token, token_expiry, token_uri, | |
| user_agent) | |
| return credentials | |
| def test_non_existent_file_storage(self): | |
| s = file.Storage(FILENAME) | |
| credentials = s.get() | |
| self.assertEquals(None, credentials) | |
| @unittest2.skipIf(not hasattr(os, 'symlink'), 'No symlink available') | |
| def test_no_sym_link_credentials(self): | |
| SYMFILENAME = FILENAME + '.sym' | |
| os.symlink(FILENAME, SYMFILENAME) | |
| s = file.Storage(SYMFILENAME) | |
| try: | |
| with self.assertRaises(file.CredentialsFileSymbolicLinkError): | |
| s.get() | |
| finally: | |
| os.unlink(SYMFILENAME) | |
| def test_pickle_and_json_interop(self): | |
| # Write a file with a pickled OAuth2Credentials. | |
| credentials = self._create_test_credentials() | |
| f = open(FILENAME, 'wb') | |
| pickle.dump(credentials, f) | |
| f.close() | |
| # Storage should be not be able to read that object, as the capability | |
| # to read and write credentials as pickled objects has been removed. | |
| s = file.Storage(FILENAME) | |
| read_credentials = s.get() | |
| self.assertEquals(None, read_credentials) | |
| # Now write it back out and confirm it has been rewritten as JSON | |
| s.put(credentials) | |
| with open(FILENAME) as f: | |
| data = json.load(f) | |
| self.assertEquals(data['access_token'], 'foo') | |
| self.assertEquals(data['_class'], 'OAuth2Credentials') | |
| self.assertEquals(data['_module'], client.OAuth2Credentials.__module__) | |
| def test_token_refresh_store_expired(self): | |
| expiration = (datetime.datetime.utcnow() - | |
| datetime.timedelta(minutes=15)) | |
| credentials = self._create_test_credentials(expiration=expiration) | |
| s = file.Storage(FILENAME) | |
| s.put(credentials) | |
| credentials = s.get() | |
| new_cred = copy.copy(credentials) | |
| new_cred.access_token = 'bar' | |
| s.put(new_cred) | |
| access_token = '1/3w' | |
| token_response = {'access_token': access_token, 'expires_in': 3600} | |
| http = HttpMockSequence([ | |
| ({'status': '200'}, json.dumps(token_response).encode('utf-8')), | |
| ]) | |
| credentials._refresh(http.request) | |
| self.assertEquals(credentials.access_token, access_token) | |
| def test_token_refresh_store_expires_soon(self): | |
| # Tests the case where an access token that is valid when it is read | |
| # from the store expires before the original request succeeds. | |
| expiration = (datetime.datetime.utcnow() + | |
| datetime.timedelta(minutes=15)) | |
| credentials = self._create_test_credentials(expiration=expiration) | |
| s = file.Storage(FILENAME) | |
| s.put(credentials) | |
| credentials = s.get() | |
| new_cred = copy.copy(credentials) | |
| new_cred.access_token = 'bar' | |
| s.put(new_cred) | |
| access_token = '1/3w' | |
| token_response = {'access_token': access_token, 'expires_in': 3600} | |
| http = HttpMockSequence([ | |
| ({'status': str(int(http_client.UNAUTHORIZED))}, | |
| b'Initial token expired'), | |
| ({'status': str(int(http_client.UNAUTHORIZED))}, | |
| b'Store token expired'), | |
| ({'status': str(int(http_client.OK))}, | |
| json.dumps(token_response).encode('utf-8')), | |
| ({'status': str(int(http_client.OK))}, | |
| b'Valid response to original request') | |
| ]) | |
| credentials.authorize(http) | |
| http.request('https://example.com') | |
| self.assertEqual(credentials.access_token, access_token) | |
| def test_token_refresh_good_store(self): | |
| expiration = (datetime.datetime.utcnow() + | |
| datetime.timedelta(minutes=15)) | |
| credentials = self._create_test_credentials(expiration=expiration) | |
| s = file.Storage(FILENAME) | |
| s.put(credentials) | |
| credentials = s.get() | |
| new_cred = copy.copy(credentials) | |
| new_cred.access_token = 'bar' | |
| s.put(new_cred) | |
| credentials._refresh(None) | |
| self.assertEquals(credentials.access_token, 'bar') | |
| def test_token_refresh_stream_body(self): | |
| expiration = (datetime.datetime.utcnow() + | |
| datetime.timedelta(minutes=15)) | |
| credentials = self._create_test_credentials(expiration=expiration) | |
| s = file.Storage(FILENAME) | |
| s.put(credentials) | |
| credentials = s.get() | |
| new_cred = copy.copy(credentials) | |
| new_cred.access_token = 'bar' | |
| s.put(new_cred) | |
| valid_access_token = '1/3w' | |
| token_response = {'access_token': valid_access_token, | |
| 'expires_in': 3600} | |
| http = HttpMockSequence([ | |
| ({'status': str(int(http_client.UNAUTHORIZED))}, | |
| b'Initial token expired'), | |
| ({'status': str(int(http_client.UNAUTHORIZED))}, | |
| b'Store token expired'), | |
| ({'status': str(int(http_client.OK))}, | |
| json.dumps(token_response).encode('utf-8')), | |
| ({'status': str(int(http_client.OK))}, 'echo_request_body') | |
| ]) | |
| body = six.StringIO('streaming body') | |
| credentials.authorize(http) | |
| _, content = http.request('https://example.com', body=body) | |
| self.assertEqual(content, 'streaming body') | |
| self.assertEqual(credentials.access_token, valid_access_token) | |
| def test_credentials_delete(self): | |
| credentials = self._create_test_credentials() | |
| s = file.Storage(FILENAME) | |
| s.put(credentials) | |
| credentials = s.get() | |
| self.assertNotEquals(None, credentials) | |
| s.delete() | |
| credentials = s.get() | |
| self.assertEquals(None, credentials) | |
| def test_access_token_credentials(self): | |
| access_token = 'foo' | |
| user_agent = 'refresh_checker/1.0' | |
| credentials = client.AccessTokenCredentials(access_token, user_agent) | |
| s = file.Storage(FILENAME) | |
| credentials = s.put(credentials) | |
| credentials = s.get() | |
| self.assertNotEquals(None, credentials) | |
| self.assertEquals('foo', credentials.access_token) | |
| self.assertTrue(os.path.exists(FILENAME)) | |
| if os.name == 'posix': # pragma: NO COVER | |
| mode = os.stat(FILENAME).st_mode | |
| self.assertEquals('0o600', oct(stat.S_IMODE(mode))) |