1# Copyright 2014 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Unit tests for oauth2client.clientsecrets."""
16
17__author__ = 'jcgregorio@google.com (Joe Gregorio)'
18
19
20import os
21import unittest
22from io import StringIO
23
24import httplib2
25
26from oauth2client import clientsecrets
27
28
29DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
30VALID_FILE = os.path.join(DATA_DIR, 'client_secrets.json')
31INVALID_FILE = os.path.join(DATA_DIR, 'unfilled_client_secrets.json')
32NONEXISTENT_FILE = os.path.join(__file__, '..', 'afilethatisntthere.json')
33
34class OAuth2CredentialsTests(unittest.TestCase):
35
36  def setUp(self):
37    pass
38
39  def tearDown(self):
40    pass
41
42  def test_validate_error(self):
43    ERRORS = [
44      ('{}', 'Invalid'),
45      ('{"foo": {}}', 'Unknown'),
46      ('{"web": {}}', 'Missing'),
47      ('{"web": {"client_id": "dkkd"}}', 'Missing'),
48      ("""{
49         "web": {
50           "client_id": "[[CLIENT ID REQUIRED]]",
51           "client_secret": "[[CLIENT SECRET REQUIRED]]",
52           "redirect_uris": ["http://localhost:8080/oauth2callback"],
53           "auth_uri": "",
54           "token_uri": ""
55         }
56       }
57       """, 'Property'),
58      ]
59    for src, match in ERRORS:
60      # Ensure that it is unicode
61      try:
62        src = src.decode('utf-8')
63      except AttributeError:
64        pass
65      # Test load(s)
66      try:
67        clientsecrets.loads(src)
68        self.fail(src + ' should not be a valid client_secrets file.')
69      except clientsecrets.InvalidClientSecretsError as e:
70        self.assertTrue(str(e).startswith(match))
71
72      # Test loads(fp)
73      try:
74        fp = StringIO(src)
75        clientsecrets.load(fp)
76        self.fail(src + ' should not be a valid client_secrets file.')
77      except clientsecrets.InvalidClientSecretsError as e:
78        self.assertTrue(str(e).startswith(match))
79
80  def test_load_by_filename(self):
81    try:
82      clientsecrets._loadfile(NONEXISTENT_FILE)
83      self.fail('should fail to load a missing client_secrets file.')
84    except clientsecrets.InvalidClientSecretsError as e:
85      self.assertTrue(str(e).startswith('File'))
86
87
88class CachedClientsecretsTests(unittest.TestCase):
89
90  class CacheMock(object):
91    def __init__(self):
92      self.cache = {}
93      self.last_get_ns = None
94      self.last_set_ns = None
95
96    def get(self, key, namespace=''):
97      # ignoring namespace for easier testing
98      self.last_get_ns = namespace
99      return self.cache.get(key, None)
100
101    def set(self, key, value, namespace=''):
102      # ignoring namespace for easier testing
103      self.last_set_ns = namespace
104      self.cache[key] = value
105
106  def setUp(self):
107    self.cache_mock = self.CacheMock()
108
109  def test_cache_miss(self):
110    client_type, client_info = clientsecrets.loadfile(
111      VALID_FILE, cache=self.cache_mock)
112    self.assertEqual('web', client_type)
113    self.assertEqual('foo_client_secret', client_info['client_secret'])
114
115    cached = self.cache_mock.cache[VALID_FILE]
116    self.assertEqual({client_type: client_info}, cached)
117
118    # make sure we're using non-empty namespace
119    ns = self.cache_mock.last_set_ns
120    self.assertTrue(bool(ns))
121    # make sure they're equal
122    self.assertEqual(ns, self.cache_mock.last_get_ns)
123
124  def test_cache_hit(self):
125    self.cache_mock.cache[NONEXISTENT_FILE] = { 'web': 'secret info' }
126
127    client_type, client_info = clientsecrets.loadfile(
128      NONEXISTENT_FILE, cache=self.cache_mock)
129    self.assertEqual('web', client_type)
130    self.assertEqual('secret info', client_info)
131    # make sure we didn't do any set() RPCs
132    self.assertEqual(None, self.cache_mock.last_set_ns)
133
134  def test_validation(self):
135    try:
136      clientsecrets.loadfile(INVALID_FILE, cache=self.cache_mock)
137      self.fail('Expected InvalidClientSecretsError to be raised '
138                'while loading %s' % INVALID_FILE)
139    except clientsecrets.InvalidClientSecretsError:
140      pass
141
142  def test_without_cache(self):
143    # this also ensures loadfile() is backward compatible
144    client_type, client_info = clientsecrets.loadfile(VALID_FILE)
145    self.assertEqual('web', client_type)
146    self.assertEqual('foo_client_secret', client_info['client_secret'])
147
148
149if __name__ == '__main__':
150  unittest.main()
151