blob: 3e966089d78dd34cd37e68b090c286c2c7deed61 [file] [log] [blame]
# -*- coding: utf-8 -*-
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for GerritHelper."""
from __future__ import print_function
import collections
import getpass
import io
import json
import os
import re
import shutil
import stat
import mock
import six
from six.moves import http_client as httplib
from six.moves import http_cookiejar as cookielib
from six.moves import urllib
from chromite.lib import config_lib
from chromite.lib import constants
from chromite.lib import cros_build_lib
from chromite.lib import cros_test_lib
from chromite.lib import gerrit
from chromite.lib import git
from chromite.lib import gob_util
from chromite.lib import osutils
from chromite.lib import retry_util
class GerritTestCase(cros_test_lib.MockTempDirTestCase):
"""Test class for tests that interact with a Gerrit server.
Configured by default to use a specially-configured test Gerrit server at
t3st-chr0m3(-review).googlesource.com. The test server configuration may be
altered by setting the following environment variables from the parent
process:
CROS_TEST_GIT_HOST: host name for git operations; defaults to
t3st-chr0me.googlesource.com.
CROS_TEST_GERRIT_HOST: host name for Gerrit operations; defaults to
t3st-chr0me-review.googlesource.com.
CROS_TEST_COOKIES_PATH: path to a cookies.txt file to use for git/Gerrit
requests; defaults to ~/.gitcookies.
CROS_TEST_COOKIE_NAMES: comma-separated list of cookie names from
CROS_TEST_COOKIES_PATH to set on requests; defaults
to none. The current implementation only sends
cookies matching the exact host name and the empty
path ("/").
"""
# pylint: disable=protected-access
TEST_USERNAME = 'test-username'
TEST_EMAIL = 'test-username@test.org'
GerritInstance = collections.namedtuple('GerritInstance', [
'cookie_names',
'cookies_path',
'gerrit_host',
'gerrit_url',
'git_host',
'git_url',
'project_prefix',
])
def _create_gerrit_instance(self, tmp_dir):
default_host = 't3st-chr0m3'
git_host = os.environ.get('CROS_TEST_GIT_HOST',
constants.GOB_HOST % default_host)
gerrit_host = os.environ.get('CROS_TEST_GERRIT_HOST',
'%s-review.googlesource.com' % default_host)
project_prefix = 'test-%s/' % (cros_build_lib.GetRandomString(),)
cookies_path = os.environ.get('CROS_TEST_COOKIES_PATH',
constants.GITCOOKIES_PATH)
# "o" is the cookie name that GoB uses in its instructions.
cookie_names_str = os.environ.get('CROS_TEST_COOKIE_NAMES', 'o')
cookie_names = {c for c in cookie_names_str.split(',') if c}
tmpcookies_path = os.path.join(tmp_dir, '.gitcookies')
if os.path.exists(cookies_path):
shutil.copy(cookies_path, tmpcookies_path)
else:
osutils.Touch(tmpcookies_path)
return self.GerritInstance(
cookie_names=cookie_names,
cookies_path=tmpcookies_path,
gerrit_host=gerrit_host,
gerrit_url='https://%s/' % gerrit_host,
git_host=git_host,
git_url='https://%s/' % git_host,
project_prefix=project_prefix,)
def setUp(self):
"""Sets up the gerrit instances in a class-specific temp dir."""
self.saved_params = {}
os.environ['HOME'] = self.tempdir
# Create gerrit instance.
gi = self.gerrit_instance = self._create_gerrit_instance(self.tempdir)
# This --global will use our tempdir $HOME we set above, not the real ~/.
cros_build_lib.run(
['git', 'config', '--global', 'http.cookiefile', gi.cookies_path],
quiet=True)
jar = cookielib.MozillaCookieJar(gi.cookies_path)
jar.load(ignore_expires=True)
def GetCookies(host, _path):
return dict(
(c.name, urllib.parse.unquote(c.value)) for c in jar
if c.domain == host and c.path == '/' and c.name in gi.cookie_names)
self.PatchObject(gob_util, 'GetCookies', GetCookies)
site_params = config_lib.GetSiteParams()
# Make all chromite code point to the test server.
self.patched_params = {
'EXTERNAL_GOB_HOST': gi.git_host,
'EXTERNAL_GERRIT_HOST': gi.gerrit_host,
'EXTERNAL_GOB_URL': gi.git_url,
'EXTERNAL_GERRIT_URL': gi.gerrit_url,
'INTERNAL_GOB_HOST': gi.git_host,
'INTERNAL_GERRIT_HOST': gi.gerrit_host,
'INTERNAL_GOB_URL': gi.git_url,
'INTERNAL_GERRIT_URL': gi.gerrit_url,
'AOSP_GOB_HOST': gi.git_host,
'AOSP_GERRIT_HOST': gi.gerrit_host,
'AOSP_GOB_URL': gi.git_url,
'AOSP_GERRIT_URL': gi.gerrit_url,
'MANIFEST_URL': '%s/%s' % (
gi.git_url, site_params.MANIFEST_PROJECT
),
'MANIFEST_INT_URL': '%s/%s' % (
gi.git_url, site_params.MANIFEST_INT_PROJECT
),
'GIT_REMOTES': {
site_params.EXTERNAL_REMOTE: gi.gerrit_url,
site_params.INTERNAL_REMOTE: gi.gerrit_url,
site_params.CHROMIUM_REMOTE: gi.gerrit_url,
site_params.CHROME_REMOTE: gi.gerrit_url
}
}
for k in self.patched_params.keys():
self.saved_params[k] = site_params.get(k)
site_params.update(self.patched_params)
def tearDown(self):
# Restore the 'patched' site parameters.
site_params = config_lib.GetSiteParams()
site_params.update(self.saved_params)
def createProject(self, suffix, description='Test project', owners=None,
submit_type='CHERRY_PICK'):
"""Create a project on the test gerrit server."""
name = self.gerrit_instance.project_prefix + suffix
body = {
'description': description,
'submit_type': submit_type,
}
if owners is not None:
body['owners'] = owners
path = 'projects/%s' % urllib.parse.quote(name, '')
conn = gob_util.CreateHttpConn(
self.gerrit_instance.gerrit_host, path, reqtype='PUT', body=body)
response = conn.getresponse()
self.assertEqual(201, response.status,
'Expected 201, got %s' % response.status)
s = io.BytesIO(response.read())
self.assertEqual(b")]}'", s.readline().rstrip())
jmsg = json.load(s)
self.assertEqual(name, jmsg['name'])
return name
def _CloneProject(self, name, path):
"""Clone a project from the test gerrit server."""
root = os.path.dirname(path)
osutils.SafeMakedirs(root)
url = '%s://%s/%s' % (
gob_util.GIT_PROTOCOL, self.gerrit_instance.git_host, name)
git.RunGit(root, ['clone', url, path])
# Install commit-msg hook.
hook_path = os.path.join(path, '.git', 'hooks', 'commit-msg')
hook_cmd = ['curl', '-n', '-o', hook_path,
'-b', self.gerrit_instance.cookies_path]
hook_cmd.append('https://%s/a/tools/hooks/commit-msg'
% self.gerrit_instance.gerrit_host)
cros_build_lib.run(hook_cmd, quiet=True)
os.chmod(hook_path, stat.S_IRWXU)
# Set git identity to test account
cros_build_lib.run(
['git', 'config', 'user.email', self.TEST_EMAIL], cwd=path, quiet=True)
return path
def cloneProject(self, name, path=None):
"""Clone a project from the test gerrit server."""
if path is None:
path = os.path.basename(name)
if path.endswith('.git'):
path = path[:-4]
path = os.path.join(self.tempdir, path)
return self._CloneProject(name, path)
@classmethod
def _CreateCommit(cls, clone_path, filename=None, msg=None, text=None,
amend=False):
"""Create a commit in the given git checkout.
Args:
clone_path: The directory on disk of the git clone.
filename: The name of the file to write. Optional.
msg: The commit message. Optional.
text: The text to append to the file. Optional.
amend: Whether to amend an existing patch. If set, we will amend the
HEAD commit in the checkout and upload that patch.
Returns:
(sha1, changeid) of the new commit.
"""
if not filename:
filename = 'test-file.txt'
if not msg:
msg = 'Test Message'
if not text:
text = 'Another day, another dollar.'
fpath = os.path.join(clone_path, filename)
osutils.WriteFile(fpath, '%s\n' % text, mode='a')
cros_build_lib.run(['git', 'add', filename], cwd=clone_path, quiet=True)
cmd = ['git', 'commit']
cmd += ['--amend', '-C', 'HEAD'] if amend else ['-m', msg]
cros_build_lib.run(cmd, cwd=clone_path, quiet=True)
return cls._GetCommit(clone_path)
def createCommit(self, clone_path, filename=None, msg=None, text=None,
amend=False):
"""Create a commit in the given git checkout.
Args:
clone_path: The directory on disk of the git clone.
filename: The name of the file to write. Optional.
msg: The commit message. Optional.
text: The text to append to the file. Optional.
amend: Whether to amend an existing patch. If set, we will amend the
HEAD commit in the checkout and upload that patch.
"""
clone_path = os.path.join(self.tempdir, clone_path)
return self._CreateCommit(clone_path, filename, msg, text, amend)
@staticmethod
def _GetCommit(clone_path, ref='HEAD'):
log_proc = cros_build_lib.run(
['git', 'log', '-n', '1', ref], cwd=clone_path,
print_cmd=False, capture_output=True, encoding='utf-8')
sha1 = None
change_id = None
for line in log_proc.output.splitlines():
match = re.match(r'^commit ([0-9a-fA-F]{40})$', line)
if match:
sha1 = match.group(1)
continue
match = re.match(r'^\s+Change-Id:\s*(\S+)$', line)
if match:
change_id = match.group(1)
continue
return (sha1, change_id)
def getCommit(self, clone_path, ref='HEAD'):
"""Get the sha1 and change-id for the head commit in a git checkout."""
clone_path = os.path.join(self.tempdir, clone_path)
(sha1, change_id) = self._GetCommit(clone_path, ref)
self.assertTrue(sha1)
self.assertTrue(change_id)
return (sha1, change_id)
@staticmethod
def _UploadChange(clone_path, branch='master', remote='origin'):
cros_build_lib.run(
['git', 'push', remote, 'HEAD:refs/for/%s' % branch], cwd=clone_path,
quiet=True)
def uploadChange(self, clone_path, branch='master', remote='origin'):
"""Create a gerrit CL from the HEAD of a git checkout."""
clone_path = os.path.join(self.tempdir, clone_path)
self._UploadChange(clone_path, branch, remote)
@staticmethod
def _PushBranch(clone_path, branch='master'):
cros_build_lib.run(
['git', 'push', 'origin', 'HEAD:refs/heads/%s' % branch],
cwd=clone_path, quiet=True)
def pushBranch(self, clone_path, branch='master'):
"""Push a branch directly to gerrit, bypassing code review."""
clone_path = os.path.join(self.tempdir, clone_path)
self._PushBranch(clone_path, branch)
def createAccount(self, name='Test User', email='test-user@test.org',
password=None, groups=None):
"""Create a new user account on gerrit."""
username = urllib.parse.quote(email.partition('@')[0])
path = 'accounts/%s' % username
body = {
'name': name,
'email': email,
}
if password:
body['http_password'] = password
if groups:
if isinstance(groups, six.string_types):
groups = [groups]
body['groups'] = groups
conn = gob_util.CreateHttpConn(
self.gerrit_instance.gerrit_host, path, reqtype='PUT', body=body)
response = conn.getresponse()
self.assertEqual(201, response.status)
s = io.BytesIO(response.read())
self.assertEqual(b")]}'", s.readline().rstrip())
jmsg = json.load(s)
self.assertEqual(email, jmsg['email'])
@cros_test_lib.NetworkTest()
class GerritHelperTest(GerritTestCase):
"""Unittests for GerritHelper."""
def _GetHelper(self, remote=config_lib.GetSiteParams().EXTERNAL_REMOTE):
return gerrit.GetGerritHelper(remote)
def createPatch(self, clone_path, project, **kwargs):
"""Create a patch in the given git checkout and upload it to gerrit.
Args:
clone_path: The directory on disk of the git clone.
project: The associated project.
**kwargs: Additional keyword arguments to pass to createCommit.
Returns:
A GerritPatch object.
"""
(revision, changeid) = self.createCommit(clone_path, **kwargs)
self.uploadChange(clone_path)
def PatchQuery():
return self._GetHelper().QuerySingleRecord(
change=changeid, project=project, branch='master')
# 'RetryException' is needed because there is a race condition between
# uploading the change and querying for the change.
gpatch = retry_util.RetryException(
gerrit.QueryHasNoResults,
5,
PatchQuery,
sleep=1)
self.assertEqual(gpatch.change_id, changeid)
self.assertEqual(gpatch.revision, revision)
return gpatch
def test001SimpleQuery(self):
"""Create one independent and three dependent changes, then query them."""
project = self.createProject('test001')
clone_path = self.cloneProject(project)
(head_sha1, head_changeid) = self.createCommit(clone_path)
for idx in range(3):
cros_build_lib.run(
['git', 'checkout', head_sha1], cwd=clone_path, quiet=True)
self.createCommit(clone_path, filename='test-file-%d.txt' % idx)
self.uploadChange(clone_path)
helper = self._GetHelper()
changes = helper.Query(owner='self', project=project)
self.assertEqual(len(changes), 4)
changes = helper.Query(head_changeid, project=project, branch='master')
self.assertEqual(len(changes), 1)
self.assertEqual(changes[0].change_id, head_changeid)
self.assertEqual(changes[0].sha1, head_sha1)
change = helper.QuerySingleRecord(
head_changeid, project=project, branch='master')
self.assertTrue(change)
self.assertEqual(change.change_id, head_changeid)
self.assertEqual(change.sha1, head_sha1)
change = helper.GrabPatchFromGerrit(project, head_changeid, head_sha1)
self.assertTrue(change)
self.assertEqual(change.change_id, head_changeid)
self.assertEqual(change.sha1, head_sha1)
@mock.patch.object(gerrit.GerritHelper, '_GERRIT_MAX_QUERY_RETURN', 2)
def test002GerritQueryTruncation(self):
"""Verify that we detect gerrit truncating our query, and handle it."""
project = self.createProject('test002')
clone_path = self.cloneProject(project)
# Using a shell loop is markedly faster than running a python loop.
num_changes = 5
cmd = ('for ((i=0; i<%i; i=i+1)); do '
'echo "Another day, another dollar." > test-file-$i.txt; '
'git add test-file-$i.txt; '
'git commit -m "Test commit $i."; '
'done' % num_changes)
cros_build_lib.run(cmd, shell=True, cwd=clone_path, quiet=True)
self.uploadChange(clone_path)
helper = self._GetHelper()
changes = helper.Query(project=project)
self.assertEqual(len(changes), num_changes)
def test003IsChangeCommitted(self):
"""Tests that we can parse a json to check if a change is committed."""
project = self.createProject('test003')
clone_path = self.cloneProject(project)
gpatch = self.createPatch(clone_path, project)
helper = self._GetHelper()
helper.SetReview(gpatch.gerrit_number, labels={'Code-Review':'+2'})
helper.SubmitChange(gpatch)
self.assertTrue(helper.IsChangeCommitted(gpatch.gerrit_number))
gpatch = self.createPatch(clone_path, project)
self.assertFalse(helper.IsChangeCommitted(gpatch.gerrit_number))
def test004GetLatestSHA1ForBranch(self):
"""Verifies that we can query the tip-of-tree commit in a git repository."""
project = self.createProject('test004')
clone_path = self.cloneProject(project)
for _ in range(5):
(master_sha1, _) = self.createCommit(clone_path)
self.pushBranch(clone_path, 'master')
for _ in range(5):
(testbranch_sha1, _) = self.createCommit(clone_path)
self.pushBranch(clone_path, 'testbranch')
helper = self._GetHelper()
self.assertEqual(
helper.GetLatestSHA1ForBranch(project, 'master'),
master_sha1)
self.assertEqual(
helper.GetLatestSHA1ForBranch(project, 'testbranch'),
testbranch_sha1)
def _ChooseReviewers(self):
all_reviewers = set(['dborowitz@google.com', 'sop@google.com',
'jrn@google.com'])
ret = list(all_reviewers.difference(['%s@google.com' % getpass.getuser()]))
self.assertGreaterEqual(len(ret), 2)
return ret
def test005SetReviewers(self):
"""Verify that we can set reviewers on a CL."""
project = self.createProject('test005')
clone_path = self.cloneProject(project)
gpatch = self.createPatch(clone_path, project)
emails = self._ChooseReviewers()
helper = self._GetHelper()
helper.SetReviewers(gpatch.gerrit_number, add=(
emails[0], emails[1]))
reviewers = gob_util.GetReviewers(helper.host, gpatch.gerrit_number)
self.assertEqual(len(reviewers), 2)
self.assertCountEqual(
[r['email'] for r in reviewers],
[emails[0], emails[1]])
helper.SetReviewers(gpatch.gerrit_number,
remove=(emails[0],))
reviewers = gob_util.GetReviewers(helper.host, gpatch.gerrit_number)
self.assertEqual(len(reviewers), 1)
self.assertEqual(reviewers[0]['email'], emails[1])
def test006PatchNotFound(self):
"""Test case where ChangeID isn't found on the server."""
changeids = ['I' + ('deadbeef' * 5), 'I' + ('beadface' * 5)]
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
changeids)
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
['*' + cid for cid in changeids])
# Change ID sequence starts at 1000.
gerrit_numbers = ['123', '543']
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
gerrit_numbers)
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
['*' + num for num in gerrit_numbers])
def test007VagueQuery(self):
"""Verify GerritHelper complains if an ID matches multiple changes."""
project = self.createProject('test007')
clone_path = self.cloneProject(project)
(sha1, _) = self.createCommit(clone_path)
(_, changeid) = self.createCommit(clone_path)
self.uploadChange(clone_path, 'master')
cros_build_lib.run(
['git', 'checkout', sha1], cwd=clone_path, quiet=True)
self.createCommit(clone_path)
self.pushBranch(clone_path, 'testbranch')
self.createCommit(
clone_path, msg='Test commit.\n\nChange-Id: %s' % changeid)
self.uploadChange(clone_path, 'testbranch')
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
[changeid])
def test008Queries(self):
"""Verify assorted query operations."""
project = self.createProject('test008')
clone_path = self.cloneProject(project)
gpatch = self.createPatch(clone_path, project)
helper = self._GetHelper()
# Multi-queries with one valid and one invalid term should raise.
invalid_change_id = 'I1234567890123456789012345678901234567890'
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
[invalid_change_id, gpatch.change_id])
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
[gpatch.change_id, invalid_change_id])
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
['9876543', gpatch.gerrit_number])
self.assertRaises(gerrit.GerritException, gerrit.GetGerritPatchInfo,
[gpatch.gerrit_number, '9876543'])
site_params = config_lib.GetSiteParams()
# Simple query by project/changeid/sha1.
patch_info = helper.GrabPatchFromGerrit(gpatch.project, gpatch.change_id,
gpatch.sha1)
self.assertEqual(patch_info.gerrit_number, gpatch.gerrit_number)
self.assertEqual(patch_info.remote, site_params.EXTERNAL_REMOTE)
# Simple query by gerrit number to external remote.
patch_info = gerrit.GetGerritPatchInfo([gpatch.gerrit_number])
self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
self.assertEqual(patch_info[0].remote, site_params.EXTERNAL_REMOTE)
# Simple query by gerrit number to internal remote.
patch_info = gerrit.GetGerritPatchInfo(['*' + gpatch.gerrit_number])
self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
self.assertEqual(patch_info[0].remote, site_params.INTERNAL_REMOTE)
# Query to external server by gerrit number and change-id which refer to
# the same change should return one result.
fq_changeid = '~'.join((gpatch.project, 'master', gpatch.change_id))
patch_info = gerrit.GetGerritPatchInfo([gpatch.gerrit_number, fq_changeid])
self.assertEqual(len(patch_info), 1)
self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
self.assertEqual(patch_info[0].remote, site_params.EXTERNAL_REMOTE)
# Query to internal server by gerrit number and change-id which refer to
# the same change should return one result.
patch_info = gerrit.GetGerritPatchInfo(
['*' + gpatch.gerrit_number, '*' + fq_changeid])
self.assertEqual(len(patch_info), 1)
self.assertEqual(patch_info[0].gerrit_number, gpatch.gerrit_number)
self.assertEqual(patch_info[0].remote, site_params.INTERNAL_REMOTE)
def test009SubmitOutdatedCommit(self):
"""Tests that we can parse a json to check if a change is committed."""
project = self.createProject('test009')
clone_path = self.cloneProject(project, 'p1')
# Create a change.
gpatch1 = self.createPatch(clone_path, project)
# Update the change.
gpatch2 = self.createPatch(clone_path, project, amend=True)
# Make sure we're talking about the same change.
self.assertEqual(gpatch1.change_id, gpatch2.change_id)
# Try submitting the out-of-date change.
helper = self._GetHelper()
helper.SetReview(gpatch1.gerrit_number, labels={'Code-Review':'+2'})
with self.assertRaises(gob_util.GOBError) as ex:
helper.SubmitChange(gpatch1)
self.assertEqual(ex.exception.http_status, httplib.CONFLICT)
self.assertFalse(helper.IsChangeCommitted(gpatch1.gerrit_number))
# Try submitting the up-to-date change.
helper.SubmitChange(gpatch2)
helper.IsChangeCommitted(gpatch2.gerrit_number)
def test011ResetReviewLabels(self):
"""Tests that we can remove a code review label."""
project = self.createProject('test011')
helper = self._GetHelper()
clone_path = self.cloneProject(project, 'p1')
gpatch = self.createPatch(clone_path, project, msg='Init')
helper.SetReview(gpatch.gerrit_number, labels={'Code-Review':'+2'})
gob_util.ResetReviewLabels(helper.host, gpatch.gerrit_number,
label='Code-Review', notify='OWNER')
def test012ApprovalTime(self):
"""Approval timestamp should be reset when a new patchset is created."""
# Create a change.
project = self.createProject('test013')
helper = self._GetHelper()
clone_path = self.cloneProject(project, 'p1')
gpatch = self.createPatch(clone_path, project, msg='Init')
helper.SetReview(gpatch.gerrit_number, labels={'Code-Review':'+2'})
# Update the change.
new_msg = 'New %s' % gpatch.commit_message
cros_build_lib.run(
['git', 'commit', '--amend', '-m', new_msg], cwd=clone_path, quiet=True)
self.uploadChange(clone_path)
gpatch2 = self._GetHelper().QuerySingleRecord(
change=gpatch.change_id, project=gpatch.project, branch='master')
self.assertNotEqual(gpatch2.approval_timestamp, 0)
self.assertNotEqual(gpatch2.commit_timestamp, 0)
self.assertEqual(gpatch2.approval_timestamp, gpatch2.commit_timestamp)
@cros_test_lib.NetworkTest()
class DirectGerritHelperTest(cros_test_lib.TestCase):
"""Unittests for GerritHelper that use the real Chromium instance."""
# A big list of real changes.
CHANGES = ['235893', '*189165', '231790', '*190026', '231647', '234645']
def testMultipleChangeDetail(self):
"""Test ordering of results in GetMultipleChangeDetail"""
changes = [x for x in self.CHANGES if not x.startswith('*')]
helper = gerrit.GetCrosExternal()
results = list(helper.GetMultipleChangeDetail([str(x) for x in changes]))
gerrit_numbers = [str(x['_number']) for x in results]
self.assertEqual(changes, gerrit_numbers)
def testQueryMultipleCurrentPatchset(self):
"""Test ordering of results in QueryMultipleCurrentPatchset"""
changes = [x for x in self.CHANGES if not x.startswith('*')]
helper = gerrit.GetCrosExternal()
results = list(helper.QueryMultipleCurrentPatchset(changes))
self.assertEqual(changes, [x.gerrit_number for _, x in results])
self.assertEqual(changes, [x for x, _ in results])
def testGetGerritPatchInfo(self):
"""Test ordering of results in GetGerritPatchInfo"""
# Swizzle from our old syntax to the new syntax.
changes = []
for change in self.CHANGES:
if change.startswith('*'):
changes.append('chrome-internal:%s' % (change[1:],))
else:
changes.append('chromium:%s' % (change,))
results = list(gerrit.GetGerritPatchInfo(changes))
self.assertEqual(changes, [x.gerrit_number_str for x in results])