Skip to content

Commit 83f59cd

Browse files
committed
tests for methodcache, making methodcache support multiple api versions
1 parent 68b8ccb commit 83f59cd

File tree

4 files changed

+147
-26
lines changed

4 files changed

+147
-26
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ api = Etsy(method_cache=None)
134134

135135
### Version 0.2.1 - in progress
136136
* Added a cache for the method table json.
137+
* Added a logging facility (TODO).
138+
137139

138140
### Version 0.2 - 05-31-2010
139141
* Added local configuration (~/.etsy) to eliminate cutting & pasting of api keys.

etsy/_core.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,8 @@ class MethodTableCache(object):
132132
def __init__(self, api, method_cache):
133133
self.api = api
134134
self.filename = self.resolve_file(method_cache)
135-
136-
137-
def etsy_home(self):
138-
return os.path.expanduser('~/.etsy')
135+
self.used_cache = False
136+
self.wrote_cache = False
139137

140138

141139
def resolve_file(self, method_cache):
@@ -144,16 +142,20 @@ def resolve_file(self, method_cache):
144142
return method_cache
145143

146144

145+
def etsy_home(self):
146+
return self.api.etsy_home()
147+
148+
147149
def default_file(self):
148150
etsy_home = self.etsy_home()
149151
d = etsy_home if os.path.isdir(etsy_home) else tempfile.gettempdir()
150-
return os.path.join(d, 'methods.json')
152+
return os.path.join(d, 'methods.%s.json' % self.api.api_version)
151153

152154

153155
def get(self):
154156
ms = self.get_cached()
155157
if not ms:
156-
ms = self.api._get('/')
158+
ms = self.api.get_method_table()
157159
self.cache(ms)
158160
return ms
159161

@@ -164,6 +166,7 @@ def get_cached(self):
164166
if time.time() - os.stat(self.filename).st_mtime > self.max_age:
165167
return None
166168
with open(self.filename, 'r') as f:
169+
self.used_cache = True
167170
return json.loads(f.read())
168171

169172

@@ -173,6 +176,7 @@ def cache(self, methods):
173176
return
174177
with open(self.filename, 'w') as f:
175178
json.dump(methods, f)
179+
self.wrote_cache = True
176180

177181

178182

@@ -219,21 +223,28 @@ def __init__(self, api_key='', key_file=None, method_cache=missing):
219223
self.type_checker = TypeChecker()
220224

221225
self.decode = json.loads
226+
self._get_methods(method_cache)
227+
222228

223-
ms = self._get_method_table(method_cache)
229+
def _get_methods(self, method_cache):
230+
self.method_cache = MethodTableCache(self, method_cache)
231+
ms = self.method_cache.get()
224232
self._methods = dict([(m['name'], m) for m in ms])
225233

226234
for method in ms:
227235
setattr(self, method['name'], APIMethod(self, method))
228236

229237

230-
def _get_method_table(self, method_cache):
231-
c = MethodTableCache(self, method_cache)
232-
return c.get()
238+
def etsy_home(self):
239+
return os.path.expanduser('~/.etsy')
240+
241+
242+
def get_method_table(self):
243+
return self.get('/')
233244

234245

235246
def _read_key(self, key_file):
236-
key_file = key_file or os.path.expanduser('~/.etsy/keys')
247+
key_file = key_file or os.path.join(self.etsy_home(), 'keys')
237248
if not os.path.isfile(key_file):
238249
raise AssertionError(
239250
"The key file '%s' does not exist. Create a key file or "

test/test_core.py

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
from __future__ import with_statement
2-
from etsy._core import API, MethodTableCache
2+
from etsy._core import API, MethodTableCache, missing
33
from cgi import parse_qs
44
from urlparse import urlparse
55
import os
66
from util import Test
7+
import tempfile
78

89

910

1011
class MockAPI(API):
1112
api_url = 'http://host'
1213
api_version = 'v1'
1314

14-
def _get_method_table(self, *args):
15+
16+
def etsy_home(self):
17+
return Test.scratch_dir
18+
19+
20+
def get_method_table(self, *args):
1521
return [{'name': 'testMethod',
1622
'uri': '/test/{test_id}',
1723
'http_method': 'GET',
@@ -210,30 +216,110 @@ def test_positional_argument_duplicated_in_kwargs(self):
210216
self.assertEqual('Positional argument duplicated in kwargs: test_id',
211217
msg)
212218

213-
219+
214220
def test_api_key_and_key_file_both_passed(self):
215-
pass
221+
msg = self.assertRaises(AssertionError, MockAPI,
222+
api_key='x', key_file='y')
223+
self.assertEqual('Keys can be read from a file or passed, but not both.',
224+
msg)
225+
216226

217227

218-
def test_methodcache_uses_etsy_home_if_exists(self):
228+
class MockAPI_NoMethods(MockAPI):
229+
def _get_methods(self, method_cache):
219230
pass
220231

221232

222-
def test_methodcache_uses_temp_dir_if_no_etsy_home(self):
223-
pass
224233

234+
class MethodTableCacheTests(Test):
235+
236+
237+
def cache(self, method_cache=missing):
238+
self.api = MockAPI_NoMethods('apikey')
239+
self._cache = MethodTableCache(self.api, method_cache)
240+
return self._cache
241+
242+
243+
def test_uses_etsy_home_if_exists(self):
244+
c = self.cache()
245+
self.assertEqual(os.path.dirname(c.filename), self.scratch_dir)
246+
247+
248+
def test_uses_temp_dir_if_no_etsy_home(self):
249+
self.delete_scratch()
250+
c = self.cache()
251+
self.assertEqual(os.path.dirname(c.filename), tempfile.gettempdir())
252+
253+
254+
def test_uses_provided_file(self):
255+
fn = os.path.join(self.scratch_dir, 'foo.json')
256+
self.assertEqual(self.cache(method_cache=fn).filename, fn)
257+
258+
259+
def test_multiple_versions(self):
260+
c = self.cache()
261+
262+
class MockAPI2(MockAPI):
263+
api_version = 'v3'
264+
265+
self.assertNotEqual(MockAPI2('key').method_cache.filename, c.filename)
266+
267+
268+
def get_uncached(self):
269+
c = self.cache()
270+
return c.get()
225271

226-
def test_none_passed_does_not_cache(self):
227-
pass
228272

273+
def test_no_cache_file_returns_results(self):
274+
self.assertEqual(2, len(self.get_uncached()))
229275

230-
def test_methodcache_expired(self):
231-
pass
276+
277+
def test_no_cache_file_writes_cache(self):
278+
self.get_uncached()
279+
self.assertTrue(self._cache.wrote_cache)
232280

233281

234-
def test_methodcache_caches_result(self):
235-
pass
282+
def test_no_cache_file(self):
283+
self.get_uncached()
284+
self.assertFalse(self._cache.used_cache)
285+
286+
287+
def get_cached(self):
288+
c = self.cache()
289+
c.get()
290+
c = self.cache()
291+
return c.get()
292+
293+
294+
def test_caching(self):
295+
self.get_cached()
296+
self.assertTrue(self._cache.used_cache)
236297

298+
299+
def test_caching_returns_results(self):
300+
self.assertEqual(2, len(self.get_cached()))
301+
302+
303+
def test_caching_doesnt_overwrite_cache(self):
304+
self.get_cached()
305+
self.assertFalse(self._cache.wrote_cache)
306+
307+
308+
def test_expired(self):
309+
self.get_cached()
310+
fn = self._cache.filename
311+
s = os.stat(fn)
312+
os.utime(fn, (s.st_atime, s.st_mtime - 48*60*60))
313+
c = self.cache()
314+
c.get()
315+
self.assertFalse(c.used_cache)
316+
237317

238-
def test_etsy_home_exists_file_doesnt(self):
239-
pass
318+
def test_none_passed_does_not_cache(self):
319+
self.get_cached()
320+
c = self.cache(method_cache=None)
321+
c.get()
322+
self.assertFalse(c.used_cache)
323+
324+
325+

test/util.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
11
from unittest import TestCase
2+
import os
3+
import shutil
4+
5+
6+
this_dir = os.path.realpath(os.path.dirname(__file__))
27

38

49
class Test(TestCase):
510

11+
scratch_dir = os.path.join(this_dir, 'scratch')
12+
13+
14+
def setUp(self):
15+
if not os.path.isdir(self.scratch_dir):
16+
os.mkdir(self.scratch_dir)
17+
18+
19+
def tearDown(self):
20+
self.delete_scratch()
21+
22+
23+
def delete_scratch(self):
24+
if os.path.isdir(self.scratch_dir):
25+
shutil.rmtree(self.scratch_dir)
26+
27+
628
def assertRaises(self, cls, f, *args, **kwargs):
729
try:
830
f(*args, **kwargs)

0 commit comments

Comments
 (0)