Merge "Add test to target_lib.py." am: f73c0f6138
Original change: https://android-review.googlesource.com/c/platform/development/+/1795808 Change-Id: Icf82fa2068901a89d43daabaefd4091c757a7d06
This commit is contained in:
@@ -59,11 +59,19 @@ class BuildInfo:
|
||||
pass
|
||||
|
||||
def to_sql_form_dict(self):
|
||||
"""
|
||||
Because sqlite can only store text but self.partitions is a list
|
||||
Turn the list into a string joined by ',', for example:
|
||||
['system', 'vendor'] => 'system,vendor'
|
||||
"""
|
||||
sql_form_dict = asdict(self)
|
||||
sql_form_dict['partitions'] = ','.join(sql_form_dict['partitions'])
|
||||
return sql_form_dict
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
Return as a normal dict.
|
||||
"""
|
||||
return asdict(self)
|
||||
|
||||
|
||||
|
||||
2
tools/otagui/test/test_ab_partitions.txt
Normal file
2
tools/otagui/test/test_ab_partitions.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
system
|
||||
vendor
|
||||
21
tools/otagui/test/test_build.prop
Normal file
21
tools/otagui/test/test_build.prop
Normal file
@@ -0,0 +1,21 @@
|
||||
ro.build.id=AOSP.MASTER
|
||||
ro.build.display.id=aosp_cf_x86_64_phone-userdebug S AOSP.MASTER 7392671 test-keys
|
||||
ro.build.version.incremental=7392671
|
||||
ro.build.version.sdk=30
|
||||
ro.build.version.preview_sdk=1
|
||||
ro.build.version.preview_sdk_fingerprint=5f1ee022916302ff92d66186575d0b95
|
||||
ro.build.version.codename=S
|
||||
ro.build.version.all_codenames=S
|
||||
ro.build.version.release=11
|
||||
ro.build.version.release_or_codename=S
|
||||
ro.build.version.security_patch=2021-05-05
|
||||
ro.build.version.base_os=
|
||||
ro.build.version.min_supported_target_sdk=23
|
||||
ro.build.date=Mon May 24 08:56:05 UTC 2021
|
||||
ro.build.date.utc=1621846565
|
||||
ro.build.type=userdebug
|
||||
ro.build.user=android-build
|
||||
ro.build.host=abfarm069
|
||||
ro.build.tags=test-keys
|
||||
ro.build.flavor=aosp_cf_x86_64_phone-userdebug
|
||||
ro.build.system_root_image=false
|
||||
18
tools/otagui/test_suite.py
Normal file
18
tools/otagui/test_suite.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import os, unittest
|
||||
|
||||
class Tests():
|
||||
def suite(self):
|
||||
modules_to_test = []
|
||||
test_dir = os.listdir('.')
|
||||
for test in test_dir:
|
||||
if test.startswith('test') and test.endswith('.py'):
|
||||
modules_to_test.append(test.rstrip('.py'))
|
||||
|
||||
alltests = unittest.TestSuite()
|
||||
for module in map(__import__, modules_to_test):
|
||||
alltests.addTest(unittest.findTestCases(module))
|
||||
return alltests
|
||||
|
||||
if __name__ == '__main__':
|
||||
MyTests = Tests()
|
||||
unittest.main(defaultTest='MyTests.suite', verbosity=2)
|
||||
192
tools/otagui/test_target_lib.py
Normal file
192
tools/otagui/test_target_lib.py
Normal file
@@ -0,0 +1,192 @@
|
||||
import unittest
|
||||
from unittest.mock import patch, mock_open, Mock, MagicMock
|
||||
from target_lib import BuildInfo, TargetLib
|
||||
import zipfile
|
||||
import os
|
||||
import sqlite3
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
class CreateTestBuild():
|
||||
def __init__(self, include_build_prop=True, include_ab_partitions=True):
|
||||
self.file = NamedTemporaryFile(dir='test/')
|
||||
self.test_path = self.file.name
|
||||
with zipfile.ZipFile(self.file, mode='w') as package:
|
||||
if include_build_prop:
|
||||
package.write('test/test_build.prop', 'SYSTEM/build.prop')
|
||||
if include_ab_partitions:
|
||||
package.write('test/test_ab_partitions.txt',
|
||||
'META/ab_partitions.txt')
|
||||
self.test_info = {
|
||||
'file_name': self.test_path.split('/')[-1],
|
||||
'path': self.test_path,
|
||||
'time': 1628698830,
|
||||
'build_id': 'AOSP.MASTER',
|
||||
'build_version': '7392671',
|
||||
'build_flavor': 'aosp_cf_x86_64_phone-userdebug',
|
||||
'partitions': ['system', 'vendor'],
|
||||
}
|
||||
if not include_build_prop:
|
||||
self.test_info['build_id'] = ''
|
||||
self.test_info['build_version'] = ''
|
||||
self.test_info['build_flavor'] = ''
|
||||
if not include_ab_partitions:
|
||||
self.test_info['partitions'] = []
|
||||
|
||||
def clean(self):
|
||||
self.file.close()
|
||||
|
||||
class TestBuildInfo(unittest.TestCase):
|
||||
def setUp(self):
|
||||
"""
|
||||
Create a virtual Android build, which only have build.prop
|
||||
and ab_partitions.txt
|
||||
"""
|
||||
self.test_build = CreateTestBuild()
|
||||
self.build_info = BuildInfo(
|
||||
self.test_build.test_info['file_name'],
|
||||
self.test_build.test_info['path'],
|
||||
self.test_build.test_info['time']
|
||||
)
|
||||
self.build_info.analyse_buildprop()
|
||||
|
||||
def tearDown(self):
|
||||
self.test_build.clean()
|
||||
|
||||
def test_analyse_buildprop(self):
|
||||
# Test if the build.prop and ab_partitions are not empty
|
||||
for key, value in self.test_build.test_info.items():
|
||||
self.assertEqual(value, self.build_info.__dict__[key],
|
||||
'The ' + key + ' is not parsed correctly.'
|
||||
)
|
||||
# Test if the ab_partitions is empty
|
||||
test_build_no_partitions = CreateTestBuild(include_ab_partitions=False)
|
||||
build_info = BuildInfo(
|
||||
test_build_no_partitions.test_info['file_name'],
|
||||
test_build_no_partitions.test_info['path'],
|
||||
test_build_no_partitions.test_info['time']
|
||||
)
|
||||
build_info.analyse_buildprop()
|
||||
self.assertEqual(build_info.partitions,
|
||||
test_build_no_partitions.test_info['partitions'],
|
||||
'The partition list is not empty if ab_partitions is not provided.'
|
||||
)
|
||||
test_build_no_partitions.clean()
|
||||
|
||||
def test_to_sql_form_dict(self):
|
||||
sql_dict = self.build_info.to_sql_form_dict()
|
||||
for key, value in self.test_build.test_info.items():
|
||||
if key != 'partitions':
|
||||
self.assertEqual(value, sql_dict[key],
|
||||
'The ' + key + ' is not parsed correctly.'
|
||||
)
|
||||
else:
|
||||
self.assertEqual(','.join(value), sql_dict[key],
|
||||
'The partition list is not coverted to sql form properly.'
|
||||
)
|
||||
|
||||
def test_to_dict(self):
|
||||
ordinary_dict = self.build_info.to_dict()
|
||||
for key, value in self.test_build.test_info.items():
|
||||
self.assertEqual(value, ordinary_dict[key],
|
||||
'The ' + key + ' is not parsed correctly.'
|
||||
)
|
||||
|
||||
|
||||
class TestTargetLib(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.test_path = 'test/test_target_lib.db'
|
||||
self.tearDown()
|
||||
self.target_build = TargetLib(path=self.test_path)
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.isfile(self.test_path):
|
||||
os.remove(self.test_path)
|
||||
|
||||
def test_init(self):
|
||||
# Test the database is created successfully
|
||||
self.assertTrue(os.path.isfile(self.test_path))
|
||||
test_columns = [
|
||||
{'name': 'FileName','type':'TEXT'},
|
||||
{'name': 'Path','type':'TEXT'},
|
||||
{'name': 'BuildID','type':'TEXT'},
|
||||
{'name': 'BuildVersion','type':'TEXT'},
|
||||
{'name': 'BuildFlavor','type':'TEXT'},
|
||||
{'name': 'Partitions','type':'TEXT'},
|
||||
{'name': 'UploadTime','type':'INTEGER'},
|
||||
]
|
||||
connect = sqlite3.connect(self.test_path)
|
||||
cursor = connect.cursor()
|
||||
cursor.execute("PRAGMA table_info(Builds)")
|
||||
columns = cursor.fetchall()
|
||||
for column in test_columns:
|
||||
column_found = list(filter(lambda x: x[1]==column['name'], columns))
|
||||
self.assertEqual(len(column_found), 1,
|
||||
'The column ' + column['name'] + ' is not found in database'
|
||||
)
|
||||
self.assertEqual(column_found[0][2], column['type'],
|
||||
'The column ' + column['name'] + ' has a wrong type'
|
||||
)
|
||||
|
||||
def test_new_build(self):
|
||||
test_build = CreateTestBuild()
|
||||
self.target_build.new_build(
|
||||
filename=test_build.test_info['file_name'],
|
||||
path=test_build.test_path
|
||||
)
|
||||
connect = sqlite3.connect(self.test_path)
|
||||
cursor = connect.cursor()
|
||||
cursor.execute("SELECT * FROM BUILDS")
|
||||
entries = cursor.fetchall()
|
||||
self.assertEqual(len(entries), 1,
|
||||
'The test build cannot be added into the database.'
|
||||
)
|
||||
test_build.clean()
|
||||
|
||||
def test_get_builds(self):
|
||||
test_build = CreateTestBuild()
|
||||
# time.time() has to be mocked, otherwise it will be the current time
|
||||
mock_time = Mock(return_value=test_build.test_info['time'])
|
||||
with patch('time.time', mock_time):
|
||||
self.target_build.new_build(
|
||||
filename=test_build.test_info['file_name'],
|
||||
path=test_build.test_path
|
||||
)
|
||||
# build_list is read and parsed from the database
|
||||
# build_info is directly parsed from the package
|
||||
# Test if the read/write database process changes the data entry
|
||||
build_list = self.target_build.get_builds()
|
||||
build_info = BuildInfo(
|
||||
test_build.test_info['file_name'],
|
||||
test_build.test_info['path'],
|
||||
test_build.test_info['time']
|
||||
)
|
||||
build_info.analyse_buildprop()
|
||||
self.assertEqual(build_list[0], build_info,
|
||||
'The list of build info cannot be extracted from database.'
|
||||
)
|
||||
test_build.clean()
|
||||
|
||||
def test_get_build_by_path(self):
|
||||
test_build = CreateTestBuild()
|
||||
# time.time() has to be mocked, otherwise it will be the current time
|
||||
mock_time = Mock(return_value=test_build.test_info['time'])
|
||||
with patch('time.time', mock_time):
|
||||
self.target_build.new_build(
|
||||
filename=test_build.test_info['file_name'],
|
||||
path=test_build.test_path
|
||||
)
|
||||
build = self.target_build.get_build_by_path(test_build.test_info['path'])
|
||||
build_info = BuildInfo(
|
||||
test_build.test_info['file_name'],
|
||||
test_build.test_info['path'],
|
||||
test_build.test_info['time']
|
||||
)
|
||||
build_info.analyse_buildprop()
|
||||
self.assertEqual(build, build_info,
|
||||
'Build info cannot be extracted by path.'
|
||||
)
|
||||
test_build.clean()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user