def test_asynchronous(self): with mocks.Requests( 'casserole.webkit.org', **{'api/cluster-endpoints': mocks.Response(text='start')}), mocks.Time: nodes = CasseroleNodes( 'https://casserole.webkit.org/api/cluster-endpoints', interval_seconds=10, asynchronous=True) self.assertEqual(['start'], nodes.nodes) with mocks.Requests( 'casserole.webkit.org', **{ 'api/cluster-endpoints': mocks.Response(text='url1,url2') }): self.assertEqual(['start'], nodes.nodes) time.sleep(15) self.assertEqual(['url1', 'url2'], nodes.nodes)
def test_list_like(self): with mocks.Requests( 'casserole.webkit.org', **{ 'api/cluster-endpoints': mocks.Response(text='url1,url2,url3') }): nodes = CasseroleNodes( 'https://casserole.webkit.org/api/cluster-endpoints') self.assertEqual(['url1', 'url2', 'url3'], [node for node in nodes]) self.assertTrue(nodes) self.assertTrue('url1' in nodes)
def _commit_response(self, url, ref): from datetime import datetime, timedelta commit = self.commit(ref) if not commit: return mocks.Response( status_code=404, url=url, text=json.dumps( dict(message='No commit found for SHA: {}'.format(ref))), ) return mocks.Response.fromJson( { 'sha': commit.hash, 'commit': { 'author': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.utcfromtimestamp(commit.timestamp - timedelta( hours=7).seconds).strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'committer': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.utcfromtimestamp(commit.timestamp - timedelta( hours=7).seconds).strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'message': commit.message + ('\ngit-svn-id: https://svn.example.org/repository/webkit/{}@{} 268f45cc-cd09-0410-ab3c-d52691b4dbfc\n' .format( 'trunk' if commit.branch == self.default_branch else commit.branch, commit.revision, ) if commit.revision else ''), 'url': 'https://{}/git/commits/{}'.format(self.api_remote, commit.hash), }, 'url': 'https://{}/commits/{}'.format(self.api_remote, commit.hash), 'html_url': 'https://{}/commit/{}'.format(self.remote, commit.hash), }, url=url)
def _commit_response(self, url, ref): commit = self.commit(ref) if not commit: return mocks.Response( status_code=404, url=url, text=json.dumps( dict(message='No commit found for SHA: {}'.format(ref))), ) return mocks.Response.fromJson( { 'sha': commit.hash, 'commit': { 'author': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.fromtimestamp( commit.timestamp).strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'committer': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.fromtimestamp( commit.timestamp).strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'message': commit.message, 'url': 'https://{}/git/commits/{}'.format(self.api_remote, commit.hash), }, 'url': 'https://{}/commits/{}'.format(self.api_remote, commit.hash), 'html_url': 'https://{}/commit/{}'.format(self.remote, commit.hash), }, url=url)
def _compare_response(self, url, ref_a, ref_b): commit_a = self.commit(ref_a) commit_b = self.commit(ref_b) if not commit_a or not commit_b: return mocks.Response( status_code=404, url=url, text=json.dumps(dict(message='Not found')), ) if commit_a.branch != self.default_branch or commit_b.branch == self.default_branch: raise NotImplementedError( 'This is a valid comparison command, but has not been implemented in the mock GitHub API' ) return mocks.Response.fromJson( { 'status': 'diverged', 'ahead_by': commit_b.identifier, 'behind_by': commit_a.identifier - commit_b.branch_point, }, url=url)
def request(self, method, url, data=None, **kwargs): from datetime import datetime, timedelta if not url.startswith('http://') and not url.startswith('https://'): return mocks.Response.create404(url) data = xmltodict.parse(data) if data else None stripped_url = url.split('://')[-1] # Latest revision if method == 'OPTIONS' and stripped_url == self.remote and data == OrderedDict( (('D:options', OrderedDict(( ('@xmlns:D', 'DAV:'), ('D:activity-collection-set', None), ))), )): return mocks.Response.fromText( url=url, data='<?xml version="1.0" encoding="utf-8"?>\n' '<D:options-response xmlns:D="DAV:">\n' '<D:activity-collection-set><D:href>/repository/webkit/!svn/act/</D:href></D:activity-collection-set></D:options-response>\n', headers={ 'SVN-Youngest-Rev': str(self.latest().revision), }) # List category match = self.REVISION_REQUEST_RE.match(stripped_url.split('!')[-1]) if method == 'PROPFIND' and stripped_url.startswith('{}!'.format( self.remote)) and match and data == OrderedDict( (('propfind', OrderedDict(( ('@xmlns', 'DAV:'), ('prop', OrderedDict((('resourcetype', OrderedDict( (('@xmlns', 'DAV:'), ))), ))), ))), )): links = [stripped_url[len(stripped_url.split('/')[0]):]] if links[0][-1] != '/': links[0] += '/' if match.group('category') == 'branches': for branch in self.branches(int(match.group('revision'))): links.append('{}{}/'.format(links[0], branch)) elif match.group('category') == 'tags': for tag in self.tags(int(match.group('revision'))): links.append('{}{}/'.format(links[0][:-5], tag)) else: return mocks.Response.create404(url) return mocks.Response( status_code=207, url=url, text='<?xml version="1.0" encoding="utf-8"?>\n' '<D:multistatus xmlns:D="DAV:" xmlns:ns0="DAV:">\n' '{}</D:multistatus>\n'.format(''.join([ '<D:response xmlns:lp1="DAV:">\n' '<D:href>{}</D:href>\n' '<D:propstat>\n' '<D:prop>\n' '<lp1:resourcetype><D:collection/></lp1:resourcetype>\n' '</D:prop>\n' '<D:status>HTTP/1.1 200 OK</D:status>\n' '</D:propstat>\n' '</D:response>\n'.format(link) for link in links ])), ) # Info for commit, branch or tag if method == 'PROPFIND' and stripped_url.startswith( '{}!'.format(self.remote) ) and match and data == OrderedDict( (('propfind', OrderedDict(( ('@xmlns', 'DAV:'), ('prop', OrderedDict(( ('resourcetype', OrderedDict((('@xmlns', 'DAV:'), ))), ('getcontentlength', OrderedDict( (('@xmlns', 'DAV:'), ))), ('deadprop-count', OrderedDict( (('@xmlns', 'http://subversion.tigris.org/xmlns/dav/'), ))), ('version-name', OrderedDict((('@xmlns', 'DAV:'), ))), ('creationdate', OrderedDict((('@xmlns', 'DAV:'), ))), ('creator-displayname', OrderedDict((('@xmlns', 'DAV:'), ))), ))), ))), )): branch = match.group('category') if branch.startswith('branches'): branch = '/'.join(branch.split('/')[1:]) if branch not in self.commits: return mocks.Response.create404(url) commit = self.commits[branch][0] for candidate in self.commits[branch]: if candidate.revision <= int(match.group('revision')): commit = candidate stripped_url = stripped_url[len(stripped_url.split('/')[0]):] if stripped_url[-1] != '/': stripped_url += '/' return mocks.Response( status_code=207, url=url, text='<?xml version="1.0" encoding="utf-8"?>\n' '<D:multistatus xmlns:D="DAV:" xmlns:ns0="DAV:">\n' '<D:response xmlns:lp1="DAV:" xmlns:lp3="http://subversion.tigris.org/xmlns/dav/" xmlns:g0="DAV:">\n' '<D:href>{}</D:href>\n' '<D:propstat>\n' '<D:prop>\n' '<lp1:resourcetype><D:collection/></lp1:resourcetype>\n' '<lp3:deadprop-count>1</lp3:deadprop-count>\n' '<lp1:version-name>{}</lp1:version-name>\n' '<lp1:creationdate>{}</lp1:creationdate>\n' '<lp1:creator-displayname>{}</lp1:creator-displayname>\n' '</D:prop>\n' '<D:status>HTTP/1.1 200 OK</D:status>\n' '</D:propstat>\n' '<D:propstat>\n' '<D:prop>\n' '<g0:getcontentlength/>\n' '</D:prop>\n' '<D:status>HTTP/1.1 404 Not Found</D:status>\n' '</D:propstat>\n' '</D:response>\n' '</D:multistatus>\n'.format( stripped_url, commit.revision, datetime.utcfromtimestamp(commit.timestamp - timedelta(hours=7).seconds). strftime('%Y-%m-%dT%H:%M:%S.103754Z'), commit.author.email, ), ) # Log for commit if method == 'REPORT' and stripped_url.startswith('{}!'.format( self.remote)) and match and data.get('S:log-report'): commits = list( self.range( category=match.group('category'), start=int(data['S:log-report']['S:start-revision']), end=int(data['S:log-report']['S:end-revision']), )) limit = int(data['S:log-report'].get('S:limit', 0)) if limit and len(commits) > limit: commits = commits[:limit] if not commits: return mocks.Response.create404(url) return mocks.Response( status_code=200, url=url, text='<?xml version="1.0" encoding="utf-8"?>\n' '<S:log-report xmlns:S="svn:" xmlns:D="DAV:">\n' '{}</S:log-report>\n'.format(''.join([ '<S:log-item>\n' '<D:version-name>{}</D:version-name>\n' '<S:date>{}</S:date>\n' '{}{}</S:log-item>\n'.format( commit.revision, datetime.utcfromtimestamp(commit.timestamp - timedelta(hours=7).seconds). strftime('%Y-%m-%dT%H:%M:%S.103754Z'), '' if data['S:log-report'].get('S:revpro') else '<D:comment>{}</D:comment>\n' '<D:creator-displayname>{}</D:creator-displayname>\n'. format( commit.message, commit.author.email, ), '<S:modified-path node-kind="file" text-mods="true" prop-mods="false">/{branch}/Changelog</S:modified-path>\n' '<S:modified-path node-kind="file" text-mods="true" prop-mods="false">/{branch}/file.cpp</S:modified-path>\n' '<S:added-path node-kind="file" text-mods="true" prop-mods="false">/{branch}/deleted.cpp</S:added-path>\n' '<S:deleted-path node-kind="file" text-mods="true" prop-mods="false">/{branch}/added.cpp</S:deleted-path>\n' .format( branch=commit.branch if commit.branch.split('/')[0] in ['trunk', 'tags'] else 'branches/{}'.format( commit.branch), ) if 'S:discover-changed-paths' in data['S:log-report'] else '', ) for commit in commits ])), ) return mocks.Response.create404(url)
def _commits_response(self, url, ref): from datetime import datetime, timedelta base = self.commit(ref) if not base: return mocks.Response( status_code=404, url=url, text=json.dumps( dict(message='No commit found for SHA: {}'.format(ref))), ) response = [] for branch in [self.default_branch ] if base.branch == self.default_branch else [ base.branch, self.default_branch ]: in_range = False previous = None for commit in reversed(self.commits[branch]): if commit.hash == ref: in_range = True if not in_range: continue previous = commit response.append({ 'sha': commit.hash, 'commit': { 'author': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.utcfromtimestamp(commit.timestamp - timedelta( hours=7).seconds). strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'committer': { 'name': commit.author.name, 'email': commit.author.email, 'date': datetime.utcfromtimestamp(commit.timestamp - timedelta( hours=7).seconds). strftime('%Y-%m-%dT%H:%M:%SZ'), }, 'message': commit.message + ('\ngit-svn-id: https://svn.example.org/repository/webkit/{}@{} 268f45cc-cd09-0410-ab3c-d52691b4dbfc\n' .format( 'trunk' if commit.branch == self.default_branch else commit.branch, commit.revision, ) if commit.revision else ''), 'url': 'https://{}/git/commits/{}'.format( self.api_remote, commit.hash), }, 'url': 'https://{}/commits/{}'.format(self.api_remote, commit.hash), 'html_url': 'https://{}/commit/{}'.format(self.remote, commit.hash), }) if branch != self.default_branch: for commit in reversed(self.commits[self.default_branch]): if previous.branch_point == commit.identifier: ref = commit.hash return mocks.Response.fromJson(response, url=url)