blob: f395b2079979e7e52755d851ae323a68e0657268 [file] [log] [blame]
#!/usr/bin/env vpython3
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import io
import json
import os
import sys
import unittest
from unittest import mock
import update_product_bundles
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),
'test')))
import common
class TestUpdateProductBundles(unittest.TestCase):
def setUp(self):
# By default, test in attended mode.
os.environ.pop('SWARMING_SERVER', None)
ffx_mock = mock.Mock()
ffx_mock.returncode = 0
self._ffx_patcher = mock.patch('common.run_ffx_command',
return_value=ffx_mock)
self._ffx_mock = self._ffx_patcher.start()
self.addCleanup(self._ffx_mock.stop)
def testConvertToProductBundleDefaultsUnknownImage(self):
self.assertEqual(
update_product_bundles.convert_to_products(['unknown-image']),
['unknown-image'])
def testConvertToProductBundleRemovesReleaseSuffix(self):
self.assertEqual(
update_product_bundles.convert_to_products(
['smart_display_eng.astro-release']), ['smart_display_eng.astro'])
def testConvertToProductBundleWarnsDeprecated(self):
with self.assertLogs(level='WARNING') as logs:
deprecated_images = [
'qemu.arm64', 'qemu.x64', 'core.x64-dfv2-release',
'workstation_eng.chromebook-x64-release'
]
self.assertEqual(
update_product_bundles.convert_to_products(deprecated_images), [
'terminal.qemu-arm64', 'terminal.x64', 'core.x64-dfv2',
'workstation_eng.chromebook-x64'
])
for i, deprecated_image in enumerate(deprecated_images):
self.assertIn(f'Image name {deprecated_image} has been deprecated',
logs.output[i])
@mock.patch('common.run_ffx_command')
def testRemoveRepositoriesRunsRemoveOnGivenRepos(self, ffx_mock):
update_product_bundles.remove_repositories(['foo', 'bar', 'fizz', 'buzz'])
ffx_mock.assert_has_calls([
mock.call(cmd=('repository', 'remove', 'foo'), check=True),
mock.call(cmd=('repository', 'remove', 'bar'), check=True),
mock.call(cmd=('repository', 'remove', 'fizz'), check=True),
mock.call(cmd=('repository', 'remove', 'buzz'), check=True),
])
@mock.patch('os.path.exists')
@mock.patch('os.path.abspath')
def testGetRepositoriesPrunesReposThatDoNotExist(self, mock_abspath,
mock_exists):
with mock.patch('common.SDK_ROOT', 'some/path'):
self._ffx_mock.return_value.stdout = json.dumps([{
"name": "terminal.x64",
"spec": {
"type": "pm",
"path": "some/path/that/exists"
}
}, {
"name": "workstation-eng.chromebook-x64",
"spec": {
"type": "pm",
"path": "some/path/that/does/not/exist"
}
}])
mock_exists.side_effect = [True, False]
mock_abspath.side_effect = lambda x: x
self.assertEqual(update_product_bundles.get_repositories(), [{
"name": "terminal.x64",
"spec": {
"type": "pm",
"path": "some/path/that/exists"
}
}])
self._ffx_mock.assert_has_calls([
mock.call(cmd=('--machine', 'json', 'repository', 'list'),
capture_output=True,
check=True),
mock.call(cmd=('repository', 'remove',
'workstation-eng.chromebook-x64'),
check=True)
])
@mock.patch('update_product_bundles.running_unattended', return_value=True)
# Disallow reading sdk_override.
@mock.patch('os.path.isfile', return_value=False)
@mock.patch('update_product_bundles.internal_hash', return_value='1.1.1')
def testLookupAndDownloadWithAuth(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
auth_file = os.path.abspath(
os.path.join(os.path.dirname(__file__), 'get_auth_token.py'))
self._ffx_mock.return_value.stdout = json.dumps({
"name": "core.x64",
"product_version": "17.20240106.2.1",
"transfer_manifest_url": "http://download-url"
})
with mock.patch(
'sys.argv',
['update_product_bundles.py', 'terminal.x64', '--internal']):
update_product_bundles.main()
self._ffx_mock.assert_has_calls([
mock.call(cmd=[
'--machine', 'json', 'product', 'lookup', 'terminal.x64', '1.1.1',
'--base-url', f'gs://fuchsia-sdk/development/1.1.1', '--auth',
auth_file
],
check=True,
capture_output=True),
mock.call(cmd=[
'product', 'download', 'http://download-url',
os.path.join(common.INTERNAL_IMAGES_ROOT, 'terminal', 'x64'),
'--auth', auth_file
],
check=True)
])
@mock.patch('common.get_hash_from_sdk', return_value='2.2.2')
@mock.patch('update_product_bundles.get_current_signature',
return_value='2.2.2')
@mock.patch('update_sdk.GetSDKOverrideGCSPath', return_value=None)
def testIgnoreDownloadImagesWithSameHash(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
with mock.patch('sys.argv', ['update_product_bundles.py', 'terminal.x64']):
update_product_bundles.main()
self.assertFalse(self._ffx_mock.called)
@mock.patch('common.get_hash_from_sdk', return_value='2.2.2')
@mock.patch('update_product_bundles.get_current_signature',
return_value='0.0')
@mock.patch('update_sdk.GetSDKOverrideGCSPath', return_value=None)
def testDownloadImagesWithDifferentHash(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
self._ffx_mock.return_value.stdout = json.dumps({
"name":
"core.x64",
"product_version":
"17.20240106.2.1",
"transfer_manifest_url":
"http://download-url"
})
with mock.patch('sys.argv', ['update_product_bundles.py', 'terminal.x64']):
update_product_bundles.main()
self._ffx_mock.assert_has_calls([
mock.call(cmd=[
'--machine', 'json', 'product', 'lookup', 'terminal.x64', '2.2.2',
'--base-url', 'gs://fuchsia/development/2.2.2'
],
check=True,
capture_output=True),
mock.call(cmd=[
'product', 'download', 'http://download-url',
os.path.join(common.IMAGES_ROOT, 'terminal', 'x64')
],
check=True)
])
@mock.patch('update_sdk.GetSDKOverrideGCSPath',
return_value='gs://my-bucket/sdk')
@mock.patch('common.get_hash_from_sdk', return_value='2.2.2')
def testSDKOverrideForSDKImages(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
self._ffx_mock.return_value.stdout = json.dumps({
"name":
"core.x64",
"product_version":
"17.20240106.2.1",
"transfer_manifest_url":
"http://download-url"
})
with mock.patch('sys.argv', ['update_product_bundles.py', 'terminal.x64']):
update_product_bundles.main()
self._ffx_mock.assert_has_calls([
mock.call(cmd=[
'--machine', 'json', 'product', 'lookup', 'terminal.x64', '2.2.2',
'--base-url', 'gs://my-bucket'
],
check=True,
capture_output=True),
mock.call(cmd=[
'product', 'download', 'http://download-url',
os.path.join(common.IMAGES_ROOT, 'terminal', 'x64')
],
check=True)
])
@mock.patch('update_product_bundles.internal_hash', return_value='1.1.1')
@mock.patch('update_product_bundles.get_current_signature',
return_value='1.1.1')
def testIgnoreDownloadInternalImagesWithSameHash(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
with mock.patch(
'sys.argv',
['update_product_bundles.py', 'terminal.x64', '--internal']):
update_product_bundles.main()
self.assertFalse(self._ffx_mock.called)
@mock.patch('update_product_bundles.get_current_signature',
return_value='0.0')
@mock.patch('update_product_bundles.internal_hash', return_value='1.1.1')
def testDownloadInternalImagesWithDifferentHash(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
self._ffx_mock.return_value.stdout = json.dumps({
"name":
"core.x64",
"product_version":
"17.20240106.2.1",
"transfer_manifest_url":
"http://download-url"
})
with mock.patch(
'sys.argv',
['update_product_bundles.py', 'terminal.x64', '--internal']):
update_product_bundles.main()
self._ffx_mock.assert_has_calls([
mock.call(cmd=[
'--machine', 'json', 'product', 'lookup', 'terminal.x64', '1.1.1',
'--base-url', 'gs://fuchsia-sdk/development/1.1.1'
],
check=True,
capture_output=True),
mock.call(cmd=[
'product', 'download', 'http://download-url',
os.path.join(common.INTERNAL_IMAGES_ROOT, 'terminal', 'x64')
],
check=True)
])
@mock.patch('update_sdk.GetSDKOverrideGCSPath',
return_value='gs://my-bucket/sdk')
@mock.patch('update_product_bundles.internal_hash', return_value='1.1.1')
def testIgnoreSDKOverrideForInternalImages(self, *_):
try:
common.get_host_os()
except:
# Ignore unsupported platforms. common.get_host_os used in
# update_product_bundles.main throws an unsupported exception.
return
self._ffx_mock.return_value.stdout = json.dumps({
"name":
"core.x64",
"product_version":
"17.20240106.2.1",
"transfer_manifest_url":
"http://download-url"
})
with mock.patch(
'sys.argv',
['update_product_bundles.py', 'terminal.x64', '--internal']):
update_product_bundles.main()
self._ffx_mock.assert_has_calls([
mock.call(cmd=[
'--machine', 'json', 'product', 'lookup', 'terminal.x64', '1.1.1',
'--base-url', 'gs://fuchsia-sdk/development/1.1.1'
],
check=True,
capture_output=True),
mock.call(cmd=[
'product', 'download', 'http://download-url',
os.path.join(common.INTERNAL_IMAGES_ROOT, 'terminal', 'x64')
],
check=True)
])
if __name__ == '__main__':
unittest.main()