1#!/usr/bin/env python3 2# 3# Copyright 2021, The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Unit tests for bazel_mode.""" 18# pylint: disable=invalid-name 19# pylint: disable=missing-function-docstring 20# pylint: disable=too-many-lines 21 22import argparse 23import re 24import shlex 25import shutil 26import subprocess 27import tempfile 28import unittest 29 30from io import StringIO 31from pathlib import Path 32from typing import List 33from unittest import mock 34 35# pylint: disable=import-error 36from pyfakefs import fake_filesystem_unittest 37 38from atest import bazel_mode 39from atest import constants 40from atest import module_info 41 42from atest.test_finders import example_finder, test_finder_base, test_info 43from atest.test_runners import atest_tf_test_runner 44 45 46ATEST_TF_RUNNER = atest_tf_test_runner.AtestTradefedTestRunner.NAME 47BAZEL_RUNNER = bazel_mode.BazelTestRunner.NAME 48MODULE_BUILD_TARGETS = {'foo1', 'foo2', 'foo3'} 49MODULE_NAME = 'foo' 50 51 52class GenerationTestFixture(fake_filesystem_unittest.TestCase): 53 """Fixture for workspace generation tests.""" 54 55 def setUp(self): 56 self.setUpPyfakefs() 57 58 self._src_root_path = Path('/src') 59 self.out_dir_path = self._src_root_path.joinpath('out') 60 self.out_dir_path.mkdir(parents=True) 61 self.product_out_path = self.out_dir_path.joinpath('product') 62 self.host_out_path = self.out_dir_path.joinpath('host') 63 self.workspace_out_path = self.out_dir_path.joinpath('workspace') 64 65 self._resource_root = self._src_root_path.joinpath( 66 'tools/asuite/atest/bazel') 67 68 self.workspace_md5_checksum = self.workspace_out_path.joinpath( 69 'workspace_md5_checksum') 70 self.resource_manager = bazel_mode.ResourceManager( 71 src_root_path=self._src_root_path, 72 resource_root_path=self._resource_root, 73 product_out_path=self.product_out_path, 74 md5_checksum_file_path = self.workspace_md5_checksum 75 ) 76 77 bazel_rules = self.resource_manager.get_resource_file_path('rules') 78 bazel_rules.mkdir(parents=True) 79 self.rules_bzl_file = bazel_rules.joinpath('rules.bzl') 80 self.rules_bzl_file.touch() 81 82 bazel_configs = self.resource_manager.get_resource_file_path('configs') 83 bazel_configs.mkdir(parents=True) 84 bazel_configs.joinpath('configs.bzl').touch() 85 86 self.resource_manager.get_resource_file_path('WORKSPACE').touch() 87 self.resource_manager.get_resource_file_path('bazelrc').touch() 88 89 def create_workspace_generator( 90 self, 91 modules=None, 92 enabled_features=None, 93 jdk_path=None, 94 ): 95 mod_info = self.create_module_info(modules) 96 97 generator = bazel_mode.WorkspaceGenerator( 98 resource_manager=self.resource_manager, 99 workspace_out_path=self.workspace_out_path, 100 host_out_path=self.host_out_path, 101 build_out_dir=self.out_dir_path, 102 mod_info=mod_info, 103 jdk_path=jdk_path, 104 enabled_features=enabled_features, 105 ) 106 107 return generator 108 109 def run_generator(self, mod_info, enabled_features=None, jdk_path=None): 110 generator = bazel_mode.WorkspaceGenerator( 111 resource_manager=self.resource_manager, 112 workspace_out_path=self.workspace_out_path, 113 host_out_path=self.host_out_path, 114 build_out_dir=self.out_dir_path, 115 mod_info=mod_info, 116 jdk_path=jdk_path, 117 enabled_features=enabled_features, 118 ) 119 120 generator.generate() 121 122 # pylint: disable=protected-access 123 def create_empty_module_info(self): 124 fake_temp_file = self.product_out_path.joinpath( 125 next(tempfile._get_candidate_names())) 126 self.fs.create_file(fake_temp_file, contents='{}') 127 return module_info.ModuleInfo(module_file=fake_temp_file) 128 129 def create_module_info(self, modules=None): 130 mod_info = self.create_empty_module_info() 131 modules = modules or [] 132 133 prerequisites = frozenset().union( 134 bazel_mode.TestTarget.DEVICE_TEST_PREREQUISITES, 135 bazel_mode.TestTarget.DEVICELESS_TEST_PREREQUISITES) 136 137 for module_name in prerequisites: 138 info = host_module(name=module_name, path='prebuilts') 139 info[constants.MODULE_INFO_ID] = module_name 140 mod_info.name_to_module_info[module_name] = info 141 142 for m in modules: 143 m[constants.MODULE_INFO_ID] = m['module_name'] 144 mod_info.name_to_module_info[m['module_name']] = m 145 for path in m['path']: 146 if path in mod_info.path_to_module_info: 147 mod_info.path_to_module_info[path].append(m) 148 else: 149 mod_info.path_to_module_info[path] = [m] 150 151 return mod_info 152 153 def assertSymlinkTo(self, symlink_path, target_path): 154 self.assertEqual(symlink_path.resolve(strict=False), target_path) 155 156 def assertTargetInWorkspace(self, name, package=''): 157 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 158 contents = build_file.read_text(encoding='utf8') 159 occurrences = len(self.find_target_by_name(name, contents)) 160 161 if occurrences == 1: 162 return 163 164 cardinality = 'Multiple' if occurrences else 'Zero' 165 self.fail( 166 f'{cardinality} targets named \'{name}\' found in \'{contents}\'' 167 ) 168 169 def assertTargetNotInWorkspace(self, name, package=''): 170 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 171 172 if not build_file.exists(): 173 return 174 175 contents = build_file.read_text(encoding='utf8') 176 matches = self.find_target_by_name(name, contents) 177 178 if not matches: 179 return 180 181 self.fail( 182 f'Unexpectedly found target(s) named \'{name}\' in \'{contents}\'' 183 ) 184 185 def assertInBuildFile(self, substring, package=''): 186 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 187 self.assertIn(substring, build_file.read_text(encoding='utf8')) 188 189 def assertNotInBuildFile(self, substring, package=''): 190 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 191 self.assertNotIn(substring, build_file.read_text(encoding='utf8')) 192 193 def assertFileInWorkspace(self, relative_path, package=''): 194 path = self.workspace_out_path.joinpath(package, relative_path) 195 self.assertTrue(path.exists()) 196 197 def assertDirInWorkspace(self, relative_path, package=''): 198 path = self.workspace_out_path.joinpath(package, relative_path) 199 self.assertTrue(path.is_dir()) 200 201 def assertFileNotInWorkspace(self, relative_path, package=''): 202 path = self.workspace_out_path.joinpath(package, relative_path) 203 self.assertFalse(path.exists()) 204 205 def find_target_by_name(self, name: str, contents: str) -> List[str]: 206 return re.findall(rf'\bname\s*=\s*"{name}"', contents) 207 208 209class BasicWorkspaceGenerationTest(GenerationTestFixture): 210 """Tests for basic workspace generation and update.""" 211 212 def test_generate_workspace_when_nonexistent(self): 213 workspace_generator = self.create_workspace_generator() 214 shutil.rmtree(workspace_generator.workspace_out_path, 215 ignore_errors=True) 216 217 workspace_generator.generate() 218 219 self.assertTrue(workspace_generator.workspace_out_path.is_dir()) 220 221 def test_regenerate_workspace_when_features_changed(self): 222 workspace_generator = self.create_workspace_generator( 223 enabled_features={bazel_mode.Features.NULL_FEATURE}) 224 workspace_generator.generate() 225 workspace_stat = workspace_generator.workspace_out_path.stat() 226 227 workspace_generator = self.create_workspace_generator() 228 workspace_generator.generate() 229 new_workspace_stat = workspace_generator.workspace_out_path.stat() 230 231 self.assertNotEqual(workspace_stat, new_workspace_stat) 232 233 def test_not_regenerate_when_feature_does_not_affect_workspace(self): 234 workspace_generator = self.create_workspace_generator( 235 enabled_features={bazel_mode.Features.NULL_FEATURE}) 236 workspace_generator.generate() 237 workspace_stat = workspace_generator.workspace_out_path.stat() 238 239 parser = argparse.ArgumentParser() 240 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 241 # pylint: disable=no-member 242 args = parser.parse_args([ 243 bazel_mode.Features.NULL_FEATURE.arg_flag, 244 '--experimental-bes-publish' 245 ]) 246 workspace_generator = self.create_workspace_generator( 247 enabled_features=set(args.bazel_mode_features)) 248 workspace_generator.generate() 249 new_workspace_stat = workspace_generator.workspace_out_path.stat() 250 251 self.assertEqual(workspace_stat, new_workspace_stat) 252 253 def test_not_regenerate_workspace_when_features_unchanged(self): 254 workspace_generator = self.create_workspace_generator( 255 enabled_features={bazel_mode.Features.NULL_FEATURE}) 256 workspace_generator.generate() 257 workspace_stat = workspace_generator.workspace_out_path.stat() 258 259 workspace_generator = self.create_workspace_generator( 260 enabled_features={bazel_mode.Features.NULL_FEATURE}) 261 workspace_generator.generate() 262 new_workspace_stat = workspace_generator.workspace_out_path.stat() 263 264 self.assertEqual(workspace_stat, new_workspace_stat) 265 266 def test_regenerate_workspace_when_module_info_deleted(self): 267 workspace_generator = self.create_workspace_generator() 268 workspace_generator.generate() 269 workspace_stat = workspace_generator.workspace_out_path.stat() 270 271 workspace_generator.mod_info.mod_info_file_path.unlink() 272 workspace_generator = self.create_workspace_generator() 273 workspace_generator.generate() 274 275 new_workspace_stat = workspace_generator.workspace_out_path.stat() 276 self.assertNotEqual(workspace_stat, new_workspace_stat) 277 278 def test_not_regenerate_workspace_when_module_info_unchanged(self): 279 workspace_generator1 = self.create_workspace_generator() 280 workspace_generator1.generate() 281 workspace_stat = workspace_generator1.workspace_out_path.stat() 282 283 workspace_generator2 = self.create_workspace_generator() 284 workspace_generator2.generate() 285 new_workspace_stat = workspace_generator2.workspace_out_path.stat() 286 287 self.assertEqual(workspace_stat, new_workspace_stat) 288 289 def test_not_regenerate_workspace_when_module_only_touched(self): 290 workspace_generator = self.create_workspace_generator() 291 workspace_generator.generate() 292 workspace_stat = workspace_generator.workspace_out_path.stat() 293 294 Path(workspace_generator.mod_info.mod_info_file_path).touch() 295 workspace_generator = self.create_workspace_generator() 296 workspace_generator.generate() 297 298 new_workspace_stat = workspace_generator.workspace_out_path.stat() 299 self.assertEqual(workspace_stat, new_workspace_stat) 300 301 def test_regenerate_workspace_when_module_info_changed(self): 302 workspace_generator = self.create_workspace_generator() 303 workspace_generator.generate() 304 workspace_stat = workspace_generator.workspace_out_path.stat() 305 306 mod_info_file_path = workspace_generator.mod_info.mod_info_file_path 307 with open(mod_info_file_path, 'a', encoding='utf8') as f: 308 f.write(' ') 309 workspace_generator = self.create_workspace_generator() 310 workspace_generator.generate() 311 312 new_workspace_stat = workspace_generator.workspace_out_path.stat() 313 self.assertNotEqual(workspace_stat, new_workspace_stat) 314 315 def test_regenerate_workspace_when_md5_file_removed(self): 316 workspace_generator = self.create_workspace_generator() 317 workspace_generator.generate() 318 workspace_stat = workspace_generator.workspace_out_path.stat() 319 320 self.workspace_md5_checksum.unlink() 321 workspace_generator = self.create_workspace_generator() 322 workspace_generator.generate() 323 new_workspace_stat = workspace_generator.workspace_out_path.stat() 324 325 self.assertNotEqual(workspace_stat, new_workspace_stat) 326 327 def test_regenerate_workspace_when_md5_file_is_broken(self): 328 workspace_generator = self.create_workspace_generator() 329 workspace_generator.generate() 330 workspace_stat = workspace_generator.workspace_out_path.stat() 331 332 self.workspace_md5_checksum.write_text('broken checksum file') 333 workspace_generator = self.create_workspace_generator() 334 workspace_generator.generate() 335 new_workspace_stat = workspace_generator.workspace_out_path.stat() 336 337 self.assertNotEqual(workspace_stat, new_workspace_stat) 338 339 def test_not_regenerate_workspace_when_workspace_files_unaffected(self): 340 workspace_generator = self.create_workspace_generator() 341 workspace_generator.generate() 342 workspace_stat = workspace_generator.workspace_out_path.stat() 343 344 workspace_generator = self.create_workspace_generator() 345 workspace_generator.generate() 346 new_workspace_stat = workspace_generator.workspace_out_path.stat() 347 348 self.assertEqual(workspace_stat, new_workspace_stat) 349 350 def test_scrub_old_workspace_when_regenerating(self): 351 workspace_generator = self.create_workspace_generator() 352 workspace_generator.generate() 353 some_file = workspace_generator.workspace_out_path.joinpath('some_file') 354 some_file.touch() 355 self.assertTrue(some_file.is_file()) 356 357 # Remove the module_info file to regenerate the workspace. 358 workspace_generator.mod_info.mod_info_file_path.unlink() 359 workspace_generator = self.create_workspace_generator() 360 workspace_generator.generate() 361 362 self.assertFalse(some_file.is_file()) 363 364 def test_regenerate_workspace_when_resource_file_changed(self): 365 workspace_generator = self.create_workspace_generator() 366 workspace_generator.generate() 367 workspace_stat = workspace_generator.workspace_out_path.stat() 368 369 with open(self.rules_bzl_file, 'a', encoding='utf8') as f: 370 f.write(' ') 371 workspace_generator = self.create_workspace_generator() 372 workspace_generator.generate() 373 374 new_workspace_stat = workspace_generator.workspace_out_path.stat() 375 self.assertNotEqual(workspace_stat, new_workspace_stat) 376 377 def test_not_regenerate_workspace_when_resource_file_only_touched(self): 378 workspace_generator = self.create_workspace_generator() 379 workspace_generator.generate() 380 workspace_stat = workspace_generator.workspace_out_path.stat() 381 382 self.rules_bzl_file.touch() 383 workspace_generator = self.create_workspace_generator() 384 workspace_generator.generate() 385 386 new_workspace_stat = workspace_generator.workspace_out_path.stat() 387 self.assertEqual(workspace_stat, new_workspace_stat) 388 389 def test_copy_workspace_resources(self): 390 gen = self.create_workspace_generator() 391 392 gen.generate() 393 394 self.assertFileInWorkspace('WORKSPACE') 395 self.assertFileInWorkspace('.bazelrc') 396 self.assertDirInWorkspace('bazel/rules') 397 self.assertDirInWorkspace('bazel/configs') 398 399 def test_generated_target_name(self): 400 mod_info = self.create_module_info(modules=[ 401 host_unit_test_module(name='hello_world_test') 402 ]) 403 info = mod_info.get_module_info('hello_world_test') 404 info[constants.MODULE_INFO_ID] = 'new_hello_world_test' 405 406 self.run_generator(mod_info) 407 408 self.assertTargetInWorkspace('new_hello_world_test') 409 self.assertTargetNotInWorkspace('hello_world_test') 410 411 def test_generate_host_unit_test_module_target(self): 412 mod_info = self.create_module_info(modules=[ 413 host_unit_test_module(name='hello_world_test') 414 ]) 415 416 self.run_generator(mod_info) 417 418 self.assertTargetInWorkspace('hello_world_test_host') 419 420 def test_not_generate_host_test_module_target(self): 421 mod_info = self.create_module_info(modules=[ 422 host_test_module(name='hello_world_test'), 423 ]) 424 425 self.run_generator(mod_info) 426 427 self.assertTargetNotInWorkspace('hello_world_test') 428 429 def test_not_generate_test_module_target_with_invalid_installed_path(self): 430 mod_info = self.create_module_info(modules=[ 431 test_module(name='hello_world_test', installed='out/invalid/path') 432 ]) 433 434 self.run_generator(mod_info) 435 436 self.assertTargetNotInWorkspace('hello_world_test_device') 437 self.assertTargetNotInWorkspace('hello_world_test_host') 438 439 def test_generate_variable_file(self): 440 gen = self.create_workspace_generator() 441 442 gen.generate() 443 444 self.assertFileInWorkspace('BUILD.bazel') 445 self.assertFileInWorkspace('constants.bzl') 446 447 448class MultiConfigUnitTestModuleTestTargetGenerationTest(GenerationTestFixture): 449 """Tests for test target generation of test modules with multi-configs.""" 450 451 def test_generate_test_rule_imports(self): 452 mod_info = self.create_module_info(modules=[ 453 multi_config(host_unit_suite(test_module( 454 name='hello_world_test', path='example/tests'))), 455 ]) 456 457 self.run_generator(mod_info, enabled_features=set([ 458 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 459 460 self.assertInBuildFile( 461 'load("//bazel/rules:tradefed_test.bzl",' 462 ' "tradefed_device_driven_test", "tradefed_deviceless_test")\n', 463 package='example/tests', 464 ) 465 466 def test_not_generate_device_test_import_when_feature_disabled(self): 467 mod_info = self.create_module_info(modules=[ 468 multi_config(host_unit_suite(test_module( 469 name='hello_world_test', path='example/tests'))), 470 ]) 471 472 self.run_generator(mod_info) 473 474 self.assertInBuildFile( 475 'load("//bazel/rules:tradefed_test.bzl",' 476 ' "tradefed_deviceless_test")\n', 477 package='example/tests', 478 ) 479 480 def test_generate_test_targets(self): 481 mod_info = self.create_module_info(modules=[ 482 multi_config(host_unit_suite(test_module( 483 name='hello_world_test', path='example/tests'))), 484 ]) 485 486 self.run_generator(mod_info, enabled_features=set([ 487 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 488 489 self.assertTargetInWorkspace('hello_world_test_device', 490 package='example/tests') 491 self.assertTargetInWorkspace('hello_world_test_host', 492 package='example/tests') 493 494 def test_not_generate_device_test_target_when_feature_disabled(self): 495 mod_info = self.create_module_info(modules=[ 496 multi_config(host_unit_suite(test_module( 497 name='hello_world_test', path='example/tests'))), 498 ]) 499 500 self.run_generator(mod_info) 501 502 self.assertTargetNotInWorkspace('hello_world_test_device', 503 package='example/tests') 504 self.assertTargetInWorkspace('hello_world_test_host', 505 package='example/tests') 506 507 508class DeviceTestModuleTestTargetGenerationTest(GenerationTestFixture): 509 """Tests for device test module test target generation.""" 510 511 def test_generate_device_driven_test_target(self): 512 mod_info = self.create_module_info(modules=[ 513 device_test_module( 514 name='hello_world_test', path='example/tests'), 515 ]) 516 517 self.run_generator(mod_info, enabled_features=set([ 518 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 519 520 self.assertInBuildFile( 521 'load("//bazel/rules:tradefed_test.bzl",' 522 ' "tradefed_device_driven_test")\n', 523 package='example/tests', 524 ) 525 self.assertTargetInWorkspace('hello_world_test_device', 526 package='example/tests') 527 528 def test_generate_target_with_suites(self): 529 mod_info = self.create_module_info(modules=[ 530 device_test_module( 531 name='hello_world_test', 532 path='example/tests', 533 compatibility_suites=['cts', 'mts']), 534 ]) 535 536 self.run_generator(mod_info, enabled_features=set([ 537 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 538 539 self.assertInBuildFile( 540 ' suites = [\n' 541 ' "cts",\n' 542 ' "mts",\n' 543 ' ],\n', 544 package='example/tests', 545 ) 546 547 def test_generate_target_with_host_dependencies(self): 548 mod_info = self.create_module_info(modules=[ 549 device_test_module( 550 name='hello_world_test', 551 path='example/tests', 552 host_dependencies=['vts_dep', 'cts_dep']), 553 host_module(name='vts_dep'), 554 host_module(name='cts_dep'), 555 ]) 556 557 self.run_generator(mod_info, enabled_features=set([ 558 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 559 560 self.assertInBuildFile( 561 ' tradefed_deps = [\n' 562 ' "//:cts_dep",\n' 563 ' "//:vts_dep",\n' 564 ' ],\n', 565 package='example/tests', 566 ) 567 568 def test_generate_target_with_device_dependencies(self): 569 mod_info = self.create_module_info(modules=[ 570 host_test_module( 571 name='hello_world_test', 572 path='example/tests', 573 target_dependencies=['helper_app']), 574 device_module(name='helper_app'), 575 ]) 576 577 self.run_generator(mod_info, enabled_features=set([ 578 bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST])) 579 580 self.assertInBuildFile( 581 ' device_data = [\n' 582 ' "//:helper_app",\n' 583 ' ],\n', 584 package='example/tests', 585 ) 586 587 def test_generate_target_with_tags(self): 588 mod_info = self.create_module_info(modules=[ 589 device_test_module( 590 name='hello_world_test', 591 path='example/tests', 592 test_options_tags=['no-remote']), 593 ]) 594 595 self.run_generator(mod_info, enabled_features=set([ 596 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 597 598 self.assertInBuildFile( 599 ' tags = [\n' 600 ' "no-remote",\n' 601 ' ],\n', 602 package='example/tests', 603 ) 604 605 def test_generate_host_driven_test_target(self): 606 mod_info = self.create_module_info(modules=[ 607 host_test_module( 608 name='hello_world_test', path='example/tests'), 609 ]) 610 611 self.run_generator(mod_info, enabled_features=set([ 612 bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST])) 613 614 self.assertInBuildFile( 615 'tradefed_host_driven_device_test(', package='example/tests') 616 617 def test_generate_multi_config_device_test_target(self): 618 mod_info = self.create_module_info(modules=[ 619 multi_config(test_module( 620 name='hello_world_test', path='example/tests')), 621 ]) 622 623 self.run_generator(mod_info, enabled_features=set([ 624 bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST, 625 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 626 627 self.assertInBuildFile( 628 'load("//bazel/rules:tradefed_test.bzl", ' 629 '"tradefed_device_driven_test", ' 630 '"tradefed_host_driven_device_test")\n', 631 package='example/tests', 632 ) 633 self.assertTargetInWorkspace('hello_world_test_device', 634 package='example/tests') 635 self.assertTargetInWorkspace('hello_world_test_host', 636 package='example/tests') 637 638 def test_not_generate_host_driven_test_target_when_feature_disabled(self): 639 mod_info = self.create_module_info(modules=[ 640 multi_config(test_module( 641 name='hello_world_test', path='example/tests')), 642 ]) 643 644 self.run_generator(mod_info, enabled_features=set([ 645 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 646 647 self.assertTargetInWorkspace('hello_world_test_device', 648 package='example/tests') 649 self.assertTargetNotInWorkspace('hello_world_test_host', 650 package='example/tests') 651 652 def test_raise_when_prerequisite_not_in_module_info(self): 653 mod_info = self.create_module_info(modules=[ 654 device_test_module(), 655 ]) 656 del mod_info.name_to_module_info['aapt'] 657 658 with self.assertRaises(Exception) as context: 659 self.run_generator(mod_info, enabled_features=set([ 660 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST])) 661 662 self.assertIn('aapt', str(context.exception)) 663 664 665class HostUnitTestModuleTestTargetGenerationTest(GenerationTestFixture): 666 """Tests for host unit test module test target generation.""" 667 668 def test_generate_deviceless_test_import(self): 669 mod_info = self.create_module_info(modules=[ 670 host_unit_test_module(name='hello_world_test'), 671 ]) 672 673 self.run_generator(mod_info) 674 675 self.assertInBuildFile( 676 'load("//bazel/rules:tradefed_test.bzl",' 677 ' "tradefed_deviceless_test")\n' 678 ) 679 680 def test_generate_deviceless_test_target(self): 681 mod_info = self.create_module_info(modules=[ 682 host_unit_test_module( 683 name='hello_world_test', path='example/tests'), 684 ]) 685 686 self.run_generator(mod_info) 687 688 self.assertInBuildFile( 689 'tradefed_deviceless_test(\n' 690 ' name = "hello_world_test_host",\n' 691 ' module_name = "hello_world_test",\n' 692 ' test = "//example/tests:hello_world_test",\n' 693 ')', 694 package='example/tests', 695 ) 696 697 def test_generate_target_with_tags(self): 698 mod_info = self.create_module_info(modules=[ 699 host_unit_test_module( 700 name='hello_world_test', 701 path='example/tests', 702 test_options_tags=['no-remote']), 703 ]) 704 705 self.run_generator(mod_info) 706 707 self.assertInBuildFile( 708 ' tags = [\n' 709 ' "no-remote",\n' 710 ' ],\n', 711 package='example/tests', 712 ) 713 714 def test_generate_test_module_prebuilt(self): 715 mod_info = self.create_module_info(modules=[ 716 host_unit_test_module(name='hello_world_test'), 717 ]) 718 719 self.run_generator(mod_info) 720 721 self.assertTargetInWorkspace('hello_world_test') 722 723 def test_raise_when_prerequisite_not_in_module_info(self): 724 mod_info = self.create_module_info(modules=[ 725 host_unit_test_module(), 726 ]) 727 del mod_info.name_to_module_info['adb'] 728 729 with self.assertRaises(Exception) as context: 730 self.run_generator(mod_info) 731 732 self.assertIn('adb', str(context.exception)) 733 734 def test_raise_when_prerequisite_module_missing_path(self): 735 mod_info = self.create_module_info(modules=[ 736 host_unit_test_module(), 737 ]) 738 mod_info.name_to_module_info['adb'].get('path').clear() 739 740 with self.assertRaises(Exception) as context: 741 self.run_generator(mod_info) 742 743 self.assertIn('adb', str(context.exception)) 744 745 def test_warning_when_prerequisite_module_has_multiple_path(self): 746 mod_info = self.create_module_info(modules=[ 747 host_unit_test_module(), 748 ]) 749 mod_info.name_to_module_info['adb'].get('path').append('the/2nd/path') 750 751 with self.assertWarns(Warning) as context: 752 self.run_generator(mod_info) 753 754 self.assertIn('adb', str(context.warnings[0].message)) 755 756 757class RobolectricTestModuleTestTargetGenerationTest(GenerationTestFixture): 758 """Tests for robolectric test module test target generation.""" 759 760 def setUp(self): 761 super().setUp() 762 self.robolectric_template_path = self.resource_manager.\ 763 get_resource_file_path(bazel_mode.ROBOLECTRIC_CONFIG, True) 764 self.fs.create_file(self.robolectric_template_path, contents='') 765 # ResourceManager only calculates md5 when registering files. So, it is 766 # necessary to call get_resource_file_path() again after writing files. 767 self.resource_manager.get_resource_file_path( 768 bazel_mode.ROBOLECTRIC_CONFIG, True) 769 770 def test_generate_robolectric_test_target(self): 771 module_name = 'hello_world_test' 772 mod_info = self.create_module_info(modules=[ 773 robolectric_test_module( 774 name=f'{module_name}', 775 compatibility_suites='robolectric-tests'), 776 ]) 777 778 self.run_generator(mod_info, enabled_features=set([ 779 bazel_mode.Features.EXPERIMENTAL_ROBOLECTRIC_TEST])) 780 781 self.assertInBuildFile( 782 'load("//bazel/rules:tradefed_test.bzl",' 783 ' "tradefed_robolectric_test")\n', 784 ) 785 self.assertTargetInWorkspace(f'{module_name}_host') 786 787 def test_not_generate_when_feature_disabled(self): 788 module_name = 'hello_world_test' 789 mod_info = self.create_module_info(modules=[ 790 robolectric_test_module( 791 name=f'{module_name}', 792 compatibility_suites='robolectric-tests'), 793 ]) 794 795 self.run_generator(mod_info) 796 797 self.assertTargetNotInWorkspace(f'{module_name}_host') 798 799 def test_not_generate_for_legacy_robolectric_test_type(self): 800 module_name = 'hello_world_test' 801 module_path = 'example/tests' 802 mod_info = self.create_module_info(modules=[ 803 robolectric_test_module( 804 name=f'{module_name}', path=module_path), 805 ]) 806 807 self.run_generator(mod_info, enabled_features=set([ 808 bazel_mode.Features.EXPERIMENTAL_ROBOLECTRIC_TEST])) 809 810 self.assertFileNotInWorkspace('BUILD.bazel', package=f'{module_path}') 811 812 def test_generate_jdk_target(self): 813 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 814 815 gen.generate() 816 817 self.assertInBuildFile( 818 'filegroup(\n' 819 f' name = "{bazel_mode.JDK_NAME}",\n' 820 ' srcs = glob([\n' 821 f' "{bazel_mode.JDK_NAME}_files/**",\n', 822 package=f'{bazel_mode.JDK_PACKAGE_NAME}' 823 ) 824 825 def test_not_generate_jdk_target_when_no_jdk_path(self): 826 gen = self.create_workspace_generator(jdk_path=None) 827 828 gen.generate() 829 830 self.assertFileNotInWorkspace( 831 'BUILD.bazel', package=f'{bazel_mode.JDK_PACKAGE_NAME}') 832 833 def test_create_symlinks_to_jdk(self): 834 jdk_path = Path('jdk_path') 835 gen = self.create_workspace_generator(jdk_path=jdk_path) 836 837 gen.generate() 838 839 self.assertSymlinkTo( 840 self.workspace_out_path.joinpath( 841 f'{bazel_mode.JDK_PACKAGE_NAME}/{bazel_mode.JDK_NAME}_files'), 842 self.resource_manager.get_src_file_path(f'{jdk_path}')) 843 844 def test_generate_android_all_target(self): 845 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 846 847 gen.generate() 848 849 self.assertInBuildFile( 850 'filegroup(\n' 851 ' name = "android-all",\n' 852 ' srcs = glob([\n' 853 ' "android-all_files/**",\n', 854 package='android-all' 855 ) 856 857 def test_not_generate_android_all_target_when_no_jdk_path(self): 858 gen = self.create_workspace_generator(jdk_path=None) 859 860 gen.generate() 861 862 self.assertFileNotInWorkspace( 863 'BUILD.bazel', package='android-all') 864 865 def test_create_symlinks_to_android_all(self): 866 module_name = 'android-all' 867 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 868 869 gen.generate() 870 871 self.assertSymlinkTo( 872 self.workspace_out_path.joinpath( 873 f'{module_name}/{module_name}_files'), 874 self.host_out_path.joinpath(f'testcases/{module_name}')) 875 876 def test_regenerate_workspace_when_robolectric_template_changed(self): 877 workspace_generator = self.create_workspace_generator() 878 workspace_generator.generate() 879 workspace_stat = workspace_generator.workspace_out_path.stat() 880 881 with open(self.robolectric_template_path, 'a', encoding='utf8') as f: 882 f.write(' ') 883 workspace_generator = self.create_workspace_generator() 884 workspace_generator.generate() 885 886 new_workspace_stat = workspace_generator.workspace_out_path.stat() 887 self.assertNotEqual(workspace_stat, new_workspace_stat) 888 889 def test_not_regenerate_workspace_when_robolectric_template_touched(self): 890 workspace_generator = self.create_workspace_generator() 891 workspace_generator.generate() 892 workspace_stat = workspace_generator.workspace_out_path.stat() 893 894 self.robolectric_template_path.touch() 895 workspace_generator = self.create_workspace_generator() 896 workspace_generator.generate() 897 898 new_workspace_stat = workspace_generator.workspace_out_path.stat() 899 self.assertEqual(workspace_stat, new_workspace_stat) 900 901 902class ModulePrebuiltTargetGenerationTest(GenerationTestFixture): 903 """Tests for module prebuilt target generation.""" 904 905 def test_generate_prebuilt_import(self): 906 mod_info = self.create_module_info(modules=[ 907 supported_test_module(), 908 ]) 909 910 self.run_generator(mod_info) 911 912 self.assertInBuildFile( 913 'load("//bazel/rules:soong_prebuilt.bzl", "soong_prebuilt")\n' 914 ) 915 916 def test_generate_prebuilt_target_for_multi_config_test_module(self): 917 mod_info = self.create_module_info(modules=[ 918 multi_config(supported_test_module(name='libhello')), 919 ]) 920 921 self.run_generator(mod_info) 922 923 self.assertInBuildFile( 924 'soong_prebuilt(\n' 925 ' name = "libhello",\n' 926 ' module_name = "libhello",\n' 927 ' files = select({\n' 928 ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' 929 ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' 930 ' }),\n' 931 ' suites = [\n' 932 ' "host-unit-tests",\n' 933 ' ],\n' 934 ')\n' 935 ) 936 937 def test_create_symlinks_to_testcases_for_multi_config_test_module(self): 938 module_name = 'hello_world_test' 939 mod_info = self.create_module_info(modules=[ 940 multi_config(supported_test_module(name=module_name)) 941 ]) 942 module_out_path = self.workspace_out_path.joinpath(module_name) 943 944 self.run_generator(mod_info) 945 946 self.assertSymlinkTo( 947 module_out_path.joinpath(f'host/testcases/{module_name}'), 948 self.host_out_path.joinpath(f'testcases/{module_name}')) 949 self.assertSymlinkTo( 950 module_out_path.joinpath(f'device/testcases/{module_name}'), 951 self.product_out_path.joinpath(f'testcases/{module_name}')) 952 953 def test_generate_files_for_host_only_test_module(self): 954 mod_info = self.create_module_info(modules=[ 955 host_only_config(supported_test_module(name='test1')), 956 ]) 957 958 self.run_generator(mod_info) 959 960 self.assertInBuildFile( 961 ' files = select({\n' 962 ' "//bazel/rules:host": glob(["test1/host/**/*"]),\n' 963 ' }),\n' 964 ) 965 966 def test_generate_files_for_device_only_test_module(self): 967 mod_info = self.create_module_info(modules=[ 968 device_only_config(supported_test_module(name='test1')), 969 ]) 970 971 self.run_generator(mod_info) 972 973 self.assertInBuildFile( 974 ' files = select({\n' 975 ' "//bazel/rules:device": glob(["test1/device/**/*"]),\n' 976 ' }),\n' 977 ) 978 979 def test_not_create_device_symlinks_for_host_only_test_module(self): 980 mod_info = self.create_module_info(modules=[ 981 host_only_config(supported_test_module(name='test1')), 982 ]) 983 984 self.run_generator(mod_info) 985 986 self.assertFileNotInWorkspace('test1/device') 987 988 def test_not_create_host_symlinks_for_device_test_module(self): 989 mod_info = self.create_module_info(modules=[ 990 device_only_config(supported_test_module(name='test1')), 991 ]) 992 993 self.run_generator(mod_info) 994 995 self.assertFileNotInWorkspace('test1/host') 996 997 998class ModuleSharedLibGenerationTest(GenerationTestFixture): 999 """Tests for module shared libs target generation.""" 1000 1001 def test_not_generate_runtime_deps_when_all_configs_incompatible(self): 1002 mod_info = self.create_module_info(modules=[ 1003 host_only_config(supported_test_module(shared_libs=['libdevice'])), 1004 device_only_config(module(name='libdevice')), 1005 ]) 1006 1007 self.run_generator(mod_info) 1008 1009 self.assertNotInBuildFile('runtime_deps') 1010 1011 def test_generate_runtime_deps_when_configs_compatible(self): 1012 mod_info = self.create_module_info(modules=[ 1013 multi_config(supported_test_module(shared_libs=['libmulti'])), 1014 multi_config_module(name='libmulti'), 1015 ]) 1016 1017 self.run_generator(mod_info) 1018 1019 self.assertInBuildFile( 1020 ' runtime_deps = select({\n' 1021 ' "//bazel/rules:device": [\n' 1022 ' "//:libmulti",\n' 1023 ' ],\n' 1024 ' "//bazel/rules:host": [\n' 1025 ' "//:libmulti",\n' 1026 ' ],\n' 1027 ' }),\n' 1028 ) 1029 1030 def test_generate_runtime_deps_when_configs_partially_compatible(self): 1031 mod_info = self.create_module_info(modules=[ 1032 multi_config(supported_test_module(shared_libs=[ 1033 'libhost', 1034 ])), 1035 host_module(name='libhost'), 1036 ]) 1037 1038 self.run_generator(mod_info) 1039 1040 self.assertInBuildFile( 1041 ' runtime_deps = select({\n' 1042 ' "//bazel/rules:device": [\n' 1043 ' ],\n' 1044 ' "//bazel/rules:host": [\n' 1045 ' "//:libhost",\n' 1046 ' ],\n' 1047 ' }),\n' 1048 ) 1049 1050 def test_generate_runtime_deps_with_mixed_compatibility(self): 1051 mod_info = self.create_module_info(modules=[ 1052 multi_config(supported_test_module(shared_libs=[ 1053 'libhost', 1054 'libdevice', 1055 'libmulti' 1056 ])), 1057 host_module(name='libhost'), 1058 device_module(name='libdevice'), 1059 multi_config_module(name='libmulti'), 1060 ]) 1061 1062 self.run_generator(mod_info) 1063 1064 self.assertInBuildFile( 1065 ' runtime_deps = select({\n' 1066 ' "//bazel/rules:device": [\n' 1067 ' "//:libdevice",\n' 1068 ' "//:libmulti",\n' 1069 ' ],\n' 1070 ' "//bazel/rules:host": [\n' 1071 ' "//:libhost",\n' 1072 ' "//:libmulti",\n' 1073 ' ],\n' 1074 ' }),\n' 1075 ) 1076 1077 def test_generate_runtime_deps_recursively(self): 1078 mod_info = self.create_module_info(modules=[ 1079 multi_config(supported_test_module(shared_libs=[ 1080 'libdirect', 1081 ])), 1082 multi_config_module(name='libdirect', shared_libs=[ 1083 'libtransitive', 1084 ]), 1085 multi_config_module(name='libtransitive'), 1086 ]) 1087 1088 self.run_generator(mod_info) 1089 1090 self.assertTargetInWorkspace('libtransitive') 1091 1092 def test_generate_shared_runtime_deps_once(self): 1093 mod_info = self.create_module_info(modules=[ 1094 multi_config(supported_test_module(shared_libs=[ 1095 'libleft', 1096 'libright', 1097 ])), 1098 multi_config_module(name='libleft', shared_libs=[ 1099 'libshared', 1100 ]), 1101 multi_config_module(name='libright', shared_libs=[ 1102 'libshared', 1103 ]), 1104 multi_config_module(name='libshared'), 1105 ]) 1106 1107 self.run_generator(mod_info) 1108 1109 self.assertTargetInWorkspace('libshared') 1110 1111 def test_generate_runtime_deps_in_order(self): 1112 mod_info = self.create_module_info(modules=[ 1113 supported_test_module(shared_libs=['libhello2', 'libhello1']), 1114 host_module(name='libhello1'), 1115 host_module(name='libhello2'), 1116 ]) 1117 1118 self.run_generator(mod_info) 1119 1120 self.assertInBuildFile( 1121 ' "//:libhello1",\n' 1122 ' "//:libhello2",\n' 1123 ) 1124 1125 def test_generate_target_for_shared_lib(self): 1126 mod_info = self.create_module_info(modules=[ 1127 supported_test_module(shared_libs=['libhello']), 1128 host_module(name='libhello'), 1129 ]) 1130 1131 self.run_generator(mod_info) 1132 1133 self.assertTargetInWorkspace('libhello') 1134 1135 def test_not_generate_for_missing_shared_lib_module(self): 1136 mod_info = self.create_module_info(modules=[ 1137 supported_test_module(shared_libs=['libhello']) 1138 ]) 1139 1140 self.run_generator(mod_info) 1141 1142 self.assertNotInBuildFile(' "//:libhello",\n') 1143 self.assertTargetNotInWorkspace('libhello') 1144 1145 def test_not_generate_when_shared_lib_uninstalled(self): 1146 mod_info = self.create_module_info(modules=[ 1147 supported_test_module(shared_libs=['libhello']), 1148 host_module(name='libhello', installed=[]), 1149 ]) 1150 1151 self.run_generator(mod_info) 1152 1153 self.assertNotInBuildFile(' "//:libhello",\n') 1154 self.assertTargetNotInWorkspace('libhello') 1155 1156 def test_not_generate_when_shared_lib_installed_path_unsupported(self): 1157 unsupported_install_path = 'out/other' 1158 mod_info = self.create_module_info(modules=[ 1159 supported_test_module(shared_libs=['libhello']), 1160 shared_lib(module('libhello', 1161 installed=[unsupported_install_path])), 1162 ]) 1163 1164 self.run_generator(mod_info) 1165 1166 self.assertNotInBuildFile('"//:libhello",\n') 1167 self.assertTargetNotInWorkspace('libhello') 1168 1169 def test_not_generate_when_shared_lib_install_path_ambiguous(self): 1170 ambiguous_install_path = 'out/f1' 1171 mod_info = self.create_module_info(modules=[ 1172 supported_test_module(shared_libs=['libhello']), 1173 module(name='libhello', installed=[ambiguous_install_path]), 1174 ]) 1175 1176 self.run_generator(mod_info) 1177 1178 self.assertNotInBuildFile('"//:libhello",\n') 1179 self.assertTargetNotInWorkspace('libhello') 1180 1181 def test_generate_target_for_rlib_dependency(self): 1182 mod_info = self.create_module_info(modules=[ 1183 multi_config(host_unit_suite(module( 1184 name='hello_world_test', 1185 dependencies=['libhost', 'libdevice']))), 1186 rlib(module(name='libhost', supported_variants=['HOST'])), 1187 rlib(module(name='libdevice', supported_variants=['DEVICE'])), 1188 ]) 1189 1190 self.run_generator(mod_info) 1191 1192 self.assertInBuildFile( 1193 'soong_uninstalled_prebuilt(\n' 1194 ' name = "libhost",\n' 1195 ' module_name = "libhost",\n' 1196 ')\n' 1197 ) 1198 self.assertInBuildFile( 1199 'soong_uninstalled_prebuilt(\n' 1200 ' name = "libdevice",\n' 1201 ' module_name = "libdevice",\n' 1202 ')\n' 1203 ) 1204 self.assertInBuildFile( 1205 ' runtime_deps = select({\n' 1206 ' "//bazel/rules:device": [\n' 1207 ' "//:libdevice",\n' 1208 ' ],\n' 1209 ' "//bazel/rules:host": [\n' 1210 ' "//:libhost",\n' 1211 ' ],\n' 1212 ' }),\n' 1213 ) 1214 1215 def test_generate_target_for_rlib_dylib_dependency(self): 1216 mod_info = self.create_module_info(modules=[ 1217 supported_test_module(dependencies=['libhello']), 1218 rlib(module(name='libhello', dependencies=['libworld'])), 1219 host_only_config(dylib(module(name='libworld'))) 1220 ]) 1221 1222 self.run_generator(mod_info) 1223 1224 self.assertTargetInWorkspace('libworld') 1225 1226 def test_generate_target_for_dylib_dependency(self): 1227 mod_info = self.create_module_info(modules=[ 1228 supported_test_module(dependencies=['libhello']), 1229 host_only_config(dylib(module(name='libhello'))) 1230 ]) 1231 1232 self.run_generator(mod_info) 1233 1234 self.assertInBuildFile( 1235 'soong_prebuilt(\n' 1236 ' name = "libhello",\n' 1237 ' module_name = "libhello",\n' 1238 ) 1239 1240 def test_generate_target_for_uninstalled_dylib_dependency(self): 1241 mod_info = self.create_module_info(modules=[ 1242 supported_test_module(dependencies=['libhello']), 1243 dylib(module(name='libhello', installed=[])) 1244 ]) 1245 1246 self.run_generator(mod_info) 1247 1248 self.assertInBuildFile( 1249 'soong_uninstalled_prebuilt(\n' 1250 ' name = "libhello",\n' 1251 ' module_name = "libhello",\n' 1252 ')\n' 1253 ) 1254 1255 def test_not_generate_target_for_non_runtime_dependency(self): 1256 mod_info = self.create_module_info(modules=[ 1257 supported_test_module(dependencies=['libhello']), 1258 host_module(name='libhello', classes=['NOT_SUPPORTED']) 1259 ]) 1260 1261 self.run_generator(mod_info) 1262 1263 self.assertNotInBuildFile('"//:libhello",\n') 1264 self.assertTargetNotInWorkspace('libhello') 1265 1266 1267 def test_generate_target_for_runtime_dependency(self): 1268 mod_info = self.create_module_info(modules=[ 1269 supported_test_module(runtime_dependencies=['libhello']), 1270 host_only_config( 1271 module(name='libhello', classes=['SHARED_LIBRARIES'])) 1272 ]) 1273 1274 self.run_generator(mod_info) 1275 1276 self.assertInBuildFile( 1277 ' runtime_deps = select({\n' 1278 ' "//bazel/rules:host": [\n' 1279 ' "//:libhello",\n' 1280 ' ],\n' 1281 ' }),\n' 1282 ) 1283 1284class SharedLibPrebuiltTargetGenerationTest(GenerationTestFixture): 1285 """Tests for runtime dependency module prebuilt target generation.""" 1286 1287 def test_create_multi_config_target_symlinks(self): 1288 host_file1 = self.host_out_path.joinpath('a/b/f1') 1289 host_file2 = self.host_out_path.joinpath('a/c/f2') 1290 device_file1 = self.product_out_path.joinpath('a/b/f1') 1291 mod_info = self.create_module_info(modules=[ 1292 supported_test_module(shared_libs=['libhello']), 1293 multi_config_module( 1294 name='libhello', 1295 installed=[str(host_file1), str(host_file2), str(device_file1)] 1296 ) 1297 ]) 1298 package_path = self.workspace_out_path 1299 1300 self.run_generator(mod_info) 1301 1302 self.assertSymlinkTo( 1303 package_path.joinpath('libhello/host/a/b/f1'), host_file1) 1304 self.assertSymlinkTo( 1305 package_path.joinpath('libhello/host/a/c/f2'), host_file2) 1306 self.assertSymlinkTo( 1307 package_path.joinpath('libhello/device/a/b/f1'), device_file1) 1308 1309 def test_create_symlinks_to_installed_path_for_non_tf_testable_deps(self): 1310 host_file = self.host_out_path.joinpath('a/b/f1') 1311 mod_info = self.create_module_info(modules=[ 1312 supported_test_module(shared_libs=['libhello']), 1313 host_module( 1314 name='libhello', 1315 installed=[str(host_file)], 1316 ) 1317 ]) 1318 package_path = self.workspace_out_path 1319 1320 self.run_generator(mod_info) 1321 1322 self.assertSymlinkTo( 1323 package_path.joinpath('libhello/host/a/b/f1'), host_file) 1324 1325 def test_create_symlinks_to_installed_path_for_lib_with_test_config(self): 1326 host_file = self.host_out_path.joinpath('a/b/f1') 1327 mod_info = self.create_module_info(modules=[ 1328 supported_test_module(shared_libs=['libhello']), 1329 host_module( 1330 name='libhello', 1331 installed=[str(host_file)], 1332 path='src/lib' 1333 ) 1334 ]) 1335 self.fs.create_file(Path('src/lib/AndroidTest.xml'), contents='') 1336 package_path = self.workspace_out_path 1337 1338 self.run_generator(mod_info) 1339 1340 self.assertSymlinkTo( 1341 package_path.joinpath('src/lib/libhello/host/a/b/f1'), host_file) 1342 1343 def test_generate_for_host_only_shared_lib_dependency(self): 1344 mod_info = self.create_module_info(modules=[ 1345 supported_test_module(shared_libs=['libhello']), 1346 host_module(name='libhello'), 1347 ]) 1348 1349 self.run_generator(mod_info) 1350 1351 self.assertInBuildFile( 1352 ' files = select({\n' 1353 ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' 1354 ' }),\n' 1355 ) 1356 self.assertFileNotInWorkspace('libhello/device') 1357 1358 def test_generate_for_device_only_shared_lib_dependency(self): 1359 mod_info = self.create_module_info(modules=[ 1360 supported_test_module(shared_libs=['libhello']), 1361 device_module(name='libhello'), 1362 ]) 1363 1364 self.run_generator(mod_info) 1365 1366 self.assertInBuildFile( 1367 ' files = select({\n' 1368 ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' 1369 ' }),\n' 1370 ) 1371 self.assertFileNotInWorkspace('libhello/host') 1372 1373 1374class DataDependenciesGenerationTest(GenerationTestFixture): 1375 """Tests for module data dependencies target generation.""" 1376 1377 def test_generate_target_for_data_dependency(self): 1378 mod_info = self.create_module_info(modules=[ 1379 supported_test_module(data_dependencies=['libdata']), 1380 host_module(name='libdata'), 1381 ]) 1382 1383 self.run_generator(mod_info) 1384 1385 self.assertInBuildFile( 1386 ' data = select({\n' 1387 ' "//bazel/rules:host": [\n' 1388 ' "//:libdata",\n' 1389 ' ],\n' 1390 ' }),\n' 1391 ) 1392 self.assertTargetInWorkspace('libdata') 1393 1394 def test_not_generate_target_for_data_file(self): 1395 # Data files are included in "data", but not in "data_dependencies". 1396 mod_info = self.create_module_info(modules=[ 1397 supported_test_module(data=['libdata']), 1398 host_module(name='libdata'), 1399 ]) 1400 1401 self.run_generator(mod_info) 1402 1403 self.assertTargetNotInWorkspace('libdata') 1404 1405 1406def create_empty_module_info(): 1407 with fake_filesystem_unittest.Patcher() as patcher: 1408 # pylint: disable=protected-access 1409 fake_temp_file_name = next(tempfile._get_candidate_names()) 1410 patcher.fs.create_file(fake_temp_file_name, contents='{}') 1411 return module_info.ModuleInfo(module_file=fake_temp_file_name) 1412 1413 1414def create_module_info(modules=None): 1415 mod_info = create_empty_module_info() 1416 modules = modules or [] 1417 1418 for m in modules: 1419 mod_info.name_to_module_info[m['module_name']] = m 1420 1421 return mod_info 1422 1423 1424def host_unit_test_module(**kwargs): 1425 return host_unit_suite(host_test_module(**kwargs)) 1426 1427 1428# We use the below alias in situations where the actual type is irrelevant to 1429# the test as long as it is supported in Bazel mode. 1430supported_test_module = host_unit_test_module 1431 1432 1433def host_test_module(**kwargs): 1434 kwargs.setdefault('name', 'hello_world_test') 1435 return host_only_config(test_module(**kwargs)) 1436 1437 1438def device_test_module(**kwargs): 1439 kwargs.setdefault('name', 'hello_world_test') 1440 return device_only_config(test_module(**kwargs)) 1441 1442 1443def robolectric_test_module(**kwargs): 1444 kwargs.setdefault('name', 'hello_world_test') 1445 return host_only_config(robolectric(test_module(**kwargs))) 1446 1447 1448def host_module(**kwargs): 1449 m = module(**kwargs) 1450 1451 if 'installed' in kwargs: 1452 return m 1453 1454 return host_only_config(m) 1455 1456 1457def device_module(**kwargs): 1458 m = module(**kwargs) 1459 1460 if 'installed' in kwargs: 1461 return m 1462 1463 return device_only_config(m) 1464 1465 1466def multi_config_module(**kwargs): 1467 m = module(**kwargs) 1468 1469 if 'installed' in kwargs: 1470 return m 1471 1472 return multi_config(m) 1473 1474 1475def test_module(**kwargs): 1476 kwargs.setdefault('name', 'hello_world_test') 1477 return test(module(**kwargs)) 1478 1479 1480# TODO(b/274822450): Using a builder pattern to reduce the number of parameters 1481# instead of disabling the warning. 1482# pylint: disable=too-many-arguments 1483# pylint: disable=too-many-locals 1484def module( 1485 name=None, 1486 path=None, 1487 installed=None, 1488 classes=None, 1489 auto_test_config=None, 1490 shared_libs=None, 1491 dependencies=None, 1492 runtime_dependencies=None, 1493 data=None, 1494 data_dependencies=None, 1495 compatibility_suites=None, 1496 host_dependencies=None, 1497 target_dependencies=None, 1498 test_options_tags=None, 1499 supported_variants=None, 1500): 1501 name = name or 'libhello' 1502 1503 m = {} 1504 1505 m['module_name'] = name 1506 m['class'] = classes or [''] 1507 m['path'] = [path or ''] 1508 m['installed'] = installed or [] 1509 m['is_unit_test'] = 'false' 1510 m['auto_test_config'] = auto_test_config or [] 1511 m['shared_libs'] = shared_libs or [] 1512 m['runtime_dependencies'] = runtime_dependencies or [] 1513 m['dependencies'] = dependencies or [] 1514 m['data'] = data or [] 1515 m['data_dependencies'] = data_dependencies or [] 1516 m['compatibility_suites'] = compatibility_suites or [] 1517 m['host_dependencies'] = host_dependencies or [] 1518 m['target_dependencies'] = target_dependencies or [] 1519 m['test_options_tags'] = test_options_tags or [] 1520 m['supported_variants'] = supported_variants or [] 1521 return m 1522 1523 1524def test(info): 1525 info['auto_test_config'] = ['true'] 1526 return info 1527 1528 1529def shared_lib(info): 1530 info['class'] = ['SHARED_LIBRARIES'] 1531 return info 1532 1533 1534def rlib(info): 1535 info['class'] = ['RLIB_LIBRARIES'] 1536 info['installed'] = [] 1537 return info 1538 1539 1540def dylib(info): 1541 info['class'] = ['DYLIB_LIBRARIES'] 1542 return info 1543 1544 1545def robolectric(info): 1546 info['class'] = ['ROBOLECTRIC'] 1547 return info 1548 1549 1550def host_unit_suite(info): 1551 info = test(info) 1552 info.setdefault('compatibility_suites', []).append('host-unit-tests') 1553 return info 1554 1555 1556def multi_config(info): 1557 name = info.get('module_name', 'lib') 1558 info['installed'] = [ 1559 f'out/host/linux-x86/{name}/{name}.jar', 1560 f'out/product/vsoc_x86/{name}/{name}.apk', 1561 ] 1562 info['supported_variants'] = [ 1563 'DEVICE', 1564 'HOST', 1565 ] 1566 return info 1567 1568 1569def host_only_config(info): 1570 name = info.get('module_name', 'lib') 1571 info['installed'] = [ 1572 f'out/host/linux-x86/{name}/{name}.jar', 1573 ] 1574 info['supported_variants'] = [ 1575 'HOST', 1576 ] 1577 return info 1578 1579 1580def device_only_config(info): 1581 name = info.get('module_name', 'lib') 1582 info['installed'] = [ 1583 f'out/product/vsoc_x86/{name}/{name}.jar', 1584 ] 1585 info['supported_variants'] = [ 1586 'DEVICE', 1587 ] 1588 return info 1589 1590 1591class PackageTest(fake_filesystem_unittest.TestCase): 1592 """Tests for Package.""" 1593 1594 class FakeTarget(bazel_mode.Target): 1595 """Fake target used for tests.""" 1596 1597 def __init__(self, name, imports=None): 1598 self._name = name 1599 self._imports = imports or set() 1600 1601 def name(self): 1602 return self._name 1603 1604 def required_imports(self): 1605 return self._imports 1606 1607 def write_to_build_file(self, f): 1608 f.write(f'{self._name}\n') 1609 1610 1611 def setUp(self): 1612 self.setUpPyfakefs() 1613 self.workspace_out_path = Path('/workspace_out_path') 1614 self.workspace_out_path.mkdir() 1615 1616 def test_raise_when_adding_existing_target(self): 1617 target_name = '<fake_target>' 1618 package = bazel_mode.Package('p') 1619 package.add_target(self.FakeTarget(target_name)) 1620 1621 with self.assertRaises(Exception) as context: 1622 package.add_target(self.FakeTarget(target_name)) 1623 1624 self.assertIn(target_name, str(context.exception)) 1625 1626 def test_write_build_file_in_package_dir(self): 1627 package_path = 'abc/def' 1628 package = bazel_mode.Package(package_path) 1629 expected_path = self.workspace_out_path.joinpath( 1630 package_path, 'BUILD.bazel') 1631 1632 package.generate(self.workspace_out_path) 1633 1634 self.assertTrue(expected_path.exists()) 1635 1636 def test_write_load_statements_in_sorted_order(self): 1637 package = bazel_mode.Package('p') 1638 target1 = self.FakeTarget('target1', imports={ 1639 bazel_mode.Import('z.bzl', 'symbol1'), 1640 }) 1641 target2 = self.FakeTarget('target2', imports={ 1642 bazel_mode.Import('a.bzl', 'symbol2'), 1643 }) 1644 package.add_target(target1) 1645 package.add_target(target2) 1646 1647 package.generate(self.workspace_out_path) 1648 1649 self.assertIn('load("a.bzl", "symbol2")\nload("z.bzl", "symbol1")\n\n', 1650 self.package_build_file_text(package)) 1651 1652 def test_write_load_statements_with_symbols_grouped_by_bzl(self): 1653 package = bazel_mode.Package('p') 1654 target1 = self.FakeTarget('target1', imports={ 1655 bazel_mode.Import('a.bzl', 'symbol1'), 1656 bazel_mode.Import('a.bzl', 'symbol3'), 1657 }) 1658 target2 = self.FakeTarget('target2', imports={ 1659 bazel_mode.Import('a.bzl', 'symbol2'), 1660 }) 1661 package.add_target(target1) 1662 package.add_target(target2) 1663 1664 package.generate(self.workspace_out_path) 1665 1666 self.assertIn('load("a.bzl", "symbol1", "symbol2", "symbol3")\n\n', 1667 self.package_build_file_text(package)) 1668 1669 def test_write_targets_in_add_order(self): 1670 package = bazel_mode.Package('p') 1671 target1 = self.FakeTarget('target1') 1672 target2 = self.FakeTarget('target2') 1673 package.add_target(target2) # Added out of order. 1674 package.add_target(target1) 1675 1676 package.generate(self.workspace_out_path) 1677 1678 self.assertIn('target2\n\ntarget1\n', 1679 self.package_build_file_text(package)) 1680 1681 def test_generate_parent_package_when_nested_exists(self): 1682 parent_path = Path('parent') 1683 parent = bazel_mode.Package(parent_path.name) 1684 nested = bazel_mode.Package(parent_path.joinpath('nested')) 1685 nested.generate(self.workspace_out_path) 1686 1687 parent.generate(self.workspace_out_path) 1688 1689 self.assertTrue(self.workspace_out_path.joinpath(parent_path).is_dir()) 1690 1691 def package_build_file_text(self, package): 1692 return self.workspace_out_path.joinpath( 1693 package.path, 'BUILD.bazel').read_text(encoding='utf8') 1694 1695 1696class DecorateFinderMethodTest(GenerationTestFixture): 1697 """Tests for _decorate_find_method().""" 1698 1699 def test_host_unit_test_with_host_arg_runner_is_overridden(self): 1700 def original_find_method(obj, test_id): 1701 return self.create_single_test_infos( 1702 obj, test_id, test_name=MODULE_NAME, 1703 runner=ATEST_TF_RUNNER) 1704 mod_info = self.create_module_info(modules=[ 1705 host_unit_test_module(name=MODULE_NAME) 1706 ]) 1707 original_finder = self.create_finder(mod_info, original_find_method) 1708 new_finder = bazel_mode.create_new_finder( 1709 mod_info, original_finder, host=True) 1710 1711 test_infos = new_finder.find_method( 1712 new_finder.test_finder_instance, MODULE_NAME) 1713 1714 self.assertEqual(len(test_infos), 1) 1715 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1716 1717 def test_host_unit_test_without_host_arg_runner_is_overridden(self): 1718 def original_find_method(obj, test_id): 1719 return self.create_single_test_infos( 1720 obj, test_id, test_name=MODULE_NAME, 1721 runner=ATEST_TF_RUNNER) 1722 mod_info = self.create_module_info(modules=[ 1723 host_unit_test_module(name=MODULE_NAME) 1724 ]) 1725 original_finder = self.create_finder(mod_info, original_find_method) 1726 new_finder = bazel_mode.create_new_finder( 1727 mod_info, original_finder, host=False) 1728 1729 test_infos = new_finder.find_method( 1730 new_finder.test_finder_instance, MODULE_NAME) 1731 1732 self.assertEqual(len(test_infos), 1) 1733 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1734 1735 def test_device_test_with_host_arg_runner_is_preserved(self): 1736 def original_find_method(obj, test_id): 1737 return self.create_single_test_infos( 1738 obj, test_id, test_name=MODULE_NAME, 1739 runner=ATEST_TF_RUNNER) 1740 mod_info = self.create_module_info(modules=[ 1741 device_test_module(name=MODULE_NAME) 1742 ]) 1743 original_finder = self.create_finder(mod_info, original_find_method) 1744 new_finder = bazel_mode.create_new_finder( 1745 mod_info, 1746 original_finder, 1747 host=True, 1748 enabled_features=[ 1749 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST 1750 ] 1751 ) 1752 1753 test_infos = new_finder.find_method( 1754 new_finder.test_finder_instance, MODULE_NAME) 1755 1756 self.assertEqual(len(test_infos), 1) 1757 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 1758 1759 def test_device_test_without_host_arg_runner_is_overridden(self): 1760 def original_find_method(obj, test_id): 1761 return self.create_single_test_infos( 1762 obj, test_id, test_name=MODULE_NAME, 1763 runner=ATEST_TF_RUNNER) 1764 mod_info = self.create_module_info(modules=[ 1765 device_test_module(name=MODULE_NAME) 1766 ]) 1767 original_finder = self.create_finder(mod_info, original_find_method) 1768 new_finder = bazel_mode.create_new_finder( 1769 mod_info, 1770 original_finder, 1771 host=False, 1772 enabled_features=[ 1773 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST 1774 ] 1775 ) 1776 1777 test_infos = new_finder.find_method( 1778 new_finder.test_finder_instance, MODULE_NAME) 1779 1780 self.assertEqual(len(test_infos), 1) 1781 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1782 1783 def test_multi_config_test_with_host_arg_runner_is_overridden(self): 1784 def original_find_method(obj, test_id): 1785 return self.create_single_test_infos( 1786 obj, test_id, test_name=MODULE_NAME, 1787 runner=ATEST_TF_RUNNER) 1788 mod_info = self.create_module_info(modules=[ 1789 multi_config(supported_test_module(name=MODULE_NAME)) 1790 ]) 1791 original_finder = self.create_finder(mod_info, original_find_method) 1792 new_finder = bazel_mode.create_new_finder( 1793 mod_info, 1794 original_finder, 1795 host=True, 1796 enabled_features=[ 1797 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST 1798 ] 1799 ) 1800 1801 test_infos = new_finder.find_method( 1802 new_finder.test_finder_instance, MODULE_NAME) 1803 1804 self.assertEqual(len(test_infos), 1) 1805 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1806 1807 def test_multi_config_test_without_host_arg_runner_is_overridden(self): 1808 def original_find_method(obj, test_id): 1809 return self.create_single_test_infos( 1810 obj, test_id, test_name=MODULE_NAME, 1811 runner=ATEST_TF_RUNNER) 1812 mod_info = self.create_module_info(modules=[ 1813 multi_config(supported_test_module(name=MODULE_NAME)) 1814 ]) 1815 original_finder = self.create_finder(mod_info, original_find_method) 1816 new_finder = bazel_mode.create_new_finder( 1817 mod_info, 1818 original_finder, 1819 host=False, 1820 enabled_features=[ 1821 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST 1822 ] 1823 ) 1824 1825 test_infos = new_finder.find_method( 1826 new_finder.test_finder_instance, MODULE_NAME) 1827 1828 self.assertEqual(len(test_infos), 1) 1829 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1830 1831 def test_host_non_unit_test_with_host_arg_runner_is_overridden(self): 1832 def original_find_method(obj, test_id): 1833 return self.create_single_test_infos( 1834 obj, test_id, test_name=MODULE_NAME, 1835 runner=ATEST_TF_RUNNER) 1836 mod_info = self.create_module_info(modules=[ 1837 host_test_module(name=MODULE_NAME) 1838 ]) 1839 original_finder = self.create_finder(mod_info, original_find_method) 1840 new_finder = bazel_mode.create_new_finder( 1841 mod_info, 1842 original_finder, 1843 host=True, 1844 enabled_features=[ 1845 bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST 1846 ] 1847 ) 1848 1849 test_infos = new_finder.find_method( 1850 new_finder.test_finder_instance, MODULE_NAME) 1851 1852 self.assertEqual(len(test_infos), 1) 1853 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 1854 1855 def test_disable_device_driven_test_feature_runner_is_preserved(self): 1856 def original_find_method(obj, test_id): 1857 return self.create_single_test_infos( 1858 obj, test_id, test_name=MODULE_NAME, 1859 runner=ATEST_TF_RUNNER) 1860 mod_info = self.create_module_info(modules=[ 1861 device_test_module(name=MODULE_NAME) 1862 ]) 1863 original_finder = self.create_finder(mod_info, original_find_method) 1864 new_finder = bazel_mode.create_new_finder( 1865 mod_info, original_finder, host=False) 1866 1867 test_infos = new_finder.find_method( 1868 new_finder.test_finder_instance, MODULE_NAME) 1869 1870 self.assertEqual(len(test_infos), 1) 1871 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 1872 1873 def test_disable_host_driven_test_feature_runner_is_preserved(self): 1874 def original_find_method(obj, test_id): 1875 return self.create_single_test_infos( 1876 obj, test_id, test_name=MODULE_NAME, 1877 runner=ATEST_TF_RUNNER) 1878 mod_info = self.create_module_info(modules=[ 1879 host_test_module(name=MODULE_NAME) 1880 ]) 1881 original_finder = self.create_finder(mod_info, original_find_method) 1882 new_finder = bazel_mode.create_new_finder( 1883 mod_info, original_finder, host=True) 1884 1885 test_infos = new_finder.find_method( 1886 new_finder.test_finder_instance, MODULE_NAME) 1887 1888 self.assertEqual(len(test_infos), 1) 1889 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 1890 1891 # pylint: disable=unused-argument 1892 def create_single_test_infos(self, obj, test_id, test_name=MODULE_NAME, 1893 runner=ATEST_TF_RUNNER): 1894 """Create list of test_info.TestInfo.""" 1895 return [test_info.TestInfo(test_name, runner, MODULE_BUILD_TARGETS)] 1896 1897 def create_finder(self, mod_info, find_method): 1898 return test_finder_base.Finder( 1899 example_finder.ExampleFinder(mod_info), 1900 find_method, 'FINDER_NAME') 1901 1902class BazelTestRunnerTest(unittest.TestCase): 1903 """Tests for BazelTestRunner.""" 1904 1905 def test_return_empty_build_reqs_when_no_test_infos(self): 1906 run_command = self.mock_run_command(side_effect=Exception('')) 1907 runner = self.create_bazel_test_runner( 1908 modules=[ 1909 supported_test_module(name='test1', path='path1'), 1910 ], 1911 run_command=run_command, 1912 ) 1913 1914 reqs = runner.get_test_runner_build_reqs([]) 1915 1916 self.assertFalse(reqs) 1917 1918 def test_query_bazel_test_targets_deps_with_host_arg(self): 1919 query_file_contents = StringIO() 1920 def get_query_file_content(args: List[str], _) -> str: 1921 query_file_contents.write(_get_query_file_content(args)) 1922 return '' 1923 1924 runner = self.create_bazel_test_runner( 1925 modules=[ 1926 multi_config(host_unit_test_module(name='test1', path='path1')), 1927 multi_config(host_unit_test_module(name='test2', path='path2')), 1928 multi_config(test_module(name='test3', path='path3')), 1929 ], 1930 run_command=get_query_file_content, 1931 host=True, 1932 ) 1933 1934 runner.get_test_runner_build_reqs([ 1935 test_info_of('test2'), 1936 test_info_of('test1'), # Intentionally out of order. 1937 test_info_of('test3'), 1938 ]) 1939 1940 self.assertEqual( 1941 'deps(tests(//path1:test1_host + ' 1942 '//path2:test2_host + ' 1943 '//path3:test3_host))', 1944 query_file_contents.getvalue()) 1945 1946 def test_query_bazel_test_targets_deps_without_host_arg(self): 1947 query_file_contents = StringIO() 1948 def get_query_file_content(args: List[str], _) -> str: 1949 query_file_contents.write(_get_query_file_content(args)) 1950 return '' 1951 1952 runner = self.create_bazel_test_runner( 1953 modules=[ 1954 multi_config(host_unit_test_module(name='test1', path='path1')), 1955 host_unit_test_module(name='test2', path='path2'), 1956 multi_config(test_module(name='test3', path='path3')), 1957 ], 1958 run_command=get_query_file_content, 1959 ) 1960 1961 runner.get_test_runner_build_reqs([ 1962 test_info_of('test2'), 1963 test_info_of('test1'), 1964 test_info_of('test3'), 1965 ]) 1966 1967 self.assertEqual( 1968 'deps(tests(//path1:test1_device + ' 1969 '//path2:test2_host + ' 1970 '//path3:test3_device))', 1971 query_file_contents.getvalue()) 1972 1973 def test_trim_whitespace_in_bazel_query_output(self): 1974 run_command = self.mock_run_command( 1975 return_value='\n'.join([' test1:host ', 'test2:device ', ' '])) 1976 runner = self.create_bazel_test_runner( 1977 modules=[ 1978 supported_test_module(name='test1', path='path1'), 1979 ], 1980 run_command=run_command, 1981 ) 1982 1983 reqs = runner.get_test_runner_build_reqs([test_info_of('test1')]) 1984 1985 self.assertSetEqual({'test1-host', 'test2-target'}, reqs) 1986 1987 def test_build_variants_in_bazel_query_output(self): 1988 run_command = self.mock_run_command( 1989 return_value='\n'.join([ 1990 'test1:host', 1991 'test2:host', 'test2:device', 1992 'test3:device', 1993 'test4:host', 'test4:host', 1994 ])) 1995 runner = self.create_bazel_test_runner( 1996 modules=[ 1997 supported_test_module(name='test1', path='path1'), 1998 supported_test_module(name='test2', path='path2'), 1999 supported_test_module(name='test3', path='path3'), 2000 supported_test_module(name='test4', path='path4'), 2001 ], 2002 run_command = run_command, 2003 ) 2004 2005 reqs = runner.get_test_runner_build_reqs([ 2006 test_info_of('test1'), 2007 test_info_of('test2'), 2008 test_info_of('test3'), 2009 test_info_of('test4')]) 2010 2011 self.assertSetEqual( 2012 {'test1-host', 'test2', 'test3-target', 'test4-host'}, 2013 reqs) 2014 2015 def test_generate_single_run_command(self): 2016 test_infos = [test_info_of('test1')] 2017 runner = self.create_bazel_test_runner_for_tests(test_infos) 2018 2019 cmd = runner.generate_run_commands(test_infos, {}) 2020 2021 self.assertEqual(1, len(cmd)) 2022 2023 def test_generate_run_command_containing_targets_with_host_arg(self): 2024 test_infos = [test_info_of('test1'), 2025 test_info_of('test2'), 2026 test_info_of('test3')] 2027 runner = self.create_bazel_test_runner( 2028 [ 2029 multi_config(host_unit_test_module(name='test1', path='path')), 2030 multi_config(host_unit_test_module(name='test2', path='path')), 2031 multi_config(test_module(name='test3', path='path')), 2032 ], 2033 host=True 2034 ) 2035 2036 cmd = runner.generate_run_commands(test_infos, {}) 2037 2038 self.assertTokensIn( 2039 ['//path:test1_host', '//path:test2_host', '//path:test3_host'], 2040 cmd[0]) 2041 2042 def test_generate_run_command_containing_targets_without_host_arg(self): 2043 test_infos = [test_info_of('test1'), test_info_of('test2')] 2044 runner = self.create_bazel_test_runner( 2045 [ 2046 multi_config(host_unit_test_module(name='test1', path='path')), 2047 host_unit_test_module(name='test2', path='path'), 2048 ], 2049 ) 2050 2051 cmd = runner.generate_run_commands(test_infos, {}) 2052 2053 self.assertTokensIn(['//path:test1_device', '//path:test2_host'], 2054 cmd[0]) 2055 2056 def test_generate_run_command_with_multi_bazel_args(self): 2057 test_infos = [test_info_of('test1')] 2058 runner = self.create_bazel_test_runner_for_tests(test_infos) 2059 extra_args = {constants.BAZEL_ARG: [['--option1=value1'], 2060 ['--option2=value2']]} 2061 2062 cmd = runner.generate_run_commands(test_infos, extra_args) 2063 2064 self.assertTokensIn(['--option1=value1', '--option2=value2'], cmd[0]) 2065 2066 def test_generate_run_command_with_multi_custom_args(self): 2067 test_infos = [test_info_of('test1')] 2068 runner = self.create_bazel_test_runner_for_tests(test_infos) 2069 extra_args = {constants.CUSTOM_ARGS: ['-hello', '--world=value']} 2070 2071 cmd = runner.generate_run_commands(test_infos, extra_args) 2072 2073 self.assertTokensIn(['--test_arg=-hello', 2074 '--test_arg=--world=value'], cmd[0]) 2075 2076 def test_generate_run_command_with_custom_and_bazel_args(self): 2077 test_infos = [test_info_of('test1')] 2078 runner = self.create_bazel_test_runner_for_tests(test_infos) 2079 extra_args = {constants.CUSTOM_ARGS: ['-hello', '--world=value'], 2080 constants.BAZEL_ARG: [['--option1=value1']]} 2081 2082 cmd = runner.generate_run_commands(test_infos, extra_args) 2083 2084 self.assertTokensIn(['--test_arg=-hello', 2085 '--test_arg=--world=value', 2086 '--option1=value1'], cmd[0]) 2087 2088 def test_generate_run_command_with_tf_supported_all_abi_arg(self): 2089 test_infos = [test_info_of('test1')] 2090 runner = self.create_bazel_test_runner_for_tests(test_infos) 2091 extra_args = {constants.ALL_ABI: True} 2092 2093 cmd = runner.generate_run_commands(test_infos, extra_args) 2094 2095 self.assertTokensIn(['--test_arg=--all-abi'], cmd[0]) 2096 2097 def test_generate_run_command_with_iterations_args(self): 2098 test_infos = [test_info_of('test1')] 2099 runner = self.create_bazel_test_runner_for_tests(test_infos) 2100 extra_args = {constants.ITERATIONS: 2} 2101 2102 cmd = runner.generate_run_commands(test_infos, extra_args) 2103 2104 self.assertTokensIn(['--runs_per_test=2'], cmd[0]) 2105 self.assertNotIn('--test_arg=--retry-strategy', shlex.split(cmd[0])) 2106 2107 def test_generate_run_command_with_testinfo_filter(self): 2108 test_filter = test_filter_of('class1', ['method1']) 2109 test_infos = [test_info_of('test1', test_filters=[test_filter])] 2110 runner = self.create_bazel_test_runner_for_tests(test_infos) 2111 2112 cmd = runner.generate_run_commands(test_infos, {}) 2113 2114 self.assertTokensIn(['--test_arg=--atest-include-filter', 2115 '--test_arg=test1:class1#method1'], cmd[0]) 2116 2117 def test_generate_run_command_with_bes_publish_enabled(self): 2118 test_infos = [test_info_of('test1')] 2119 extra_args = { 2120 constants.BAZEL_MODE_FEATURES: [ 2121 bazel_mode.Features.EXPERIMENTAL_BES_PUBLISH 2122 ] 2123 } 2124 build_metadata = bazel_mode.BuildMetadata( 2125 'master', 'aosp_cf_x86_64_phone-userdebug') 2126 env = { 2127 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2128 'ATEST_BAZEL_BES_PUBLISH_CONFIG': 'bes_publish' 2129 } 2130 runner = self.create_bazel_test_runner_for_tests( 2131 test_infos, build_metadata=build_metadata, env=env) 2132 2133 cmd = runner.generate_run_commands( 2134 test_infos, 2135 extra_args, 2136 ) 2137 2138 self.assertTokensIn([ 2139 '--bazelrc=/dir/atest.bazelrc', 2140 '--config=bes_publish', 2141 '--build_metadata=ab_branch=master', 2142 '--build_metadata=ab_target=aosp_cf_x86_64_phone-userdebug' 2143 ], cmd[0]) 2144 2145 def test_generate_run_command_with_remote_enabled(self): 2146 test_infos = [test_info_of('test1')] 2147 extra_args = { 2148 constants.BAZEL_MODE_FEATURES: [ 2149 bazel_mode.Features.EXPERIMENTAL_REMOTE 2150 ] 2151 } 2152 env = { 2153 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2154 'ATEST_BAZEL_REMOTE_CONFIG': 'remote' 2155 } 2156 runner = self.create_bazel_test_runner_for_tests( 2157 test_infos, env=env) 2158 2159 cmd = runner.generate_run_commands( 2160 test_infos, 2161 extra_args, 2162 ) 2163 2164 self.assertTokensIn([ 2165 '--config=remote', 2166 ], cmd[0]) 2167 2168 def test_generate_run_command_with_verbose_args(self): 2169 test_infos = [test_info_of('test1')] 2170 runner = self.create_bazel_test_runner_for_tests(test_infos) 2171 extra_args = {constants.VERBOSE: True} 2172 2173 cmd = runner.generate_run_commands(test_infos, extra_args) 2174 2175 self.assertTokensIn(['--test_output=all'], cmd[0]) 2176 2177 def create_bazel_test_runner(self, 2178 modules, 2179 run_command=None, 2180 host=False, 2181 build_metadata=None, 2182 env=None): 2183 return bazel_mode.BazelTestRunner( 2184 'result_dir', 2185 mod_info=create_module_info(modules), 2186 src_top=Path('/src'), 2187 workspace_path=Path('/src/workspace'), 2188 run_command=run_command or self.mock_run_command(), 2189 extra_args={constants.HOST: host}, 2190 build_metadata = build_metadata, 2191 env = env 2192 ) 2193 2194 def create_bazel_test_runner_for_tests(self, 2195 test_infos, 2196 build_metadata=None, 2197 env=None): 2198 return self.create_bazel_test_runner( 2199 modules=[supported_test_module(name=t.test_name, path='path') 2200 for t in test_infos], 2201 build_metadata=build_metadata, 2202 env=env 2203 ) 2204 2205 def create_completed_process(self, args, returncode, stdout): 2206 return subprocess.CompletedProcess(args, returncode, stdout) 2207 2208 def mock_run_command(self, **kwargs): 2209 return mock.create_autospec(bazel_mode.default_run_command, **kwargs) 2210 2211 def assertTokensIn(self, expected_tokens, s): 2212 tokens = shlex.split(s) 2213 for token in expected_tokens: 2214 self.assertIn(token, tokens) 2215 2216 2217class FeatureParserTest(unittest.TestCase): 2218 """Tests for parsing Bazel mode feature flags.""" 2219 2220 def test_parse_args_with_bazel_mode_feature(self): 2221 parser = argparse.ArgumentParser() 2222 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 2223 # pylint: disable=no-member 2224 args = parser.parse_args([bazel_mode.Features.NULL_FEATURE.arg_flag]) 2225 2226 self.assertListEqual([bazel_mode.Features.NULL_FEATURE], 2227 args.bazel_mode_features) 2228 2229 def test_parse_args_without_bazel_mode_feature(self): 2230 parser = argparse.ArgumentParser() 2231 parser.add_argument('--foo', 2232 action='append_const', 2233 const='foo', 2234 dest='foo') 2235 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 2236 args = parser.parse_args(['--foo']) 2237 2238 self.assertIsNone(args.bazel_mode_features) 2239 2240 2241def test_info_of(module_name, test_filters=None): 2242 return test_info.TestInfo( 2243 module_name, BAZEL_RUNNER, [], 2244 data={constants.TI_FILTER: frozenset(test_filters)} 2245 if test_filters else None) 2246 2247 2248def test_filter_of(class_name, methods=None): 2249 return test_info.TestFilter( 2250 class_name, frozenset(methods) if methods else frozenset()) 2251 2252 2253def _get_query_file_content(args: List[str]) -> str: 2254 for arg in args: 2255 if arg.startswith('--query_file='): 2256 return Path(arg.split('=')[1]).read_text() 2257 2258 raise Exception('Query file not found!') 2259 2260 2261if __name__ == '__main__': 2262 unittest.main() 2263