appengine_wrappers.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 3# found in the LICENSE file. 4 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. 7try: 8 import google.appengine.ext.blobstore as blobstore 9 from google.appengine.ext.blobstore.blobstore import BlobReferenceProperty 10 import google.appengine.ext.db as db 11 import google.appengine.ext.webapp as webapp 12 import google.appengine.api.files as files 13 import google.appengine.api.memcache as memcache 14 import google.appengine.api.urlfetch as urlfetch 15 # Default to a 5 minute cache timeout. 16 CACHE_TIMEOUT = 300 17except ImportError: 18 # Cache for one second because zero means cache forever. 19 CACHE_TIMEOUT = 1 20 import re 21 from StringIO import StringIO 22 23 FAKE_URL_FETCHER_CONFIGURATION = None 24 25 def ConfigureFakeUrlFetch(configuration): 26 """|configuration| is a dictionary mapping strings to fake urlfetch classes. 27 A fake urlfetch class just needs to have a fetch method. The keys of the 28 dictionary are treated as regex, and they are matched with the URL to 29 determine which fake urlfetch is used. 30 """ 31 global FAKE_URL_FETCHER_CONFIGURATION 32 FAKE_URL_FETCHER_CONFIGURATION = dict( 33 (re.compile(k), v) for k, v in configuration.iteritems()) 34 35 def _GetConfiguration(key): 36 if not FAKE_URL_FETCHER_CONFIGURATION: 37 raise ValueError('No fake fetch paths have been configured. ' 38 'See ConfigureFakeUrlFetch in appengine_wrappers.py.') 39 for k, v in FAKE_URL_FETCHER_CONFIGURATION.iteritems(): 40 if k.match(key): 41 return v 42 return None 43 44 class _RPC(object): 45 def __init__(self, result=None): 46 self.result = result 47 48 def get_result(self): 49 return self.result 50 51 class FakeUrlFetch(object): 52 """A fake urlfetch module that uses the current 53 |FAKE_URL_FETCHER_CONFIGURATION| to map urls to fake fetchers. 54 """ 55 class _Response(object): 56 def __init__(self, content): 57 self.content = content 58 self.headers = { 'content-type': 'none' } 59 self.status_code = 200 60 61 def fetch(self, url, **kwargs): 62 response = self._Response(_GetConfiguration(url).fetch(url)) 63 if response.content is None: 64 response.status_code = 404 65 return response 66 67 def create_rpc(self): 68 return _RPC() 69 70 def make_fetch_call(self, rpc, url, **kwargs): 71 rpc.result = self.fetch(url) 72 urlfetch = FakeUrlFetch() 73 74 class NotImplemented(object): 75 def __getattr__(self, attr): 76 raise NotImplementedError() 77 78 _BLOBS = {} 79 class FakeBlobstore(object): 80 class BlobReader(object): 81 def __init__(self, blob_key): 82 self._data = _BLOBS[blob_key].getvalue() 83 84 def read(self): 85 return self._data 86 87 blobstore = FakeBlobstore() 88 89 class FakeFileInterface(object): 90 """This class allows a StringIO object to be used in a with block like a 91 file. 92 """ 93 def __init__(self, io): 94 self._io = io 95 96 def __exit__(self, *args): 97 pass 98 99 def write(self, data): 100 self._io.write(data) 101 102 def __enter__(self, *args): 103 return self._io 104 105 class FakeFiles(object): 106 _next_blobstore_key = 0 107 class blobstore(object): 108 @staticmethod 109 def create(): 110 FakeFiles._next_blobstore_key += 1 111 return FakeFiles._next_blobstore_key 112 113 @staticmethod 114 def get_blob_key(filename): 115 return filename 116 117 def open(self, filename, mode): 118 _BLOBS[filename] = StringIO() 119 return FakeFileInterface(_BLOBS[filename]) 120 121 def GetBlobKeys(self): 122 return _BLOBS.keys() 123 124 def finalize(self, filename): 125 pass 126 127 files = FakeFiles() 128 129 class InMemoryMemcache(object): 130 """A fake memcache that does nothing. 131 """ 132 class Client(object): 133 def set_multi_async(self, mapping, namespace='', time=0): 134 return 135 136 def get_multi_async(self, keys, namespace='', time=0): 137 return _RPC(result=dict((k, None) for k in keys)) 138 139 def set(self, key, value, namespace='', time=0): 140 return 141 142 def get(self, key, namespace='', time=0): 143 return None 144 145 def delete(self, key, namespace): 146 return 147 148 memcache = InMemoryMemcache() 149 150 class webapp(object): 151 class RequestHandler(object): 152 """A fake webapp.RequestHandler class for Handler to extend. 153 """ 154 def __init__(self, request, response): 155 self.request = request 156 self.response = response 157 158 def redirect(self, path): 159 self.request.path = path 160 161 class _Db_Result(object): 162 def __init__(self, data): 163 self._data = data 164 165 class _Result(object): 166 def __init__(self, value): 167 self.value = value 168 169 def get(self): 170 return self._Result(self._data) 171 172 class db(object): 173 _store = {} 174 class StringProperty(object): 175 pass 176 177 class Model(object): 178 def __init__(self, key_='', value=''): 179 self._key = key_ 180 self._value = value 181 182 @staticmethod 183 def gql(query, key): 184 return _Db_Result(db._store.get(key, None)) 185 186 def put(self): 187 db._store[self._key] = self._value 188 189 class BlobReferenceProperty(object): 190 pass 191