BigW Consortium Gitlab

Commit 83f59cda by Dan McKinley

tests for methodcache, making methodcache support multiple api versions

parent 68b8ccb8
......@@ -134,6 +134,8 @@ api = Etsy(method_cache=None)
### Version 0.2.1 - in progress
* Added a cache for the method table json.
* Added a logging facility (TODO).
### Version 0.2 - 05-31-2010
* Added local configuration (~/.etsy) to eliminate cutting & pasting of api keys.
......
......@@ -132,10 +132,8 @@ class MethodTableCache(object):
def __init__(self, api, method_cache):
self.api = api
self.filename = self.resolve_file(method_cache)
def etsy_home(self):
return os.path.expanduser('~/.etsy')
self.used_cache = False
self.wrote_cache = False
def resolve_file(self, method_cache):
......@@ -144,16 +142,20 @@ class MethodTableCache(object):
return method_cache
def etsy_home(self):
return self.api.etsy_home()
def default_file(self):
etsy_home = self.etsy_home()
d = etsy_home if os.path.isdir(etsy_home) else tempfile.gettempdir()
return os.path.join(d, 'methods.json')
return os.path.join(d, 'methods.%s.json' % self.api.api_version)
def get(self):
ms = self.get_cached()
if not ms:
ms = self.api._get('/')
ms = self.api.get_method_table()
self.cache(ms)
return ms
......@@ -164,6 +166,7 @@ class MethodTableCache(object):
if time.time() - os.stat(self.filename).st_mtime > self.max_age:
return None
with open(self.filename, 'r') as f:
self.used_cache = True
return json.loads(f.read())
......@@ -173,6 +176,7 @@ class MethodTableCache(object):
return
with open(self.filename, 'w') as f:
json.dump(methods, f)
self.wrote_cache = True
......@@ -219,21 +223,28 @@ class API(object):
self.type_checker = TypeChecker()
self.decode = json.loads
self._get_methods(method_cache)
ms = self._get_method_table(method_cache)
def _get_methods(self, method_cache):
self.method_cache = MethodTableCache(self, method_cache)
ms = self.method_cache.get()
self._methods = dict([(m['name'], m) for m in ms])
for method in ms:
setattr(self, method['name'], APIMethod(self, method))
def _get_method_table(self, method_cache):
c = MethodTableCache(self, method_cache)
return c.get()
def etsy_home(self):
return os.path.expanduser('~/.etsy')
def get_method_table(self):
return self.get('/')
def _read_key(self, key_file):
key_file = key_file or os.path.expanduser('~/.etsy/keys')
key_file = key_file or os.path.join(self.etsy_home(), 'keys')
if not os.path.isfile(key_file):
raise AssertionError(
"The key file '%s' does not exist. Create a key file or "
......
from __future__ import with_statement
from etsy._core import API, MethodTableCache
from etsy._core import API, MethodTableCache, missing
from cgi import parse_qs
from urlparse import urlparse
import os
from util import Test
import tempfile
......@@ -11,7 +12,12 @@ class MockAPI(API):
api_url = 'http://host'
api_version = 'v1'
def _get_method_table(self, *args):
def etsy_home(self):
return Test.scratch_dir
def get_method_table(self, *args):
return [{'name': 'testMethod',
'uri': '/test/{test_id}',
'http_method': 'GET',
......@@ -210,30 +216,110 @@ class CoreTests(Test):
self.assertEqual('Positional argument duplicated in kwargs: test_id',
msg)
def test_api_key_and_key_file_both_passed(self):
pass
msg = self.assertRaises(AssertionError, MockAPI,
api_key='x', key_file='y')
self.assertEqual('Keys can be read from a file or passed, but not both.',
msg)
def test_methodcache_uses_etsy_home_if_exists(self):
class MockAPI_NoMethods(MockAPI):
def _get_methods(self, method_cache):
pass
def test_methodcache_uses_temp_dir_if_no_etsy_home(self):
pass
class MethodTableCacheTests(Test):
def cache(self, method_cache=missing):
self.api = MockAPI_NoMethods('apikey')
self._cache = MethodTableCache(self.api, method_cache)
return self._cache
def test_uses_etsy_home_if_exists(self):
c = self.cache()
self.assertEqual(os.path.dirname(c.filename), self.scratch_dir)
def test_uses_temp_dir_if_no_etsy_home(self):
self.delete_scratch()
c = self.cache()
self.assertEqual(os.path.dirname(c.filename), tempfile.gettempdir())
def test_uses_provided_file(self):
fn = os.path.join(self.scratch_dir, 'foo.json')
self.assertEqual(self.cache(method_cache=fn).filename, fn)
def test_multiple_versions(self):
c = self.cache()
class MockAPI2(MockAPI):
api_version = 'v3'
self.assertNotEqual(MockAPI2('key').method_cache.filename, c.filename)
def get_uncached(self):
c = self.cache()
return c.get()
def test_none_passed_does_not_cache(self):
pass
def test_no_cache_file_returns_results(self):
self.assertEqual(2, len(self.get_uncached()))
def test_methodcache_expired(self):
pass
def test_no_cache_file_writes_cache(self):
self.get_uncached()
self.assertTrue(self._cache.wrote_cache)
def test_methodcache_caches_result(self):
pass
def test_no_cache_file(self):
self.get_uncached()
self.assertFalse(self._cache.used_cache)
def get_cached(self):
c = self.cache()
c.get()
c = self.cache()
return c.get()
def test_caching(self):
self.get_cached()
self.assertTrue(self._cache.used_cache)
def test_caching_returns_results(self):
self.assertEqual(2, len(self.get_cached()))
def test_caching_doesnt_overwrite_cache(self):
self.get_cached()
self.assertFalse(self._cache.wrote_cache)
def test_expired(self):
self.get_cached()
fn = self._cache.filename
s = os.stat(fn)
os.utime(fn, (s.st_atime, s.st_mtime - 48*60*60))
c = self.cache()
c.get()
self.assertFalse(c.used_cache)
def test_etsy_home_exists_file_doesnt(self):
pass
def test_none_passed_does_not_cache(self):
self.get_cached()
c = self.cache(method_cache=None)
c.get()
self.assertFalse(c.used_cache)
from unittest import TestCase
import os
import shutil
this_dir = os.path.realpath(os.path.dirname(__file__))
class Test(TestCase):
scratch_dir = os.path.join(this_dir, 'scratch')
def setUp(self):
if not os.path.isdir(self.scratch_dir):
os.mkdir(self.scratch_dir)
def tearDown(self):
self.delete_scratch()
def delete_scratch(self):
if os.path.isdir(self.scratch_dir):
shutil.rmtree(self.scratch_dir)
def assertRaises(self, cls, f, *args, **kwargs):
try:
f(*args, **kwargs)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment