| #!/usr/bin/env python3 |
| # |
| # Copyright 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 bazel_mode.""" |
| # pylint: disable=invalid-name |
| # pylint: disable=missing-function-docstring |
| # pylint: disable=too-many-lines |
| |
| import argparse |
| import re |
| import shlex |
| import shutil |
| import tempfile |
| import unittest |
| |
| from pathlib import Path |
| from typing import List |
| from unittest import mock |
| |
| # pylint: disable=import-error |
| from pyfakefs import fake_filesystem_unittest |
| |
| import bazel_mode |
| import constants |
| import module_info |
| |
| from test_finders import test_info |
| from test_runners import atest_tf_test_runner |
| |
| |
| ATEST_TF_RUNNER = atest_tf_test_runner.AtestTradefedTestRunner.NAME |
| BAZEL_RUNNER = bazel_mode.BazelTestRunner.NAME |
| MODULE_BUILD_TARGETS = {'foo1', 'foo2', 'foo3'} |
| MODULE_NAME = 'foo' |
| |
| |
| class GenerationTestFixture(fake_filesystem_unittest.TestCase): |
| """Fixture for workspace generation tests.""" |
| |
| def setUp(self): |
| self.setUpPyfakefs() |
| |
| self.src_root_path = Path('/src') |
| self.out_dir_path = self.src_root_path.joinpath('out') |
| self.out_dir_path.mkdir(parents=True) |
| self.product_out_path = self.out_dir_path.joinpath('product') |
| self.host_out_path = self.out_dir_path.joinpath('host') |
| self.workspace_out_path = self.out_dir_path.joinpath('workspace') |
| |
| def create_workspace_generator(self, modules=None, enabled_features=None): |
| mod_info = self.create_module_info(modules) |
| |
| generator = bazel_mode.WorkspaceGenerator( |
| self.src_root_path, |
| self.workspace_out_path, |
| self.product_out_path, |
| self.host_out_path, |
| self.out_dir_path, |
| mod_info, |
| enabled_features=enabled_features, |
| ) |
| |
| return generator |
| |
| def run_generator(self, mod_info, enabled_features=None): |
| generator = bazel_mode.WorkspaceGenerator( |
| self.src_root_path, |
| self.workspace_out_path, |
| self.product_out_path, |
| self.host_out_path, |
| self.out_dir_path, |
| mod_info, |
| enabled_features=enabled_features, |
| ) |
| |
| generator.generate() |
| |
| # pylint: disable=protected-access |
| @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'}) |
| def create_empty_module_info(self): |
| fake_temp_file_name = next(tempfile._get_candidate_names()) |
| self.fs.create_file(fake_temp_file_name, contents='{}') |
| return module_info.ModuleInfo(module_file=fake_temp_file_name) |
| |
| def create_module_info(self, modules=None): |
| mod_info = self.create_empty_module_info() |
| modules = modules or [] |
| |
| prerequisites = frozenset().union( |
| bazel_mode.TestTarget.DEVICE_TEST_PREREQUISITES, |
| bazel_mode.TestTarget.DEVICELESS_TEST_PREREQUISITES) |
| |
| for module_name in prerequisites: |
| info = host_module(name=module_name, path='prebuilts') |
| mod_info.name_to_module_info[module_name] = info |
| |
| for m in modules: |
| mod_info.name_to_module_info[m['module_name']] = m |
| |
| return mod_info |
| |
| def assertSymlinkTo(self, symlink_path, target_path): |
| self.assertEqual(symlink_path.resolve(strict=False), target_path) |
| |
| def assertTargetInWorkspace(self, name, package=''): |
| build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') |
| contents = build_file.read_text(encoding='utf8') |
| occurrences = len(self.find_target_by_name(name, contents)) |
| |
| if occurrences == 1: |
| return |
| |
| cardinality = 'Multiple' if occurrences else 'Zero' |
| self.fail( |
| f'{cardinality} targets named \'{name}\' found in \'{contents}\'' |
| ) |
| |
| def assertTargetNotInWorkspace(self, name, package=''): |
| build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') |
| |
| if not build_file.exists(): |
| return |
| |
| contents = build_file.read_text(encoding='utf8') |
| matches = self.find_target_by_name(name, contents) |
| |
| if not matches: |
| return |
| |
| self.fail( |
| f'Unexpectedly found target(s) named \'{name}\' in \'{contents}\'' |
| ) |
| |
| def assertInBuildFile(self, substring, package=''): |
| build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') |
| self.assertIn(substring, build_file.read_text(encoding='utf8')) |
| |
| def assertNotInBuildFile(self, substring, package=''): |
| build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') |
| self.assertNotIn(substring, build_file.read_text(encoding='utf8')) |
| |
| def assertFileInWorkspace(self, relative_path, package=''): |
| path = self.workspace_out_path.joinpath(package, relative_path) |
| self.assertTrue(path.exists()) |
| |
| def assertFileNotInWorkspace(self, relative_path, package=''): |
| path = self.workspace_out_path.joinpath(package, relative_path) |
| self.assertFalse(path.exists()) |
| |
| def find_target_by_name(self, name: str, contents: str) -> List[str]: |
| return re.findall(rf'\bname\s*=\s*"{name}"', contents) |
| |
| |
| class BasicWorkspaceGenerationTest(GenerationTestFixture): |
| """Tests for basic workspace generation and update.""" |
| |
| def test_generate_workspace_when_nonexistent(self): |
| workspace_generator = self.create_workspace_generator() |
| shutil.rmtree(workspace_generator.workspace_out_path, |
| ignore_errors=True) |
| |
| workspace_generator.generate() |
| |
| self.assertTrue(workspace_generator.workspace_out_path.is_dir()) |
| |
| def test_regenerate_workspace_when_features_changed(self): |
| workspace_generator = self.create_workspace_generator( |
| enabled_features={bazel_mode.Features.NULL_FEATURE}) |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| self.assertNotEqual(workspace_stat, new_workspace_stat) |
| |
| def test_not_regenerate_workspace_when_features_unchanged(self): |
| workspace_generator = self.create_workspace_generator( |
| enabled_features={bazel_mode.Features.NULL_FEATURE}) |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| workspace_generator = self.create_workspace_generator( |
| enabled_features={bazel_mode.Features.NULL_FEATURE}) |
| workspace_generator.generate() |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| self.assertEqual(workspace_stat, new_workspace_stat) |
| |
| def test_regenerate_workspace_when_module_info_deleted(self): |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| workspace_generator.mod_info.mod_info_file_path.unlink() |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| self.assertNotEqual(workspace_stat, new_workspace_stat) |
| |
| def test_not_regenerate_workspace_when_module_info_unchanged(self): |
| workspace_generator1 = self.create_workspace_generator() |
| workspace_generator1.generate() |
| workspace_stat = workspace_generator1.workspace_out_path.stat() |
| |
| workspace_generator2 = self.create_workspace_generator() |
| workspace_generator2.generate() |
| new_workspace_stat = workspace_generator2.workspace_out_path.stat() |
| |
| self.assertEqual(workspace_stat, new_workspace_stat) |
| |
| def test_not_regenerate_workspace_when_module_only_touched(self): |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| Path(workspace_generator.mod_info.mod_info_file_path).touch() |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| self.assertEqual(workspace_stat, new_workspace_stat) |
| |
| def test_regenerate_workspace_when_module_info_changed(self): |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| mod_info_file_path = workspace_generator.mod_info.mod_info_file_path |
| with open(mod_info_file_path, 'a', encoding='utf8') as f: |
| f.write(' ') |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| self.assertNotEqual(workspace_stat, new_workspace_stat) |
| |
| def test_regenerate_workspace_when_md5_file_removed(self): |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| workspace_stat = workspace_generator.workspace_out_path.stat() |
| |
| workspace_generator.mod_info.mod_info_file_path.unlink() |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| |
| new_workspace_stat = workspace_generator.workspace_out_path.stat() |
| self.assertNotEqual(workspace_stat, new_workspace_stat) |
| |
| def test_scrub_old_workspace_when_regenerating(self): |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| some_file = workspace_generator.workspace_out_path.joinpath('some_file') |
| some_file.touch() |
| self.assertTrue(some_file.is_file()) |
| |
| # Remove the md5 file to regenerate the workspace. |
| workspace_generator.mod_info.mod_info_file_path.unlink() |
| workspace_generator = self.create_workspace_generator() |
| workspace_generator.generate() |
| |
| self.assertFalse(some_file.is_file()) |
| |
| def test_generate_workspace_file(self): |
| gen = self.create_workspace_generator() |
| |
| gen.generate() |
| |
| self.assertTrue(gen.workspace_out_path.joinpath('WORKSPACE').exists()) |
| |
| def test_generate_bazelrc_file(self): |
| gen = self.create_workspace_generator() |
| bazelrc_path = gen.workspace_out_path.joinpath('.bazelrc') |
| |
| gen.generate() |
| |
| self.assertSymlinkTo( |
| bazelrc_path, |
| self.src_root_path.joinpath('tools/asuite/atest/bazel/bazelrc') |
| ) |
| |
| def test_generate_rules_dir(self): |
| gen = self.create_workspace_generator() |
| rules_dir_path = gen.workspace_out_path.joinpath('bazel/rules') |
| |
| gen.generate() |
| |
| self.assertSymlinkTo( |
| rules_dir_path, |
| self.src_root_path.joinpath('tools/asuite/atest/bazel/rules') |
| ) |
| |
| def test_generate_configs_dir(self): |
| gen = self.create_workspace_generator() |
| configs_dir_path = gen.workspace_out_path.joinpath('bazel/configs') |
| |
| gen.generate() |
| |
| self.assertSymlinkTo( |
| configs_dir_path, |
| self.src_root_path.joinpath('tools/asuite/atest/bazel/configs') |
| ) |
| |
| def test_generate_host_unit_test_module_target(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module(name='hello_world_test') |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('hello_world_test_host') |
| |
| def test_not_generate_host_test_module_target(self): |
| mod_info = self.create_module_info(modules=[ |
| host_test_module(name='hello_world_test'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetNotInWorkspace('hello_world_test') |
| |
| def test_not_generate_test_module_target_with_invalid_installed_path(self): |
| mod_info = self.create_module_info(modules=[ |
| test_module(name='hello_world_test', installed='out/invalid/path') |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetNotInWorkspace('hello_world_test_device') |
| self.assertTargetNotInWorkspace('hello_world_test_host') |
| |
| |
| class MultiConfigTestModuleTestTargetGenerationTest(GenerationTestFixture): |
| """Tests for test target generation of test modules with multi-configs.""" |
| |
| def test_generate_test_rule_imports(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(host_unit_suite(test_module( |
| name='hello_world_test', path='example/tests'))), |
| ]) |
| |
| self.run_generator(mod_info, enabled_features=set([ |
| bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) |
| |
| self.assertInBuildFile( |
| 'load("//bazel/rules:tradefed_test.bzl",' |
| ' "tradefed_device_test", "tradefed_deviceless_test")\n', |
| package='example/tests', |
| ) |
| |
| def test_not_generate_device_test_import_when_feature_disabled(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(host_unit_suite(test_module( |
| name='hello_world_test', path='example/tests'))), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'load("//bazel/rules:tradefed_test.bzl",' |
| ' "tradefed_deviceless_test")\n', |
| package='example/tests', |
| ) |
| |
| def test_generate_test_targets(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(host_unit_suite(test_module( |
| name='hello_world_test', path='example/tests'))), |
| ]) |
| |
| self.run_generator(mod_info, enabled_features=set([ |
| bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) |
| |
| self.assertTargetInWorkspace('hello_world_test_device', |
| package='example/tests') |
| self.assertTargetInWorkspace('hello_world_test_host', |
| package='example/tests') |
| |
| def test_not_generate_device_test_target_when_feature_disabled(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(host_unit_suite(test_module( |
| name='hello_world_test', path='example/tests'))), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetNotInWorkspace('hello_world_test_device', |
| package='example/tests') |
| self.assertTargetInWorkspace('hello_world_test_host', |
| package='example/tests') |
| |
| |
| class DeviceTestModuleTestTargetGenerationTest(GenerationTestFixture): |
| """Tests for device test module test target generation.""" |
| |
| def test_generate_device_driven_test_target(self): |
| mod_info = self.create_module_info(modules=[ |
| device_test_module( |
| name='hello_world_test', path='example/tests'), |
| ]) |
| |
| self.run_generator(mod_info, enabled_features=set([ |
| bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) |
| |
| self.assertInBuildFile( |
| 'load("//bazel/rules:tradefed_test.bzl",' |
| ' "tradefed_device_test")\n', |
| package='example/tests', |
| ) |
| self.assertTargetInWorkspace('hello_world_test_device', |
| package='example/tests') |
| |
| def test_raise_when_prerequisite_not_in_module_info(self): |
| mod_info = self.create_module_info(modules=[ |
| device_test_module(), |
| ]) |
| del mod_info.name_to_module_info['aapt'] |
| |
| with self.assertRaises(Exception) as context: |
| self.run_generator(mod_info, enabled_features=set([ |
| bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) |
| |
| self.assertIn('aapt', str(context.exception)) |
| |
| |
| class HostUnitTestModuleTestTargetGenerationTest(GenerationTestFixture): |
| """Tests for host unit test module test target generation.""" |
| |
| def test_generate_deviceless_test_import(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module(name='hello_world_test'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'load("//bazel/rules:tradefed_test.bzl",' |
| ' "tradefed_deviceless_test")\n' |
| ) |
| |
| def test_generate_deviceless_test_target(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module( |
| name='hello_world_test', path='example/tests'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'tradefed_deviceless_test(\n' |
| ' name = "hello_world_test_host",\n' |
| ' test = "//example/tests:hello_world_test",\n' |
| ')', |
| package='example/tests', |
| ) |
| |
| def test_generate_test_module_prebuilt(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module(name='hello_world_test'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('hello_world_test') |
| |
| def test_raise_when_prerequisite_not_in_module_info(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module(), |
| ]) |
| del mod_info.name_to_module_info['adb'] |
| |
| with self.assertRaises(Exception) as context: |
| self.run_generator(mod_info) |
| |
| self.assertIn('adb', str(context.exception)) |
| |
| def test_raise_when_prerequisite_module_missing_path(self): |
| mod_info = self.create_module_info(modules=[ |
| host_unit_test_module(), |
| ]) |
| mod_info.name_to_module_info['adb'].get('path').clear() |
| |
| with self.assertRaises(Exception) as context: |
| self.run_generator(mod_info) |
| |
| self.assertIn('adb', str(context.exception)) |
| |
| |
| class ModulePrebuiltTargetGenerationTest(GenerationTestFixture): |
| """Tests for module prebuilt target generation.""" |
| |
| def test_generate_prebuilt_import(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'load("//bazel/rules:soong_prebuilt.bzl", "soong_prebuilt")\n' |
| ) |
| |
| def test_generate_prebuilt_target_for_multi_config_test_module(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(name='libhello')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'soong_prebuilt(\n' |
| ' name = "libhello",\n' |
| ' module_name = "libhello",\n' |
| ' files = select({\n' |
| ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' |
| ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' |
| ' }),\n' |
| ')\n' |
| ) |
| |
| def test_create_symlinks_to_testcases_for_multi_config_test_module(self): |
| module_name = 'hello_world_test' |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(name=module_name)) |
| ]) |
| module_out_path = self.workspace_out_path.joinpath(module_name) |
| |
| self.run_generator(mod_info) |
| |
| self.assertSymlinkTo( |
| module_out_path.joinpath(f'host/testcases/{module_name}'), |
| self.host_out_path.joinpath(f'testcases/{module_name}')) |
| self.assertSymlinkTo( |
| module_out_path.joinpath(f'device/testcases/{module_name}'), |
| self.product_out_path.joinpath(f'testcases/{module_name}')) |
| |
| def test_generate_files_for_host_only_test_module(self): |
| mod_info = self.create_module_info(modules=[ |
| host_only_config(supported_test_module(name='test1')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' files = select({\n' |
| ' "//bazel/rules:host": glob(["test1/host/**/*"]),\n' |
| ' }),\n' |
| ) |
| |
| def test_generate_files_for_device_only_test_module(self): |
| mod_info = self.create_module_info(modules=[ |
| device_only_config(supported_test_module(name='test1')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' files = select({\n' |
| ' "//bazel/rules:device": glob(["test1/device/**/*"]),\n' |
| ' }),\n' |
| ) |
| |
| def test_not_create_device_symlinks_for_host_only_test_module(self): |
| mod_info = self.create_module_info(modules=[ |
| host_only_config(supported_test_module(name='test1')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertFileNotInWorkspace('test1/device') |
| |
| def test_not_create_host_symlinks_for_device_test_module(self): |
| mod_info = self.create_module_info(modules=[ |
| device_only_config(supported_test_module(name='test1')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertFileNotInWorkspace('test1/host') |
| |
| |
| class ModuleSharedLibGenerationTest(GenerationTestFixture): |
| """Tests for module shared libs target generation.""" |
| |
| def test_not_generate_runtime_deps_when_all_configs_incompatible(self): |
| mod_info = self.create_module_info(modules=[ |
| host_only_config(supported_test_module(shared_libs=['libdevice'])), |
| device_only_config(module(name='libdevice')), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile('runtime_deps') |
| |
| def test_generate_runtime_deps_when_configs_compatible(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(shared_libs=['libmulti'])), |
| multi_config_module(name='libmulti'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' runtime_deps = select({\n' |
| ' "//bazel/rules:device": [\n' |
| ' "//:libmulti",\n' |
| ' ],\n' |
| ' "//bazel/rules:host": [\n' |
| ' "//:libmulti",\n' |
| ' ],\n' |
| ' }),\n' |
| ) |
| |
| def test_generate_runtime_deps_when_configs_partially_compatible(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(shared_libs=[ |
| 'libhost', |
| ])), |
| host_module(name='libhost'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' runtime_deps = select({\n' |
| ' "//bazel/rules:device": [\n' |
| ' ],\n' |
| ' "//bazel/rules:host": [\n' |
| ' "//:libhost",\n' |
| ' ],\n' |
| ' }),\n' |
| ) |
| |
| def test_generate_runtime_deps_with_mixed_compatibility(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(shared_libs=[ |
| 'libhost', |
| 'libdevice', |
| 'libmulti' |
| ])), |
| host_module(name='libhost'), |
| device_module(name='libdevice'), |
| multi_config_module(name='libmulti'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' runtime_deps = select({\n' |
| ' "//bazel/rules:device": [\n' |
| ' "//:libdevice",\n' |
| ' "//:libmulti",\n' |
| ' ],\n' |
| ' "//bazel/rules:host": [\n' |
| ' "//:libhost",\n' |
| ' "//:libmulti",\n' |
| ' ],\n' |
| ' }),\n' |
| ) |
| |
| def test_generate_runtime_deps_recursively(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(shared_libs=[ |
| 'libdirect', |
| ])), |
| multi_config_module(name='libdirect', shared_libs=[ |
| 'libtransitive', |
| ]), |
| multi_config_module(name='libtransitive'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('libtransitive') |
| |
| def test_generate_shared_runtime_deps_once(self): |
| mod_info = self.create_module_info(modules=[ |
| multi_config(supported_test_module(shared_libs=[ |
| 'libleft', |
| 'libright', |
| ])), |
| multi_config_module(name='libleft', shared_libs=[ |
| 'libshared', |
| ]), |
| multi_config_module(name='libright', shared_libs=[ |
| 'libshared', |
| ]), |
| multi_config_module(name='libshared'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('libshared') |
| |
| def test_generate_runtime_deps_in_order(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello2', 'libhello1']), |
| host_module(name='libhello1'), |
| host_module(name='libhello2'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' "//:libhello1",\n' |
| ' "//:libhello2",\n' |
| ) |
| |
| def test_generate_target_for_shared_lib(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| host_module(name='libhello'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('libhello') |
| |
| def test_not_generate_for_missing_shared_lib_module(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile(' "//:libhello",\n') |
| self.assertTargetNotInWorkspace('libhello') |
| |
| def test_not_generate_when_shared_lib_uninstalled(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| host_module(name='libhello', installed=[]), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile(' "//:libhello",\n') |
| self.assertTargetNotInWorkspace('libhello') |
| |
| def test_not_generate_when_shared_lib_installed_path_unsupported(self): |
| unsupported_install_path = 'out/other' |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| shared_lib(module('libhello', |
| installed=[unsupported_install_path])), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile('"//:libhello",\n') |
| self.assertTargetNotInWorkspace('libhello') |
| |
| def test_not_generate_when_shared_lib_install_path_ambiguous(self): |
| ambiguous_install_path = 'out/f1' |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| module(name='libhello', installed=[ambiguous_install_path]), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile('"//:libhello",\n') |
| self.assertTargetNotInWorkspace('libhello') |
| |
| def test_generate_target_for_rlib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(dependencies=['libhello']), |
| rlib(module(name='libhello')) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'soong_uninstalled_prebuilt(\n' |
| ' name = "libhello",\n' |
| ' module_name = "libhello",\n' |
| ')\n' |
| ) |
| |
| def test_generate_target_for_rlib_dylib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(dependencies=['libhello']), |
| rlib(module(name='libhello', dependencies=['libworld'])), |
| host_only_config(dylib(module(name='libworld'))) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetInWorkspace('libworld') |
| |
| def test_generate_target_for_dylib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(dependencies=['libhello']), |
| host_only_config(dylib(module(name='libhello'))) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'soong_prebuilt(\n' |
| ' name = "libhello",\n' |
| ' module_name = "libhello",\n' |
| ) |
| |
| def test_generate_target_for_uninstalled_dylib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(dependencies=['libhello']), |
| dylib(module(name='libhello', installed=[])) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| 'soong_uninstalled_prebuilt(\n' |
| ' name = "libhello",\n' |
| ' module_name = "libhello",\n' |
| ')\n' |
| ) |
| |
| def test_not_generate_target_for_non_runtime_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(dependencies=['libhello']), |
| host_module(name='libhello', classes=['NOT_SUPPORTED']) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertNotInBuildFile('"//:libhello",\n') |
| self.assertTargetNotInWorkspace('libhello') |
| |
| |
| def test_generate_target_for_runtime_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(runtime_dependencies=['libhello']), |
| host_only_config( |
| module(name='libhello', classes=['SHARED_LIBRARIES'])) |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' runtime_deps = select({\n' |
| ' "//bazel/rules:host": [\n' |
| ' "//:libhello",\n' |
| ' ],\n' |
| ' }),\n' |
| ) |
| |
| class SharedLibPrebuiltTargetGenerationTest(GenerationTestFixture): |
| """Tests for runtime dependency module prebuilt target generation.""" |
| |
| def test_create_multi_config_target_symlinks(self): |
| host_file1 = self.host_out_path.joinpath('a/b/f1') |
| host_file2 = self.host_out_path.joinpath('a/c/f2') |
| device_file1 = self.product_out_path.joinpath('a/b/f1') |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| multi_config_module( |
| name='libhello', |
| installed=[str(host_file1), str(host_file2), str(device_file1)] |
| ) |
| ]) |
| package_path = self.workspace_out_path |
| |
| self.run_generator(mod_info) |
| |
| self.assertSymlinkTo( |
| package_path.joinpath('libhello/host/a/b/f1'), host_file1) |
| self.assertSymlinkTo( |
| package_path.joinpath('libhello/host/a/c/f2'), host_file2) |
| self.assertSymlinkTo( |
| package_path.joinpath('libhello/device/a/b/f1'), device_file1) |
| |
| def test_create_symlinks_to_installed_path_for_non_tf_testable_deps(self): |
| host_file = self.host_out_path.joinpath('a/b/f1') |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| host_module( |
| name='libhello', |
| installed=[str(host_file)], |
| auto_test_config=['true'] |
| ) |
| ]) |
| package_path = self.workspace_out_path |
| |
| self.run_generator(mod_info) |
| |
| self.assertSymlinkTo( |
| package_path.joinpath('libhello/host/a/b/f1'), host_file) |
| |
| def test_create_symlinks_to_installed_path_for_lib_with_test_config(self): |
| host_file = self.host_out_path.joinpath('a/b/f1') |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| host_module( |
| name='libhello', |
| installed=[str(host_file)], |
| path='src/lib' |
| ) |
| ]) |
| self.fs.create_file(Path('src/lib/AndroidTest.xml'), contents='') |
| package_path = self.workspace_out_path |
| |
| self.run_generator(mod_info) |
| |
| self.assertSymlinkTo( |
| package_path.joinpath('src/lib/libhello/host/a/b/f1'), host_file) |
| |
| def test_generate_for_host_only_shared_lib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| host_module(name='libhello'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' files = select({\n' |
| ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' |
| ' }),\n' |
| ) |
| self.assertFileNotInWorkspace('libhello/device') |
| |
| def test_generate_for_device_only_shared_lib_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(shared_libs=['libhello']), |
| device_module(name='libhello'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' files = select({\n' |
| ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' |
| ' }),\n' |
| ) |
| self.assertFileNotInWorkspace('libhello/host') |
| |
| |
| class DataDependenciesGenerationTest(GenerationTestFixture): |
| """Tests for module data dependencies target generation.""" |
| |
| def test_generate_target_for_data_dependency(self): |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(data_dependencies=['libdata']), |
| host_module(name='libdata'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertInBuildFile( |
| ' data = select({\n' |
| ' "//bazel/rules:host": [\n' |
| ' "//:libdata",\n' |
| ' ],\n' |
| ' }),\n' |
| ) |
| self.assertTargetInWorkspace('libdata') |
| |
| def test_not_generate_target_for_data_file(self): |
| # Data files are included in "data", but not in "data_dependencies". |
| mod_info = self.create_module_info(modules=[ |
| supported_test_module(data=['libdata']), |
| host_module(name='libdata'), |
| ]) |
| |
| self.run_generator(mod_info) |
| |
| self.assertTargetNotInWorkspace('libdata') |
| |
| |
| @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'}) |
| def create_empty_module_info(): |
| with fake_filesystem_unittest.Patcher() as patcher: |
| # pylint: disable=protected-access |
| fake_temp_file_name = next(tempfile._get_candidate_names()) |
| patcher.fs.create_file(fake_temp_file_name, contents='{}') |
| return module_info.ModuleInfo(module_file=fake_temp_file_name) |
| |
| |
| def create_module_info(modules=None): |
| mod_info = create_empty_module_info() |
| modules = modules or [] |
| |
| for m in modules: |
| mod_info.name_to_module_info[m['module_name']] = m |
| |
| return mod_info |
| |
| |
| def host_unit_test_module(**kwargs): |
| return host_unit_suite(host_test_module(**kwargs)) |
| |
| |
| # We use the below alias in situations where the actual type is irrelevant to |
| # the test as long as it is supported in Bazel mode. |
| supported_test_module = host_unit_test_module |
| |
| |
| def host_test_module(**kwargs): |
| kwargs.setdefault('name', 'hello_world_test') |
| return host_only_config(test_module(**kwargs)) |
| |
| |
| def device_test_module(**kwargs): |
| kwargs.setdefault('name', 'hello_world_test') |
| return device_only_config(test_module(**kwargs)) |
| |
| |
| def host_module(**kwargs): |
| m = module(**kwargs) |
| |
| if 'installed' in kwargs: |
| return m |
| |
| return host_only_config(m) |
| |
| |
| def device_module(**kwargs): |
| m = module(**kwargs) |
| |
| if 'installed' in kwargs: |
| return m |
| |
| return device_only_config(m) |
| |
| |
| def multi_config_module(**kwargs): |
| m = module(**kwargs) |
| |
| if 'installed' in kwargs: |
| return m |
| |
| return multi_config(m) |
| |
| |
| def test_module(**kwargs): |
| kwargs.setdefault('name', 'hello_world_test') |
| return test(module(**kwargs)) |
| |
| |
| # pylint: disable=too-many-arguments |
| def module( |
| name=None, |
| path=None, |
| installed=None, |
| classes=None, |
| auto_test_config=None, |
| shared_libs=None, |
| dependencies=None, |
| runtime_dependencies=None, |
| data=None, |
| data_dependencies=None, |
| ): |
| name = name or 'libhello' |
| |
| m = {} |
| |
| m['module_name'] = name |
| m['class'] = classes |
| m['path'] = [path or ''] |
| m['installed'] = installed or [] |
| m['is_unit_test'] = 'false' |
| m['auto_test_config'] = auto_test_config or [] |
| m['shared_libs'] = shared_libs or [] |
| m['runtime_dependencies'] = runtime_dependencies or [] |
| m['dependencies'] = dependencies or [] |
| m['data'] = data or [] |
| m['data_dependencies'] = data_dependencies or [] |
| return m |
| |
| |
| def test(info): |
| info['auto_test_config'] = ['true'] |
| return info |
| |
| |
| def shared_lib(info): |
| info['class'] = ['SHARED_LIBRARIES'] |
| return info |
| |
| |
| def rlib(info): |
| info['class'] = ['RLIB_LIBRARIES'] |
| info['installed'] = [] |
| return info |
| |
| |
| def dylib(info): |
| info['class'] = ['DYLIB_LIBRARIES'] |
| return info |
| |
| |
| def host_unit_suite(info): |
| info = test(info) |
| info.setdefault('compatibility_suites', []).append('host-unit-tests') |
| return info |
| |
| |
| def multi_config(info): |
| name = info.get('module_name', 'lib') |
| info['installed'] = [ |
| f'out/host/linux-x86/{name}/{name}.jar', |
| f'out/product/vsoc_x86/{name}/{name}.apk', |
| ] |
| info['supported_variants'] = [ |
| 'DEVICE', |
| 'HOST', |
| ] |
| return info |
| |
| |
| def host_only_config(info): |
| name = info.get('module_name', 'lib') |
| info['installed'] = [ |
| f'out/host/linux-x86/{name}/{name}.jar', |
| ] |
| info['supported_variants'] = [ |
| 'HOST', |
| ] |
| return info |
| |
| |
| def device_only_config(info): |
| name = info.get('module_name', 'lib') |
| info['installed'] = [ |
| f'out/product/vsoc_x86/{name}/{name}.jar', |
| ] |
| info['supported_variants'] = [ |
| 'DEVICE', |
| ] |
| return info |
| |
| |
| class PackageTest(fake_filesystem_unittest.TestCase): |
| """Tests for Package.""" |
| |
| class FakeTarget(bazel_mode.Target): |
| """Fake target used for tests.""" |
| |
| def __init__(self, name, imports=None): |
| self._name = name |
| self._imports = imports or set() |
| |
| def name(self): |
| return self._name |
| |
| def required_imports(self): |
| return self._imports |
| |
| def write_to_build_file(self, f): |
| f.write(f'{self._name}\n') |
| |
| |
| def setUp(self): |
| self.setUpPyfakefs() |
| self.workspace_out_path = Path('/workspace_out_path') |
| self.workspace_out_path.mkdir() |
| |
| def test_raise_when_adding_existing_target(self): |
| target_name = '<fake_target>' |
| package = bazel_mode.Package('p') |
| package.add_target(self.FakeTarget(target_name)) |
| |
| with self.assertRaises(Exception) as context: |
| package.add_target(self.FakeTarget(target_name)) |
| |
| self.assertIn(target_name, str(context.exception)) |
| |
| def test_write_build_file_in_package_dir(self): |
| package_path = 'abc/def' |
| package = bazel_mode.Package(package_path) |
| expected_path = self.workspace_out_path.joinpath( |
| package_path, 'BUILD.bazel') |
| |
| package.generate(self.workspace_out_path) |
| |
| self.assertTrue(expected_path.exists()) |
| |
| def test_write_load_statements_in_sorted_order(self): |
| package = bazel_mode.Package('p') |
| target1 = self.FakeTarget('target1', imports={ |
| bazel_mode.Import('z.bzl', 'symbol1'), |
| }) |
| target2 = self.FakeTarget('target2', imports={ |
| bazel_mode.Import('a.bzl', 'symbol2'), |
| }) |
| package.add_target(target1) |
| package.add_target(target2) |
| |
| package.generate(self.workspace_out_path) |
| |
| self.assertIn('load("a.bzl", "symbol2")\nload("z.bzl", "symbol1")\n\n', |
| self.package_build_file_text(package)) |
| |
| def test_write_load_statements_with_symbols_grouped_by_bzl(self): |
| package = bazel_mode.Package('p') |
| target1 = self.FakeTarget('target1', imports={ |
| bazel_mode.Import('a.bzl', 'symbol1'), |
| bazel_mode.Import('a.bzl', 'symbol3'), |
| }) |
| target2 = self.FakeTarget('target2', imports={ |
| bazel_mode.Import('a.bzl', 'symbol2'), |
| }) |
| package.add_target(target1) |
| package.add_target(target2) |
| |
| package.generate(self.workspace_out_path) |
| |
| self.assertIn('load("a.bzl", "symbol1", "symbol2", "symbol3")\n\n', |
| self.package_build_file_text(package)) |
| |
| def test_write_targets_in_add_order(self): |
| package = bazel_mode.Package('p') |
| target1 = self.FakeTarget('target1') |
| target2 = self.FakeTarget('target2') |
| package.add_target(target2) # Added out of order. |
| package.add_target(target1) |
| |
| package.generate(self.workspace_out_path) |
| |
| self.assertIn('target2\n\ntarget1\n', |
| self.package_build_file_text(package)) |
| |
| def test_generate_parent_package_when_nested_exists(self): |
| parent_path = Path('parent') |
| parent = bazel_mode.Package(parent_path.name) |
| nested = bazel_mode.Package(parent_path.joinpath('nested')) |
| nested.generate(self.workspace_out_path) |
| |
| parent.generate(self.workspace_out_path) |
| |
| self.assertTrue(self.workspace_out_path.joinpath(parent_path).is_dir()) |
| |
| def package_build_file_text(self, package): |
| return self.workspace_out_path.joinpath( |
| package.path, 'BUILD.bazel').read_text(encoding='utf8') |
| |
| |
| class DecorateFinderMethodTest(fake_filesystem_unittest.TestCase): |
| """Tests for _decorate_find_method().""" |
| |
| def setUp(self): |
| self.setUpPyfakefs() |
| |
| # pylint: disable=protected-access |
| # TODO(b/197600827): Add self._env in Module_info instead of mocking |
| # os.environ directly. |
| @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'}) |
| def test_unit_test_runner_is_overridden(self): |
| original_find_method = lambda obj, test_id:( |
| self.create_single_test_infos(obj, test_id, test_name=MODULE_NAME, |
| runner=ATEST_TF_RUNNER)) |
| mod_info = self.create_single_test_module_info(MODULE_NAME, |
| is_unit_test=True) |
| new_find_method = bazel_mode._decorate_find_method( |
| mod_info, original_find_method) |
| |
| test_infos = new_find_method('finder_obj', 'test_id') |
| |
| self.assertEqual(len(test_infos), 1) |
| self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) |
| |
| # pylint: disable=protected-access |
| @mock.patch.dict('os.environ', {constants.ANDROID_BUILD_TOP:'/'}) |
| def test_not_unit_test_runner_is_preserved(self): |
| original_find_method = lambda obj, test_id:( |
| self.create_single_test_infos(obj, test_id, test_name=MODULE_NAME, |
| runner=ATEST_TF_RUNNER)) |
| mod_info = self.create_single_test_module_info( |
| MODULE_NAME, is_unit_test=False) |
| new_find_method = bazel_mode._decorate_find_method( |
| mod_info, original_find_method) |
| |
| test_infos = new_find_method('finder_obj', 'test_id') |
| |
| self.assertEqual(len(test_infos), 1) |
| self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) |
| |
| # pylint: disable=unused-argument |
| def create_single_test_infos(self, obj, test_id, test_name=MODULE_NAME, |
| runner=ATEST_TF_RUNNER): |
| """Create list of test_info.TestInfo.""" |
| return [test_info.TestInfo(test_name, runner, MODULE_BUILD_TARGETS)] |
| |
| def create_single_test_module_info(self, module_name, is_unit_test=True): |
| """Create module-info file with single module.""" |
| compatibility_suites = '["host-unit-tests"]' |
| if not is_unit_test: |
| compatibility_suites = "[]" |
| unit_test_mod_info_content = ('{"%s": {"class": ["NATIVE_TESTS"],' + |
| ' "compatibility_suites": %s }}') % ( |
| module_name, compatibility_suites) |
| fake_temp_file_name = next(tempfile._get_candidate_names()) |
| self.fs.create_file(fake_temp_file_name, |
| contents=unit_test_mod_info_content) |
| return module_info.ModuleInfo(module_file=fake_temp_file_name) |
| |
| |
| class BazelTestRunnerTest(unittest.TestCase): |
| """Tests for BazelTestRunner.""" |
| |
| def test_return_empty_build_reqs_when_no_test_infos(self): |
| run_command = self.mock_run_command(side_effect=Exception('')) |
| runner = self.create_bazel_test_runner( |
| modules=[ |
| supported_test_module(name='test1', path='path1'), |
| ], |
| test_infos=[], |
| run_command=run_command, |
| ) |
| |
| reqs = runner.get_test_runner_build_reqs() |
| |
| self.assertFalse(reqs) |
| |
| def test_query_bazel_test_targets_deps_for_build_reqs(self): |
| run_command = self.mock_run_command() |
| runner = self.create_bazel_test_runner( |
| modules=[ |
| supported_test_module(name='test1', path='path1'), |
| supported_test_module(name='test2', path='path2') |
| ], |
| test_infos = [ |
| test_info_of('test2'), |
| test_info_of('test1'), # Intentionally out of order. |
| ], |
| run_command=run_command, |
| ) |
| |
| runner.get_test_runner_build_reqs() |
| |
| call_args = run_command.call_args[0][0] |
| self.assertIn( |
| 'deps(tests(//path1:test1_host + //path2:test2_host))', |
| call_args, |
| ) |
| |
| def test_trim_whitespace_in_bazel_query_output(self): |
| run_command = self.mock_run_command( |
| return_value='\n'.join([' test1 ', 'test2 ', ' '])) |
| runner = self.create_bazel_test_runner( |
| modules=[ |
| supported_test_module(name='test1', path='path1'), |
| ], |
| test_infos = [test_info_of('test1')], |
| run_command=run_command, |
| ) |
| |
| reqs = runner.get_test_runner_build_reqs() |
| |
| self.assertSetEqual({'test1', 'test2'}, reqs) |
| |
| def test_generate_single_run_command(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| |
| cmd = runner.generate_run_commands(test_infos, {}) |
| |
| self.assertEqual(1, len(cmd)) |
| |
| def test_generate_run_command_containing_targets(self): |
| test_infos = [test_info_of('test1'), test_info_of('test2')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| |
| cmd = runner.generate_run_commands(test_infos, {}) |
| |
| self.assertTokensIn(['//path:test1_host', '//path:test2_host'], cmd[0]) |
| |
| def test_generate_run_command_with_multi_bazel_args(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| extra_args = {constants.BAZEL_ARG: [['--option1=value1'], |
| ['--option2=value2']]} |
| |
| cmd = runner.generate_run_commands(test_infos, extra_args) |
| |
| self.assertTokensIn(['--option1=value1', '--option2=value2'], cmd[0]) |
| |
| def test_generate_run_command_with_multi_custom_args(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| extra_args = {constants.CUSTOM_ARGS: ['-hello', '--world=value']} |
| |
| cmd = runner.generate_run_commands(test_infos, extra_args) |
| |
| self.assertTokensIn(['--test_arg=-hello', |
| '--test_arg=--world=value'], cmd[0]) |
| |
| def test_generate_run_command_with_custom_and_bazel_args(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| extra_args = {constants.CUSTOM_ARGS: ['-hello', '--world=value'], |
| constants.BAZEL_ARG: [['--option1=value1']]} |
| |
| cmd = runner.generate_run_commands(test_infos, extra_args) |
| |
| self.assertTokensIn(['--test_arg=-hello', |
| '--test_arg=--world=value', |
| '--option1=value1'], cmd[0]) |
| |
| def test_generate_run_command_with_tf_supported_host_arg(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| extra_args = {constants.HOST: True} |
| |
| cmd = runner.generate_run_commands(test_infos, extra_args) |
| |
| self.assertTokensIn(['--test_arg=-n', |
| '--test_arg=--prioritize-host-config', |
| '--test_arg=--skip-host-arch-check'], cmd[0]) |
| |
| def test_generate_run_command_with_iterations_args(self): |
| test_infos = [test_info_of('test1')] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| extra_args = {constants.ITERATIONS: 2} |
| |
| cmd = runner.generate_run_commands(test_infos, extra_args) |
| |
| self.assertTokensIn(['--runs_per_test=2'], cmd[0]) |
| self.assertNotIn('--test_arg=--retry-strategy', shlex.split(cmd[0])) |
| |
| def test_generate_run_command_with_testinfo_filter(self): |
| test_filter = test_filter_of('class1', ['method1']) |
| test_infos = [test_info_of('test1', test_filters=[test_filter])] |
| runner = self.create_bazel_test_runner_for_tests(test_infos) |
| |
| cmd = runner.generate_run_commands(test_infos, {}) |
| |
| self.assertTokensIn(['--test_arg=--atest-include-filter', |
| '--test_arg=test1:class1#method1'], cmd[0]) |
| |
| def create_bazel_test_runner(self, modules, test_infos, run_command=None): |
| return bazel_mode.BazelTestRunner( |
| 'result_dir', |
| mod_info=create_module_info(modules), |
| test_infos=test_infos, |
| src_top=Path('/src'), |
| workspace_path=Path('/src/workspace'), |
| run_command=run_command or self.mock_run_command() |
| ) |
| |
| def create_bazel_test_runner_for_tests(self, test_infos): |
| return self.create_bazel_test_runner( |
| modules=[supported_test_module(name=t.test_name, path='path') |
| for t in test_infos], |
| test_infos=test_infos |
| ) |
| |
| def mock_run_command(self, **kwargs): |
| return mock.create_autospec(bazel_mode.default_run_command, **kwargs) |
| |
| def assertTokensIn(self, expected_tokens, s): |
| tokens = shlex.split(s) |
| for token in expected_tokens: |
| self.assertIn(token, tokens) |
| |
| |
| class FeatureParserTest(unittest.TestCase): |
| """Tests for parsing Bazel mode feature flags.""" |
| |
| def test_parse_args_with_bazel_mode_feature(self): |
| parser = argparse.ArgumentParser() |
| bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') |
| # pylint: disable=no-member |
| args = parser.parse_args([bazel_mode.Features.NULL_FEATURE.arg_flag]) |
| |
| self.assertListEqual([bazel_mode.Features.NULL_FEATURE], |
| args.bazel_mode_features) |
| |
| def test_parse_args_without_bazel_mode_feature(self): |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--foo', |
| action='append_const', |
| const='foo', |
| dest='foo') |
| bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') |
| args = parser.parse_args(['--foo']) |
| |
| self.assertIsNone(args.bazel_mode_features) |
| |
| |
| def test_info_of(module_name, test_filters=None): |
| return test_info.TestInfo( |
| module_name, BAZEL_RUNNER, [], |
| data={constants.TI_FILTER: frozenset(test_filters)} |
| if test_filters else None) |
| |
| |
| def test_filter_of(class_name, methods=None): |
| return test_info.TestFilter( |
| class_name, frozenset(methods) if methods else frozenset()) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |