blob: d4d6faaa1be0ef6f82213b81e3681c1ab53852f4 [file] [log] [blame]
#!/usr/bin/env python3
#
# Copyright (C) 2021 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for mainline_modules_sdks.py."""
import dataclasses
from pathlib import Path
import os
import tempfile
import unittest
import zipfile
import mainline_modules_sdks as mm
MAINLINE_MODULES_BY_APEX = dict((m.apex, m) for m in mm.MAINLINE_MODULES)
class FakeSnapshotBuilder(mm.SnapshotBuilder):
"""A fake snapshot builder that does not run the build.
This skips the whole build process and just creates some fake sdk
modules.
"""
def create_snapshot_file(self, name, version):
zip_file = Path(self.get_sdk_path(name, version))
with zipfile.ZipFile(zip_file, "w") as z:
z.writestr("Android.bp", "")
if name.endswith("-sdk"):
z.writestr("sdk_library/public/removed.txt", "")
z.writestr("sdk_library/public/source.srcjar", "")
z.writestr("sdk_library/public/lib.jar", "")
z.writestr("sdk_library/public/api.txt", "")
def build_snapshots(self, build_release, sdk_versions, modules):
# Create input file structure.
sdks_out_dir = Path(self.get_mainline_sdks_path())
sdks_out_dir.mkdir(parents=True, exist_ok=True)
# Create a fake sdk zip file for each module.
for module in modules:
for sdk in module.sdks:
for sdk_version in sdk_versions:
self.create_snapshot_file(sdk, sdk_version)
class TestProduceDist(unittest.TestCase):
def test(self):
"""Verify the dist/mainline-sdks directory is populated correctly"""
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_out_dir = os.path.join(tmp_dir, "out")
os.mkdir(tmp_out_dir)
tmp_dist_dir = os.path.join(tmp_dir, "dist")
os.mkdir(tmp_dist_dir)
modules = [
MAINLINE_MODULES_BY_APEX["com.android.art"],
MAINLINE_MODULES_BY_APEX["com.android.ipsec"],
]
subprocess_runner = mm.SubprocessRunner()
snapshot_builder = FakeSnapshotBuilder(
subprocess_runner=subprocess_runner,
out_dir=tmp_out_dir,
)
build_releases = [
mm.Q,
mm.R,
mm.S,
mm.LATEST,
mm.LEGACY_BUILD_RELEASE,
]
producer = mm.SdkDistProducer(
subprocess_runner=subprocess_runner,
snapshot_builder=snapshot_builder,
dist_dir=tmp_dist_dir,
)
producer.produce_dist(modules, build_releases)
files = []
for abs_dir, _, filenames in os.walk(tmp_dist_dir):
rel_dir = os.path.relpath(abs_dir, tmp_dist_dir)
for f in filenames:
files.append(os.path.join(rel_dir, f))
# pylint: disable=line-too-long
self.assertEqual(
[
# Legacy copy of the snapshots, for use by tools that don't support build specific snapshots.
"mainline-sdks/current/com.android.art/host-exports/art-module-host-exports-current.zip",
"mainline-sdks/current/com.android.art/sdk/art-module-sdk-current.zip",
"mainline-sdks/current/com.android.art/test-exports/art-module-test-exports-current.zip",
"mainline-sdks/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip",
# Build specific snapshots.
"mainline-sdks/for-S-build/current/com.android.art/host-exports/art-module-host-exports-current.zip",
"mainline-sdks/for-S-build/current/com.android.art/sdk/art-module-sdk-current.zip",
"mainline-sdks/for-S-build/current/com.android.art/test-exports/art-module-test-exports-current.zip",
"mainline-sdks/for-S-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip",
"mainline-sdks/for-latest-build/current/com.android.art/host-exports/art-module-host-exports-current.zip",
"mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current.zip",
"mainline-sdks/for-latest-build/current/com.android.art/test-exports/art-module-test-exports-current.zip",
"mainline-sdks/for-latest-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip",
# Legacy stubs directory containing unpacked java_sdk_library artifacts.
"stubs/com.android.art/sdk_library/public/api.txt",
"stubs/com.android.art/sdk_library/public/lib.jar",
"stubs/com.android.art/sdk_library/public/removed.txt",
"stubs/com.android.art/sdk_library/public/source.srcjar",
"stubs/com.android.ipsec/sdk_library/public/api.txt",
"stubs/com.android.ipsec/sdk_library/public/lib.jar",
"stubs/com.android.ipsec/sdk_library/public/removed.txt",
"stubs/com.android.ipsec/sdk_library/public/source.srcjar",
],
sorted(files))
def pathToTestData(relative_path):
"""Construct a path to a test data file.
The relative_path is relative to the location of this file.
"""
this_file = __file__
# When running as a python_test_host (name=<x>) with an embedded launcher
# the __file__ points to .../<x>/<x>.py but the .../<x> is not a directory
# it is a binary with the launcher and the python file embedded inside. In
# that case a test data file <rel> is at .../<x>_data/<rel>, not
# .../<x>/<x>_data/<rel> so it is necessary to trim the base name (<x>.py)
# from the file.
if not os.path.isfile(this_file):
this_file = os.path.dirname(this_file)
# When the python file is at .../<x>.py (or in the case of an embedded
# launcher at .../<x>/<x>.py) then the test data is at .../<x>_data/<rel>.
this_file_without_ext, _ = os.path.splitext(this_file)
return os.path.join(this_file_without_ext + "_data", relative_path)
def readTestData(relative_path):
with open(pathToTestData(relative_path), "r") as f:
return f.read()
class TestSoongConfigBoilerplateInserter(unittest.TestCase):
def apply_transformations(self, src, transformations, expected):
producer = mm.SdkDistProducer(
subprocess_runner=None,
snapshot_builder=None,
script=self._testMethodName,
)
with tempfile.TemporaryDirectory() as tmp_dir:
path = os.path.join(tmp_dir, "Android.bp")
with open(path, "w") as f:
f.write(src)
mm.apply_transformations(producer, tmp_dir, transformations)
with open(path, "r") as f:
result = f.read()
self.maxDiff = None
self.assertEqual(expected, result)
def test_common_mainline_module(self):
"""Tests the transformations applied to a common mainline module.
This uses ipsec as an example of a common mainline module. This checks
that the correct Soong config module types and variables are used and
that it imports the definitions from the correct location.
"""
src = readTestData("ipsec_Android.bp.input")
expected = readTestData("ipsec_Android.bp.expected")
module = MAINLINE_MODULES_BY_APEX["com.android.ipsec"]
transformations = module.transformations()
self.apply_transformations(src, transformations, expected)
def test_art(self):
"""Tests the transformations applied to a the ART mainline module.
The ART mainline module uses a different Soong config setup to the
common mainline modules. This checks that the ART specific Soong config
module types, variable and imports are used.
"""
src = readTestData("art_Android.bp.input")
expected = readTestData("art_Android.bp.expected")
module = MAINLINE_MODULES_BY_APEX["com.android.art"]
transformations = module.transformations()
self.apply_transformations(src, transformations, expected)
class TestFilterModules(unittest.TestCase):
def test_no_filter(self):
modules = mm.filter_modules(mm.MAINLINE_MODULES)
self.assertEqual(modules, mm.MAINLINE_MODULES)
def test_with_filter(self):
os.environ["TARGET_BUILD_APPS"] = "com.android.art"
modules = mm.filter_modules(mm.MAINLINE_MODULES)
expected = MAINLINE_MODULES_BY_APEX["com.android.art"]
self.assertEqual(modules, [expected])
if __name__ == "__main__":
unittest.main(verbosity=2)