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 23from io import StringIO 24from pathlib import Path 25import re 26import shlex 27import shutil 28import subprocess 29import tempfile 30from typing import List 31import unittest 32from unittest import mock 33from atest import bazel_mode 34from atest import constants 35from atest import module_info 36from atest.test_finders import example_finder, test_finder_base, test_info 37from atest.test_runners import atest_tf_test_runner 38from pyfakefs import fake_filesystem_unittest 39 40 41ATEST_TF_RUNNER = atest_tf_test_runner.AtestTradefedTestRunner.NAME 42BAZEL_RUNNER = bazel_mode.BazelTestRunner.NAME 43MODULE_BUILD_TARGETS = {'foo1', 'foo2', 'foo3'} 44MODULE_NAME = 'foo' 45 46 47class GenerationTestFixture(fake_filesystem_unittest.TestCase): 48 """Fixture for workspace generation tests.""" 49 50 def setUp(self): 51 self.setUpPyfakefs() 52 53 self._src_root_path = Path('/src') 54 self.out_dir_path = self._src_root_path.joinpath('out') 55 self.out_dir_path.mkdir(parents=True) 56 self.product_out_path = self.out_dir_path.joinpath('product') 57 self.host_out_path = self.out_dir_path.joinpath('host') 58 self.workspace_out_path = self.out_dir_path.joinpath('workspace') 59 60 self._resource_root = self._src_root_path.joinpath( 61 'tools/asuite/atest/bazel' 62 ) 63 64 self.workspace_md5_checksum = self.workspace_out_path.joinpath( 65 'workspace_md5_checksum' 66 ) 67 self.resource_manager = bazel_mode.ResourceManager( 68 src_root_path=self._src_root_path, 69 resource_root_path=self._resource_root, 70 product_out_path=self.product_out_path, 71 md5_checksum_file_path=self.workspace_md5_checksum, 72 ) 73 74 bazel_rules = self.resource_manager.get_resource_file_path('rules') 75 bazel_rules.mkdir(parents=True) 76 self.rules_bzl_file = bazel_rules.joinpath('rules.bzl') 77 self.rules_bzl_file.touch() 78 79 bazel_configs = self.resource_manager.get_resource_file_path('configs') 80 bazel_configs.mkdir(parents=True) 81 bazel_configs.joinpath('configs.bzl').touch() 82 83 self.resource_manager.get_resource_file_path('WORKSPACE').touch() 84 self.resource_manager.get_resource_file_path('bazelrc').touch() 85 self.resource_manager.get_resource_file_path('bazel.sh').touch() 86 87 rules_python = self.resource_manager.get_src_file_path( 88 'external/bazelbuild-rules_python' 89 ) 90 rules_python.mkdir(parents=True) 91 rules_java = self.resource_manager.get_src_file_path( 92 'external/bazelbuild-rules_java' 93 ) 94 rules_java.mkdir(parents=True) 95 96 def create_workspace_generator( 97 self, 98 modules=None, 99 enabled_features=None, 100 jdk_path=None, 101 ): 102 mod_info = self.create_module_info(modules) 103 104 generator = bazel_mode.WorkspaceGenerator( 105 resource_manager=self.resource_manager, 106 workspace_out_path=self.workspace_out_path, 107 host_out_path=self.host_out_path, 108 build_out_dir=self.out_dir_path, 109 mod_info=mod_info, 110 jdk_path=jdk_path, 111 enabled_features=enabled_features, 112 ) 113 114 return generator 115 116 def run_generator(self, mod_info, enabled_features=None, jdk_path=None): 117 generator = bazel_mode.WorkspaceGenerator( 118 resource_manager=self.resource_manager, 119 workspace_out_path=self.workspace_out_path, 120 host_out_path=self.host_out_path, 121 build_out_dir=self.out_dir_path, 122 mod_info=mod_info, 123 jdk_path=jdk_path, 124 enabled_features=enabled_features, 125 ) 126 127 generator.generate() 128 129 # pylint: disable=protected-access 130 def create_empty_module_info(self): 131 fake_temp_file = self.product_out_path.joinpath( 132 next(tempfile._get_candidate_names()) 133 ) 134 self.fs.create_file(fake_temp_file, contents='{}') 135 return module_info.load_from_file(module_file=fake_temp_file) 136 137 def create_module_info(self, modules=None): 138 mod_info = self.create_empty_module_info() 139 modules = modules or [] 140 141 prerequisites = frozenset().union( 142 bazel_mode.TestTarget.DEVICE_TEST_PREREQUISITES, 143 bazel_mode.TestTarget.DEVICELESS_TEST_PREREQUISITES, 144 ) 145 146 for module_name in prerequisites: 147 info = host_module(name=module_name, path='prebuilts') 148 info[constants.MODULE_INFO_ID] = module_name 149 mod_info.name_to_module_info[module_name] = info 150 151 for m in modules: 152 m[constants.MODULE_INFO_ID] = m['module_name'] 153 mod_info.name_to_module_info[m['module_name']] = m 154 for path in m['path']: 155 if path in mod_info.path_to_module_info: 156 mod_info.path_to_module_info[path].append(m) 157 else: 158 mod_info.path_to_module_info[path] = [m] 159 160 return mod_info 161 162 def assertSymlinkTo(self, symlink_path, target_path): 163 self.assertEqual(symlink_path.resolve(strict=False), target_path) 164 165 def assertTargetInWorkspace(self, name, package=''): 166 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 167 contents = build_file.read_text(encoding='utf8') 168 occurrences = len(self.find_target_by_name(name, contents)) 169 170 if occurrences == 1: 171 return 172 173 cardinality = 'Multiple' if occurrences else 'Zero' 174 self.fail(f"{cardinality} targets named '{name}' found in '{contents}'") 175 176 def assertTargetNotInWorkspace(self, name, package=''): 177 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 178 179 if not build_file.exists(): 180 return 181 182 contents = build_file.read_text(encoding='utf8') 183 matches = self.find_target_by_name(name, contents) 184 185 if not matches: 186 return 187 188 self.fail(f"Unexpectedly found target(s) named '{name}' in '{contents}'") 189 190 def assertInBuildFile(self, substring, package=''): 191 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 192 self.assertIn(substring, build_file.read_text(encoding='utf8')) 193 194 def assertNotInBuildFile(self, substring, package=''): 195 build_file = self.workspace_out_path.joinpath(package, 'BUILD.bazel') 196 self.assertNotIn(substring, build_file.read_text(encoding='utf8')) 197 198 def assertFileInWorkspace(self, relative_path, package=''): 199 path = self.workspace_out_path.joinpath(package, relative_path) 200 self.assertTrue(path.exists()) 201 202 def assertDirInWorkspace(self, relative_path, package=''): 203 path = self.workspace_out_path.joinpath(package, relative_path) 204 self.assertTrue(path.is_dir()) 205 206 def assertFileNotInWorkspace(self, relative_path, package=''): 207 path = self.workspace_out_path.joinpath(package, relative_path) 208 self.assertFalse(path.exists()) 209 210 def find_target_by_name(self, name: str, contents: str) -> List[str]: 211 return re.findall(rf'\bname\s*=\s*"{name}"', contents) 212 213 def add_device_def_to_filesystem(self): 214 bazel_device_def = self.resource_manager.get_resource_file_path( 215 'device_def' 216 ) 217 bazel_device_def.mkdir(parents=True) 218 bazel_device_def.joinpath('device_def.bzl').touch() 219 220 221class BasicWorkspaceGenerationTest(GenerationTestFixture): 222 """Tests for basic workspace generation and update.""" 223 224 def test_generate_workspace_when_nonexistent(self): 225 workspace_generator = self.create_workspace_generator() 226 shutil.rmtree(workspace_generator.workspace_out_path, ignore_errors=True) 227 228 workspace_generator.generate() 229 230 self.assertTrue(workspace_generator.workspace_out_path.is_dir()) 231 232 def test_regenerate_workspace_when_features_changed(self): 233 workspace_generator = self.create_workspace_generator( 234 enabled_features={bazel_mode.Features.NULL_FEATURE} 235 ) 236 workspace_generator.generate() 237 workspace_stat = workspace_generator.workspace_out_path.stat() 238 239 workspace_generator = self.create_workspace_generator() 240 workspace_generator.generate() 241 new_workspace_stat = workspace_generator.workspace_out_path.stat() 242 243 self.assertNotEqual(workspace_stat, new_workspace_stat) 244 245 def test_not_regenerate_when_feature_does_not_affect_workspace(self): 246 workspace_generator = self.create_workspace_generator( 247 enabled_features={bazel_mode.Features.NULL_FEATURE} 248 ) 249 workspace_generator.generate() 250 workspace_stat = workspace_generator.workspace_out_path.stat() 251 252 parser = argparse.ArgumentParser() 253 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 254 # pylint: disable=no-member 255 args = parser.parse_args([ 256 bazel_mode.Features.NULL_FEATURE.arg_flag, 257 '--experimental-bes-publish', 258 ]) 259 workspace_generator = self.create_workspace_generator( 260 enabled_features=set(args.bazel_mode_features) 261 ) 262 workspace_generator.generate() 263 new_workspace_stat = workspace_generator.workspace_out_path.stat() 264 265 self.assertEqual(workspace_stat, new_workspace_stat) 266 267 def test_not_regenerate_workspace_when_features_unchanged(self): 268 workspace_generator = self.create_workspace_generator( 269 enabled_features={bazel_mode.Features.NULL_FEATURE} 270 ) 271 workspace_generator.generate() 272 workspace_stat = workspace_generator.workspace_out_path.stat() 273 274 workspace_generator = self.create_workspace_generator( 275 enabled_features={bazel_mode.Features.NULL_FEATURE} 276 ) 277 workspace_generator.generate() 278 new_workspace_stat = workspace_generator.workspace_out_path.stat() 279 280 self.assertEqual(workspace_stat, new_workspace_stat) 281 282 def test_regenerate_workspace_when_module_info_deleted(self): 283 workspace_generator = self.create_workspace_generator() 284 workspace_generator.generate() 285 workspace_stat = workspace_generator.workspace_out_path.stat() 286 287 workspace_generator.mod_info.mod_info_file_path.unlink() 288 workspace_generator = self.create_workspace_generator() 289 workspace_generator.generate() 290 291 new_workspace_stat = workspace_generator.workspace_out_path.stat() 292 self.assertNotEqual(workspace_stat, new_workspace_stat) 293 294 def test_not_regenerate_workspace_when_module_info_unchanged(self): 295 workspace_generator1 = self.create_workspace_generator() 296 workspace_generator1.generate() 297 workspace_stat = workspace_generator1.workspace_out_path.stat() 298 299 workspace_generator2 = self.create_workspace_generator() 300 workspace_generator2.generate() 301 new_workspace_stat = workspace_generator2.workspace_out_path.stat() 302 303 self.assertEqual(workspace_stat, new_workspace_stat) 304 305 def test_not_regenerate_workspace_when_module_only_touched(self): 306 workspace_generator = self.create_workspace_generator() 307 workspace_generator.generate() 308 workspace_stat = workspace_generator.workspace_out_path.stat() 309 310 Path(workspace_generator.mod_info.mod_info_file_path).touch() 311 workspace_generator = self.create_workspace_generator() 312 workspace_generator.generate() 313 314 new_workspace_stat = workspace_generator.workspace_out_path.stat() 315 self.assertEqual(workspace_stat, new_workspace_stat) 316 317 def test_regenerate_workspace_when_module_info_changed(self): 318 workspace_generator = self.create_workspace_generator() 319 workspace_generator.generate() 320 workspace_stat = workspace_generator.workspace_out_path.stat() 321 322 mod_info_file_path = workspace_generator.mod_info.mod_info_file_path 323 with open(mod_info_file_path, 'a', encoding='utf8') as f: 324 f.write(' ') 325 workspace_generator = self.create_workspace_generator() 326 workspace_generator.generate() 327 328 new_workspace_stat = workspace_generator.workspace_out_path.stat() 329 self.assertNotEqual(workspace_stat, new_workspace_stat) 330 331 def test_regenerate_workspace_when_md5_file_removed(self): 332 workspace_generator = self.create_workspace_generator() 333 workspace_generator.generate() 334 workspace_stat = workspace_generator.workspace_out_path.stat() 335 336 self.workspace_md5_checksum.unlink() 337 workspace_generator = self.create_workspace_generator() 338 workspace_generator.generate() 339 new_workspace_stat = workspace_generator.workspace_out_path.stat() 340 341 self.assertNotEqual(workspace_stat, new_workspace_stat) 342 343 def test_regenerate_workspace_when_md5_file_is_broken(self): 344 workspace_generator = self.create_workspace_generator() 345 workspace_generator.generate() 346 workspace_stat = workspace_generator.workspace_out_path.stat() 347 348 self.workspace_md5_checksum.write_text('broken checksum file') 349 workspace_generator = self.create_workspace_generator() 350 workspace_generator.generate() 351 new_workspace_stat = workspace_generator.workspace_out_path.stat() 352 353 self.assertNotEqual(workspace_stat, new_workspace_stat) 354 355 def test_not_regenerate_workspace_when_workspace_files_unaffected(self): 356 workspace_generator = self.create_workspace_generator() 357 workspace_generator.generate() 358 workspace_stat = workspace_generator.workspace_out_path.stat() 359 360 workspace_generator = self.create_workspace_generator() 361 workspace_generator.generate() 362 new_workspace_stat = workspace_generator.workspace_out_path.stat() 363 364 self.assertEqual(workspace_stat, new_workspace_stat) 365 366 def test_scrub_old_workspace_when_regenerating(self): 367 workspace_generator = self.create_workspace_generator() 368 workspace_generator.generate() 369 some_file = workspace_generator.workspace_out_path.joinpath('some_file') 370 some_file.touch() 371 self.assertTrue(some_file.is_file()) 372 373 # Remove the module_info file to regenerate the workspace. 374 workspace_generator.mod_info.mod_info_file_path.unlink() 375 workspace_generator = self.create_workspace_generator() 376 workspace_generator.generate() 377 378 self.assertFalse(some_file.is_file()) 379 380 def test_regenerate_workspace_when_resource_file_changed(self): 381 workspace_generator = self.create_workspace_generator() 382 workspace_generator.generate() 383 workspace_stat = workspace_generator.workspace_out_path.stat() 384 385 with open(self.rules_bzl_file, 'a', encoding='utf8') as f: 386 f.write(' ') 387 workspace_generator = self.create_workspace_generator() 388 workspace_generator.generate() 389 390 new_workspace_stat = workspace_generator.workspace_out_path.stat() 391 self.assertNotEqual(workspace_stat, new_workspace_stat) 392 393 def test_not_regenerate_workspace_when_resource_file_only_touched(self): 394 workspace_generator = self.create_workspace_generator() 395 workspace_generator.generate() 396 workspace_stat = workspace_generator.workspace_out_path.stat() 397 398 self.rules_bzl_file.touch() 399 workspace_generator = self.create_workspace_generator() 400 workspace_generator.generate() 401 402 new_workspace_stat = workspace_generator.workspace_out_path.stat() 403 self.assertEqual(workspace_stat, new_workspace_stat) 404 405 def test_copy_workspace_resources(self): 406 gen = self.create_workspace_generator() 407 408 gen.generate() 409 410 self.assertFileInWorkspace('WORKSPACE') 411 self.assertFileInWorkspace('.bazelrc') 412 self.assertDirInWorkspace('bazel/rules') 413 self.assertDirInWorkspace('bazel/configs') 414 415 def test_generated_target_name(self): 416 mod_info = self.create_module_info( 417 modules=[host_unit_test_module(name='hello_world_test')] 418 ) 419 info = mod_info.get_module_info('hello_world_test') 420 info[constants.MODULE_INFO_ID] = 'new_hello_world_test' 421 422 self.run_generator(mod_info) 423 424 self.assertTargetInWorkspace('new_hello_world_test') 425 self.assertTargetNotInWorkspace('hello_world_test') 426 427 def test_generate_host_unit_test_module_target(self): 428 mod_info = self.create_module_info( 429 modules=[host_unit_test_module(name='hello_world_test')] 430 ) 431 432 self.run_generator(mod_info) 433 434 self.assertTargetInWorkspace('hello_world_test_host') 435 436 def test_not_generate_host_test_module_target(self): 437 mod_info = self.create_module_info( 438 modules=[ 439 host_test_module(name='hello_world_test'), 440 ] 441 ) 442 443 self.run_generator(mod_info) 444 445 self.assertTargetNotInWorkspace('hello_world_test') 446 447 def test_not_generate_test_module_target_with_invalid_installed_path(self): 448 mod_info = self.create_module_info( 449 modules=[ 450 test_module(name='hello_world_test', installed='out/invalid/path') 451 ] 452 ) 453 454 self.run_generator(mod_info) 455 456 self.assertTargetNotInWorkspace('hello_world_test_device') 457 self.assertTargetNotInWorkspace('hello_world_test_host') 458 459 def test_generate_variable_file(self): 460 gen = self.create_workspace_generator() 461 462 gen.generate() 463 464 self.assertFileInWorkspace('BUILD.bazel') 465 self.assertFileInWorkspace('constants.bzl') 466 467 468class MultiConfigUnitTestModuleTestTargetGenerationTest(GenerationTestFixture): 469 """Tests for test target generation of test modules with multi-configs.""" 470 471 def setUp(self): 472 super().setUp() 473 super().add_device_def_to_filesystem() 474 475 def test_generate_test_rule_imports(self): 476 mod_info = self.create_module_info( 477 modules=[ 478 multi_config( 479 host_unit_suite( 480 test_module(name='hello_world_test', path='example/tests') 481 ) 482 ), 483 ] 484 ) 485 486 self.run_generator( 487 mod_info, 488 enabled_features=set( 489 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 490 ), 491 ) 492 493 self.assertInBuildFile( 494 'load("//bazel/rules:tradefed_test.bzl",' 495 ' "tradefed_device_driven_test", "tradefed_deviceless_test")\n', 496 package='example/tests', 497 ) 498 499 def test_not_generate_device_test_import_when_feature_disabled(self): 500 mod_info = self.create_module_info( 501 modules=[ 502 multi_config( 503 host_unit_suite( 504 test_module(name='hello_world_test', path='example/tests') 505 ) 506 ), 507 ] 508 ) 509 510 self.run_generator(mod_info) 511 512 self.assertInBuildFile( 513 'load("//bazel/rules:tradefed_test.bzl", "tradefed_deviceless_test")\n', 514 package='example/tests', 515 ) 516 517 def test_generate_test_targets(self): 518 mod_info = self.create_module_info( 519 modules=[ 520 multi_config( 521 host_unit_suite( 522 test_module(name='hello_world_test', path='example/tests') 523 ) 524 ), 525 ] 526 ) 527 528 self.run_generator( 529 mod_info, 530 enabled_features=set( 531 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 532 ), 533 ) 534 535 self.assertTargetInWorkspace( 536 'hello_world_test_device', package='example/tests' 537 ) 538 self.assertTargetInWorkspace( 539 'hello_world_test_host', package='example/tests' 540 ) 541 542 def test_not_generate_device_test_target_when_feature_disabled(self): 543 mod_info = self.create_module_info( 544 modules=[ 545 multi_config( 546 host_unit_suite( 547 test_module(name='hello_world_test', path='example/tests') 548 ) 549 ), 550 ] 551 ) 552 553 self.run_generator(mod_info) 554 555 self.assertTargetNotInWorkspace( 556 'hello_world_test_device', package='example/tests' 557 ) 558 self.assertTargetInWorkspace( 559 'hello_world_test_host', package='example/tests' 560 ) 561 562 563class DeviceTestModuleTestTargetGenerationTest(GenerationTestFixture): 564 """Tests for device test module test target generation.""" 565 566 def setUp(self): 567 super().setUp() 568 super().add_device_def_to_filesystem() 569 570 def test_generate_device_driven_test_target(self): 571 mod_info = self.create_module_info( 572 modules=[ 573 device_test_module(name='hello_world_test', path='example/tests'), 574 ] 575 ) 576 577 self.run_generator( 578 mod_info, 579 enabled_features=set( 580 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 581 ), 582 ) 583 584 self.assertInBuildFile( 585 'load("//bazel/rules:tradefed_test.bzl",' 586 ' "tradefed_device_driven_test")\n', 587 package='example/tests', 588 ) 589 self.assertDirInWorkspace('device_def') 590 self.assertTargetInWorkspace( 591 'hello_world_test_device', package='example/tests' 592 ) 593 594 def test_generate_target_with_suites(self): 595 mod_info = self.create_module_info( 596 modules=[ 597 device_test_module( 598 name='hello_world_test', 599 path='example/tests', 600 compatibility_suites=['cts', 'mts'], 601 ), 602 ] 603 ) 604 605 self.run_generator( 606 mod_info, 607 enabled_features=set( 608 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 609 ), 610 ) 611 612 self.assertInBuildFile( 613 ' suites = [\n "cts",\n "mts",\n ],\n', 614 package='example/tests', 615 ) 616 617 def test_generate_target_with_host_dependencies(self): 618 mod_info = self.create_module_info( 619 modules=[ 620 device_test_module( 621 name='hello_world_test', 622 path='example/tests', 623 host_dependencies=['vts_dep', 'cts_dep'], 624 ), 625 host_module(name='vts_dep'), 626 host_module(name='cts_dep'), 627 ] 628 ) 629 630 self.run_generator( 631 mod_info, 632 enabled_features=set( 633 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 634 ), 635 ) 636 637 self.assertInBuildFile( 638 ' tradefed_deps = [\n' 639 ' "//:cts_dep",\n' 640 ' "//:vts_dep",\n' 641 ' ],\n', 642 package='example/tests', 643 ) 644 645 def test_generate_target_with_device_dependencies(self): 646 mod_info = self.create_module_info( 647 modules=[ 648 host_test_module( 649 name='hello_world_test', 650 path='example/tests', 651 target_dependencies=['helper_app'], 652 ), 653 device_module(name='helper_app'), 654 ] 655 ) 656 657 self.run_generator( 658 mod_info, 659 enabled_features=set( 660 [bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST] 661 ), 662 ) 663 664 self.assertInBuildFile( 665 ' device_data = [\n "//:helper_app",\n ],\n', 666 package='example/tests', 667 ) 668 669 def test_generate_target_with_tags(self): 670 mod_info = self.create_module_info( 671 modules=[ 672 device_test_module( 673 name='hello_world_test', 674 path='example/tests', 675 test_options_tags=['no-remote'], 676 ), 677 ] 678 ) 679 680 self.run_generator( 681 mod_info, 682 enabled_features=set( 683 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 684 ), 685 ) 686 687 self.assertInBuildFile( 688 ' tags = [\n "no-remote",\n ],\n', 689 package='example/tests', 690 ) 691 692 def test_generate_host_driven_test_target(self): 693 mod_info = self.create_module_info( 694 modules=[ 695 host_test_module(name='hello_world_test', path='example/tests'), 696 ] 697 ) 698 699 self.run_generator( 700 mod_info, 701 enabled_features=set( 702 [bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST] 703 ), 704 ) 705 706 self.assertInBuildFile( 707 'tradefed_host_driven_device_test(', package='example/tests' 708 ) 709 710 def test_generate_multi_config_device_test_target(self): 711 mod_info = self.create_module_info( 712 modules=[ 713 multi_config( 714 test_module(name='hello_world_test', path='example/tests') 715 ), 716 ] 717 ) 718 719 self.run_generator( 720 mod_info, 721 enabled_features=set([ 722 bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST, 723 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST, 724 ]), 725 ) 726 727 self.assertInBuildFile( 728 'load("//bazel/rules:tradefed_test.bzl", ' 729 '"tradefed_device_driven_test", ' 730 '"tradefed_host_driven_device_test")\n', 731 package='example/tests', 732 ) 733 self.assertTargetInWorkspace( 734 'hello_world_test_device', package='example/tests' 735 ) 736 self.assertTargetInWorkspace( 737 'hello_world_test_host', package='example/tests' 738 ) 739 740 def test_not_generate_host_driven_test_target_when_feature_disabled(self): 741 mod_info = self.create_module_info( 742 modules=[ 743 multi_config( 744 test_module(name='hello_world_test', path='example/tests') 745 ), 746 ] 747 ) 748 749 self.run_generator( 750 mod_info, 751 enabled_features=set( 752 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 753 ), 754 ) 755 756 self.assertTargetInWorkspace( 757 'hello_world_test_device', package='example/tests' 758 ) 759 self.assertTargetNotInWorkspace( 760 'hello_world_test_host', package='example/tests' 761 ) 762 763 def test_raise_when_prerequisite_not_in_module_info(self): 764 mod_info = self.create_module_info( 765 modules=[ 766 device_test_module(), 767 ] 768 ) 769 del mod_info.name_to_module_info['aapt'] 770 771 with self.assertRaises(Exception) as context: 772 self.run_generator( 773 mod_info, 774 enabled_features=set( 775 [bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST] 776 ), 777 ) 778 779 self.assertIn('aapt', str(context.exception)) 780 781 782class HostUnitTestModuleTestTargetGenerationTest(GenerationTestFixture): 783 """Tests for host unit test module test target generation.""" 784 785 def test_generate_deviceless_test_import(self): 786 mod_info = self.create_module_info( 787 modules=[ 788 host_unit_test_module(name='hello_world_test'), 789 ] 790 ) 791 792 self.run_generator(mod_info) 793 794 self.assertInBuildFile( 795 'load("//bazel/rules:tradefed_test.bzl", "tradefed_deviceless_test")\n' 796 ) 797 798 def test_generate_deviceless_test_target(self): 799 mod_info = self.create_module_info( 800 modules=[ 801 host_unit_test_module( 802 name='hello_world_test', path='example/tests' 803 ), 804 ] 805 ) 806 807 self.run_generator(mod_info) 808 809 self.assertInBuildFile( 810 'tradefed_deviceless_test(\n' 811 ' name = "hello_world_test_host",\n' 812 ' module_name = "hello_world_test",\n' 813 ' test = "//example/tests:hello_world_test",\n' 814 ')', 815 package='example/tests', 816 ) 817 818 def test_generate_target_with_tags(self): 819 mod_info = self.create_module_info( 820 modules=[ 821 host_unit_test_module( 822 name='hello_world_test', 823 path='example/tests', 824 test_options_tags=['no-remote'], 825 ), 826 ] 827 ) 828 829 self.run_generator(mod_info) 830 831 self.assertInBuildFile( 832 ' tags = [\n "no-remote",\n ],\n', 833 package='example/tests', 834 ) 835 836 def test_generate_test_module_prebuilt(self): 837 mod_info = self.create_module_info( 838 modules=[ 839 host_unit_test_module(name='hello_world_test'), 840 ] 841 ) 842 843 self.run_generator(mod_info) 844 845 self.assertTargetInWorkspace('hello_world_test') 846 847 def test_raise_when_prerequisite_not_in_module_info(self): 848 mod_info = self.create_module_info( 849 modules=[ 850 host_unit_test_module(), 851 ] 852 ) 853 del mod_info.name_to_module_info['adb'] 854 855 with self.assertRaises(Exception) as context: 856 self.run_generator(mod_info) 857 858 self.assertIn('adb', str(context.exception)) 859 860 def test_raise_when_prerequisite_module_missing_path(self): 861 mod_info = self.create_module_info( 862 modules=[ 863 host_unit_test_module(), 864 ] 865 ) 866 mod_info.name_to_module_info['adb'].get('path').clear() 867 868 with self.assertRaises(Exception) as context: 869 self.run_generator(mod_info) 870 871 self.assertIn('adb', str(context.exception)) 872 873 def test_warning_when_prerequisite_module_has_multiple_path(self): 874 mod_info = self.create_module_info( 875 modules=[ 876 host_unit_test_module(), 877 ] 878 ) 879 mod_info.name_to_module_info['adb'].get('path').append('the/2nd/path') 880 881 with self.assertWarns(Warning) as context: 882 self.run_generator(mod_info) 883 884 self.assertIn('adb', str(context.warnings[0].message)) 885 886 887class RemoteAvdTestTargetGenerationTest(GenerationTestFixture): 888 """Unit tests for generating Bazel targets on remote AVD.""" 889 890 def setUp(self): 891 super().setUp() 892 super().add_device_def_to_filesystem() 893 894 def test_generate_remote_avd_test_target(self): 895 mod_info = self.create_module_info( 896 modules=[ 897 device_test_module(name='hello_world_test', path='example/tests'), 898 ] 899 ) 900 901 self.run_generator( 902 mod_info, 903 enabled_features=set([ 904 bazel_mode.Features.EXPERIMENTAL_REMOTE_AVD, 905 bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST, 906 ]), 907 ) 908 909 self.assertInBuildFile( 910 'load("//bazel/rules:tradefed_test.bzl",' 911 ' "tradefed_device_driven_test")\n', 912 package='example/tests', 913 ) 914 self.assertDirInWorkspace('device_def') 915 self.assertTargetInWorkspace( 916 'hello_world_test_device', package='example/tests' 917 ) 918 919 def test_generate_remote_avd_test_target_no_device_test_flag(self): 920 mod_info = self.create_module_info( 921 modules=[ 922 device_test_module(name='hello_world_test', path='example/tests'), 923 ] 924 ) 925 926 with self.assertRaises(Exception) as context: 927 self.run_generator( 928 mod_info, 929 enabled_features=set([bazel_mode.Features.EXPERIMENTAL_REMOTE_AVD]), 930 ) 931 932 self.assertIn( 933 '--experimental-device-driven-test" flag is not set', 934 str(context.exception), 935 ) 936 937 938class RobolectricTestModuleTestTargetGenerationTest(GenerationTestFixture): 939 """Tests for robolectric test module test target generation.""" 940 941 def setUp(self): 942 super().setUp() 943 self.robolectric_template_path = ( 944 self.resource_manager.get_resource_file_path( 945 bazel_mode.ROBOLECTRIC_CONFIG, True 946 ) 947 ) 948 self.fs.create_file(self.robolectric_template_path, contents='') 949 # ResourceManager only calculates md5 when registering files. So, it is 950 # necessary to call get_resource_file_path() again after writing files. 951 self.resource_manager.get_resource_file_path( 952 bazel_mode.ROBOLECTRIC_CONFIG, True 953 ) 954 955 def test_generate_robolectric_test_target(self): 956 module_name = 'hello_world_test' 957 mod_info = self.create_module_info( 958 modules=[ 959 robolectric_test_module( 960 name=f'{module_name}', compatibility_suites='robolectric-tests' 961 ), 962 ] 963 ) 964 965 self.run_generator( 966 mod_info, 967 enabled_features=set( 968 [bazel_mode.Features.EXPERIMENTAL_ROBOLECTRIC_TEST] 969 ), 970 ) 971 972 self.assertInBuildFile( 973 'load("//bazel/rules:tradefed_test.bzl",' 974 ' "tradefed_robolectric_test")\n', 975 ) 976 self.assertTargetInWorkspace(f'{module_name}_host') 977 978 def test_not_generate_when_feature_disabled(self): 979 module_name = 'hello_world_test' 980 mod_info = self.create_module_info( 981 modules=[ 982 robolectric_test_module( 983 name=f'{module_name}', compatibility_suites='robolectric-tests' 984 ), 985 ] 986 ) 987 988 self.run_generator(mod_info) 989 990 self.assertTargetNotInWorkspace(f'{module_name}_host') 991 992 def test_not_generate_for_legacy_robolectric_test_type(self): 993 module_name = 'hello_world_test' 994 module_path = 'example/tests' 995 mod_info = self.create_module_info( 996 modules=[ 997 robolectric_test_module(name=f'{module_name}', path=module_path), 998 ] 999 ) 1000 1001 self.run_generator( 1002 mod_info, 1003 enabled_features=set( 1004 [bazel_mode.Features.EXPERIMENTAL_ROBOLECTRIC_TEST] 1005 ), 1006 ) 1007 1008 self.assertFileNotInWorkspace('BUILD.bazel', package=f'{module_path}') 1009 1010 def test_generate_jdk_target(self): 1011 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 1012 1013 gen.generate() 1014 1015 self.assertInBuildFile( 1016 'filegroup(\n' 1017 f' name = "{bazel_mode.JDK_NAME}",\n' 1018 ' srcs = glob([\n' 1019 f' "{bazel_mode.JDK_NAME}_files/**",\n', 1020 package=f'{bazel_mode.JDK_PACKAGE_NAME}', 1021 ) 1022 1023 def test_not_generate_jdk_target_when_no_jdk_path(self): 1024 gen = self.create_workspace_generator(jdk_path=None) 1025 1026 gen.generate() 1027 1028 self.assertFileNotInWorkspace( 1029 'BUILD.bazel', package=f'{bazel_mode.JDK_PACKAGE_NAME}' 1030 ) 1031 1032 def test_create_symlinks_to_jdk(self): 1033 jdk_path = Path('jdk_path') 1034 gen = self.create_workspace_generator(jdk_path=jdk_path) 1035 1036 gen.generate() 1037 1038 self.assertSymlinkTo( 1039 self.workspace_out_path.joinpath( 1040 f'{bazel_mode.JDK_PACKAGE_NAME}/{bazel_mode.JDK_NAME}_files' 1041 ), 1042 self.resource_manager.get_src_file_path(f'{jdk_path}'), 1043 ) 1044 1045 def test_generate_android_all_target(self): 1046 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 1047 1048 gen.generate() 1049 1050 self.assertInBuildFile( 1051 'filegroup(\n' 1052 ' name = "android-all",\n' 1053 ' srcs = glob([\n' 1054 ' "android-all_files/**",\n', 1055 package='android-all', 1056 ) 1057 1058 def test_not_generate_android_all_target_when_no_jdk_path(self): 1059 gen = self.create_workspace_generator(jdk_path=None) 1060 1061 gen.generate() 1062 1063 self.assertFileNotInWorkspace('BUILD.bazel', package='android-all') 1064 1065 def test_create_symlinks_to_android_all(self): 1066 module_name = 'android-all' 1067 gen = self.create_workspace_generator(jdk_path=Path('jdk_src_root')) 1068 1069 gen.generate() 1070 1071 self.assertSymlinkTo( 1072 self.workspace_out_path.joinpath(f'{module_name}/{module_name}_files'), 1073 self.host_out_path.joinpath(f'testcases/{module_name}'), 1074 ) 1075 1076 def test_regenerate_workspace_when_robolectric_template_changed(self): 1077 workspace_generator = self.create_workspace_generator() 1078 workspace_generator.generate() 1079 workspace_stat = workspace_generator.workspace_out_path.stat() 1080 1081 with open(self.robolectric_template_path, 'a', encoding='utf8') as f: 1082 f.write(' ') 1083 workspace_generator = self.create_workspace_generator() 1084 workspace_generator.generate() 1085 1086 new_workspace_stat = workspace_generator.workspace_out_path.stat() 1087 self.assertNotEqual(workspace_stat, new_workspace_stat) 1088 1089 def test_not_regenerate_workspace_when_robolectric_template_touched(self): 1090 workspace_generator = self.create_workspace_generator() 1091 workspace_generator.generate() 1092 workspace_stat = workspace_generator.workspace_out_path.stat() 1093 1094 self.robolectric_template_path.touch() 1095 workspace_generator = self.create_workspace_generator() 1096 workspace_generator.generate() 1097 1098 new_workspace_stat = workspace_generator.workspace_out_path.stat() 1099 self.assertEqual(workspace_stat, new_workspace_stat) 1100 1101 1102class ModulePrebuiltTargetGenerationTest(GenerationTestFixture): 1103 """Tests for module prebuilt target generation.""" 1104 1105 def test_generate_prebuilt_import(self): 1106 mod_info = self.create_module_info( 1107 modules=[ 1108 supported_test_module(), 1109 ] 1110 ) 1111 1112 self.run_generator(mod_info) 1113 1114 self.assertInBuildFile( 1115 'load("//bazel/rules:soong_prebuilt.bzl", "soong_prebuilt")\n' 1116 ) 1117 1118 def test_generate_prebuilt_target_for_multi_config_test_module(self): 1119 mod_info = self.create_module_info( 1120 modules=[ 1121 multi_config(supported_test_module(name='libhello')), 1122 ] 1123 ) 1124 1125 self.run_generator(mod_info) 1126 1127 self.assertInBuildFile( 1128 'soong_prebuilt(\n' 1129 ' name = "libhello",\n' 1130 ' module_name = "libhello",\n' 1131 ' files = select({\n' 1132 ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' 1133 ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' 1134 ' }),\n' 1135 ' suites = [\n' 1136 ' "host-unit-tests",\n' 1137 ' ],\n' 1138 ')\n' 1139 ) 1140 1141 def test_create_symlinks_to_testcases_for_multi_config_test_module(self): 1142 module_name = 'hello_world_test' 1143 mod_info = self.create_module_info( 1144 modules=[multi_config(supported_test_module(name=module_name))] 1145 ) 1146 module_out_path = self.workspace_out_path.joinpath(module_name) 1147 1148 self.run_generator(mod_info) 1149 1150 self.assertSymlinkTo( 1151 module_out_path.joinpath(f'host/testcases/{module_name}'), 1152 self.host_out_path.joinpath(f'testcases/{module_name}'), 1153 ) 1154 self.assertSymlinkTo( 1155 module_out_path.joinpath(f'device/testcases/{module_name}'), 1156 self.product_out_path.joinpath(f'testcases/{module_name}'), 1157 ) 1158 1159 def test_generate_files_for_host_only_test_module(self): 1160 mod_info = self.create_module_info( 1161 modules=[ 1162 host_only_config(supported_test_module(name='test1')), 1163 ] 1164 ) 1165 1166 self.run_generator(mod_info) 1167 1168 self.assertInBuildFile( 1169 ' files = select({\n' 1170 ' "//bazel/rules:host": glob(["test1/host/**/*"]),\n' 1171 ' }),\n' 1172 ) 1173 1174 def test_generate_files_for_device_only_test_module(self): 1175 mod_info = self.create_module_info( 1176 modules=[ 1177 device_only_config(supported_test_module(name='test1')), 1178 ] 1179 ) 1180 1181 self.run_generator(mod_info) 1182 1183 self.assertInBuildFile( 1184 ' files = select({\n' 1185 ' "//bazel/rules:device": glob(["test1/device/**/*"]),\n' 1186 ' }),\n' 1187 ) 1188 1189 def test_not_create_device_symlinks_for_host_only_test_module(self): 1190 mod_info = self.create_module_info( 1191 modules=[ 1192 host_only_config(supported_test_module(name='test1')), 1193 ] 1194 ) 1195 1196 self.run_generator(mod_info) 1197 1198 self.assertFileNotInWorkspace('test1/device') 1199 1200 def test_not_create_host_symlinks_for_device_test_module(self): 1201 mod_info = self.create_module_info( 1202 modules=[ 1203 device_only_config(supported_test_module(name='test1')), 1204 ] 1205 ) 1206 1207 self.run_generator(mod_info) 1208 1209 self.assertFileNotInWorkspace('test1/host') 1210 1211 1212class ModuleSharedLibGenerationTest(GenerationTestFixture): 1213 """Tests for module shared libs target generation.""" 1214 1215 def test_not_generate_runtime_deps_when_all_configs_incompatible(self): 1216 mod_info = self.create_module_info( 1217 modules=[ 1218 host_only_config(supported_test_module(shared_libs=['libdevice'])), 1219 device_only_config(module(name='libdevice')), 1220 ] 1221 ) 1222 1223 self.run_generator(mod_info) 1224 1225 self.assertNotInBuildFile('runtime_deps') 1226 1227 def test_generate_runtime_deps_when_configs_compatible(self): 1228 mod_info = self.create_module_info( 1229 modules=[ 1230 multi_config(supported_test_module(shared_libs=['libmulti'])), 1231 multi_config_module(name='libmulti'), 1232 ] 1233 ) 1234 1235 self.run_generator(mod_info) 1236 1237 self.assertInBuildFile( 1238 ' runtime_deps = select({\n' 1239 ' "//bazel/rules:device": [\n' 1240 ' "//:libmulti",\n' 1241 ' ],\n' 1242 ' "//bazel/rules:host": [\n' 1243 ' "//:libmulti",\n' 1244 ' ],\n' 1245 ' }),\n' 1246 ) 1247 1248 def test_generate_runtime_deps_when_configs_partially_compatible(self): 1249 mod_info = self.create_module_info( 1250 modules=[ 1251 multi_config( 1252 supported_test_module( 1253 shared_libs=[ 1254 'libhost', 1255 ] 1256 ) 1257 ), 1258 host_module(name='libhost'), 1259 ] 1260 ) 1261 1262 self.run_generator(mod_info) 1263 1264 self.assertInBuildFile( 1265 ' runtime_deps = select({\n' 1266 ' "//bazel/rules:device": [\n' 1267 ' ],\n' 1268 ' "//bazel/rules:host": [\n' 1269 ' "//:libhost",\n' 1270 ' ],\n' 1271 ' }),\n' 1272 ) 1273 1274 def test_generate_runtime_deps_with_mixed_compatibility(self): 1275 mod_info = self.create_module_info( 1276 modules=[ 1277 multi_config( 1278 supported_test_module( 1279 shared_libs=['libhost', 'libdevice', 'libmulti'] 1280 ) 1281 ), 1282 host_module(name='libhost'), 1283 device_module(name='libdevice'), 1284 multi_config_module(name='libmulti'), 1285 ] 1286 ) 1287 1288 self.run_generator(mod_info) 1289 1290 self.assertInBuildFile( 1291 ' runtime_deps = select({\n' 1292 ' "//bazel/rules:device": [\n' 1293 ' "//:libdevice",\n' 1294 ' "//:libmulti",\n' 1295 ' ],\n' 1296 ' "//bazel/rules:host": [\n' 1297 ' "//:libhost",\n' 1298 ' "//:libmulti",\n' 1299 ' ],\n' 1300 ' }),\n' 1301 ) 1302 1303 def test_generate_runtime_deps_recursively(self): 1304 mod_info = self.create_module_info( 1305 modules=[ 1306 multi_config( 1307 supported_test_module( 1308 shared_libs=[ 1309 'libdirect', 1310 ] 1311 ) 1312 ), 1313 multi_config_module( 1314 name='libdirect', 1315 shared_libs=[ 1316 'libtransitive', 1317 ], 1318 ), 1319 multi_config_module(name='libtransitive'), 1320 ] 1321 ) 1322 1323 self.run_generator(mod_info) 1324 1325 self.assertTargetInWorkspace('libtransitive') 1326 1327 def test_generate_shared_runtime_deps_once(self): 1328 mod_info = self.create_module_info( 1329 modules=[ 1330 multi_config( 1331 supported_test_module( 1332 shared_libs=[ 1333 'libleft', 1334 'libright', 1335 ] 1336 ) 1337 ), 1338 multi_config_module( 1339 name='libleft', 1340 shared_libs=[ 1341 'libshared', 1342 ], 1343 ), 1344 multi_config_module( 1345 name='libright', 1346 shared_libs=[ 1347 'libshared', 1348 ], 1349 ), 1350 multi_config_module(name='libshared'), 1351 ] 1352 ) 1353 1354 self.run_generator(mod_info) 1355 1356 self.assertTargetInWorkspace('libshared') 1357 1358 def test_generate_runtime_deps_in_order(self): 1359 mod_info = self.create_module_info( 1360 modules=[ 1361 supported_test_module(shared_libs=['libhello2', 'libhello1']), 1362 host_module(name='libhello1'), 1363 host_module(name='libhello2'), 1364 ] 1365 ) 1366 1367 self.run_generator(mod_info) 1368 1369 self.assertInBuildFile( 1370 ' "//:libhello1",\n "//:libhello2",\n' 1371 ) 1372 1373 def test_generate_target_for_shared_lib(self): 1374 mod_info = self.create_module_info( 1375 modules=[ 1376 supported_test_module(shared_libs=['libhello']), 1377 host_module(name='libhello'), 1378 ] 1379 ) 1380 1381 self.run_generator(mod_info) 1382 1383 self.assertTargetInWorkspace('libhello') 1384 1385 def test_not_generate_for_missing_shared_lib_module(self): 1386 mod_info = self.create_module_info( 1387 modules=[supported_test_module(shared_libs=['libhello'])] 1388 ) 1389 1390 self.run_generator(mod_info) 1391 1392 self.assertNotInBuildFile(' "//:libhello",\n') 1393 self.assertTargetNotInWorkspace('libhello') 1394 1395 def test_not_generate_when_shared_lib_uninstalled(self): 1396 mod_info = self.create_module_info( 1397 modules=[ 1398 supported_test_module(shared_libs=['libhello']), 1399 host_module(name='libhello', installed=[]), 1400 ] 1401 ) 1402 1403 self.run_generator(mod_info) 1404 1405 self.assertNotInBuildFile(' "//:libhello",\n') 1406 self.assertTargetNotInWorkspace('libhello') 1407 1408 def test_not_generate_when_shared_lib_installed_path_unsupported(self): 1409 unsupported_install_path = 'out/other' 1410 mod_info = self.create_module_info( 1411 modules=[ 1412 supported_test_module(shared_libs=['libhello']), 1413 shared_lib( 1414 module('libhello', installed=[unsupported_install_path]) 1415 ), 1416 ] 1417 ) 1418 1419 self.run_generator(mod_info) 1420 1421 self.assertNotInBuildFile('"//:libhello",\n') 1422 self.assertTargetNotInWorkspace('libhello') 1423 1424 def test_not_generate_when_shared_lib_install_path_ambiguous(self): 1425 ambiguous_install_path = 'out/f1' 1426 mod_info = self.create_module_info( 1427 modules=[ 1428 supported_test_module(shared_libs=['libhello']), 1429 module(name='libhello', installed=[ambiguous_install_path]), 1430 ] 1431 ) 1432 1433 self.run_generator(mod_info) 1434 1435 self.assertNotInBuildFile('"//:libhello",\n') 1436 self.assertTargetNotInWorkspace('libhello') 1437 1438 def test_generate_target_for_rlib_dependency(self): 1439 mod_info = self.create_module_info( 1440 modules=[ 1441 multi_config( 1442 host_unit_suite( 1443 module( 1444 name='hello_world_test', 1445 dependencies=['libhost', 'libdevice'], 1446 ) 1447 ) 1448 ), 1449 rlib(module(name='libhost', supported_variants=['HOST'])), 1450 rlib(module(name='libdevice', supported_variants=['DEVICE'])), 1451 ] 1452 ) 1453 1454 self.run_generator(mod_info) 1455 1456 self.assertInBuildFile( 1457 'soong_uninstalled_prebuilt(\n' 1458 ' name = "libhost",\n' 1459 ' module_name = "libhost",\n' 1460 ')\n' 1461 ) 1462 self.assertInBuildFile( 1463 'soong_uninstalled_prebuilt(\n' 1464 ' name = "libdevice",\n' 1465 ' module_name = "libdevice",\n' 1466 ')\n' 1467 ) 1468 self.assertInBuildFile( 1469 ' runtime_deps = select({\n' 1470 ' "//bazel/rules:device": [\n' 1471 ' "//:libdevice",\n' 1472 ' ],\n' 1473 ' "//bazel/rules:host": [\n' 1474 ' "//:libhost",\n' 1475 ' ],\n' 1476 ' }),\n' 1477 ) 1478 1479 def test_generate_target_for_rlib_dylib_dependency(self): 1480 mod_info = self.create_module_info( 1481 modules=[ 1482 supported_test_module(dependencies=['libhello']), 1483 rlib(module(name='libhello', dependencies=['libworld'])), 1484 host_only_config(dylib(module(name='libworld'))), 1485 ] 1486 ) 1487 1488 self.run_generator(mod_info) 1489 1490 self.assertTargetInWorkspace('libworld') 1491 1492 def test_generate_target_for_dylib_dependency(self): 1493 mod_info = self.create_module_info( 1494 modules=[ 1495 supported_test_module(dependencies=['libhello']), 1496 host_only_config(dylib(module(name='libhello'))), 1497 ] 1498 ) 1499 1500 self.run_generator(mod_info) 1501 1502 self.assertInBuildFile( 1503 'soong_prebuilt(\n' 1504 ' name = "libhello",\n' 1505 ' module_name = "libhello",\n' 1506 ) 1507 1508 def test_generate_target_for_uninstalled_dylib_dependency(self): 1509 mod_info = self.create_module_info( 1510 modules=[ 1511 supported_test_module(dependencies=['libhello']), 1512 dylib(module(name='libhello', installed=[])), 1513 ] 1514 ) 1515 1516 self.run_generator(mod_info) 1517 1518 self.assertInBuildFile( 1519 'soong_uninstalled_prebuilt(\n' 1520 ' name = "libhello",\n' 1521 ' module_name = "libhello",\n' 1522 ')\n' 1523 ) 1524 1525 def test_not_generate_target_for_non_runtime_dependency(self): 1526 mod_info = self.create_module_info( 1527 modules=[ 1528 supported_test_module(dependencies=['libhello']), 1529 host_module(name='libhello', classes=['NOT_SUPPORTED']), 1530 ] 1531 ) 1532 1533 self.run_generator(mod_info) 1534 1535 self.assertNotInBuildFile('"//:libhello",\n') 1536 self.assertTargetNotInWorkspace('libhello') 1537 1538 def test_generate_target_for_runtime_dependency(self): 1539 mod_info = self.create_module_info( 1540 modules=[ 1541 supported_test_module(runtime_dependencies=['libhello']), 1542 host_only_config( 1543 module(name='libhello', classes=['SHARED_LIBRARIES']) 1544 ), 1545 ] 1546 ) 1547 1548 self.run_generator(mod_info) 1549 1550 self.assertInBuildFile( 1551 ' runtime_deps = select({\n' 1552 ' "//bazel/rules:host": [\n' 1553 ' "//:libhello",\n' 1554 ' ],\n' 1555 ' }),\n' 1556 ) 1557 1558 1559class SharedLibPrebuiltTargetGenerationTest(GenerationTestFixture): 1560 """Tests for runtime dependency module prebuilt target generation.""" 1561 1562 def test_create_multi_config_target_symlinks(self): 1563 host_file1 = self.host_out_path.joinpath('a/b/f1') 1564 host_file2 = self.host_out_path.joinpath('a/c/f2') 1565 device_file1 = self.product_out_path.joinpath('a/b/f1') 1566 mod_info = self.create_module_info( 1567 modules=[ 1568 supported_test_module(shared_libs=['libhello']), 1569 multi_config_module( 1570 name='libhello', 1571 installed=[str(host_file1), str(host_file2), str(device_file1)], 1572 ), 1573 ] 1574 ) 1575 package_path = self.workspace_out_path 1576 1577 self.run_generator(mod_info) 1578 1579 self.assertSymlinkTo( 1580 package_path.joinpath('libhello/host/a/b/f1'), host_file1 1581 ) 1582 self.assertSymlinkTo( 1583 package_path.joinpath('libhello/host/a/c/f2'), host_file2 1584 ) 1585 self.assertSymlinkTo( 1586 package_path.joinpath('libhello/device/a/b/f1'), device_file1 1587 ) 1588 1589 def test_create_symlinks_to_installed_path_for_non_tf_testable_deps(self): 1590 host_file = self.host_out_path.joinpath('a/b/f1') 1591 mod_info = self.create_module_info( 1592 modules=[ 1593 supported_test_module(shared_libs=['libhello']), 1594 host_module( 1595 name='libhello', 1596 installed=[str(host_file)], 1597 ), 1598 ] 1599 ) 1600 package_path = self.workspace_out_path 1601 1602 self.run_generator(mod_info) 1603 1604 self.assertSymlinkTo( 1605 package_path.joinpath('libhello/host/a/b/f1'), host_file 1606 ) 1607 1608 def test_create_symlinks_to_installed_path_for_lib_with_test_config(self): 1609 host_file = self.host_out_path.joinpath('a/b/f1') 1610 mod_info = self.create_module_info( 1611 modules=[ 1612 supported_test_module(shared_libs=['libhello']), 1613 host_module( 1614 name='libhello', installed=[str(host_file)], path='src/lib' 1615 ), 1616 ] 1617 ) 1618 self.fs.create_file(Path('src/lib/AndroidTest.xml'), contents='') 1619 package_path = self.workspace_out_path 1620 1621 self.run_generator(mod_info) 1622 1623 self.assertSymlinkTo( 1624 package_path.joinpath('src/lib/libhello/host/a/b/f1'), host_file 1625 ) 1626 1627 def test_generate_for_host_only_shared_lib_dependency(self): 1628 mod_info = self.create_module_info( 1629 modules=[ 1630 supported_test_module(shared_libs=['libhello']), 1631 host_module(name='libhello'), 1632 ] 1633 ) 1634 1635 self.run_generator(mod_info) 1636 1637 self.assertInBuildFile( 1638 ' files = select({\n' 1639 ' "//bazel/rules:host": glob(["libhello/host/**/*"]),\n' 1640 ' }),\n' 1641 ) 1642 self.assertFileNotInWorkspace('libhello/device') 1643 1644 def test_generate_for_device_only_shared_lib_dependency(self): 1645 mod_info = self.create_module_info( 1646 modules=[ 1647 supported_test_module(shared_libs=['libhello']), 1648 device_module(name='libhello'), 1649 ] 1650 ) 1651 1652 self.run_generator(mod_info) 1653 1654 self.assertInBuildFile( 1655 ' files = select({\n' 1656 ' "//bazel/rules:device": glob(["libhello/device/**/*"]),\n' 1657 ' }),\n' 1658 ) 1659 self.assertFileNotInWorkspace('libhello/host') 1660 1661 1662class DataDependenciesGenerationTest(GenerationTestFixture): 1663 """Tests for module data dependencies target generation.""" 1664 1665 def test_generate_target_for_data_dependency(self): 1666 mod_info = self.create_module_info( 1667 modules=[ 1668 supported_test_module(data_dependencies=['libdata']), 1669 host_module(name='libdata'), 1670 ] 1671 ) 1672 1673 self.run_generator(mod_info) 1674 1675 self.assertInBuildFile( 1676 ' data = select({\n' 1677 ' "//bazel/rules:host": [\n' 1678 ' "//:libdata",\n' 1679 ' ],\n' 1680 ' }),\n' 1681 ) 1682 self.assertTargetInWorkspace('libdata') 1683 1684 def test_not_generate_target_for_data_file(self): 1685 # Data files are included in "data", but not in "data_dependencies". 1686 mod_info = self.create_module_info( 1687 modules=[ 1688 supported_test_module(data=['libdata']), 1689 host_module(name='libdata'), 1690 ] 1691 ) 1692 1693 self.run_generator(mod_info) 1694 1695 self.assertTargetNotInWorkspace('libdata') 1696 1697 1698def create_empty_module_info(): 1699 return module_info.load_from_dict({}) 1700 1701 1702def create_module_info(modules=None): 1703 mod_info = create_empty_module_info() 1704 modules = modules or [] 1705 1706 for m in modules: 1707 mod_info.name_to_module_info[m['module_name']] = m 1708 1709 return mod_info 1710 1711 1712def host_unit_test_module(**kwargs): 1713 return host_unit_suite(host_test_module(**kwargs)) 1714 1715 1716# We use the below alias in situations where the actual type is irrelevant to 1717# the test as long as it is supported in Bazel mode. 1718supported_test_module = host_unit_test_module 1719 1720 1721def host_test_module(**kwargs): 1722 kwargs.setdefault('name', 'hello_world_test') 1723 return host_only_config(test_module(**kwargs)) 1724 1725 1726def device_test_module(**kwargs): 1727 kwargs.setdefault('name', 'hello_world_test') 1728 return device_only_config(test_module(**kwargs)) 1729 1730 1731def robolectric_test_module(**kwargs): 1732 kwargs.setdefault('name', 'hello_world_test') 1733 return host_only_config(robolectric(test_module(**kwargs))) 1734 1735 1736def host_module(**kwargs): 1737 m = module(**kwargs) 1738 1739 if 'installed' in kwargs: 1740 return m 1741 1742 return host_only_config(m) 1743 1744 1745def device_module(**kwargs): 1746 m = module(**kwargs) 1747 1748 if 'installed' in kwargs: 1749 return m 1750 1751 return device_only_config(m) 1752 1753 1754def multi_config_module(**kwargs): 1755 m = module(**kwargs) 1756 1757 if 'installed' in kwargs: 1758 return m 1759 1760 return multi_config(m) 1761 1762 1763def test_module(**kwargs): 1764 kwargs.setdefault('name', 'hello_world_test') 1765 return test(module(**kwargs)) 1766 1767 1768# TODO(b/274822450): Using a builder pattern to reduce the number of parameters 1769# instead of disabling the warning. 1770# pylint: disable=too-many-arguments 1771# pylint: disable=too-many-locals 1772def module( 1773 name=None, 1774 path=None, 1775 installed=None, 1776 classes=None, 1777 auto_test_config=None, 1778 shared_libs=None, 1779 dependencies=None, 1780 runtime_dependencies=None, 1781 data=None, 1782 data_dependencies=None, 1783 compatibility_suites=None, 1784 host_dependencies=None, 1785 target_dependencies=None, 1786 test_options_tags=None, 1787 supported_variants=None, 1788): 1789 name = name or 'libhello' 1790 1791 m = {} 1792 1793 m['module_name'] = name 1794 m['class'] = classes or [''] 1795 m['path'] = [path or ''] 1796 m['installed'] = installed or [] 1797 m['is_unit_test'] = 'false' 1798 m['auto_test_config'] = auto_test_config or [] 1799 m['shared_libs'] = shared_libs or [] 1800 m['runtime_dependencies'] = runtime_dependencies or [] 1801 m['dependencies'] = dependencies or [] 1802 m['data'] = data or [] 1803 m['data_dependencies'] = data_dependencies or [] 1804 m['compatibility_suites'] = compatibility_suites or [] 1805 m['host_dependencies'] = host_dependencies or [] 1806 m['target_dependencies'] = target_dependencies or [] 1807 m['test_options_tags'] = test_options_tags or [] 1808 m['supported_variants'] = supported_variants or [] 1809 return m 1810 1811 1812def test(info): 1813 info['auto_test_config'] = ['true'] 1814 return info 1815 1816 1817def shared_lib(info): 1818 info['class'] = ['SHARED_LIBRARIES'] 1819 return info 1820 1821 1822def rlib(info): 1823 info['class'] = ['RLIB_LIBRARIES'] 1824 info['installed'] = [] 1825 return info 1826 1827 1828def dylib(info): 1829 info['class'] = ['DYLIB_LIBRARIES'] 1830 return info 1831 1832 1833def robolectric(info): 1834 info['class'] = ['ROBOLECTRIC'] 1835 return info 1836 1837 1838def host_unit_suite(info): 1839 info = test(info) 1840 info.setdefault('compatibility_suites', []).append('host-unit-tests') 1841 return info 1842 1843 1844def multi_config(info): 1845 name = info.get('module_name', 'lib') 1846 info['installed'] = [ 1847 f'out/host/linux-x86/{name}/{name}.jar', 1848 f'out/product/vsoc_x86/{name}/{name}.apk', 1849 ] 1850 info['supported_variants'] = [ 1851 'DEVICE', 1852 'HOST', 1853 ] 1854 return info 1855 1856 1857def host_only_config(info): 1858 name = info.get('module_name', 'lib') 1859 info['installed'] = [ 1860 f'out/host/linux-x86/{name}/{name}.jar', 1861 ] 1862 info['supported_variants'] = [ 1863 'HOST', 1864 ] 1865 return info 1866 1867 1868def device_only_config(info): 1869 name = info.get('module_name', 'lib') 1870 info['installed'] = [ 1871 f'out/product/vsoc_x86/{name}/{name}.jar', 1872 ] 1873 info['supported_variants'] = [ 1874 'DEVICE', 1875 ] 1876 return info 1877 1878 1879class PackageTest(fake_filesystem_unittest.TestCase): 1880 """Tests for Package.""" 1881 1882 class FakeTarget(bazel_mode.Target): 1883 """Fake target used for tests.""" 1884 1885 def __init__(self, name, imports=None): 1886 self._name = name 1887 self._imports = imports or set() 1888 1889 def name(self): 1890 return self._name 1891 1892 def required_imports(self): 1893 return self._imports 1894 1895 def write_to_build_file(self, f): 1896 f.write(f'{self._name}\n') 1897 1898 def setUp(self): 1899 self.setUpPyfakefs() 1900 self.workspace_out_path = Path('/workspace_out_path') 1901 self.workspace_out_path.mkdir() 1902 1903 def test_raise_when_adding_existing_target(self): 1904 target_name = '<fake_target>' 1905 package = bazel_mode.Package('p') 1906 package.add_target(self.FakeTarget(target_name)) 1907 1908 with self.assertRaises(Exception) as context: 1909 package.add_target(self.FakeTarget(target_name)) 1910 1911 self.assertIn(target_name, str(context.exception)) 1912 1913 def test_write_build_file_in_package_dir(self): 1914 package_path = 'abc/def' 1915 package = bazel_mode.Package(package_path) 1916 expected_path = self.workspace_out_path.joinpath( 1917 package_path, 'BUILD.bazel' 1918 ) 1919 1920 package.generate(self.workspace_out_path) 1921 1922 self.assertTrue(expected_path.exists()) 1923 1924 def test_write_load_statements_in_sorted_order(self): 1925 package = bazel_mode.Package('p') 1926 target1 = self.FakeTarget( 1927 'target1', 1928 imports={ 1929 bazel_mode.Import('z.bzl', 'symbol1'), 1930 }, 1931 ) 1932 target2 = self.FakeTarget( 1933 'target2', 1934 imports={ 1935 bazel_mode.Import('a.bzl', 'symbol2'), 1936 }, 1937 ) 1938 package.add_target(target1) 1939 package.add_target(target2) 1940 1941 package.generate(self.workspace_out_path) 1942 1943 self.assertIn( 1944 'load("a.bzl", "symbol2")\nload("z.bzl", "symbol1")\n\n', 1945 self.package_build_file_text(package), 1946 ) 1947 1948 def test_write_load_statements_with_symbols_grouped_by_bzl(self): 1949 package = bazel_mode.Package('p') 1950 target1 = self.FakeTarget( 1951 'target1', 1952 imports={ 1953 bazel_mode.Import('a.bzl', 'symbol1'), 1954 bazel_mode.Import('a.bzl', 'symbol3'), 1955 }, 1956 ) 1957 target2 = self.FakeTarget( 1958 'target2', 1959 imports={ 1960 bazel_mode.Import('a.bzl', 'symbol2'), 1961 }, 1962 ) 1963 package.add_target(target1) 1964 package.add_target(target2) 1965 1966 package.generate(self.workspace_out_path) 1967 1968 self.assertIn( 1969 'load("a.bzl", "symbol1", "symbol2", "symbol3")\n\n', 1970 self.package_build_file_text(package), 1971 ) 1972 1973 def test_write_targets_in_add_order(self): 1974 package = bazel_mode.Package('p') 1975 target1 = self.FakeTarget('target1') 1976 target2 = self.FakeTarget('target2') 1977 package.add_target(target2) # Added out of order. 1978 package.add_target(target1) 1979 1980 package.generate(self.workspace_out_path) 1981 1982 self.assertIn('target2\n\ntarget1\n', self.package_build_file_text(package)) 1983 1984 def test_generate_parent_package_when_nested_exists(self): 1985 parent_path = Path('parent') 1986 parent = bazel_mode.Package(parent_path.name) 1987 nested = bazel_mode.Package(parent_path.joinpath('nested')) 1988 nested.generate(self.workspace_out_path) 1989 1990 parent.generate(self.workspace_out_path) 1991 1992 self.assertTrue(self.workspace_out_path.joinpath(parent_path).is_dir()) 1993 1994 def package_build_file_text(self, package): 1995 return self.workspace_out_path.joinpath( 1996 package.path, 'BUILD.bazel' 1997 ).read_text(encoding='utf8') 1998 1999 2000class DecorateFinderMethodTest(GenerationTestFixture): 2001 """Tests for _decorate_find_method().""" 2002 2003 def test_host_unit_test_with_host_arg_runner_is_overridden(self): 2004 def original_find_method(obj, test_id): 2005 return self.create_single_test_infos( 2006 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2007 ) 2008 2009 mod_info = self.create_module_info( 2010 modules=[host_unit_test_module(name=MODULE_NAME)] 2011 ) 2012 original_finder = self.create_finder(mod_info, original_find_method) 2013 new_finder = bazel_mode.create_new_finder( 2014 mod_info, original_finder, host=True 2015 ) 2016 2017 test_infos = new_finder.find_method( 2018 new_finder.test_finder_instance, MODULE_NAME 2019 ) 2020 2021 self.assertEqual(len(test_infos), 1) 2022 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2023 2024 def test_host_unit_test_without_host_arg_runner_is_overridden(self): 2025 def original_find_method(obj, test_id): 2026 return self.create_single_test_infos( 2027 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2028 ) 2029 2030 mod_info = self.create_module_info( 2031 modules=[host_unit_test_module(name=MODULE_NAME)] 2032 ) 2033 original_finder = self.create_finder(mod_info, original_find_method) 2034 new_finder = bazel_mode.create_new_finder( 2035 mod_info, original_finder, host=False 2036 ) 2037 2038 test_infos = new_finder.find_method( 2039 new_finder.test_finder_instance, MODULE_NAME 2040 ) 2041 2042 self.assertEqual(len(test_infos), 1) 2043 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2044 2045 def test_device_test_with_host_arg_runner_is_preserved(self): 2046 def original_find_method(obj, test_id): 2047 return self.create_single_test_infos( 2048 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2049 ) 2050 2051 mod_info = self.create_module_info( 2052 modules=[device_test_module(name=MODULE_NAME)] 2053 ) 2054 original_finder = self.create_finder(mod_info, original_find_method) 2055 new_finder = bazel_mode.create_new_finder( 2056 mod_info, 2057 original_finder, 2058 host=True, 2059 enabled_features=[bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST], 2060 ) 2061 2062 test_infos = new_finder.find_method( 2063 new_finder.test_finder_instance, MODULE_NAME 2064 ) 2065 2066 self.assertEqual(len(test_infos), 1) 2067 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 2068 2069 def test_device_test_without_host_arg_runner_is_overridden(self): 2070 def original_find_method(obj, test_id): 2071 return self.create_single_test_infos( 2072 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2073 ) 2074 2075 mod_info = self.create_module_info( 2076 modules=[device_test_module(name=MODULE_NAME)] 2077 ) 2078 original_finder = self.create_finder(mod_info, original_find_method) 2079 new_finder = bazel_mode.create_new_finder( 2080 mod_info, 2081 original_finder, 2082 host=False, 2083 enabled_features=[bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST], 2084 ) 2085 2086 test_infos = new_finder.find_method( 2087 new_finder.test_finder_instance, MODULE_NAME 2088 ) 2089 2090 self.assertEqual(len(test_infos), 1) 2091 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2092 2093 def test_multi_config_test_with_host_arg_runner_is_overridden(self): 2094 def original_find_method(obj, test_id): 2095 return self.create_single_test_infos( 2096 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2097 ) 2098 2099 mod_info = self.create_module_info( 2100 modules=[multi_config(supported_test_module(name=MODULE_NAME))] 2101 ) 2102 original_finder = self.create_finder(mod_info, original_find_method) 2103 new_finder = bazel_mode.create_new_finder( 2104 mod_info, 2105 original_finder, 2106 host=True, 2107 enabled_features=[bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST], 2108 ) 2109 2110 test_infos = new_finder.find_method( 2111 new_finder.test_finder_instance, MODULE_NAME 2112 ) 2113 2114 self.assertEqual(len(test_infos), 1) 2115 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2116 2117 def test_multi_config_test_without_host_arg_runner_is_overridden(self): 2118 def original_find_method(obj, test_id): 2119 return self.create_single_test_infos( 2120 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2121 ) 2122 2123 mod_info = self.create_module_info( 2124 modules=[multi_config(supported_test_module(name=MODULE_NAME))] 2125 ) 2126 original_finder = self.create_finder(mod_info, original_find_method) 2127 new_finder = bazel_mode.create_new_finder( 2128 mod_info, 2129 original_finder, 2130 host=False, 2131 enabled_features=[bazel_mode.Features.EXPERIMENTAL_DEVICE_DRIVEN_TEST], 2132 ) 2133 2134 test_infos = new_finder.find_method( 2135 new_finder.test_finder_instance, MODULE_NAME 2136 ) 2137 2138 self.assertEqual(len(test_infos), 1) 2139 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2140 2141 def test_host_non_unit_test_with_host_arg_runner_is_overridden(self): 2142 def original_find_method(obj, test_id): 2143 return self.create_single_test_infos( 2144 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2145 ) 2146 2147 mod_info = self.create_module_info( 2148 modules=[host_test_module(name=MODULE_NAME)] 2149 ) 2150 original_finder = self.create_finder(mod_info, original_find_method) 2151 new_finder = bazel_mode.create_new_finder( 2152 mod_info, 2153 original_finder, 2154 host=True, 2155 enabled_features=[bazel_mode.Features.EXPERIMENTAL_HOST_DRIVEN_TEST], 2156 ) 2157 2158 test_infos = new_finder.find_method( 2159 new_finder.test_finder_instance, MODULE_NAME 2160 ) 2161 2162 self.assertEqual(len(test_infos), 1) 2163 self.assertEqual(test_infos[0].test_runner, BAZEL_RUNNER) 2164 2165 def test_disable_device_driven_test_feature_runner_is_preserved(self): 2166 def original_find_method(obj, test_id): 2167 return self.create_single_test_infos( 2168 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2169 ) 2170 2171 mod_info = self.create_module_info( 2172 modules=[device_test_module(name=MODULE_NAME)] 2173 ) 2174 original_finder = self.create_finder(mod_info, original_find_method) 2175 new_finder = bazel_mode.create_new_finder( 2176 mod_info, original_finder, host=False 2177 ) 2178 2179 test_infos = new_finder.find_method( 2180 new_finder.test_finder_instance, MODULE_NAME 2181 ) 2182 2183 self.assertEqual(len(test_infos), 1) 2184 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 2185 2186 def test_disable_host_driven_test_feature_runner_is_preserved(self): 2187 def original_find_method(obj, test_id): 2188 return self.create_single_test_infos( 2189 obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2190 ) 2191 2192 mod_info = self.create_module_info( 2193 modules=[host_test_module(name=MODULE_NAME)] 2194 ) 2195 original_finder = self.create_finder(mod_info, original_find_method) 2196 new_finder = bazel_mode.create_new_finder( 2197 mod_info, original_finder, host=True 2198 ) 2199 2200 test_infos = new_finder.find_method( 2201 new_finder.test_finder_instance, MODULE_NAME 2202 ) 2203 2204 self.assertEqual(len(test_infos), 1) 2205 self.assertEqual(test_infos[0].test_runner, ATEST_TF_RUNNER) 2206 2207 # pylint: disable=unused-argument 2208 def create_single_test_infos( 2209 self, obj, test_id, test_name=MODULE_NAME, runner=ATEST_TF_RUNNER 2210 ): 2211 """Create list of test_info.TestInfo.""" 2212 return [test_info.TestInfo(test_name, runner, MODULE_BUILD_TARGETS)] 2213 2214 def create_finder(self, mod_info, find_method): 2215 return test_finder_base.Finder( 2216 example_finder.ExampleFinder(mod_info), find_method, 'FINDER_NAME' 2217 ) 2218 2219 2220class BazelTestRunnerTest(fake_filesystem_unittest.TestCase): 2221 """Tests for BazelTestRunner.""" 2222 2223 def test_return_empty_build_reqs_when_no_test_infos(self): 2224 run_command = self.mock_run_command(side_effect=Exception('')) 2225 runner = self.create_bazel_test_runner( 2226 modules=[ 2227 supported_test_module(name='test1', path='path1'), 2228 ], 2229 run_command=run_command, 2230 ) 2231 2232 reqs = runner.get_test_runner_build_reqs([]) 2233 2234 self.assertFalse(reqs) 2235 2236 def test_query_bazel_test_targets_deps_with_host_arg(self): 2237 query_file_contents = StringIO() 2238 2239 def get_query_file_content(args: List[str], _) -> str: 2240 query_file_contents.write(_get_query_file_content(args)) 2241 return '' 2242 2243 runner = self.create_bazel_test_runner( 2244 modules=[ 2245 multi_config(host_unit_test_module(name='test1', path='path1')), 2246 multi_config(host_unit_test_module(name='test2', path='path2')), 2247 multi_config(test_module(name='test3', path='path3')), 2248 ], 2249 run_command=get_query_file_content, 2250 host=True, 2251 ) 2252 2253 runner.get_test_runner_build_reqs([ 2254 test_info_of('test2'), 2255 test_info_of('test1'), # Intentionally out of order. 2256 test_info_of('test3'), 2257 ]) 2258 2259 self.assertEqual( 2260 'deps(tests(//path1:test1_host + ' 2261 '//path2:test2_host + ' 2262 '//path3:test3_host))', 2263 query_file_contents.getvalue(), 2264 ) 2265 2266 def test_query_bazel_test_targets_deps_without_host_arg(self): 2267 query_file_contents = StringIO() 2268 2269 def get_query_file_content(args: List[str], _) -> str: 2270 query_file_contents.write(_get_query_file_content(args)) 2271 return '' 2272 2273 runner = self.create_bazel_test_runner( 2274 modules=[ 2275 multi_config(host_unit_test_module(name='test1', path='path1')), 2276 host_unit_test_module(name='test2', path='path2'), 2277 multi_config(test_module(name='test3', path='path3')), 2278 ], 2279 run_command=get_query_file_content, 2280 ) 2281 2282 runner.get_test_runner_build_reqs([ 2283 test_info_of('test2'), 2284 test_info_of('test1'), 2285 test_info_of('test3'), 2286 ]) 2287 2288 self.assertEqual( 2289 'deps(tests(//path1:test1_device + ' 2290 '//path2:test2_host + ' 2291 '//path3:test3_device))', 2292 query_file_contents.getvalue(), 2293 ) 2294 2295 def test_trim_whitespace_in_bazel_query_output(self): 2296 run_command = self.mock_run_command( 2297 return_value='\n'.join([' test1:host ', 'test2:device ', ' ']) 2298 ) 2299 runner = self.create_bazel_test_runner( 2300 modules=[ 2301 supported_test_module(name='test1', path='path1'), 2302 ], 2303 run_command=run_command, 2304 ) 2305 2306 reqs = runner.get_test_runner_build_reqs([test_info_of('test1')]) 2307 2308 self.assertSetEqual({'test1-host', 'test2-target'}, reqs) 2309 2310 def test_build_variants_in_bazel_query_output(self): 2311 run_command = self.mock_run_command( 2312 return_value='\n'.join([ 2313 'test1:host', 2314 'test2:host', 2315 'test2:device', 2316 'test3:device', 2317 'test4:host', 2318 'test4:host', 2319 ]) 2320 ) 2321 runner = self.create_bazel_test_runner( 2322 modules=[ 2323 supported_test_module(name='test1', path='path1'), 2324 supported_test_module(name='test2', path='path2'), 2325 supported_test_module(name='test3', path='path3'), 2326 supported_test_module(name='test4', path='path4'), 2327 ], 2328 run_command=run_command, 2329 ) 2330 2331 reqs = runner.get_test_runner_build_reqs([ 2332 test_info_of('test1'), 2333 test_info_of('test2'), 2334 test_info_of('test3'), 2335 test_info_of('test4'), 2336 ]) 2337 2338 self.assertSetEqual( 2339 {'test1-host', 'test2', 'test3-target', 'test4-host'}, reqs 2340 ) 2341 2342 def test_generate_single_run_command(self): 2343 test_infos = [test_info_of('test1')] 2344 runner = self.create_bazel_test_runner_for_tests(test_infos) 2345 2346 cmd = runner.generate_run_commands(test_infos, {}) 2347 2348 self.assertEqual(1, len(cmd)) 2349 2350 def test_generate_run_command_containing_targets_with_host_arg(self): 2351 test_infos = [ 2352 test_info_of('test1'), 2353 test_info_of('test2'), 2354 test_info_of('test3'), 2355 ] 2356 runner = self.create_bazel_test_runner( 2357 [ 2358 multi_config(host_unit_test_module(name='test1', path='path')), 2359 multi_config(host_unit_test_module(name='test2', path='path')), 2360 multi_config(test_module(name='test3', path='path')), 2361 ], 2362 host=True, 2363 ) 2364 2365 cmd = runner.generate_run_commands(test_infos, {}) 2366 2367 self.assertTokensIn( 2368 ['//path:test1_host', '//path:test2_host', '//path:test3_host'], cmd[0] 2369 ) 2370 2371 def test_generate_run_command_containing_targets_without_host_arg(self): 2372 test_infos = [test_info_of('test1'), test_info_of('test2')] 2373 runner = self.create_bazel_test_runner( 2374 [ 2375 multi_config(host_unit_test_module(name='test1', path='path')), 2376 host_unit_test_module(name='test2', path='path'), 2377 ], 2378 ) 2379 2380 cmd = runner.generate_run_commands(test_infos, {}) 2381 2382 self.assertTokensIn(['//path:test1_device', '//path:test2_host'], cmd[0]) 2383 2384 def test_generate_run_command_with_multi_bazel_args(self): 2385 test_infos = [test_info_of('test1')] 2386 runner = self.create_bazel_test_runner_for_tests(test_infos) 2387 extra_args = { 2388 constants.BAZEL_ARG: [['--option1=value1'], ['--option2=value2']] 2389 } 2390 2391 cmd = runner.generate_run_commands(test_infos, extra_args) 2392 2393 self.assertTokensIn(['--option1=value1', '--option2=value2'], cmd[0]) 2394 2395 def test_generate_run_command_with_multi_custom_args(self): 2396 test_infos = [test_info_of('test1')] 2397 runner = self.create_bazel_test_runner_for_tests(test_infos) 2398 extra_args = {constants.CUSTOM_ARGS: ['-hello', '--world=value']} 2399 2400 cmd = runner.generate_run_commands(test_infos, extra_args) 2401 2402 self.assertTokensIn( 2403 ['--test_arg=-hello', '--test_arg=--world=value'], cmd[0] 2404 ) 2405 2406 def test_generate_run_command_with_custom_and_bazel_args(self): 2407 test_infos = [test_info_of('test1')] 2408 runner = self.create_bazel_test_runner_for_tests(test_infos) 2409 extra_args = { 2410 constants.CUSTOM_ARGS: ['-hello', '--world=value'], 2411 constants.BAZEL_ARG: [['--option1=value1']], 2412 } 2413 2414 cmd = runner.generate_run_commands(test_infos, extra_args) 2415 2416 self.assertTokensIn( 2417 ['--test_arg=-hello', '--test_arg=--world=value', '--option1=value1'], 2418 cmd[0], 2419 ) 2420 2421 def test_generate_run_command_removes_serial(self): 2422 test_infos = [test_info_of('test1')] 2423 runner = self.create_bazel_test_runner_for_tests(test_infos) 2424 extra_args = {constants.CUSTOM_ARGS: ['--serial=0.0.0.0']} 2425 2426 cmd = runner.generate_run_commands(test_infos, extra_args) 2427 2428 self.assertNotIn('--test-arg=--serial', shlex.split(cmd[0])) 2429 self.assertNotIn('--test-arg=--0.0.0.0', shlex.split(cmd[0])) 2430 2431 def test_generate_run_command_with_tf_supported_all_abi_arg(self): 2432 test_infos = [test_info_of('test1')] 2433 runner = self.create_bazel_test_runner_for_tests(test_infos) 2434 extra_args = {constants.ALL_ABI: True} 2435 2436 cmd = runner.generate_run_commands(test_infos, extra_args) 2437 2438 self.assertTokensIn(['--test_arg=--all-abi'], cmd[0]) 2439 2440 def test_generate_run_command_with_iterations_args(self): 2441 test_infos = [test_info_of('test1')] 2442 runner = self.create_bazel_test_runner_for_tests(test_infos) 2443 extra_args = {constants.ITERATIONS: 2} 2444 2445 cmd = runner.generate_run_commands(test_infos, extra_args) 2446 2447 self.assertTokensIn(['--runs_per_test=2'], cmd[0]) 2448 self.assertNotIn('--test_arg=--retry-strategy', shlex.split(cmd[0])) 2449 2450 def test_generate_run_command_with_testinfo_filter(self): 2451 test_filter = test_filter_of('class1', ['method1']) 2452 test_infos = [test_info_of('test1', test_filters=[test_filter])] 2453 runner = self.create_bazel_test_runner_for_tests(test_infos) 2454 2455 cmd = runner.generate_run_commands(test_infos, {}) 2456 2457 self.assertTokensIn( 2458 [ 2459 '--test_arg=--atest-include-filter', 2460 '--test_arg=test1:class1#method1', 2461 ], 2462 cmd[0], 2463 ) 2464 2465 def test_generate_run_command_with_bes_publish_enabled(self): 2466 test_infos = [test_info_of('test1')] 2467 extra_args = { 2468 constants.BAZEL_MODE_FEATURES: [ 2469 bazel_mode.Features.EXPERIMENTAL_BES_PUBLISH 2470 ] 2471 } 2472 build_metadata = bazel_mode.BuildMetadata( 2473 'master', 'aosp_cf_x86_64_phone-userdebug' 2474 ) 2475 env = { 2476 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2477 'ATEST_BAZEL_BES_PUBLISH_CONFIG': 'bes_publish', 2478 } 2479 runner = self.create_bazel_test_runner_for_tests( 2480 test_infos, build_metadata=build_metadata, env=env 2481 ) 2482 2483 cmd = runner.generate_run_commands( 2484 test_infos, 2485 extra_args, 2486 ) 2487 2488 self.assertTokensIn( 2489 [ 2490 '--bazelrc=/dir/atest.bazelrc', 2491 '--config=bes_publish', 2492 '--build_metadata=ab_branch=master', 2493 '--build_metadata=ab_target=aosp_cf_x86_64_phone-userdebug', 2494 ], 2495 cmd[0], 2496 ) 2497 2498 def test_generate_run_command_with_no_bazel_detailed_summary(self): 2499 test_infos = [test_info_of('test1')] 2500 extra_args = { 2501 constants.BAZEL_MODE_FEATURES: [ 2502 bazel_mode.Features.NO_BAZEL_DETAILED_SUMMARY 2503 ] 2504 } 2505 runner = self.create_bazel_test_runner_for_tests(test_infos) 2506 2507 cmd = runner.generate_run_commands(test_infos, extra_args) 2508 2509 self.assertTokensNotIn( 2510 [ 2511 '--test_summary=detailed', 2512 ], 2513 cmd[0], 2514 ) 2515 2516 def test_generate_run_command_without_no_bazel_detailed_summary(self): 2517 test_infos = [test_info_of('test1')] 2518 extra_args = {} 2519 runner = self.create_bazel_test_runner_for_tests(test_infos) 2520 2521 cmd = runner.generate_run_commands(test_infos, extra_args) 2522 2523 self.assertTokensIn( 2524 [ 2525 '--test_summary=detailed', 2526 ], 2527 cmd[0], 2528 ) 2529 2530 def test_generate_run_command_with_return_until_failure(self): 2531 test_infos = [test_info_of('test1')] 2532 extra_args = {constants.RERUN_UNTIL_FAILURE: 5} 2533 runner = self.create_bazel_test_runner_for_tests(test_infos) 2534 2535 cmd = runner.generate_run_commands(test_infos, extra_args) 2536 2537 self.assertTokensIn( 2538 [ 2539 '--test_arg=--retry-strategy', 2540 '--test_arg=RERUN_UNTIL_FAILURE', 2541 '--test_arg=--max-testcase-run-count', 2542 '--test_arg=5', 2543 ], 2544 cmd[0], 2545 ) 2546 2547 def test_not_zip_test_output_files_when_bes_publish_not_enabled(self): 2548 test_infos = [test_info_of('test1')] 2549 extra_args = {} 2550 runner = self.create_bazel_test_runner_for_tests(test_infos) 2551 2552 cmd = runner.generate_run_commands( 2553 test_infos, 2554 extra_args, 2555 ) 2556 2557 self.assertTokensIn( 2558 [ 2559 '--nozip_undeclared_test_outputs', 2560 ], 2561 cmd[0], 2562 ) 2563 2564 def test_zip_test_output_files_when_bes_publish_enabled(self): 2565 test_infos = [test_info_of('test1')] 2566 extra_args = { 2567 constants.BAZEL_MODE_FEATURES: [ 2568 bazel_mode.Features.EXPERIMENTAL_BES_PUBLISH 2569 ] 2570 } 2571 build_metadata = bazel_mode.BuildMetadata( 2572 'master', 'aosp_cf_x86_64_phone-userdebug' 2573 ) 2574 env = { 2575 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2576 'ATEST_BAZEL_BES_PUBLISH_CONFIG': 'bes_publish', 2577 } 2578 runner = self.create_bazel_test_runner_for_tests( 2579 test_infos, build_metadata=build_metadata, env=env 2580 ) 2581 2582 cmd = runner.generate_run_commands( 2583 test_infos, 2584 extra_args, 2585 ) 2586 2587 self.assertTokensNotIn( 2588 [ 2589 '--nozip_undeclared_test_outputs', 2590 ], 2591 cmd[0], 2592 ) 2593 2594 def test_generate_run_command_with_remote_enabled(self): 2595 test_infos = [test_info_of('test1')] 2596 extra_args = { 2597 constants.BAZEL_MODE_FEATURES: [bazel_mode.Features.EXPERIMENTAL_REMOTE] 2598 } 2599 env = { 2600 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2601 'ATEST_BAZEL_REMOTE_CONFIG': 'remote_deviceless', 2602 } 2603 runner = self.create_bazel_test_runner_for_tests(test_infos, env=env) 2604 2605 cmd = runner.generate_run_commands( 2606 test_infos, 2607 extra_args, 2608 ) 2609 2610 self.assertTokensIn( 2611 [ 2612 '--config=remote_deviceless', 2613 ], 2614 cmd[0], 2615 ) 2616 2617 def test_generate_run_command_with_remote_avd_enabled(self): 2618 test_infos = [test_info_of('test1')] 2619 extra_args = { 2620 constants.BAZEL_MODE_FEATURES: [ 2621 bazel_mode.Features.EXPERIMENTAL_REMOTE_AVD 2622 ] 2623 } 2624 env = { 2625 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2626 'ATEST_BAZEL_REMOTE_AVD_CONFIG': 'remote_avd', 2627 } 2628 runner = self.create_bazel_test_runner_for_tests(test_infos, env=env) 2629 2630 cmd = runner.generate_run_commands( 2631 test_infos, 2632 extra_args, 2633 ) 2634 2635 self.assertTokensIn( 2636 [ 2637 '--config=remote_avd', 2638 ], 2639 cmd[0], 2640 ) 2641 2642 def test_generate_run_command_with_remote_avd_config_not_found(self): 2643 test_infos = [test_info_of('test1')] 2644 extra_args = { 2645 constants.BAZEL_MODE_FEATURES: [ 2646 bazel_mode.Features.EXPERIMENTAL_REMOTE_AVD 2647 ] 2648 } 2649 env = { 2650 'ATEST_BAZELRC': '/dir/atest.bazelrc', 2651 } 2652 runner = self.create_bazel_test_runner_for_tests(test_infos, env=env) 2653 2654 with self.assertRaises(Exception) as context: 2655 runner.generate_run_commands( 2656 test_infos, 2657 extra_args, 2658 ) 2659 2660 self.assertIn( 2661 'ATEST_BAZEL_REMOTE_AVD_CONFIG environment variable is not set.', 2662 str(context.exception), 2663 ) 2664 2665 def test_generate_run_command_with_verbose_args(self): 2666 test_infos = [test_info_of('test1')] 2667 runner = self.create_bazel_test_runner_for_tests(test_infos) 2668 extra_args = {constants.VERBOSE: True} 2669 2670 cmd = runner.generate_run_commands(test_infos, extra_args) 2671 2672 self.assertTokensIn(['--test_output=all'], cmd[0]) 2673 2674 def test_disable_test_result_caching_with_wait_for_debug_args(self): 2675 test_infos = [test_info_of('test1')] 2676 runner = self.create_bazel_test_runner_for_tests(test_infos) 2677 extra_args = {constants.WAIT_FOR_DEBUGGER: True} 2678 2679 cmd = runner.generate_run_commands(test_infos, extra_args) 2680 2681 self.assertTokensIn( 2682 ['--test_arg=--wait-for-debugger', '--cache_test_results=no'], cmd[0] 2683 ) 2684 2685 def test_cache_test_results_arg_not_used_with_wait_for_debug_args(self): 2686 test_infos = [test_info_of('test1')] 2687 runner = self.create_bazel_test_runner_for_tests(test_infos) 2688 extra_args = { 2689 constants.WAIT_FOR_DEBUGGER: True, 2690 constants.BAZEL_ARG: [['--cache_test_resultsfoo']], 2691 } 2692 2693 cmd = runner.generate_run_commands(test_infos, extra_args) 2694 2695 self.assertTokensNotIn(['--cache_test_resultsfoo'], cmd[0]) 2696 2697 def test_retrieve_test_output_info_for_host_test(self): 2698 test_infos = [test_info_of('test1')] 2699 runner = self.create_bazel_test_runner_for_tests(test_infos) 2700 2701 output_file_path, package_name, target_suffix = ( 2702 runner.retrieve_test_output_info(test_infos[0]) 2703 ) 2704 2705 self.assertEqual( 2706 f'/src/workspace/{bazel_mode.BAZEL_TEST_LOGS_DIR_NAME}' 2707 f'/path/test1_host/{bazel_mode.TEST_OUTPUT_DIR_NAME}', 2708 str(output_file_path), 2709 ) 2710 self.assertEqual('path', package_name) 2711 self.assertEqual('host', target_suffix) 2712 2713 def test_retrieve_test_output_info_for_device_driven_test(self): 2714 runner = self.create_bazel_test_runner( 2715 modules=[ 2716 multi_config(device_test_module(name='test1', path='path1')), 2717 ], 2718 ) 2719 2720 output_file_path, package_name, target_suffix = ( 2721 runner.retrieve_test_output_info(test_info_of('test1')) 2722 ) 2723 2724 self.assertEqual( 2725 f'/src/workspace/{bazel_mode.BAZEL_TEST_LOGS_DIR_NAME}' 2726 f'/path1/test1_device/{bazel_mode.TEST_OUTPUT_DIR_NAME}', 2727 str(output_file_path), 2728 ) 2729 self.assertEqual('path1', package_name) 2730 self.assertEqual('device', target_suffix) 2731 2732 def test_result_dir_symlink_to_test_output_dir(self): 2733 self.setUpPyfakefs() 2734 test_infos = [test_info_of('test1')] 2735 runner = self.create_bazel_test_runner_for_tests(test_infos) 2736 2737 runner.organize_test_logs(test_infos) 2738 2739 self.assertSymlinkTo( 2740 Path('result_dir/log/path/test1_host'), 2741 Path( 2742 f'/src/workspace/{bazel_mode.BAZEL_TEST_LOGS_DIR_NAME}' 2743 f'/path/test1_host/{bazel_mode.TEST_OUTPUT_DIR_NAME}' 2744 ), 2745 ) 2746 2747 def test_not_create_result_log_dir_when_test_output_zip_exist(self): 2748 self.setUpPyfakefs() 2749 test_infos = [test_info_of('test1')] 2750 runner = self.create_bazel_test_runner_for_tests(test_infos) 2751 test_output_zip = Path( 2752 f'/src/workspace/{bazel_mode.BAZEL_TEST_LOGS_DIR_NAME}' 2753 f'/path/test1_host/{bazel_mode.TEST_OUTPUT_DIR_NAME}' 2754 f'/{bazel_mode.TEST_OUTPUT_ZIP_NAME}' 2755 ) 2756 self.fs.create_file(test_output_zip, contents='') 2757 2758 runner.organize_test_logs(test_infos) 2759 2760 self.assertFalse(Path('result_dir/log/').exists()) 2761 2762 def test_avoid_result_dir_symlink_duplication(self): 2763 self.setUpPyfakefs() 2764 test_infos = [test_info_of('test1')] 2765 old_symlink_to_dir = Path(tempfile.mkdtemp()) 2766 log_path = Path('result_dir/log/path/test1_host') 2767 log_path.parent.mkdir(parents=True, exist_ok=True) 2768 log_path.symlink_to(old_symlink_to_dir) 2769 runner = self.create_bazel_test_runner_for_tests(test_infos) 2770 2771 runner.organize_test_logs(test_infos) 2772 2773 self.assertSymlinkTo(log_path, old_symlink_to_dir) 2774 2775 def create_bazel_test_runner( 2776 self, 2777 modules, 2778 run_command=None, 2779 host=False, 2780 build_metadata=None, 2781 env=None, 2782 enable_features=None, 2783 ): 2784 return bazel_mode.BazelTestRunner( 2785 'result_dir', 2786 mod_info=create_module_info(modules), 2787 src_top=Path('/src'), 2788 workspace_path=Path('/src/workspace'), 2789 run_command=run_command or self.mock_run_command(), 2790 extra_args={constants.HOST: host}, 2791 build_metadata=build_metadata, 2792 env=env, 2793 generate_workspace_fn=lambda *_: None, 2794 enabled_features=enable_features or [], 2795 ) 2796 2797 def create_bazel_test_runner_for_tests( 2798 self, test_infos, build_metadata=None, env=None 2799 ): 2800 return self.create_bazel_test_runner( 2801 modules=[ 2802 supported_test_module(name=t.test_name, path='path') 2803 for t in test_infos 2804 ], 2805 build_metadata=build_metadata, 2806 env=env, 2807 ) 2808 2809 def create_completed_process(self, args, returncode, stdout): 2810 return subprocess.CompletedProcess(args, returncode, stdout) 2811 2812 def mock_run_command(self, **kwargs): 2813 return mock.create_autospec(bazel_mode.default_run_command, **kwargs) 2814 2815 def assertTokensIn(self, expected_tokens, s): 2816 tokens = shlex.split(s) 2817 for token in expected_tokens: 2818 self.assertIn(token, tokens) 2819 2820 def assertTokensNotIn(self, unexpected_tokens, s): 2821 tokens = shlex.split(s) 2822 for token in unexpected_tokens: 2823 self.assertNotIn(token, tokens) 2824 2825 def assertSymlinkTo(self, symlink_path, target_path): 2826 self.assertEqual(symlink_path.resolve(strict=False), target_path) 2827 2828 2829class FeatureParserTest(unittest.TestCase): 2830 """Tests for parsing Bazel mode feature flags.""" 2831 2832 def test_parse_args_with_bazel_mode_feature(self): 2833 parser = argparse.ArgumentParser() 2834 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 2835 # pylint: disable=no-member 2836 args = parser.parse_args([bazel_mode.Features.NULL_FEATURE.arg_flag]) 2837 2838 self.assertListEqual( 2839 [bazel_mode.Features.NULL_FEATURE], args.bazel_mode_features 2840 ) 2841 2842 def test_parse_args_without_bazel_mode_feature(self): 2843 parser = argparse.ArgumentParser() 2844 parser.add_argument('--foo', action='append_const', const='foo', dest='foo') 2845 bazel_mode.add_parser_arguments(parser, dest='bazel_mode_features') 2846 args = parser.parse_args(['--foo']) 2847 2848 self.assertIsNone(args.bazel_mode_features) 2849 2850 2851def test_info_of(module_name, test_filters=None): 2852 return test_info.TestInfo( 2853 module_name, 2854 BAZEL_RUNNER, 2855 [], 2856 data={constants.TI_FILTER: frozenset(test_filters)} 2857 if test_filters 2858 else None, 2859 ) 2860 2861 2862def test_filter_of(class_name, methods=None): 2863 return test_info.TestFilter( 2864 class_name, frozenset(methods) if methods else frozenset() 2865 ) 2866 2867 2868def _get_query_file_content(args: List[str]) -> str: 2869 for arg in args: 2870 if arg.startswith('--query_file='): 2871 return Path(arg.split('=')[1]).read_text(encoding='utf-8') 2872 2873 raise FileNotFoundError('Query file not found!') 2874 2875 2876if __name__ == '__main__': 2877 unittest.main() 2878