OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 # This will attempt to import the actual App Engine modules, and if it fails, | 5 # This will attempt to import the actual App Engine modules, and if it fails, |
6 # they will be replaced with fake modules. This is useful during testing. | 6 # they will be replaced with fake modules. This is useful during testing. |
7 try: | 7 try: |
8 import google.appengine.ext.blobstore as blobstore | 8 import google.appengine.ext.blobstore as blobstore |
9 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty | 9 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty |
10 import google.appengine.ext.db as db | 10 import google.appengine.ext.db as db |
11 import google.appengine.ext.webapp as webapp | 11 import google.appengine.ext.webapp as webapp |
12 import google.appengine.api.files as files | 12 import google.appengine.api.files as files |
13 import google.appengine.api.memcache as memcache | 13 import google.appengine.api.memcache as memcache |
14 import google.appengine.api.urlfetch as urlfetch | 14 import google.appengine.api.urlfetch as urlfetch |
15 except ImportError: | 15 except ImportError: |
16 import re | 16 import re |
17 | 17 |
18 from future import Future | |
19 | |
18 FAKE_URL_FETCHER_CONFIGURATION = None | 20 FAKE_URL_FETCHER_CONFIGURATION = None |
19 | 21 |
20 def ConfigureFakeUrlFetch(configuration): | 22 def ConfigureFakeUrlFetch(configuration): |
21 """|configuration| is a dictionary mapping strings to fake urlfetch classes. | 23 """|configuration| is a dictionary mapping strings to fake urlfetch classes. |
22 A fake urlfetch class just needs to have a fetch method. The keys of the | 24 A fake urlfetch class just needs to have a fetch method. The keys of the |
23 dictionary are treated as regex, and they are matched with the URL to | 25 dictionary are treated as regex, and they are matched with the URL to |
24 determine which fake urlfetch is used. | 26 determine which fake urlfetch is used. |
25 """ | 27 """ |
26 global FAKE_URL_FETCHER_CONFIGURATION | 28 global FAKE_URL_FETCHER_CONFIGURATION |
27 FAKE_URL_FETCHER_CONFIGURATION = dict( | 29 FAKE_URL_FETCHER_CONFIGURATION = dict( |
28 (re.compile(k), v) for k, v in configuration.iteritems()) | 30 (re.compile(k), v) for k, v in configuration.iteritems()) |
29 | 31 |
30 def _GetConfiguration(key): | 32 def _GetConfiguration(key): |
31 if not FAKE_URL_FETCHER_CONFIGURATION: | 33 if not FAKE_URL_FETCHER_CONFIGURATION: |
32 raise ValueError('No fake fetch paths have been configured. ' | 34 raise ValueError('No fake fetch paths have been configured. ' |
33 'See ConfigureFakeUrlFetch in appengine_wrappers.py.') | 35 'See ConfigureFakeUrlFetch in appengine_wrappers.py.') |
34 for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems(): | 36 for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems(): |
35 if k.match(key): | 37 if k.match(key): |
36 return v | 38 return v |
37 return None | 39 return None |
38 | 40 |
41 class _RPC(object): | |
42 def __init__(self, result=None): | |
43 self.result = result | |
44 | |
45 def get_result(self): | |
46 return self.result | |
47 | |
39 class FakeUrlFetch(object): | 48 class FakeUrlFetch(object): |
40 """A fake urlfetch module that uses the current | 49 """A fake urlfetch module that uses the current |
41 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. | 50 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. |
42 """ | 51 """ |
43 class _Response(object): | 52 class _Response(object): |
44 def __init__(self, content): | 53 def __init__(self, content): |
45 self.content = content | 54 self.content = content |
46 self.headers = { 'content-type': 'none' } | 55 self.headers = { 'content-type': 'none' } |
47 self.status_code = 200 | 56 self.status_code = 200 |
48 | 57 |
49 class _RPC(object): | |
50 def __init__(self): | |
51 self.result = None | |
52 | |
53 def wait(self): | |
54 pass | |
55 | |
56 def get_result(self): | |
57 return self.result | |
58 | |
59 def fetch(self, url): | 58 def fetch(self, url): |
60 return self._Response(_GetConfiguration(url).fetch(url)) | 59 return self._Response(_GetConfiguration(url).fetch(url)) |
61 | 60 |
62 def create_rpc(self): | 61 def create_rpc(self): |
63 return self._RPC() | 62 return _RPC() |
64 | 63 |
65 def make_fetch_call(self, rpc, url): | 64 def make_fetch_call(self, rpc, url): |
66 rpc.result = self.fetch(url) | 65 rpc.result = self.fetch(url) |
67 urlfetch = FakeUrlFetch() | 66 urlfetch = FakeUrlFetch() |
68 | 67 |
69 class NotImplemented(object): | 68 class NotImplemented(object): |
70 def __getattr__(self, attr): | 69 def __getattr__(self, attr): |
71 raise NotImplementedError() | 70 raise NotImplementedError() |
72 | 71 |
73 blobstore = NotImplemented() | 72 blobstore = NotImplemented() |
74 files = NotImplemented() | 73 files = NotImplemented() |
75 | 74 |
76 class InMemoryMemcache(object): | 75 class InMemoryMemcache(object): |
77 """A memcache that stores items in memory instead of using the memcache | 76 """A fake memcache that does nothing. AppEngineMemcache already stores items |
78 module. | 77 in local memory. |
79 """ | 78 """ |
80 def __init__(self): | 79 class Client(object): |
81 self._cache = {} | 80 def set_multi_async(self, mapping, namespace='', time=300): |
not at google - send to devlin
2012/08/20 05:27:10
300 looks especially arbitrary here. Make it 0 or
cduvall
2012/08/20 21:28:09
Done.
| |
81 return | |
82 | 82 |
83 def set(self, key, value, namespace, time=60): | 83 def get_multi_async(self, keys, namespace='', time=300): |
84 if namespace not in self._cache: | 84 return _RPC(result=dict((k, None) for k in keys)) |
85 self._cache[namespace] = {} | |
86 self._cache[namespace][key] = value | |
87 | 85 |
88 def get(self, key, namespace): | 86 def set(self, key, value, namespace='', time=300): |
89 if namespace not in self._cache: | 87 return |
90 return None | 88 |
91 return self._cache[namespace].get(key, None) | 89 def get(self, key, namespace='', time=300): |
90 return None | |
92 | 91 |
93 def delete(self, key, namespace): | 92 def delete(self, key, namespace): |
94 if namespace in self._cache: | 93 return |
95 self._cache[namespace].pop(key) | |
96 memcache = InMemoryMemcache() | 94 memcache = InMemoryMemcache() |
97 | 95 |
98 # A fake webapp.RequestHandler class for Handler to extend. | |
99 class webapp(object): | 96 class webapp(object): |
100 class RequestHandler(object): | 97 class RequestHandler(object): |
98 """A fake webapp.RequestHandler class for Handler to extend. | |
99 """ | |
101 def __init__(self, request, response): | 100 def __init__(self, request, response): |
102 self.request = request | 101 self.request = request |
103 self.response = response | 102 self.response = response |
104 | 103 |
105 def redirect(self, path): | 104 def redirect(self, path): |
106 self.request.path = path | 105 self.request.path = path |
107 | 106 |
108 class _Db_Result(object): | 107 class _Db_Result(object): |
109 def get(self): | 108 def get(self): |
110 return [] | 109 return [] |
111 | 110 |
112 class db(object): | 111 class db(object): |
113 class StringProperty(object): | 112 class StringProperty(object): |
114 pass | 113 pass |
115 | 114 |
116 class Model(object): | 115 class Model(object): |
117 @staticmethod | 116 @staticmethod |
118 def gql(*args): | 117 def gql(*args): |
119 return _Db_Result() | 118 return _Db_Result() |
120 | 119 |
121 class BlobReferenceProperty(object): | 120 class BlobReferenceProperty(object): |
122 pass | 121 pass |
OLD | NEW |