15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import posixpath 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochfrom future import Future 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from path_util import AssertIsDirectory, IsDirectory 104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class _Response(object): 134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def __init__(self, content=''): 144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self.content = content 15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.headers = {'Content-Type': 'none'} 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.status_code = 200 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class FakeUrlFetcher(object): 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, base_path): 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._base_path = base_path 224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) # Mock capabilities. Perhaps this class should be MockUrlFetcher. 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._sync_count = 0 244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_count = 0 254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_resolve_count = 0 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _ReadFile(self, filename): 28e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch # Fake DownloadError, the error that appengine usually raises. 29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch class DownloadError(Exception): pass 30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch try: 31e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch with open(os.path.join(self._base_path, filename), 'r') as f: 32e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch return f.read() 33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch except IOError as e: 34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch raise DownloadError(e) 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _ListDir(self, directory): 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # In some tests, we need to test listing a directory from the HTML returned 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # from SVN. This reads an HTML file that has the directories HTML. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not os.path.isdir(os.path.join(self._base_path, directory)): 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._ReadFile(directory[:-1]) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) files = os.listdir(os.path.join(self._base_path, directory)) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) html = '<html><title>Revision: 00000</title>\n' 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for filename in files: 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if filename.startswith('.'): 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if os.path.isdir(os.path.join(self._base_path, directory, filename)): 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) html += '<a>' + filename + '/</a>\n' 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) html += '<a>' + filename + '</a>\n' 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) html += '</html>' 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return html 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def FetchAsync(self, url): 544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_count += 1 55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) url = url.rsplit('?', 1)[0] 564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def resolve(): 574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_resolve_count += 1 584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return self._DoFetch(url) 59effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch return Future(callback=resolve) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def Fetch(self, url): 624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._sync_count += 1 634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return self._DoFetch(url) 644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def _DoFetch(self, url): 66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) url = url.rsplit('?', 1)[0] 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result = _Response() 685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if IsDirectory(url): 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.content = self._ListDir(url) 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) result.content = self._ReadFile(url) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return result 734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def CheckAndReset(self, sync_count=0, async_count=0, async_resolve_count=0): 754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) '''Returns a tuple (success, error). Use in tests like: 764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self.assertTrue(*fetcher.CheckAndReset(...)) 774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ''' 784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) errors = [] 794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) for desc, expected, actual in ( 804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ('sync_count', sync_count, self._sync_count), 814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ('async_count', async_count, self._async_count), 824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ('async_resolve_count', async_resolve_count, 834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_resolve_count)): 844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if actual != expected: 854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) errors.append('%s: expected %s got %s' % (desc, expected, actual)) 864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) try: 874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return (len(errors) == 0, ', '.join(errors)) 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) finally: 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self.Reset() 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def Reset(self): 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._sync_count = 0 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_count = 0 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._async_resolve_count = 0 954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)class FakeURLFSFetcher(object): 984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) '''Use a file_system to resolve fake fetches. Mimics the interface of Google 994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) Appengine's urlfetch. 1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) ''' 1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def __init__(self, file_system, base_path): 1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) AssertIsDirectory(base_path) 1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._base_path = base_path 1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) self._file_system = file_system 1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def FetchAsync(self, url, **kwargs): 1084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return Future(value=self.Fetch(url)) 1094e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) def Fetch(self, url, **kwargs): 1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return _Response(self._file_system.ReadSingle( 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) posixpath.join(self._base_path, url)).Get()) 113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) def UpdateFS(self, file_system, base_path=None): 115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) '''Replace the underlying FileSystem used to reslove URLs. 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ''' 117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._file_system = file_system 118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) self._base_path = base_path or self._base_path 119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)class MockURLFetcher(object): 122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def __init__(self, fetcher): 123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetcher = fetcher 124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.Reset() 125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def Fetch(self, url, **kwargs): 127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_count += 1 128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return self._fetcher.Fetch(url, **kwargs) 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def FetchAsync(self, url, **kwargs): 131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_async_count += 1 1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) def next(result): 133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_resolve_count += 1 1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return result 1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return self._fetcher.FetchAsync(url, **kwargs).Then(next) 136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def CheckAndReset(self, 138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) fetch_count=0, 139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) fetch_async_count=0, 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) fetch_resolve_count=0): 141f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) errors = [] 142f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) for desc, expected, actual in ( 143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ('fetch_count', fetch_count, self._fetch_count), 144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ('fetch_async_count', fetch_async_count, self._fetch_async_count), 145f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) ('fetch_resolve_count', fetch_resolve_count, 146f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_resolve_count)): 147f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if actual != expected: 148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) errors.append('%s: expected %s got %s' % (desc, expected, actual)) 149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try: 150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return (len(errors) == 0, ', '.join(errors)) 151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) finally: 152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self.Reset() 153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) def Reset(self): 155f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_count = 0 156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_async_count = 0 157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._fetch_resolve_count = 0 158