Movatterモバイル変換


[0]ホーム

URL:


Google Git
Sign in
chromium /chromium /src /refs/heads/main /. /tools /bisect_test.py
blob: 0092bc4ed36648052836a8914f08f90f1f3bb878 [file] [log] [blame] [edit]
# Copyright 2012 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import base64
import functools
import io
import json
import os
import re
import subprocess
import sys
import tempfile
import unittest
import urllib.request
from unittest.mockimport(ANY,Mock,MagicMock, mock_open, patch, call,
PropertyMock)
bisect_builds= __import__('bisect-builds')
if'NO_MOCK_SERVER'notin os.environ:
maybe_patch= patch
else:
# SetupEnvironment for gsutil to connect to real server.
options= bisect_builds.ParseCommandLine(['-a','linux64','-g','1'])
bisect_builds.SetupEnvironment(options)
bisect_builds.SetupAndroidEnvironment()
# Mock object that always wraps for the spec.
# This will pass the call through and ignore the return_value and side_effect.
classWrappedMock(MagicMock):
def __init__(self,
spec=None,
return_value=None,
side_effect=None,
*args,
**kwargs):
wraps= kwargs.pop('wraps', spec)
super().__init__(spec,*args,**kwargs, wraps=wraps)
maybe_patch= functools.partial(patch, spec=True, new_callable=WrappedMock)
maybe_patch.object= functools.partial(patch.object,
spec=True,
new_callable=WrappedMock)
classBisectTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Patch the name pattern for pkgutil to accept "bisect-builds" as module
# name.
if sys.version_info[:2]>(3,8):
dotted_words= r'(?!\d)([\w-]+)(\.(?!\d)(\w+))*'
name_pattern= re.compile(
f'^(?P<pkg>{dotted_words})'
f'(?P<cln>:(?P<obj>{dotted_words})?)?$', re.UNICODE)
cls.name_pattern_patcher= patch('pkgutil._NAME_PATTERN', name_pattern)
cls.name_pattern_patcher.start()
# patch cache filename to prevent pollute working dir.
fd, cls.tmp_cache_file= tempfile.mkstemp(suffix='.json')
os.close(fd)
cls.cache_filename_patcher= patch(
'bisect-builds.ArchiveBuild._rev_list_cache_filename',
new=PropertyMock(return_value=cls.tmp_cache_file))
cls.cache_filename_patcher.start()
@classmethod
def tearDownClass(cls):
if sys.version_info[:2]>(3,8):
cls.name_pattern_patcher.stop()
cls.cache_filename_patcher.stop()
os.unlink(cls.tmp_cache_file)
classBisectTest(BisectTestCase):
max_rev=10000
def setUp(self):
self.patchers=[]
self.patchers.append(patch('bisect-builds.DownloadJob._fetch'))
self.patchers.append(
patch('bisect-builds.ArchiveBuild.run_revision',
return_value=(0,'','')))
self.patchers.append(
patch('bisect-builds.SnapshotBuild._get_rev_list',
return_value=range(self.max_rev)))
for eachin self.patchers:
each.start()
def tearDown(self):
for eachin self.patchers:
each.stop()
def bisect(self, good_rev, bad_rev, evaluate, num_runs=1):
options= bisect_builds.ParseCommandLine([
'-a','linux64','-g',
str(good_rev),'-b',
str(bad_rev),'--times',
str(num_runs),'--no-local-cache'
])
archive_build= bisect_builds.create_archive_build(options)
(minrev, maxrev)= bisect_builds.Bisect(archive_build=archive_build,
evaluate=evaluate,
try_args=options.args)
return(minrev, maxrev)
@patch('builtins.print')
def testBisectConsistentAnswer(self, mock_print):
def get_steps():
steps=[]
for callin mock_print.call_args_list:
if call.argsand call.args[0].startswith('You have'):
steps.append(int(re.search(r'(\d+) steps', call.args[0])[1]))
return steps
self.assertEqual(self.bisect(1000,100,lambda*args:'g'),(100,101))
self.assertSequenceEqual(get_steps(), range(10,1,-1))
mock_print.reset_mock()
self.assertEqual(self.bisect(100,1000,lambda*args:'b'),(100,101))
self.assertSequenceEqual(get_steps(), range(10,0,-1))
mock_print.reset_mock()
self.assertEqual(self.bisect(2000,200,lambda*args:'b'),(1999,2000))
self.assertSequenceEqual(get_steps(), range(11,0,-1))
mock_print.reset_mock()
self.assertEqual(self.bisect(200,2000,lambda*args:'g'),(1999,2000))
self.assertSequenceEqual(get_steps(), range(11,1,-1))
@patch('bisect-builds.ArchiveBuild.run_revision', return_value=(0,'',''))
def test_bisect_should_retry(self, mock_run_revision):
evaluator=Mock(side_effect='rgrgrbr')
self.assertEqual(self.bisect(9,1, evaluator),(2,3))
tested_revisions=[c.args[0]for cin evaluator.call_args_list]
self.assertEqual(tested_revisions,[5,5,3,3,2,2])
self.assertEqual(mock_run_revision.call_count,6)
evaluator=Mock(side_effect='rgrrrgrbr')
self.assertEqual(self.bisect(1,10, evaluator),(8,9))
tested_revisions=[c.args[0]for cin evaluator.call_args_list]
self.assertEqual(tested_revisions,[6,6,8,8,8,8,9,9])
def test_bisect_should_unknown(self):
evaluator=Mock(side_effect='uuuggggg')
self.assertEqual(self.bisect(9,1, evaluator),(1,2))
tested_revisions=[c.args[0]for cin evaluator.call_args_list]
self.assertEqual(tested_revisions,[5,3,6,7,2])
evaluator=Mock(side_effect='uuugggggg')
self.assertEqual(self.bisect(1,9, evaluator),(8,9))
tested_revisions=[c.args[0]for cin evaluator.call_args_list]
self.assertEqual(tested_revisions,[5,7,4,3,8])
def test_bisect_should_quit(self):
evaluator=Mock(side_effect=SystemExit())
with self.assertRaises(SystemExit):
self.assertEqual(self.bisect(9,1, evaluator),(None,None))
def test_edge_cases(self):
with self.assertRaises(bisect_builds.BisectException):
self.assertEqual(self.bisect(1,1,Mock()),(1,1))
self.assertEqual(self.bisect(2,1,Mock()),(1,2))
self.assertEqual(self.bisect(1,2,Mock()),(1,2))
classDownloadJobTest(BisectTestCase):
@patch('bisect-builds.gsutil_download')
def test_fetch_gsutil(self, mock_gsutil_download):
fetch= bisect_builds.DownloadJob('gs://some-file.zip',123)
fetch.start()
fetch.wait_for()
mock_gsutil_download.assert_called_once()
@patch('urllib.request.urlretrieve')
def test_fetch_http(self, mock_urlretrieve):
fetch= bisect_builds.DownloadJob('http://some-file.zip',123)
fetch.start()
fetch.wait_for()
mock_urlretrieve.assert_called_once()
@patch('tempfile.mkstemp', return_value=(321,'some-file.zip'))
@patch('urllib.request.urlretrieve')
@patch('os.close')
@patch('os.unlink')
def test_should_del(self, mock_unlink, mock_close, mock_urlretrieve,
mock_mkstemp):
fetch= bisect_builds.DownloadJob('http://some-file.zip',123)
fetch.start().wait_for()
fetch.stop()
mock_mkstemp.assert_called_once()
mock_close.assert_called_once()
mock_urlretrieve.assert_called_once()
mock_unlink.assert_called_with('some-file.zip')
@patch('urllib.request.urlretrieve')
def test_stop_wait_for_should_be_able_to_reenter(self, mock_urlretrieve):
fetch= bisect_builds.DownloadJob('http://some-file.zip',123)
fetch.start()
fetch.wait_for()
fetch.wait_for()
fetch.stop()
fetch.stop()
@patch('tempfile.mkstemp',
side_effect=[(321,'some-file.apks'),(123,'file2.apk')])
@patch('bisect-builds.gsutil_download')
@patch('os.close')
@patch('os.unlink')
def test_should_support_multiple_files(self, mock_unlink, mock_close,
mock_gsutil, mock_mkstemp):
urls={
'trichrome':
('gs://chrome-unsigned/android-B0urB0N/129.0.6626.0/high-arm_64/'
'TrichromeChromeGoogle6432Stable.apks'),
'trichrome_library':
('gs://chrome-unsigned/android-B0urB0N/129.0.6626.0/high-arm_64/'
'TrichromeLibraryGoogle6432Stable.apk'),
}
fetch= bisect_builds.DownloadJob(urls,123)
result= fetch.start().wait_for()
fetch.stop()
self.assertDictEqual(result,{
'trichrome':'some-file.apks',
'trichrome_library':'file2.apk',
})
self.assertEqual(mock_mkstemp.call_count,2)
self.assertEqual(mock_close.call_count,2)
mock_unlink.assert_has_calls(
[call('some-file.apks'), call('file2.apk')], any_order=True)
self.assertEqual(mock_gsutil.call_count,2)
@patch(
"urllib.request.urlopen",
side_effect=urllib.request.HTTPError('url',404,'Not Found',None,None),
)
@patch('subprocess.Popen', spec=subprocess.Popen)
@patch('bisect-builds.GSUTILS_PATH', new='/some/path')
def test_download_failure_should_raised(self, mock_Popen, mock_urlopen):
fetch= bisect_builds.DownloadJob('http://some-file.zip',123)
with self.assertRaises(urllib.request.HTTPError):
fetch.start().wait_for()
mock_Popen.return_value.communicate.return_value=(b'', b'status=403')
mock_Popen.return_value.returncode=1
fetch= bisect_builds.DownloadJob('gs://some-file.zip',123)
with self.assertRaises(bisect_builds.BisectException):
fetch.start().wait_for()
classArchiveBuildTest(BisectTestCase):
def setUp(self):
self.patcher= patch.multiple(
bisect_builds.ArchiveBuild,
__abstractmethods__=set(),
build_type='release',
_get_rev_list=Mock(return_value=list(map(str, range(10)))),
_rev_list_cache_key='abc')
self.patcher.start()
def tearDown(self):
self.patcher.stop()
def create_build(self,*args):
args=['-a','linux64','-g','0','-b','9',*args]
options= bisect_builds.ParseCommandLine(args)
return bisect_builds.ArchiveBuild(options)
def test_cache_should_not_work_if_not_enabled(self):
build= self.create_build('--no-local-cache')
self.assertFalse(build.use_local_cache)
with patch('builtins.open')as m:
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
bisect_builds.ArchiveBuild._get_rev_list.assert_called_once()
m.assert_not_called()
def test_cache_should_save_and_load(self):
build= self.create_build()
self.assertTrue(build.use_local_cache)
# Load the non-existent cache and write to it.
cached_data=[]
# The cache file would be opened 3 times:
# 1. read by _load_rev_list_cache
# 2. read by _save_rev_list_cache for existing cache
# 3. write by _save_rev_list_cache
write_mock=MagicMock()
write_mock.__enter__().write.side_effect=lambda d: cached_data.append(d)
with patch('builtins.open',
side_effect=[FileNotFoundError,FileNotFoundError, write_mock]):
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
bisect_builds.ArchiveBuild._get_rev_list.assert_called_once()
cached_json= json.loads(''.join(cached_data))
self.assertDictEqual(cached_json,{'abc':[str(x)for xin range(10)]})
# Load cache with cached data.
build= self.create_build('--use-local-cache')
bisect_builds.ArchiveBuild._get_rev_list.reset_mock()
with patch('builtins.open', mock_open(read_data=''.join(cached_data))):
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
bisect_builds.ArchiveBuild._get_rev_list.assert_not_called()
@patch.object(bisect_builds.ArchiveBuild,'_load_rev_list_cache')
@patch.object(bisect_builds.ArchiveBuild,'_save_rev_list_cache')
@patch.object(bisect_builds.ArchiveBuild,
'_get_rev_list',
return_value=[str(x)for xin range(10)])
def test_should_request_partial_rev_list(self, mock_get_rev_list,
mock_save_rev_list_cache,
mock_load_rev_list_cache):
build= self.create_build('--no-local-cache')
# missing latest
mock_load_rev_list_cache.return_value=[str(x)for xin range(5)]
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
mock_get_rev_list.assert_called_with('4','9')
# missing old and latest
mock_load_rev_list_cache.return_value=[str(x)for xin range(1,5)]
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
mock_get_rev_list.assert_called_with('0','9')
# missing old
mock_load_rev_list_cache.return_value=[str(x)for xin range(3,10)]
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
mock_get_rev_list.assert_called_with('0','3')
# no intersect
mock_load_rev_list_cache.return_value=['c','d','e']
self.assertEqual(build.get_rev_list(),[str(x)for xin range(10)])
mock_save_rev_list_cache.assert_called_with([str(x)for xin range(10)]+
['c','d','e'])
mock_get_rev_list.assert_called_with('0','c')
@patch.object(bisect_builds.ArchiveBuild,'_get_rev_list', return_value=[])
def test_should_raise_error_when_no_rev_list(self, mock_get_rev_list):
build= self.create_build('--no-local-cache')
with self.assertRaises(bisect_builds.BisectException):
build.get_rev_list()
mock_get_rev_list.assert_any_call('0','9')
mock_get_rev_list.assert_any_call()
@unittest.skipIf('NO_MOCK_SERVER'notin os.environ,
'The test is to ensure NO_MOCK_SERVER working correctly')
@maybe_patch('bisect-builds.GetRevisionFromVersion', return_value=123)
def test_no_mock(self, mock_GetRevisionFromVersion):
self.assertEqual(bisect_builds.GetRevisionFromVersion('127.0.6533.74'),
1313161)
mock_GetRevisionFromVersion.assert_called()
@patch('bisect-builds.ArchiveBuild._install_revision')
@patch('bisect-builds.ArchiveBuild._launch_revision',
return_value=(1,'',''))
def test_run_revision_should_return_early(self, mock_launch_revision,
mock_install_revision):
build= self.create_build()
build.run_revision('','',[])
mock_launch_revision.assert_called_once()
@patch('bisect-builds.ArchiveBuild._install_revision')
@patch('bisect-builds.ArchiveBuild._launch_revision',
return_value=(0,'',''))
def test_run_revision_should_do_all_runs(self, mock_launch_revision,
mock_install_revision):
build= self.create_build('--time','10')
build.run_revision('','',[])
self.assertEqual(mock_launch_revision.call_count,10)
@patch('bisect-builds.UnzipFilenameToDir')
@patch('glob.glob', return_value=['temp-dir/linux64/chrome'])
@patch('os.path.abspath', return_value='/tmp/temp-dir/linux64/chrome')
def test_install_revision_should_unzip_and_search_executable(
self, mock_abspath, mock_glob, mock_UnzipFilenameToDir):
build= self.create_build()
self.assertEqual(build._install_revision('some-file.zip','temp-dir'),
{'chrome':'/tmp/temp-dir/linux64/chrome'})
mock_UnzipFilenameToDir.assert_called_once_with('some-file.zip','temp-dir')
mock_glob.assert_called_once_with('temp-dir/*/chrome')
mock_abspath.assert_called_once_with('temp-dir/linux64/chrome')
@patch('bisect-builds.UnzipFilenameToDir')
@patch('glob.glob',
side_effect=[['temp-dir/chrome-linux64/chrome'],
['temp-dir/chromedriver_linux64/chromedriver']])
@patch('os.path.abspath',
side_effect=[
'/tmp/temp-dir/chrome-linux64/chrome',
'/tmp/temp-dir/chromedriver_linux64/chromedriver'
])
def test_install_chromedriver(self, mock_abspath, mock_glob,
mock_UnzipFilenameToDir):
build= self.create_build('--chromedriver')
self.assertEqual(
build._install_revision(
{
'chrome':'some-file.zip',
'chromedriver':'some-other-file.zip',
},'temp-dir'),
{
'chrome':'/tmp/temp-dir/chrome-linux64/chrome',
'chromedriver':'/tmp/temp-dir/chromedriver_linux64/chromedriver',
})
mock_UnzipFilenameToDir.assert_has_calls([
call('some-file.zip','temp-dir'),
call('some-other-file.zip','temp-dir'),
])
mock_glob.assert_has_calls([
call('temp-dir/*/chrome'),
call('temp-dir/*/chromedriver'),
])
mock_abspath.assert_has_calls([
call('temp-dir/chrome-linux64/chrome'),
call('temp-dir/chromedriver_linux64/chromedriver')
])
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_launch_revision_should_run_command(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
build= self.create_build()
build._launch_revision('temp-dir',{'chrome':'temp-dir/linux64/chrome'},
[])
mock_Popen.assert_called_once_with(
'temp-dir/linux64/chrome --user-data-dir=temp-dir/profile',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
@unittest.skipIf(sys.platform.startswith('win'),'This test is not for win')
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_launch_revision_should_run_command_for_mac(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
build= self.create_build()
build._launch_revision(
'temp-dir',{
'chrome':
'temp-dir/full-build-mac/'
'Google Chrome.app/Contents/MacOS/Google Chrome'
},[])
mock_Popen.assert_called_once_with(
"'temp-dir/full-build-mac/"
"Google Chrome.app/Contents/MacOS/Google Chrome'"
' --user-data-dir=temp-dir/profile',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
@unittest.skipUnless(sys.platform.startswith('win'),
'This test is for win only')
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_launch_revision_should_run_command_for_win(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
build= self.create_build()
build._launch_revision(
'C:\\temp-dir',{
'chrome':'C:\\temp-dir\\full-build-win\\chrome.exe'
},[])
mock_Popen.assert_called_once_with(
"C:\\temp-dir\\full-build-win\\chrome.exe "
'--user-data-dir=C:\\temp-dir/profile',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_command_replacement(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
build= self.create_build(
'--chromedriver','-c',
'CHROMEDRIVER=%d BROWSER_EXECUTABLE_PATH=%p pytest %a')
build._launch_revision('/tmp',{
'chrome':'/tmp/chrome',
'chromedriver':'/tmp/chromedriver'
},['--args','--args2="word 1"','word 2'])
if sys.platform.startswith('win'):
mock_Popen.assert_called_once_with(
'CHROMEDRIVER=/tmp/chromedriver BROWSER_EXECUTABLE_PATH=/tmp/chrome '
'pytest --user-data-dir=/tmp/profile --args "--args2=\\"word 1\\"" '
'"word 2"',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
else:
mock_Popen.assert_called_once_with(
'CHROMEDRIVER=/tmp/chromedriver BROWSER_EXECUTABLE_PATH=/tmp/chrome '
'pytest --user-data-dir=/tmp/profile --args \'--args2="word 1"\' '
'\'word 2\'',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
classReleaseBuildTest(BisectTestCase):
def test_should_look_up_path_context(self):
options= bisect_builds.ParseCommandLine(
['-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88'])
self.assertEqual(options.archive,'linux64')
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
self.assertEqual(build.binary_name,'chrome')
self.assertEqual(build.listing_platform_dir,'linux64/')
self.assertEqual(build.archive_name,'chrome-linux64.zip')
self.assertEqual(build.archive_extract_dir,'chrome-linux64')
@maybe_patch(
'bisect-builds.GsutilList',
return_value=[
'gs://chrome-unsigned/desktop-5c0tCh/%s/linux64/chrome-linux64.zip'%
xfor xin['127.0.6533.74','127.0.6533.75','127.0.6533.76']
])
def test_get_rev_list(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.76',
'--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
self.assertEqual(build.get_rev_list(),
['127.0.6533.74','127.0.6533.75','127.0.6533.76'])
mock_GsutilList.assert_any_call('gs://chrome-unsigned/desktop-5c0tCh')
mock_GsutilList.assert_any_call(*[
'gs://chrome-unsigned/desktop-5c0tCh/%s/linux64/chrome-linux64.zip'% x
for xin['127.0.6533.74','127.0.6533.75','127.0.6533.76']
],
ignore_fail=True)
self.assertEqual(mock_GsutilList.call_count,2)
@patch('bisect-builds.GsutilList',
return_value=['127.0.6533.74','127.0.6533.75','127.0.6533.76'])
def test_should_save_and_load_cache(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.77',
'--use-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
# Load the non-existent cache and write to it.
cached_data=[]
write_mock=MagicMock()
write_mock.__enter__().write.side_effect=lambda d: cached_data.append(d)
with patch('builtins.open',
side_effect=[FileNotFoundError,FileNotFoundError, write_mock]):
self.assertEqual(build.get_rev_list(),
['127.0.6533.74','127.0.6533.75','127.0.6533.76'])
mock_GsutilList.assert_called()
cached_json= json.loads(''.join(cached_data))
self.assertDictEqual(
cached_json,{
build._rev_list_cache_key:
['127.0.6533.74','127.0.6533.75','127.0.6533.76']
})
# Load cache with cached data and merge with new data
mock_GsutilList.return_value=['127.0.6533.76','127.0.6533.77']
build= bisect_builds.create_archive_build(options)
with patch('builtins.open', mock_open(read_data=''.join(cached_data))):
self.assertEqual(
build.get_rev_list(),
['127.0.6533.74','127.0.6533.75','127.0.6533.76','127.0.6533.77'])
print(mock_GsutilList.call_args)
mock_GsutilList.assert_any_call(
'gs://chrome-unsigned/desktop-5c0tCh'
'/127.0.6533.76/linux64/chrome-linux64.zip',
'gs://chrome-unsigned/desktop-5c0tCh'
'/127.0.6533.77/linux64/chrome-linux64.zip',
ignore_fail=True)
def test_get_download_url(self):
options= bisect_builds.ParseCommandLine(
['-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.77'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
download_urls= build.get_download_url('127.0.6533.74')
self.assertEqual(
download_urls,'gs://chrome-unsigned/desktop-5c0tCh'
'/127.0.6533.74/linux64/chrome-linux64.zip')
options= bisect_builds.ParseCommandLine([
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.77',
'--chromedriver'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
download_urls= build.get_download_url('127.0.6533.74')
self.assertEqual(
download_urls,{
'chrome':
'gs://chrome-unsigned/desktop-5c0tCh'
'/127.0.6533.74/linux64/chrome-linux64.zip',
'chromedriver':
'gs://chrome-unsigned/desktop-5c0tCh'
'/127.0.6533.74/linux64/chromedriver_linux64.zip',
})
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision_with_real_zipfile(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.77',
'--chromedriver','-c','driver=%d prog=%p'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ReleaseBuild)
download_job= build.get_download_job('127.0.6533.74')
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
self.assertRegex(mock_run.call_args.args[0],
r'driver=.+/chromedriver prog=.+/chrome')
classArchiveBuildWithCommitPositionTest(BisectTestCase):
def setUp(self):
patch.multiple(bisect_builds.ArchiveBuildWithCommitPosition,
__abstractmethods__=set(),
build_type='release').start()
@maybe_patch('bisect-builds.GetRevisionFromVersion', return_value=1313161)
@maybe_patch('bisect-builds.GetChromiumRevision', return_value=999999999)
def test_should_convert_revision_as_commit_position(
self, mock_GetChromiumRevision, mock_GetRevisionFromVersion):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','127.0.6533.74'])
build= bisect_builds.ArchiveBuildWithCommitPosition(options)
self.assertEqual(build.good_revision,1313161)
self.assertEqual(build.bad_revision,999999999)
mock_GetRevisionFromVersion.assert_called_once_with('127.0.6533.74')
mock_GetChromiumRevision.assert_called()
classOfficialBuildTest(BisectTestCase):
def test_should_lookup_path_context(self):
options= bisect_builds.ParseCommandLine(
['-o','-a','linux64','-g','0','-b','10'])
self.assertEqual(options.archive,'linux64')
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.OfficialBuild)
self.assertEqual(build.binary_name,'chrome')
self.assertEqual(build.listing_platform_dir,'linux-builder-perf/')
self.assertEqual(build.archive_name,'chrome-perf-linux.zip')
self.assertEqual(build.archive_extract_dir,'full-build-linux')
@maybe_patch('bisect-builds.GsutilList',
return_value=[
'full-build-linux_%d.zip'% x
for xin range(1313161,1313164)
])
def test_get_rev_list(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-o','-a','linux64','-g','1313161','-b','1313163',
'--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.OfficialBuild)
self.assertEqual(build.get_rev_list(), list(range(1313161,1313164)))
mock_GsutilList.assert_called_once_with(
'gs://chrome-test-builds/official-by-commit/linux-builder-perf/')
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision_with_real_zipfile(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-o','-a','linux64','-g','1313161','-b','1313163',
'--chromedriver','-c','driver=%d prog=%p'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.OfficialBuild)
download_job= build.get_download_job(1334339)
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
self.assertRegex(mock_run.call_args.args[0],
r'driver=.+/chromedriver prog=.+/chrome')
classSnapshotBuildTest(BisectTestCase):
def test_should_lookup_path_context(self):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','0','-b','10'])
self.assertEqual(options.archive,'linux64')
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
self.assertEqual(build.binary_name,'chrome')
self.assertEqual(build.listing_platform_dir,'Linux_x64/')
self.assertEqual(build.archive_name,'chrome-linux.zip')
self.assertEqual(build.archive_extract_dir,'chrome-linux')
CommonDataXMLContent='''<?xml version='1.0' encoding='UTF-8'?>
<ListBucketResult xmlns='http://doc.s3.amazonaws.com/2006-03-01'>
<Name>chromium-browser-snapshots</Name>
<Prefix>Linux_x64/</Prefix>
<Marker></Marker>
<NextMarker></NextMarker>
<Delimiter>/</Delimiter>
<IsTruncated>true</IsTruncated>
<CommonPrefixes>
<Prefix>Linux_x64/1313161/</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>Linux_x64/1313163/</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>Linux_x64/1313185/</Prefix>
</CommonPrefixes>
</ListBucketResult>
'''
@maybe_patch('urllib.request.urlopen',
return_value=io.BytesIO(CommonDataXMLContent.encode('utf8')))
@patch('bisect-builds.GetChromiumRevision', return_value=1313185)
def test_get_rev_list(self, mock_GetChromiumRevision, mock_urlopen):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','1313161','-b','1313185','--no-local-cache'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
rev_list= build.get_rev_list()
mock_urlopen.assert_any_call(
'http://commondatastorage.googleapis.com/chromium-browser-snapshots/'
'?delimiter=/&prefix=Linux_x64/&marker=Linux_x64/1313161')
self.assertEqual(mock_urlopen.call_count,1)
self.assertEqual(rev_list,[1313161,1313163,1313185])
@patch('bisect-builds.SnapshotBuild._fetch_and_parse',
return_value=([int(s)
for sin sorted([str(x)for xin range(1,11)])],None))
def test_get_rev_list_should_start_from_a_marker(self, mock_fetch_and_parse):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','0','-b','9','--no-local-cache'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
rev_list= build._get_rev_list(0,9)
self.assertEqual(rev_list, list(range(1,10)))
mock_fetch_and_parse.assert_called_once_with(
'http://commondatastorage.googleapis.com/chromium-browser-snapshots/'
'?delimiter=/&prefix=Linux_x64/&marker=Linux_x64/0')
mock_fetch_and_parse.reset_mock()
rev_list= build._get_rev_list(1,9)
self.assertEqual(rev_list, list(range(1,10)))
mock_fetch_and_parse.assert_called_once_with(
'http://commondatastorage.googleapis.com/chromium-browser-snapshots/'
'?delimiter=/&prefix=Linux_x64/&marker=Linux_x64/1')
@patch('bisect-builds.SnapshotBuild._fetch_and_parse',
return_value=([int(s)
for sin sorted([str(x)for xin range(1,11)])],None))
def test_get_rev_list_should_scan_all_pages(self, mock_fetch_and_parse):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','3','-b','11','--no-local-cache'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
rev_list= build._get_rev_list(0,11)
self.assertEqual(sorted(rev_list), list(range(1,11)))
mock_fetch_and_parse.assert_called_once_with(
'http://commondatastorage.googleapis.com/chromium-browser-snapshots/'
'?delimiter=/&prefix=Linux_x64/')
def test_get_download_url(self):
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','3','-b','11'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
download_urls= build.get_download_url(123)
self.assertEqual(
download_urls,
'http://commondatastorage.googleapis.com/chromium-browser-snapshots'
'/Linux_x64/123/chrome-linux.zip',
)
options= bisect_builds.ParseCommandLine(
['-a','linux64','-g','3','-b','11','--chromedriver'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
download_urls= build.get_download_url(123)
self.assertDictEqual(
download_urls,{
'chrome':
'http://commondatastorage.googleapis.com/chromium-browser-snapshots'
'/Linux_x64/123/chrome-linux.zip',
'chromedriver':
'http://commondatastorage.googleapis.com/chromium-browser-snapshots'
'/Linux_x64/123/chromedriver_linux64.zip'
})
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision_with_real_zipfile(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-a','linux64','-g','1313161','-b','1313185','--chromedriver',
'-c','driver=%d prog=%p'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
download_job= build.get_download_job(1313161)
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
self.assertRegex(mock_run.call_args.args[0],
r'driver=.+/chromedriver prog=.+/chrome')
@patch('bisect-builds.GetChromiumRevision', return_value=1313185)
def test_get_bad_revision(self, mock_GetChromiumRevision):
options= bisect_builds.ParseCommandLine(['-a','linux64','-g','1313161'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
mock_GetChromiumRevision.assert_called_once_with(
'http://commondatastorage.googleapis.com/chromium-browser-snapshots'
'/Linux_x64/LAST_CHANGE')
self.assertEqual(build.bad_revision,1313185)
classChromeForTestingBuild(BisectTestCase):
def test_should_lookup_path_context(self):
options= bisect_builds.ParseCommandLine(
['-cft','-a','linux64','-g','0','-b','10'])
self.assertEqual(options.archive,'linux64')
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
self.assertEqual(build.binary_name,'chrome')
self.assertEqual(build.listing_platform_dir,'linux64/')
self.assertEqual(build.archive_name,'chrome-linux64.zip')
self.assertEqual(build.chromedriver_binary_name,'chromedriver')
self.assertEqual(build.chromedriver_archive_name,
'chromedriver-linux64.zip')
CommonDataXMLContent='''<?xml version='1.0' encoding='UTF-8'?>
<ListBucketResult xmlns="http://doc.s3.amazonaws.com/2006-03-01">
<Name>chrome-for-testing-per-commit-public</Name>
<Prefix>linux64/</Prefix>
<Marker/>
<Delimiter>/</Delimiter>
<IsTruncated>false</IsTruncated>
<Contents>
<Key>linux64/LAST_CHANGE</Key>
<Generation>1733959087133532</Generation>
<MetaGeneration>1</MetaGeneration>
<LastModified>2024-12-11T23:18:07.235Z</LastModified>
<ETag>"dd60cb93e225ab33d7254beca56b507a"</ETag>
<Size>7</Size>
</Contents>
<CommonPrefixes>
<Prefix>linux64/r1390729/</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>linux64/r1390746/</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>linux64/r1390757/</Prefix>
</CommonPrefixes>
</ListBucketResult>
'''
@maybe_patch('urllib.request.urlopen',
return_value=io.BytesIO(CommonDataXMLContent.encode('utf8')))
@patch('bisect-builds.GetChromiumRevision', return_value=1390757)
def test_get_rev_list(self, mock_GetChromiumRevision, mock_urlopen):
options= bisect_builds.ParseCommandLine([
'-cft','-a','linux64','-g','1390729','-b','1390757',
'--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
rev_list= build.get_rev_list()
mock_urlopen.assert_any_call(
'https://storage.googleapis.com/chrome-for-testing-per-commit-public/'
'?delimiter=/&prefix=linux64/&marker=linux64/r1390729')
self.assertEqual(mock_urlopen.call_count,1)
self.assertEqual(rev_list,[1390729,1390746,1390757])
def test_get_marker(self):
options= bisect_builds.ParseCommandLine(
['-cft','-a','linux64','-g','1','-b','3'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
self.assertEqual('linux64/r1390729',
build._get_marker_for_revision(1390729))
def test_get_download_url(self):
options= bisect_builds.ParseCommandLine(
['-cft','-a','linux64','-g','3','-b','11'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
download_urls= build.get_download_url(123)
self.assertEqual(
download_urls,
'https://storage.googleapis.com/chrome-for-testing-per-commit-public'
'/linux64/r123/chrome-linux64.zip',
)
options= bisect_builds.ParseCommandLine(
['-cft','-a','linux64','-g','3','-b','11','--chromedriver'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
download_urls= build.get_download_url(123)
download_urls= build.get_download_url(123)
self.assertEqual(
download_urls,{
'chrome':
'https://storage.googleapis.com/chrome-for-testing-per-commit-public'
'/linux64/r123/chrome-linux64.zip',
'chromedriver':
'https://storage.googleapis.com/chrome-for-testing-per-commit-public'
'/linux64/r123/chromedriver-linux64.zip',
})
@patch('bisect-builds.GetChromiumRevision', return_value=1390757)
def test_get_bad_revision(self, mock_GetChromiumRevision):
options= bisect_builds.ParseCommandLine(
['-cft','-a','linux64','-g','3'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ChromeForTestingBuild)
mock_GetChromiumRevision.assert_called_once_with(
'https://storage.googleapis.com/chrome-for-testing-per-commit-public'
'/linux64/LAST_CHANGE')
self.assertEqual(build.bad_revision,1390757)
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision_with_real_zipfile(self, mock_run):
options= bisect_builds.ParseCommandLine([
'--cft','-a','linux64','-g','1','--chromedriver','-c',
'driver=%d prog=%p'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.SnapshotBuild)
download_job= build.get_download_job(build.bad_revision)
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
self.assertRegex(mock_run.call_args.args[0],
r'driver=.+/chromedriver prog=.+/chrome')
classASANBuildTest(BisectTestCase):
CommonDataXMLContent='''<?xml version='1.0' encoding='UTF-8'?>
<ListBucketResult xmlns='http://doc.s3.amazonaws.com/2006-03-01'>
<Name>chromium-browser-asan</Name>
<Prefix>mac-release/asan-mac-release</Prefix>
<Marker></Marker>
<NextMarker></NextMarker>
<Delimiter>.zip</Delimiter>
<IsTruncated>true</IsTruncated>
<CommonPrefixes>
<Prefix>mac-release/asan-mac-release-1313186.zip</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>mac-release/asan-mac-release-1313195.zip</Prefix>
</CommonPrefixes>
<CommonPrefixes>
<Prefix>mac-release/asan-mac-release-1313210.zip</Prefix>
</CommonPrefixes>
</ListBucketResult>
'''
@maybe_patch('urllib.request.urlopen',
return_value=io.BytesIO(CommonDataXMLContent.encode('utf8')))
def test_get_rev_list(self, mock_urlopen):
options= bisect_builds.ParseCommandLine([
'--asan','-a','mac','-g','1313161','-b','1313210',
'--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.ASANBuild)
rev_list= build.get_rev_list()
# print(mock_urlopen.call_args_list)
mock_urlopen.assert_any_call(
'http://commondatastorage.googleapis.com/chromium-browser-asan/'
'?delimiter=.zip&prefix=mac-release/asan-mac-release'
'&marker=mac-release/asan-mac-release-1313161.zip')
self.assertEqual(mock_urlopen.call_count,1)
self.assertEqual(rev_list,[1313186,1313195,1313210])
classAndroidBuildTest(BisectTestCase):
def setUp(self):
# patch for devil_imports
self.patchers=[]
flag_changer_patcher= maybe_patch('bisect-builds.flag_changer',
create=True)
self.patchers.append(flag_changer_patcher)
self.mock_flag_changer= flag_changer_patcher.start()
chrome_patcher= maybe_patch('bisect-builds.chrome', create=True)
self.patchers.append(chrome_patcher)
self.mock_chrome= chrome_patcher.start()
version_codes_patcher= maybe_patch('bisect-builds.version_codes',
create=True)
self.patchers.append(version_codes_patcher)
self.mock_version_codes= version_codes_patcher.start()
self.mock_version_codes.LOLLIPOP=21
self.mock_version_codes.NOUGAT=24
self.mock_version_codes.PIE=28
self.mock_version_codes.Q=29
initial_android_device_patcher= patch(
'bisect-builds.InitializeAndroidDevice')
self.patchers.append(initial_android_device_patcher)
self.mock_initial_android_device= initial_android_device_patcher.start()
self.device= self.mock_initial_android_device.return_value
self.set_sdk_level(bisect_builds.version_codes.Q)
def set_sdk_level(self, level):
self.device.build_version_sdk= level
def tearDown(self):
for patcherin self.patchers:
patcher.stop()
classAndroidReleaseBuildTest(AndroidBuildTest):
def setUp(self):
super().setUp()
self.set_sdk_level(bisect_builds.version_codes.PIE)
@maybe_patch(
'bisect-builds.GsutilList',
return_value=[
'gs://chrome-signed/android-B0urB0N/%s/arm_64/MonochromeStable.apk'%
xfor xin['127.0.6533.76','127.0.6533.78','127.0.6533.79']
])
def test_get_android_rev_list(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64','--apk','chrome_stable','-g',
'127.0.6533.76','-b','127.0.6533.79','--signed','--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidReleaseBuild)
self.assertEqual(build.get_rev_list(),
['127.0.6533.76','127.0.6533.78','127.0.6533.79'])
mock_GsutilList.assert_any_call('gs://chrome-signed/android-B0urB0N')
mock_GsutilList.assert_any_call(*[
'gs://chrome-signed/android-B0urB0N/%s/arm_64/MonochromeStable.apk'% x
for xin['127.0.6533.76','127.0.6533.78','127.0.6533.79']
],
ignore_fail=True)
self.assertEqual(mock_GsutilList.call_count,2)
@patch('bisect-builds.InstallOnAndroid')
def test_install_revision(self, mock_InstallOnAndroid):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64','-g','127.0.6533.76','-b',
'127.0.6533.79','--apk','chrome'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidReleaseBuild)
build._install_revision('chrome.apk','temp-dir')
mock_InstallOnAndroid.assert_called_once_with(self.device,'chrome.apk')
@patch('bisect-builds.LaunchOnAndroid')
def test_launch_revision(self, mock_LaunchOnAndroid):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64','-g','127.0.6533.76','-b',
'127.0.6533.79','--apk','chrome'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidReleaseBuild)
build._launch_revision('temp-dir',None)
mock_LaunchOnAndroid.assert_called_once_with(self.device,'chrome')
@patch('bisect-builds.LaunchOnAndroid')
def test_webview_launch_revision(self, mock_LaunchOnAndroid):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64','-g','127.0.6533.76','-b',
'127.0.6533.79','--apk','system_webview'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidReleaseBuild)
build._launch_revision('temp-dir',None)
mock_LaunchOnAndroid.assert_called_once_with(self.device,'system_webview')
with self.assertRaises(bisect_builds.BisectException):
build._launch_revision('temp-dir',None,['args'])
classAndroidSnapshotBuildTest(AndroidBuildTest):
def setUp(self):
super().setUp()
self.set_sdk_level(bisect_builds.version_codes.PIE)
@patch('bisect-builds.UnzipFilenameToDir')
@patch('bisect-builds.InstallOnAndroid')
@patch('glob.glob', return_value=['Monochrome.apk'])
def test_install_revision(self, mock_glob, mock_InstallOnAndroid, mock_unzip):
options= bisect_builds.ParseCommandLine([
'-a','android-arm64','-g','1313161','-b','1313210','--apk',
'chrome'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidSnapshotBuild)
build._install_revision('chrome.zip','temp-dir')
mock_glob.assert_called_once_with('temp-dir/*/apks/Monochrome.apk')
mock_InstallOnAndroid.assert_called_once_with(self.device,'Monochrome.apk')
@patch('bisect-builds.UnzipFilenameToDir')
@patch('sys.stdout', new_callable=io.StringIO)
@patch('glob.glob',
side_effect=[[],
[
"temp-dir/full-build-linux/apks/MonochromeBeta.apk",
"temp-dir/full-build-linux/apks/ChromePublic.apk"
]])
def test_install_revision_with_show_available_apks(self, mock_glob,
mock_stdout, mock_unzip):
options= bisect_builds.ParseCommandLine([
'-a','android-arm64','-g','1313161','-b','1313210','--apk',
'chrome'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidSnapshotBuild)
with self.assertRaises(bisect_builds.BisectException):
build._install_revision('chrome.zip','temp-dir')
self.assertIn("The list of available --apk:", mock_stdout.getvalue())
self.assertIn("chrome_beta", mock_stdout.getvalue())
self.assertIn("chromium", mock_stdout.getvalue())
@patch('bisect-builds.UnzipFilenameToDir')
@patch('sys.stdout', new_callable=io.StringIO)
@patch('glob.glob',
side_effect=[[],["temp-dir/full-build-linux/apks/unknown.apks"]])
def test_install_revision_with_show_unknown_apks(self, mock_glob, mock_stdout,
mock_unzip):
options= bisect_builds.ParseCommandLine([
'-a','android-arm64','-g','1313161','-b','1313210','--apk',
'chrome'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidSnapshotBuild)
with self.assertRaises(bisect_builds.BisectException):
build._install_revision('chrome.zip','temp-dir')
self.assertIn("No supported apk found. But found following",
mock_stdout.getvalue())
self.assertIn("unknown.apks", mock_stdout.getvalue())
classAndroidTrichromeReleaseBuildTest(AndroidBuildTest):
def setUp(self):
super().setUp()
self.set_sdk_level(bisect_builds.version_codes.Q)
@maybe_patch(
'bisect-builds.GsutilList',
side_effect=[[
'gs://chrome-unsigned/android-B0urB0N/%s/'% xfor xin[
'129.0.6626.0','129.0.6626.1','129.0.6627.0','129.0.6627.1',
'129.0.6628.0','129.0.6628.1'
]
],
[('gs://chrome-unsigned/android-B0urB0N/%s/'
'high-arm_64/TrichromeChromeGoogle6432Stable.apks')% x
for xin['129.0.6626.0','129.0.6627.0','129.0.6628.0']]])
def test_get_rev_list(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64-high','--apk','chrome_stable','-g',
'129.0.6626.0','-b','129.0.6628.0','--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeReleaseBuild)
self.assertEqual(build.get_rev_list(),
['129.0.6626.0','129.0.6627.0','129.0.6628.0'])
print(mock_GsutilList.call_args_list)
mock_GsutilList.assert_any_call('gs://chrome-unsigned/android-B0urB0N')
mock_GsutilList.assert_any_call(*[
('gs://chrome-unsigned/android-B0urB0N/%s/'
'high-arm_64/TrichromeChromeGoogle6432Stable.apks')% xfor xin[
'129.0.6626.0','129.0.6626.1','129.0.6627.0','129.0.6627.1',
'129.0.6628.0'
]
],
ignore_fail=True)
self.assertEqual(mock_GsutilList.call_count,2)
def test_should_raise_exception_for_PIE(self):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64-high','--apk','chrome_stable','-g',
'129.0.6626.0','-b','129.0.6667.0'
])
self.set_sdk_level(bisect_builds.version_codes.PIE)
with self.assertRaises(bisect_builds.BisectException):
bisect_builds.create_archive_build(options)
def test_get_download_url(self):
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64-high','--apk','chrome_stable','-g',
'129.0.6626.0','-b','129.0.6628.0'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeReleaseBuild)
download_urls= build.get_download_url('129.0.6626.0')
self.maxDiff=1000
self.assertDictEqual(
download_urls,{
'trichrome':
('gs://chrome-unsigned/android-B0urB0N/129.0.6626.0/high-arm_64/'
'TrichromeChromeGoogle6432Stable.apks'),
'trichrome_library':
('gs://chrome-unsigned/android-B0urB0N/129.0.6626.0/high-arm_64/'
'TrichromeLibraryGoogle6432Stable.apk'),
})
@patch('bisect-builds.InstallOnAndroid')
def test_install_revision(self, mock_InstallOnAndroid):
downloads={
'trichrome':'some-file.apks',
'trichrome_library':'file2.apk',
}
options= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64-high','--apk','chrome_stable','-g',
'129.0.6626.0','-b','129.0.6628.0'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeReleaseBuild)
build._install_revision(downloads,'tmp-dir')
mock_InstallOnAndroid.assert_any_call(self.device,'some-file.apks')
mock_InstallOnAndroid.assert_any_call(self.device,'file2.apk')
classAndroidTrichromeOfficialBuildTest(AndroidBuildTest):
@maybe_patch('bisect-builds.GsutilList',
return_value=[
'full-build-linux_%d.zip'% x
for xin[1334339,1334342,1334344,1334345,1334356]
])
def test_get_rev_list(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','chrome','-g','1334338',
'-b','1334380','--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
self.assertEqual(build.get_rev_list(),
[1334339,1334342,1334344,1334345,1334356])
mock_GsutilList.assert_called_once_with(
'gs://chrome-test-builds/official-by-commit/'
'android_arm64_high_end-builder-perf/')
def test_get_download_url(self):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','chrome','-g','1334338',
'-b','1334380'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
self.assertEqual(
build.get_download_url(1334338),
'gs://chrome-test-builds/official-by-commit'
'/android_arm64_high_end-builder-perf/full-build-linux_1334338.zip')
@patch('glob.glob',
side_effect=[[
'temp-dir/full-build-linux/apks/TrichromeChromeGoogle6432.apks'
],['temp-dir/full-build-linux/apks/TrichromeLibraryGoogle6432.apk']])
@patch('bisect-builds.UnzipFilenameToDir')
@patch('bisect-builds.InstallOnAndroid')
def test_install_revision(self, mock_InstallOnAndroid,
mock_UnzipFilenameToDir, mock_glob):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','chrome','-g','1334338',
'-b','1334380'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
build._install_revision('download.zip','tmp-dir')
mock_UnzipFilenameToDir.assert_called_once_with('download.zip','tmp-dir')
mock_InstallOnAndroid.assert_any_call(
self.device,
'temp-dir/full-build-linux/apks/TrichromeLibraryGoogle6432.apk')
mock_InstallOnAndroid.assert_any_call(
self.device,
'temp-dir/full-build-linux/apks/TrichromeChromeGoogle6432.apks')
@patch('sys.stdout', new_callable=io.StringIO)
@patch('glob.glob',
side_effect=[[],
['temp-dir/TrichromeChromeGoogle6432Canary.minimal.apks']
])
@patch('bisect-builds.UnzipFilenameToDir')
def test_install_revision_with_show_available_apks(self,
mock_UnzipFilenameToDir,
mock_glob, mock_stdout):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','chrome','-g','1334338',
'-b','1334380'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
with self.assertRaises(bisect_builds.BisectException):
build._install_revision('download.zip','tmp-dir')
self.assertIn("The list of available --apk:", mock_stdout.getvalue())
self.assertIn("chrome_canary", mock_stdout.getvalue())
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.InstallOnAndroid')
@patch('bisect-builds.LaunchOnAndroid')
def test_run_revision_with_real_zipfile(self, mock_LaunchOnAndroid,
mock_InstallOnAndroid):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','chrome','-g','1334338',
'-b','1334380'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
download_job= build.get_download_job(1334339)
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
print(mock_InstallOnAndroid.call_args_list)
self.assertRegex(mock_InstallOnAndroid.mock_calls[0].args[1],
'full-build-linux/apks/TrichromeLibraryGoogle6432.apk$')
self.assertRegex(
mock_InstallOnAndroid.mock_calls[1].args[1],
'full-build-linux/apks/TrichromeChromeGoogle6432.minimal.apks$')
mock_LaunchOnAndroid.assert_called_once_with(self.device,'chrome')
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.InstallOnAndroid')
@patch('bisect-builds.LaunchOnAndroid')
def test_run_revision_with_webview_apk_with_unsupported_versions(
self, mock_LaunchOnAndroid, mock_InstallOnAndroid):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','system_webview','-g',
'100000','-b','100010'
])
with self.assertRaises(bisect_builds.BisectException):
_= bisect_builds.create_archive_build(options)
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.InstallOnAndroid')
@patch('bisect-builds.LaunchOnAndroid')
def test_webview_launch_revision(self, mock_LaunchOnAndroid,
mock_InstallOnAndroid):
options= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','--apk','system_webview','-g',
'1350000','-b','1350010'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.AndroidTrichromeOfficialBuild)
download_job= build.get_download_job(1334339)
zip_file= download_job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(zip_file, tempdir,[])
print(mock_InstallOnAndroid.call_args_list)
self.assertRegex(mock_InstallOnAndroid.mock_calls[0].args[1],
'full-build-linux/apks/TrichromeLibraryGoogle6432.apk$')
self.assertRegex(
mock_InstallOnAndroid.mock_calls[1].args[1],
'full-build-linux/apks/TrichromeWebViewGoogle6432.minimal.apks$')
mock_LaunchOnAndroid.assert_called_once_with(self.device,'system_webview')
classLinuxReleaseBuildTest(BisectTestCase):
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_launch_revision_should_has_no_sandbox(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
options= bisect_builds.ParseCommandLine(
['-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88'])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.LinuxReleaseBuild)
build._launch_revision('temp-dir',{'chrome':'temp-dir/linux64/chrome'},
[])
mock_Popen.assert_called_once_with(
'temp-dir/linux64/chrome --user-data-dir=temp-dir/profile --no-sandbox',
cwd=None,
shell=True,
bufsize=-1,
stdout=ANY,
stderr=ANY)
classIOSReleaseBuildTest(BisectTestCase):
@maybe_patch(
'bisect-builds.GsutilList',
side_effect=[[
'gs://chrome-unsigned/ios-G1N/127.0.6533.76/',
'gs://chrome-unsigned/ios-G1N/127.0.6533.77/',
'gs://chrome-unsigned/ios-G1N/127.0.6533.78/'
],
[
'gs://chrome-unsigned/ios-G1N'
'/127.0.6533.76/iphoneos17.5/ios/10863/canary.ipa',
'gs://chrome-unsigned/ios-G1N'
'/127.0.6533.77/iphoneos17.5/ios/10866/canary.ipa',
'gs://chrome-unsigned/ios-G1N'
'/127.0.6533.78/iphoneos17.5/ios/10868/canary.ipa'
]])
def test_list_rev(self, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios','--ipa=canary.ipa','--device-id','321','-g',
'127.0.6533.74','-b','127.0.6533.78','--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSReleaseBuild)
self.assertEqual(build.get_rev_list(),
['127.0.6533.76','127.0.6533.77','127.0.6533.78'])
mock_GsutilList.assert_any_call('gs://chrome-unsigned/ios-G1N')
mock_GsutilList.assert_any_call(*[
'gs://chrome-unsigned/ios-G1N/%s/*/ios/*/canary.ipa'% x
for xin['127.0.6533.76','127.0.6533.77','127.0.6533.78']
],
ignore_fail=True)
@patch('bisect-builds.UnzipFilenameToDir')
@patch('glob.glob', return_value=['Payload/canary.app/Info.plist'])
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_install_revision(self, mock_Popen, mock_glob,
mock_UnzipFilenameToDir):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
options= bisect_builds.ParseCommandLine([
'-r','-a','ios','--ipa=canary.ipa','--device-id','321','-g',
'127.0.6533.74','-b','127.0.6533.78'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSReleaseBuild)
build._install_revision('canary.ipa','tempdir')
mock_glob.assert_called_once_with('tempdir/Payload/*/Info.plist')
mock_Popen.assert_has_calls([
call([
'xcrun','devicectl','device','install','app','--device','321',
'canary.ipa'
],
cwd=None,
shell=False,
bufsize=-1,
stdout=-1,
stderr=-1),
call([
'plutil','-extract','CFBundleIdentifier','raw',
'Payload/canary.app/Info.plist'
],
cwd=None,
shell=False,
bufsize=-1,
stdout=-1,
stderr=-1)
],
any_order=True)
@patch('subprocess.Popen', spec=subprocess.Popen)
def test_launch_revision(self, mock_Popen):
mock_Popen.return_value.communicate.return_value=('','')
mock_Popen.return_value.returncode=0
options= bisect_builds.ParseCommandLine([
'-r','-a','ios','--ipa=canary.ipa','--device-id','321','-g',
'127.0.6533.74','-b','127.0.6533.78','--','args1','args2'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSReleaseBuild)
build._launch_revision('tempdir','com.google.chrome.ios', options.args)
mock_Popen.assert_any_call([
'xcrun','devicectl','device','process','launch','--device','321',
'com.google.chrome.ios','args1','args2'
],
cwd=None,
shell=False,
bufsize=-1,
stdout=-1,
stderr=-1)
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios','--ipa=canary.ipa','--device-id','321','-g',
'127.0.6533.74','-b','127.0.6533.78'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSReleaseBuild)
job= build.get_download_job('127.0.6533.76')
ipa= job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(ipa, tempdir, options.args)
mock_run.assert_has_calls([
call([
'xcrun','devicectl','device','install','app','--device','321',
ANY
]),
call(['plutil','-extract','CFBundleIdentifier','raw', ANY]),
call([
'xcrun','devicectl','device','process','launch','--device',
'321','stdout'
])
])
classIOSSimulatorReleaseBuildTest(BisectTestCase):
@maybe_patch(
'bisect-builds.GsutilList',
side_effect=[
[
'gs://bling-archive/128.0.6534.0/',
'gs://bling-archive/128.0.6534.1/',
'gs://bling-archive/128.0.6535.0/',
'gs://bling-archive/128.0.6535.1/',
'gs://bling-archive/128.0.6536.0/',
],
[
'gs://bling-archive/128.0.6534.0/20240612011643/Chromium.tar.gz',
'gs://bling-archive/128.0.6536.0/20240613011356/Chromium.tar.gz',
]
])
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'',''))
def test_list_rev(self, mock_run, mock_GsutilList):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios-simulator','--device-id','321','-g','128.0.6534.0',
'-b','128.0.6536.0','--no-local-cache'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSSimulatorReleaseBuild)
self.assertEqual(build.get_rev_list(),['128.0.6534.0','128.0.6536.0'])
mock_run.assert_called_once_with(['xcrun','simctl','boot','321'])
mock_GsutilList.assert_any_call('gs://bling-archive')
mock_GsutilList.assert_any_call(*[
'gs://bling-archive/%s/*/Chromium.tar.gz'% xfor xin[
'128.0.6534.0','128.0.6534.1','128.0.6535.0','128.0.6535.1',
'128.0.6536.0'
]
],
ignore_fail=True)
@patch('bisect-builds.UnzipFilenameToDir')
@patch('glob.glob', return_value=['Info.plist'])
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'',''))
def test_install_revision(self, mock_run, mock_glob, mock_UnzipFilenameToDir):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios-simulator','--device-id','321','-g','128.0.6534.0',
'-b','128.0.6539.0'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSSimulatorReleaseBuild)
build._install_revision('Chromium.tar.gz','tempdir')
mock_UnzipFilenameToDir.assert_called_once_with('Chromium.tar.gz',
'tempdir')
self.assertEqual(mock_glob.call_count,2)
mock_run.assert_has_calls([
call(['xcrun','simctl','boot','321']),
call(['xcrun','simctl','install','321', ANY]),
call(['plutil','-extract','CFBundleIdentifier','raw','Info.plist']),
])
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'',''))
def test_launch_revision(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios-simulator','--device-id','321','-g','128.0.6534.0',
'-b','128.0.6539.0'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSSimulatorReleaseBuild)
build._launch_revision('tempdir','com.google.chrome.ios.dev',
['args1','args2'])
mock_run.assert_any_call([
'xcrun','simctl','launch','321','com.google.chrome.ios.dev',
'args1','args2'
])
@unittest.skipUnless('NO_MOCK_SERVER'in os.environ,
'The test only valid when NO_MOCK_SERVER')
@patch('bisect-builds.ArchiveBuild._run', return_value=(0,'stdout',''))
def test_run_revision(self, mock_run):
options= bisect_builds.ParseCommandLine([
'-r','-a','ios-simulator','--device-id','321','-g','128.0.6534.0',
'-b','128.0.6539.0'
])
build= bisect_builds.create_archive_build(options)
self.assertIsInstance(build, bisect_builds.IOSSimulatorReleaseBuild)
job= build.get_download_job('128.0.6534.0')
download= job.start().wait_for()
with tempfile.TemporaryDirectory(prefix='bisect_tmp')as tempdir:
build.run_revision(download, tempdir, options.args)
mock_run.assert_has_calls([
call(['xcrun','simctl','boot','321']),
call(['xcrun','simctl','install','321', ANY]),
call(['plutil','-extract','CFBundleIdentifier','raw', ANY]),
call(['xcrun','simctl','launch','321','stdout'])
])
classMaybeSwitchBuildTypeTest(BisectTestCase):
def test_generate_new_command_without_cache(self):
command_line=[
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88',
'--no-local-cache'
]
options= bisect_builds.ParseCommandLine(command_line)
with patch('sys.argv',['bisect-builds.py',*command_line]):
new_cmd= bisect_builds.MaybeSwitchBuildType(
options, bisect_builds.ChromiumVersion('127.0.6533.74'),
bisect_builds.ChromiumVersion('127.0.6533.88'))
self.assertEqual(new_cmd[1:],[
'-o','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88',
'--verify-range','--no-local-cache'
])
def test_android_signed_with_args(self):
command_line=[
'-r','--archive=android-arm64-high','--good=127.0.6533.74','-b',
'127.0.6533.88','--apk=chrome','--signed','--no-local-cache','--',
'args1','--args2'
]
options= bisect_builds.ParseCommandLine(command_line)
with patch('sys.argv',['bisect-builds.py',*command_line]):
new_cmd= bisect_builds.MaybeSwitchBuildType(options,'127.0.6533.74',
'127.0.6533.88')
self.assertEqual(new_cmd[1:],[
'-o','-a','android-arm64-high','-g','127.0.6533.74','-b',
'127.0.6533.88','--verify-range','--apk=chrome','--no-local-cache',
'--','args1','--args2'
])
def test_no_official_build(self):
command_line=[
'-r','-a','ios','--ipa=canary.ipa','--device-id','321','-g',
'127.0.6533.74','-b','127.0.6533.78','--no-local-cache'
]
options= bisect_builds.ParseCommandLine(command_line)
with patch('sys.argv',['bisect-builds.py',*command_line]):
new_cmd= bisect_builds.MaybeSwitchBuildType(options,'127.0.6533.74',
'127.0.6533.88')
self.assertEqual(new_cmd,None)
@patch('bisect-builds.ArchiveBuild.get_rev_list', return_value=list(range(3)))
def test_generate_suggestion_with_cache(self, mock_get_rev_list):
command_line=[
'-r','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88',
'--use-local-cache'
]
options= bisect_builds.ParseCommandLine(command_line)
with patch('sys.argv',['bisect-builds.py',*command_line]):
new_cmd= bisect_builds.MaybeSwitchBuildType(options,'127.0.6533.74',
'127.0.6533.88')
self.assertEqual(new_cmd[1:],[
'-o','-a','linux64','-g','127.0.6533.74','-b','127.0.6533.88',
'--verify-range','--use-local-cache'
])
mock_get_rev_list.assert_called()
classMethodTest(BisectTestCase):
@patch('sys.stderr', new_callable=io.StringIO)
def test_ParseCommandLine(self, mock_stderr):
opts= bisect_builds.ParseCommandLine(
['-a','linux64','-g','1','args1','args2 3','-b','2'])
self.assertEqual(opts.build_type,'snapshot')
self.assertEqual(opts.args,['args1','args2 3'])
opts= bisect_builds.ParseCommandLine(
['-a','linux64','-g','1','args1','args2 3'])
self.assertEqual(opts.args,['args1','args2 3'])
opts= bisect_builds.ParseCommandLine(
['-a','linux64','-g','1','--','args1','args2 3','-b','2'])
self.assertEqual(opts.args,['args1','args2 3','-b','2'])
with self.assertRaises(SystemExit):
bisect_builds.ParseCommandLine(['-a','mac64','-o','-g','1'])
self.assertRegexpMatches(
mock_stderr.getvalue(), r'To bisect for mac64, please choose from '
r'release(-r), snapshot(-s)')
@patch('bisect-builds._DetectArchive', return_value='linux64')
def test_ParseCommandLine_DetectArchive(self, mock_detect_archive):
opts= bisect_builds.ParseCommandLine(['-o','-g','1'])
self.assertEqual(opts.archive,'linux64')
def test_ParseCommandLine_default_apk(self):
opts= bisect_builds.ParseCommandLine(
['-o','-a','android-arm','-g','1'])
self.assertEqual(opts.apk,'chrome')
opts= bisect_builds.ParseCommandLine(['-a','android-arm64','-g','1'])
self.assertEqual(opts.apk,'chromium')
def test_ParseCommandLine_default_ipa(self):
opts= bisect_builds.ParseCommandLine(
['-r','-a','ios','-g','127.0.6533.74','-b','127.0.6533.88'])
self.assertEqual(opts.ipa,'canary')
def test_ParseCommandLine_DetectArchive_with_apk(self):
opts= bisect_builds.ParseCommandLine(['-o','--apk','chrome','-g','1'])
self.assertEqual(opts.archive,'android-arm64')
def test_ParseCommandLine_DetectArchive_with_ipa(self):
opts= bisect_builds.ParseCommandLine(
['-r','--ipa','stable','-g','127.0.6533.74','-b','127.0.6533.88'])
self.assertEqual(opts.archive,'ios-simulator')
@patch('sys.stderr', new_callable=io.StringIO)
def test_ParseCommandLine_apk_error(self, mock_stderr):
with self.assertRaises(SystemExit):
bisect_builds.ParseCommandLine(
['-a','linux64','--apk','chrome','-g','1'])
self.assertIn('--apk is only supported', mock_stderr.getvalue())
@patch('sys.stderr', new_callable=io.StringIO)
def test_ParseCommandLine_ipa_error(self, mock_stderr):
with self.assertRaises(SystemExit):
bisect_builds.ParseCommandLine(
['-a','linux64','--ipa','stable','-g','1'])
self.assertIn('--ipa is only supported', mock_stderr.getvalue())
@patch('sys.stderr', new_callable=io.StringIO)
def test_ParseCommandLine_signed_error(self, mock_stderr):
with self.assertRaises(SystemExit):
bisect_builds.ParseCommandLine(['-a','linux64','--signed','-g','1'])
self.assertIn('--signed is only supported', mock_stderr.getvalue())
@patch('sys.stderr', new_callable=io.StringIO)
def test_ParseCommandLine_webview_incompatibility_error(self, mock_stderr):
with self.assertRaises(SystemExit):
_= bisect_builds.ParseCommandLine([
'-r','-a','android-arm64-high','-g','127.0.6533.76','-b',
'127.0.6533.79','--apk','system_webview'
])
self.assertIn(
'Bisecting WebView for android-arm64-high, please choose official '
'builds (-o)', mock_stderr.getvalue())
opts= bisect_builds.ParseCommandLine([
'-o','-a','android-arm64-high','-g','1334017','-b','1335078',
'--apk','system_webview'
])
self.assertEqual(opts.apk,'system_webview')
self.assertEqual(opts.archive,'android-arm64-high')
self.assertEqual(opts.build_type,'official')
@patch('urllib.request.urlopen')
@patch('builtins.open')
@patch('sys.stdout', new_callable=io.StringIO)
def test_update_script(self, mock_stdout, mock_open, mock_urlopen):
mock_urlopen.return_value= io.BytesIO(
base64.b64encode('content'.encode('utf-8')))
with self.assertRaises(SystemExit):
bisect_builds.ParseCommandLine(['--update-script'])
mock_urlopen.assert_called_once_with(
'https://chromium.googlesource.com/chromium/src/+/HEAD/'
'tools/bisect-builds.py?format=TEXT')
mock_open.assert_called_once()
mock_open.return_value.__enter__().write.assert_called_once_with('content')
self.assertEqual(mock_stdout.getvalue(),'Update successful!\n')
@patch("urllib.request.urlopen",
side_effect=[
urllib.request.HTTPError('url',404,'Not Found',None,None),
urllib.request.HTTPError('url',404,'Not Found',None,None),
io.BytesIO(b"NOT_A_JSON"),
io.BytesIO(b'{"chromium_main_branch_position": 123}'),
])
def test_GetRevisionFromVersion(self, mock_urlopen):
self.assertEqual(123,
bisect_builds.GetRevisionFromVersion('127.0.6533.134'))
mock_urlopen.assert_has_calls([
call('https://chromiumdash.appspot.com/fetch_version'
'?version=127.0.6533.134'),
call('https://chromiumdash.appspot.com/fetch_version'
'?version=127.0.6533.0'),
])
@maybe_patch("urllib.request.urlopen",
side_effect=[
io.BytesIO(b'{"chromium_main_branch_position": null}'),
io.BytesIO(b'{"message": "DEP\\n"}'),
io.BytesIO(b')]}\'\n{"message": "Cr-Branched-From: '
b'3d60439cfb36485e76a1c5bb7f513d3721b20da1-'
b'refs/heads/master@{#870763}\\n"}'),
])
def test_GetRevisionFromSourceTag(self, mock_urlopen):
self.assertEqual(870763,
bisect_builds.GetRevisionFromVersion('91.0.4472.38'))
mock_urlopen.assert_has_calls([
call('https://chromiumdash.appspot.com/fetch_version'
'?version=91.0.4472.38'),
call('https://chromium.googlesource.com/chromium/src/'
'+/refs/tags/91.0.4472.38?format=JSON'),
call('https://chromium.googlesource.com/chromium/src/'
'+/refs/tags/91.0.4472.38^?format=JSON'),
])
def test_join_args(self):
test_data=['a','b c','C:\\a b\\c','/a b/c','"a"',"'a'"]
quoted_command= bisect_builds.join_args(
[sys.executable,'-c','import sys, json; print(json.dumps(sys.argv))']
+ test_data)
subproc= subprocess.Popen(
quoted_command, shell=True, stdout=subprocess.PIPE)
stdout, _= subproc.communicate()
dumped_argv= json.loads(stdout.decode('utf-8'))
self.assertListEqual(dumped_argv,['-c']+ test_data)
classChromiumVersionTest(BisectTestCase):
def test_cmpare_version_numbers(self):
v127_0_6533_74= bisect_builds.ChromiumVersion('127.0.6533.74')
v127_0_6533_75= bisect_builds.ChromiumVersion('127.0.6533.75')
v127_0_6533_75_with_space= bisect_builds.ChromiumVersion('127.0.6533.75 ')
v127= bisect_builds.ChromiumVersion('127')
self.assertLess(v127_0_6533_74, v127_0_6533_75)
self.assertLessEqual(v127_0_6533_74, v127_0_6533_75)
self.assertGreater(v127_0_6533_75, v127_0_6533_74)
self.assertGreaterEqual(v127_0_6533_75, v127_0_6533_74)
self.assertEqual(v127_0_6533_75, v127_0_6533_75_with_space)
self.assertLess(v127, v127_0_6533_74)
if __name__=='__main__':
unittest.main()

[8]ページ先頭

©2009-2025 Movatter.jp