1#!/usr/bin/env python3 2# 3# Copyright 2018, 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"""Unittests for atest_tf_test_runner.""" 18 19# pylint: disable=missing-function-docstring 20# pylint: disable=too-many-lines 21# pylint: disable=unused-argument 22 23from io import StringIO 24import json 25import os 26from pathlib import Path 27import shlex 28import sys 29import tempfile 30import unittest 31from unittest import mock 32 33from atest import arg_parser 34from atest import atest_configs 35from atest import atest_utils 36from atest import constants 37from atest import module_info 38from atest import module_info_unittest_base 39from atest import unittest_constants as uc 40from atest import unittest_utils 41from atest.test_finders import test_finder_utils 42from atest.test_finders import test_info 43from atest.test_runner_invocation import TestRunnerInvocation 44from atest.test_runners import atest_tf_test_runner as atf_tr 45from atest.test_runners import event_handler 46from pyfakefs import fake_filesystem_unittest 47 48# pylint: disable=protected-access 49# pylint: disable=invalid-name 50# TODO(147567606): Replace {serial} with {extra_args} for general extra 51# arguments testing. 52RUN_CMD_ARGS = ( 53 '--log-level-display VERBOSE --log-level VERBOSE' 54 '{device_early_release}{serial}' 55) 56LOG_ARGS = atf_tr.AtestTradefedTestRunner._LOG_ARGS.format( 57 log_root_option_name=constants.LOG_ROOT_OPTION_NAME, 58 log_ext_option=constants.LOG_SAVER_EXT_OPTION, 59 log_path=os.path.join(uc.TEST_INFO_DIR, atf_tr.LOG_FOLDER_NAME), 60 proto_path=os.path.join( 61 uc.TEST_INFO_DIR, constants.ATEST_TEST_RECORD_PROTO 62 ), 63) 64RUN_ENV_STR = '' 65RUN_CMD = atf_tr.AtestTradefedTestRunner._RUN_CMD.format( 66 env=RUN_ENV_STR, 67 exe=atf_tr.AtestTradefedTestRunner.EXECUTABLE, 68 template='{template}', 69 log_saver=constants.ATEST_TF_LOG_SAVER, 70 tf_customize_template='{tf_customize_template}', 71 args=RUN_CMD_ARGS, 72 log_args=LOG_ARGS, 73) 74FULL_CLASS2_NAME = 'android.jank.cts.ui.SomeOtherClass' 75CLASS2_FILTER = test_info.TestFilter(FULL_CLASS2_NAME, frozenset()) 76METHOD2_FILTER = test_info.TestFilter( 77 uc.FULL_CLASS_NAME, frozenset([uc.METHOD2_NAME]) 78) 79MODULE_ARG1 = [ 80 (constants.TF_INCLUDE_FILTER_OPTION, 'A'), 81 (constants.TF_INCLUDE_FILTER_OPTION, 'B'), 82] 83MODULE_ARG2 = [] 84CLASS2_METHOD_FILTER = test_info.TestFilter( 85 FULL_CLASS2_NAME, frozenset([uc.METHOD_NAME, uc.METHOD2_NAME]) 86) 87MODULE2_INFO = test_info.TestInfo( 88 uc.MODULE2_NAME, 89 atf_tr.AtestTradefedTestRunner.NAME, 90 set(), 91 data={ 92 constants.TI_REL_CONFIG: uc.CONFIG2_FILE, 93 constants.TI_FILTER: frozenset(), 94 }, 95) 96CLASS1_BUILD_TARGETS = {'class_1_build_target'} 97CLASS1_INFO = test_info.TestInfo( 98 uc.MODULE_NAME, 99 atf_tr.AtestTradefedTestRunner.NAME, 100 CLASS1_BUILD_TARGETS, 101 data={ 102 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 103 constants.TI_FILTER: frozenset([uc.CLASS_FILTER]), 104 }, 105) 106CLASS2_BUILD_TARGETS = {'class_2_build_target'} 107CLASS2_INFO = test_info.TestInfo( 108 uc.MODULE_NAME, 109 atf_tr.AtestTradefedTestRunner.NAME, 110 CLASS2_BUILD_TARGETS, 111 data={ 112 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 113 constants.TI_FILTER: frozenset([CLASS2_FILTER]), 114 }, 115) 116CLASS3_BUILD_TARGETS = {'class_3_build_target'} 117CLASS3_INFO = test_info.TestInfo( 118 uc.MODULE_NAME, 119 atf_tr.AtestTradefedTestRunner.NAME, 120 CLASS3_BUILD_TARGETS, 121 data={ 122 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 123 constants.TI_FILTER: frozenset(), 124 constants.TI_MODULE_ARG: MODULE_ARG1, 125 }, 126) 127CLASS4_BUILD_TARGETS = {'class_4_build_target'} 128CLASS4_INFO = test_info.TestInfo( 129 uc.MODULE_NAME, 130 atf_tr.AtestTradefedTestRunner.NAME, 131 CLASS4_BUILD_TARGETS, 132 data={ 133 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 134 constants.TI_FILTER: frozenset(), 135 constants.TI_MODULE_ARG: MODULE_ARG2, 136 }, 137) 138CLASS1_CLASS2_MODULE_INFO = test_info.TestInfo( 139 uc.MODULE_NAME, 140 atf_tr.AtestTradefedTestRunner.NAME, 141 uc.MODULE_BUILD_TARGETS | CLASS1_BUILD_TARGETS | CLASS2_BUILD_TARGETS, 142 uc.MODULE_DATA, 143) 144FLAT_CLASS_INFO = test_info.TestInfo( 145 uc.MODULE_NAME, 146 atf_tr.AtestTradefedTestRunner.NAME, 147 CLASS1_BUILD_TARGETS | CLASS2_BUILD_TARGETS, 148 data={ 149 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 150 constants.TI_FILTER: frozenset([uc.CLASS_FILTER, CLASS2_FILTER]), 151 }, 152) 153FLAT2_CLASS_INFO = test_info.TestInfo( 154 uc.MODULE_NAME, 155 atf_tr.AtestTradefedTestRunner.NAME, 156 CLASS3_BUILD_TARGETS | CLASS4_BUILD_TARGETS, 157 data={ 158 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 159 constants.TI_FILTER: frozenset(), 160 constants.TI_MODULE_ARG: MODULE_ARG1 + MODULE_ARG2, 161 }, 162) 163GTF_INT_CONFIG = os.path.join(uc.GTF_INT_DIR, uc.GTF_INT_NAME + '.xml') 164CLASS2_METHOD_INFO = test_info.TestInfo( 165 uc.MODULE_NAME, 166 atf_tr.AtestTradefedTestRunner.NAME, 167 set(), 168 data={ 169 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 170 constants.TI_FILTER: frozenset([ 171 test_info.TestFilter( 172 FULL_CLASS2_NAME, frozenset([uc.METHOD_NAME, uc.METHOD2_NAME]) 173 ) 174 ]), 175 }, 176) 177METHOD_AND_CLASS2_METHOD = test_info.TestInfo( 178 uc.MODULE_NAME, 179 atf_tr.AtestTradefedTestRunner.NAME, 180 uc.MODULE_BUILD_TARGETS, 181 data={ 182 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 183 constants.TI_FILTER: frozenset( 184 [uc.METHOD_FILTER, CLASS2_METHOD_FILTER] 185 ), 186 }, 187) 188METHOD_METHOD2_AND_CLASS2_METHOD = test_info.TestInfo( 189 uc.MODULE_NAME, 190 atf_tr.AtestTradefedTestRunner.NAME, 191 uc.MODULE_BUILD_TARGETS, 192 data={ 193 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 194 constants.TI_FILTER: frozenset( 195 [uc.FLAT_METHOD_FILTER, CLASS2_METHOD_FILTER] 196 ), 197 }, 198) 199METHOD2_INFO = test_info.TestInfo( 200 uc.MODULE_NAME, 201 atf_tr.AtestTradefedTestRunner.NAME, 202 set(), 203 data={ 204 constants.TI_REL_CONFIG: uc.CONFIG_FILE, 205 constants.TI_FILTER: frozenset([METHOD2_FILTER]), 206 }, 207) 208 209INT_INFO = test_info.TestInfo( 210 uc.INT_NAME, 211 atf_tr.AtestTradefedTestRunner.NAME, 212 set(), 213 test_finder='INTEGRATION', 214) 215 216MOD_INFO = test_info.TestInfo( 217 uc.MODULE_NAME, 218 atf_tr.AtestTradefedTestRunner.NAME, 219 set(), 220 test_finder='MODULE', 221) 222 223MOD_INFO_NO_TEST_FINDER = test_info.TestInfo( 224 uc.MODULE_NAME, atf_tr.AtestTradefedTestRunner.NAME, set() 225) 226 227EVENTS_NORMAL = [ 228 ( 229 'TEST_MODULE_STARTED', 230 { 231 'moduleContextFileName': 'serial-util1146216{974}2772610436.ser', 232 'moduleName': 'someTestModule', 233 }, 234 ), 235 ('TEST_RUN_STARTED', {'testCount': 2}), 236 ( 237 'TEST_STARTED', 238 { 239 'start_time': 52, 240 'className': 'someClassName', 241 'testName': 'someTestName', 242 }, 243 ), 244 ( 245 'TEST_ENDED', 246 { 247 'end_time': 1048, 248 'className': 'someClassName', 249 'testName': 'someTestName', 250 }, 251 ), 252 ( 253 'TEST_STARTED', 254 { 255 'start_time': 48, 256 'className': 'someClassName2', 257 'testName': 'someTestName2', 258 }, 259 ), 260 ( 261 'TEST_FAILED', 262 { 263 'className': 'someClassName2', 264 'testName': 'someTestName2', 265 'trace': 'someTrace', 266 }, 267 ), 268 ( 269 'TEST_ENDED', 270 { 271 'end_time': 9876450, 272 'className': 'someClassName2', 273 'testName': 'someTestName2', 274 }, 275 ), 276 ('TEST_RUN_ENDED', {}), 277 ('TEST_MODULE_ENDED', {'foo': 'bar'}), 278] 279 280ANDROID_HOST_OUT = '/my/android/out/host/abc' 281 282 283# pylint: disable=too-many-public-methods 284class AtestTradefedTestRunnerUnittests(unittest.TestCase): 285 """Unit tests for atest_tf_test_runner.py""" 286 287 def setUp(self): 288 self.tr = atf_tr.AtestTradefedTestRunner( 289 results_dir=uc.TEST_INFO_DIR, extra_args={constants.HOST: False} 290 ) 291 self._global_args = arg_parser.create_atest_arg_parser().parse_args([]) 292 self._global_args.device_count_config = 0 293 mock.patch.object(atest_configs, 'GLOBAL_ARGS', self._global_args).start() 294 295 def tearDown(self): 296 mock.patch.stopall() 297 298 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_start_socket_server') 299 @mock.patch.object(atf_tr.AtestTradefedTestRunner, 'run') 300 @mock.patch.object( 301 atf_tr.AtestTradefedTestRunner, 302 '_create_test_args', 303 return_value=['some_args'], 304 ) 305 @mock.patch.object( 306 atf_tr.AtestTradefedTestRunner, 307 'generate_run_commands', 308 return_value='some_cmd', 309 ) 310 @mock.patch.object( 311 atf_tr.AtestTradefedTestRunner, '_process_connection', return_value=None 312 ) 313 @mock.patch('select.select') 314 @mock.patch('os.killpg', return_value=None) 315 @mock.patch('os.getpgid', return_value=None) 316 @mock.patch('signal.signal', return_value=None) 317 def test_run_tests_pretty( 318 self, 319 _signal, 320 _pgid, 321 _killpg, 322 mock_select, 323 _process, 324 _run_cmd, 325 _test_args, 326 mock_run, 327 mock_start_socket_server, 328 ): 329 """Test _run_tests_pretty method.""" 330 mock_subproc = mock.Mock() 331 mock_run.return_value = mock_subproc 332 mock_subproc.returncode = 0 333 mock_subproc.poll.side_effect = [True, True, None] 334 mock_server = mock.Mock() 335 mock_server.getsockname.return_value = ('', '') 336 mock_start_socket_server.return_value = mock_server 337 mock_reporter = mock.Mock() 338 339 # Test no early TF exit 340 mock_conn = mock.Mock() 341 mock_server.accept.return_value = (mock_conn, 'some_addr') 342 mock_server.close.return_value = True 343 mock_select.side_effect = [ 344 ([mock_server], None, None), 345 ([mock_conn], None, None), 346 ] 347 self.tr.run_tests_pretty([MODULE2_INFO], {}, mock_reporter) 348 349 # Test early TF exit 350 with tempfile.NamedTemporaryFile() as tmp_file: 351 with open(tmp_file.name, 'w', encoding='utf-8') as f: 352 f.write('tf msg') 353 self.tr.test_log_file = tmp_file 354 mock_select.side_effect = [([], None, None)] 355 mock_subproc.poll.side_effect = None 356 capture_output = StringIO() 357 sys.stdout = capture_output 358 self.assertRaises( 359 atf_tr.TradeFedExitError, 360 self.tr.run_tests_pretty, 361 [MODULE2_INFO], 362 {}, 363 mock_reporter, 364 ) 365 366 sys.stdout = sys.__stdout__ 367 self.assertTrue('tf msg' in capture_output.getvalue()) 368 369 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_process_connection') 370 @mock.patch('select.select') 371 def test_start_monitor_2_connection(self, mock_select, mock_process): 372 """Test _start_monitor method.""" 373 mock_server = mock.Mock() 374 mock_subproc = mock.Mock() 375 mock_reporter = mock.Mock() 376 mock_conn1 = mock.Mock() 377 mock_conn2 = mock.Mock() 378 mock_server.accept.side_effect = [ 379 (mock_conn1, 'addr 1'), 380 (mock_conn2, 'addr 2'), 381 ] 382 mock_select.side_effect = [ 383 ([mock_server], None, None), 384 ([mock_server], None, None), 385 ([mock_conn1], None, None), 386 ([mock_conn2], None, None), 387 ([mock_conn1], None, None), 388 ([mock_conn2], None, None), 389 ] 390 mock_process.side_effect = ['abc', 'def', False, False] 391 mock_subproc.poll.side_effect = [None, None, None, None, None, True] 392 self.tr._start_monitor(mock_server, mock_subproc, mock_reporter, {}) 393 self.assertEqual(mock_process.call_count, 4) 394 calls = [mock.call.accept(), mock.call.close()] 395 mock_server.assert_has_calls(calls) 396 mock_conn1.assert_has_calls([mock.call.close()]) 397 mock_conn2.assert_has_calls([mock.call.close()]) 398 399 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_process_connection') 400 @mock.patch('select.select') 401 def test_start_monitor_tf_exit_before_2nd_connection( 402 self, mock_select, mock_process 403 ): 404 """Test _start_monitor method.""" 405 mock_server = mock.Mock() 406 mock_subproc = mock.Mock() 407 mock_reporter = mock.Mock() 408 mock_conn1 = mock.Mock() 409 mock_conn2 = mock.Mock() 410 mock_server.accept.side_effect = [ 411 (mock_conn1, 'addr 1'), 412 (mock_conn2, 'addr 2'), 413 ] 414 mock_select.side_effect = [ 415 ([mock_server], None, None), 416 ([mock_server], None, None), 417 ([mock_conn1], None, None), 418 ([mock_conn2], None, None), 419 ([mock_conn1], None, None), 420 ([mock_conn2], None, None), 421 ] 422 mock_process.side_effect = ['abc', 'def', False, False] 423 # TF exit early but have not processed data in socket buffer. 424 mock_subproc.poll.side_effect = [None, None, True, True, True, True] 425 self.tr._start_monitor(mock_server, mock_subproc, mock_reporter, {}) 426 self.assertEqual(mock_process.call_count, 4) 427 calls = [mock.call.accept(), mock.call.close()] 428 mock_server.assert_has_calls(calls) 429 mock_conn1.assert_has_calls([mock.call.close()]) 430 mock_conn2.assert_has_calls([mock.call.close()]) 431 432 def test_start_socket_server(self): 433 """Test start_socket_server method.""" 434 server = self.tr._start_socket_server() 435 host, port = server.getsockname() 436 self.assertEqual(host, atf_tr.SOCKET_HOST) 437 self.assertLessEqual(port, 65535) 438 self.assertGreaterEqual(port, 1024) 439 server.close() 440 441 @mock.patch('os.path.exists') 442 @mock.patch.dict('os.environ', {'APE_API_KEY': '/tmp/123.json'}) 443 def test_try_set_gts_authentication_key_is_set_by_user(self, mock_exist): 444 """Test try_set_authentication_key_is_set_by_user method.""" 445 # Test key is set by user. 446 self.tr._try_set_gts_authentication_key() 447 mock_exist.assert_not_called() 448 449 @mock.patch('os.path.join', return_value='/tmp/file_not_exist.json') 450 def test_try_set_gts_authentication_key_not_set(self, _): 451 """Test try_set_authentication_key_not_set method.""" 452 # Delete the environment variable if it's set. This is fine for this 453 # method because it's for validating the APE_API_KEY isn't set. 454 if os.environ.get('APE_API_KEY'): 455 del os.environ['APE_API_KEY'] 456 self.tr._try_set_gts_authentication_key() 457 self.assertEqual(os.environ.get('APE_API_KEY'), None) 458 459 @mock.patch.object(event_handler.EventHandler, 'process_event') 460 def test_process_connection(self, mock_pe): 461 """Test _process_connection method.""" 462 mock_socket = mock.Mock() 463 for name, data in EVENTS_NORMAL: 464 data_map = {mock_socket: ''} 465 socket_data = '%s %s' % (name, json.dumps(data)) 466 mock_socket.recv.return_value = socket_data 467 self.tr._process_connection(data_map, mock_socket, mock_pe) 468 469 calls = [ 470 mock.call.process_event(name, data) for name, data in EVENTS_NORMAL 471 ] 472 mock_pe.assert_has_calls(calls) 473 mock_socket.recv.return_value = '' 474 self.assertFalse( 475 self.tr._process_connection(data_map, mock_socket, mock_pe) 476 ) 477 478 @mock.patch.object(event_handler.EventHandler, 'process_event') 479 def test_process_connection_multiple_lines_in_single_recv(self, mock_pe): 480 """Test _process_connection when recv reads multiple lines in one go.""" 481 mock_socket = mock.Mock() 482 squashed_events = '\n'.join( 483 ['%s %s' % (name, json.dumps(data)) for name, data in EVENTS_NORMAL] 484 ) 485 socket_data = [squashed_events, ''] 486 mock_socket.recv.side_effect = socket_data 487 data_map = {mock_socket: ''} 488 self.tr._process_connection(data_map, mock_socket, mock_pe) 489 calls = [ 490 mock.call.process_event(name, data) for name, data in EVENTS_NORMAL 491 ] 492 mock_pe.assert_has_calls(calls) 493 494 @mock.patch.object(event_handler.EventHandler, 'process_event') 495 def test_process_connection_with_buffering(self, mock_pe): 496 """Test _process_connection when events overflow socket buffer size.""" 497 mock_socket = mock.Mock() 498 module_events = [EVENTS_NORMAL[0], EVENTS_NORMAL[-1]] 499 socket_events = [ 500 '%s %s' % (name, json.dumps(data)) for name, data in module_events 501 ] 502 # test try-block code by breaking apart first event after first } 503 index = socket_events[0].index('}') + 1 504 socket_data = [socket_events[0][:index], socket_events[0][index:]] 505 # test non-try block buffering with second event 506 socket_data.extend([socket_events[1][:-4], socket_events[1][-4:], '']) 507 mock_socket.recv.side_effect = socket_data 508 data_map = {mock_socket: ''} 509 self.tr._process_connection(data_map, mock_socket, mock_pe) 510 self.tr._process_connection(data_map, mock_socket, mock_pe) 511 self.tr._process_connection(data_map, mock_socket, mock_pe) 512 self.tr._process_connection(data_map, mock_socket, mock_pe) 513 calls = [ 514 mock.call.process_event(name, data) for name, data in module_events 515 ] 516 mock_pe.assert_has_calls(calls) 517 518 @mock.patch.object(event_handler.EventHandler, 'process_event') 519 def test_process_connection_with_not_completed_event_data(self, mock_pe): 520 """Test _process_connection when event have \n prefix.""" 521 mock_socket = mock.Mock() 522 mock_socket.recv.return_value = '\n%s %s' % ( 523 EVENTS_NORMAL[0][0], 524 json.dumps(EVENTS_NORMAL[0][1]), 525 ) 526 data_map = {mock_socket: ''} 527 self.tr._process_connection(data_map, mock_socket, mock_pe) 528 calls = [mock.call.process_event(EVENTS_NORMAL[0][0], EVENTS_NORMAL[0][1])] 529 mock_pe.assert_has_calls(calls) 530 531 @mock.patch.object( 532 atf_tr.AtestTradefedTestRunner, 533 '_is_all_tests_parameter_auto_enabled', 534 return_value=False, 535 ) 536 @mock.patch('os.environ.get', return_value=None) 537 @mock.patch('atest.atest_utils.get_result_server_args') 538 def test_generate_run_commands_without_serial_env( 539 self, mock_resultargs, _, _mock_all 540 ): 541 """Test generate_run_command method.""" 542 # Basic Run Cmd 543 mock_resultargs.return_value = [] 544 unittest_utils.assert_strict_equal( 545 self, 546 self.tr.generate_run_commands([], {}), 547 [ 548 RUN_CMD.format( 549 serial='', 550 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 551 tf_customize_template='', 552 device_early_release=' --no-early-device-release', 553 ) 554 ], 555 ) 556 unittest_utils.assert_strict_equal( 557 self, 558 self.tr.generate_run_commands([], {}), 559 [ 560 RUN_CMD.format( 561 serial='', 562 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 563 tf_customize_template='', 564 device_early_release=' --no-early-device-release', 565 ) 566 ], 567 ) 568 569 @mock.patch( 570 'atest.test_runners.atest_tf_test_runner.is_log_upload_enabled', 571 return_value=True, 572 ) 573 @mock.patch.object( 574 atf_tr.AtestTradefedTestRunner, 575 '_is_all_tests_parameter_auto_enabled', 576 return_value=False, 577 ) 578 @mock.patch('os.environ.get', return_value=None) 579 @mock.patch('atest.atest_utils.get_result_server_args') 580 def test_generate_run_commands_with_upload_enabled( 581 self, mock_resultargs, _, _mock_all, _upload_enabled 582 ): 583 result_arg = '--result_arg' 584 mock_resultargs.return_value = [result_arg] 585 586 run_command = self.tr.generate_run_commands([], {}) 587 588 self.assertIn('--result_arg', run_command[0].split()) 589 590 @mock.patch( 591 'atest.test_runners.atest_tf_test_runner.is_log_upload_enabled', 592 return_value=False, 593 ) 594 @mock.patch.object( 595 atf_tr.AtestTradefedTestRunner, 596 '_is_all_tests_parameter_auto_enabled', 597 return_value=False, 598 ) 599 @mock.patch('os.environ.get', return_value=None) 600 @mock.patch('atest.atest_utils.get_result_server_args') 601 def test_generate_run_commands_without_upload_enabled( 602 self, mock_resultargs, _, _mock_all, _upload_enabled 603 ): 604 result_arg = '--result_arg' 605 mock_resultargs.return_value = [result_arg] 606 607 run_command = self.tr.generate_run_commands([], {}) 608 609 self.assertNotIn('--result_arg', run_command[0].split()) 610 611 @mock.patch.object( 612 atf_tr.AtestTradefedTestRunner, 613 '_is_all_tests_parameter_auto_enabled', 614 return_value=False, 615 ) 616 @mock.patch('os.environ.get') 617 @mock.patch('atest.atest_utils.get_result_server_args') 618 def test_generate_run_commands_with_serial_env( 619 self, mock_resultargs, mock_env, _mock_all 620 ): 621 """Test generate_run_command method.""" 622 # Basic Run Cmd 623 env_device_serial = 'env-device-0' 624 mock_resultargs.return_value = [] 625 mock_env.return_value = env_device_serial 626 env_serial_arg = ' --serial %s' % env_device_serial 627 # Serial env be set and without --serial arg. 628 unittest_utils.assert_strict_equal( 629 self, 630 self.tr.generate_run_commands([], {}), 631 [ 632 RUN_CMD.format( 633 serial=env_serial_arg, 634 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 635 tf_customize_template='', 636 device_early_release=' --no-early-device-release', 637 ) 638 ], 639 ) 640 # Serial env be set but with --serial arg. 641 arg_device_serial = 'arg-device-0' 642 arg_serial_arg = ' --serial %s' % arg_device_serial 643 unittest_utils.assert_strict_equal( 644 self, 645 self.tr.generate_run_commands( 646 [], {constants.SERIAL: [arg_device_serial]} 647 ), 648 [ 649 RUN_CMD.format( 650 serial=arg_serial_arg, 651 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 652 tf_customize_template='', 653 device_early_release=' --no-early-device-release', 654 ) 655 ], 656 ) 657 # Serial env be set but with -n arg 658 unittest_utils.assert_strict_equal( 659 self, 660 self.tr.generate_run_commands([], {constants.HOST: True}), 661 [ 662 RUN_CMD.format( 663 serial='', 664 template=self.tr._TF_DEVICELESS_TEST_TEMPLATE, 665 tf_customize_template='', 666 device_early_release=' --no-early-device-release', 667 ) 668 + ' -n --prioritize-host-config --skip-host-arch-check' 669 ], 670 ) 671 672 def test_flatten_test_filters(self): 673 """Test flatten_test_filters method.""" 674 # No Flattening 675 filters = self.tr.flatten_test_filters({uc.CLASS_FILTER}) 676 unittest_utils.assert_strict_equal( 677 self, frozenset([uc.CLASS_FILTER]), filters 678 ) 679 filters = self.tr.flatten_test_filters({CLASS2_FILTER}) 680 unittest_utils.assert_strict_equal( 681 self, frozenset([CLASS2_FILTER]), filters 682 ) 683 filters = self.tr.flatten_test_filters({uc.METHOD_FILTER}) 684 unittest_utils.assert_strict_equal( 685 self, frozenset([uc.METHOD_FILTER]), filters 686 ) 687 filters = self.tr.flatten_test_filters( 688 {uc.METHOD_FILTER, CLASS2_METHOD_FILTER} 689 ) 690 unittest_utils.assert_strict_equal( 691 self, frozenset([uc.METHOD_FILTER, CLASS2_METHOD_FILTER]), filters 692 ) 693 # Flattening 694 filters = self.tr.flatten_test_filters({uc.METHOD_FILTER, METHOD2_FILTER}) 695 unittest_utils.assert_strict_equal( 696 self, filters, frozenset([uc.FLAT_METHOD_FILTER]) 697 ) 698 filters = self.tr.flatten_test_filters({ 699 uc.METHOD_FILTER, 700 METHOD2_FILTER, 701 CLASS2_METHOD_FILTER, 702 }) 703 unittest_utils.assert_strict_equal( 704 self, filters, frozenset([uc.FLAT_METHOD_FILTER, CLASS2_METHOD_FILTER]) 705 ) 706 707 def test_flatten_test_infos(self): 708 """Test _flatten_test_infos method.""" 709 # No Flattening 710 test_infos = self.tr._flatten_test_infos({uc.MODULE_INFO}) 711 unittest_utils.assert_equal_testinfo_sets( 712 self, test_infos, {uc.MODULE_INFO} 713 ) 714 715 test_infos = self.tr._flatten_test_infos([uc.MODULE_INFO, MODULE2_INFO]) 716 unittest_utils.assert_equal_testinfo_sets( 717 self, test_infos, {uc.MODULE_INFO, MODULE2_INFO} 718 ) 719 720 test_infos = self.tr._flatten_test_infos({CLASS1_INFO}) 721 unittest_utils.assert_equal_testinfo_sets(self, test_infos, {CLASS1_INFO}) 722 723 test_infos = self.tr._flatten_test_infos({uc.INT_INFO}) 724 unittest_utils.assert_equal_testinfo_sets(self, test_infos, {uc.INT_INFO}) 725 726 test_infos = self.tr._flatten_test_infos({uc.METHOD_INFO}) 727 unittest_utils.assert_equal_testinfo_sets( 728 self, test_infos, {uc.METHOD_INFO} 729 ) 730 731 # Flattening 732 test_infos = self.tr._flatten_test_infos({CLASS1_INFO, CLASS2_INFO}) 733 unittest_utils.assert_equal_testinfo_sets( 734 self, test_infos, {FLAT_CLASS_INFO} 735 ) 736 737 test_infos = self.tr._flatten_test_infos( 738 {CLASS1_INFO, uc.INT_INFO, CLASS2_INFO} 739 ) 740 unittest_utils.assert_equal_testinfo_sets( 741 self, test_infos, {uc.INT_INFO, FLAT_CLASS_INFO} 742 ) 743 744 test_infos = self.tr._flatten_test_infos( 745 {CLASS1_INFO, uc.MODULE_INFO, CLASS2_INFO} 746 ) 747 unittest_utils.assert_equal_testinfo_sets( 748 self, test_infos, {CLASS1_CLASS2_MODULE_INFO} 749 ) 750 751 test_infos = self.tr._flatten_test_infos( 752 {MODULE2_INFO, uc.INT_INFO, CLASS1_INFO, CLASS2_INFO, uc.GTF_INT_INFO} 753 ) 754 unittest_utils.assert_equal_testinfo_sets( 755 self, 756 test_infos, 757 {uc.INT_INFO, uc.GTF_INT_INFO, FLAT_CLASS_INFO, MODULE2_INFO}, 758 ) 759 760 test_infos = self.tr._flatten_test_infos( 761 {uc.METHOD_INFO, CLASS2_METHOD_INFO} 762 ) 763 unittest_utils.assert_equal_testinfo_sets( 764 self, test_infos, {METHOD_AND_CLASS2_METHOD} 765 ) 766 767 test_infos = self.tr._flatten_test_infos( 768 {uc.METHOD_INFO, METHOD2_INFO, CLASS2_METHOD_INFO} 769 ) 770 unittest_utils.assert_equal_testinfo_sets( 771 self, test_infos, {METHOD_METHOD2_AND_CLASS2_METHOD} 772 ) 773 test_infos = self.tr._flatten_test_infos({ 774 uc.METHOD_INFO, 775 METHOD2_INFO, 776 CLASS2_METHOD_INFO, 777 MODULE2_INFO, 778 uc.INT_INFO, 779 }) 780 unittest_utils.assert_equal_testinfo_sets( 781 self, 782 test_infos, 783 {uc.INT_INFO, MODULE2_INFO, METHOD_METHOD2_AND_CLASS2_METHOD}, 784 ) 785 786 test_infos = self.tr._flatten_test_infos({CLASS3_INFO, CLASS4_INFO}) 787 unittest_utils.assert_equal_testinfo_sets( 788 self, test_infos, {FLAT2_CLASS_INFO} 789 ) 790 791 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 792 def test_create_test_args(self, mock_config): 793 """Test _create_test_args method.""" 794 # Only compile '--skip-loading-config-jar' in TF if it's not 795 # INTEGRATION finder or the finder property isn't set. 796 mock_config.return_value = '', '' 797 args = self.tr._create_test_args([MOD_INFO], {}) 798 self.assertTrue(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 799 800 args = self.tr._create_test_args([INT_INFO], {}) 801 self.assertFalse(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 802 803 args = self.tr._create_test_args([MOD_INFO_NO_TEST_FINDER], {}) 804 self.assertFalse(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 805 806 args = self.tr._create_test_args([MOD_INFO_NO_TEST_FINDER, INT_INFO], {}) 807 self.assertFalse(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 808 809 args = self.tr._create_test_args([MOD_INFO_NO_TEST_FINDER], {}) 810 self.assertFalse(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 811 812 args = self.tr._create_test_args( 813 [MOD_INFO_NO_TEST_FINDER, INT_INFO, MOD_INFO], {} 814 ) 815 self.assertFalse(constants.TF_SKIP_LOADING_CONFIG_JAR in args) 816 817 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 818 def test_create_test_args_with_test_filter_appends_to_atest_include_filter( 819 self, mock_config 820 ): 821 mock_config.return_value = '', '' 822 args = self.tr._create_test_args( 823 [MOD_INFO], {constants.TEST_FILTER: '*MyTestFilter*'} 824 ) 825 826 self.assertEqual(args.count(constants.TF_ATEST_INCLUDE_FILTER), 1) 827 self.assertEqual( 828 args[args.index(constants.TF_ATEST_INCLUDE_FILTER) + 1], 829 uc.MODULE_NAME + ':*MyTestFilter*', 830 ) 831 832 @mock.patch.object( 833 atf_tr.AtestTradefedTestRunner, 834 '_is_all_tests_parameter_auto_enabled', 835 return_value=False, 836 ) 837 @mock.patch('os.environ.get', return_value=None) 838 @mock.patch('atest.atest_utils.get_result_server_args') 839 def test_generate_run_commands_collect_tests_only( 840 self, mock_resultargs, _, _mock_is_all 841 ): 842 """Test generate_run_command method.""" 843 # Testing without collect-tests-only 844 mock_resultargs.return_value = [] 845 extra_args = {} 846 unittest_utils.assert_strict_equal( 847 self, 848 self.tr.generate_run_commands([], extra_args), 849 [ 850 RUN_CMD.format( 851 serial='', 852 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 853 tf_customize_template='', 854 device_early_release=' --no-early-device-release', 855 ) 856 ], 857 ) 858 # Testing with collect-tests-only 859 mock_resultargs.return_value = [] 860 extra_args = {constants.COLLECT_TESTS_ONLY: True} 861 unittest_utils.assert_strict_equal( 862 self, 863 self.tr.generate_run_commands([], extra_args), 864 [ 865 RUN_CMD.format( 866 serial=' --collect-tests-only', 867 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 868 tf_customize_template='', 869 device_early_release=' --no-early-device-release', 870 ) 871 ], 872 ) 873 874 @mock.patch.object( 875 atf_tr.AtestTradefedTestRunner, 876 '_is_all_tests_parameter_auto_enabled', 877 return_value=False, 878 ) 879 @mock.patch('os.environ.get', return_value=None) 880 @mock.patch('atest.atest_utils.get_result_server_args') 881 def test_generate_run_commands_incremental_setup( 882 self, mock_resultargs, _, _mock_is_all 883 ): 884 """Test generate_run_command method with incremental setup.""" 885 mock_resultargs.return_value = [] 886 extra_args = {atf_tr._INCREMENTAL_SETUP_KEY: True} 887 888 run_commands = self.tr.generate_run_commands([], extra_args) 889 890 unittest_utils.assert_strict_equal( 891 self, 892 run_commands, 893 [ 894 RUN_CMD.format( 895 serial=' --incremental-setup=YES', 896 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 897 tf_customize_template='', 898 device_early_release=' --no-early-device-release', 899 ) 900 ], 901 ) 902 903 @mock.patch.object( 904 atf_tr.AtestTradefedTestRunner, 905 '_is_all_tests_parameter_auto_enabled', 906 return_value=False, 907 ) 908 @mock.patch('os.environ.get', return_value=None) 909 @mock.patch('atest.atest_utils.get_result_server_args') 910 def test_generate_run_commands_with_tf_template( 911 self, mock_resultargs, _, _mock_all 912 ): 913 """Test generate_run_command method.""" 914 tf_tmplate_key1 = 'tf_tmplate_key1' 915 tf_tmplate_val1 = 'tf_tmplate_val1' 916 tf_tmplate_key2 = 'tf_tmplate_key2' 917 tf_tmplate_val2 = 'tf_tmplate_val2' 918 # Testing with only one tradefed template command 919 mock_resultargs.return_value = [] 920 extra_args = { 921 constants.TF_TEMPLATE: [ 922 '{}={}'.format(tf_tmplate_key1, tf_tmplate_val1) 923 ] 924 } 925 unittest_utils.assert_strict_equal( 926 self, 927 self.tr.generate_run_commands([], extra_args), 928 [ 929 RUN_CMD.format( 930 serial='', 931 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 932 device_early_release=' --no-early-device-release', 933 tf_customize_template='--template:map {}={}', 934 ).format(tf_tmplate_key1, tf_tmplate_val1) 935 ], 936 ) 937 # Testing with two tradefed template commands 938 extra_args = { 939 constants.TF_TEMPLATE: [ 940 '{}={}'.format(tf_tmplate_key1, tf_tmplate_val1), 941 '{}={}'.format(tf_tmplate_key2, tf_tmplate_val2), 942 ] 943 } 944 unittest_utils.assert_strict_equal( 945 self, 946 self.tr.generate_run_commands([], extra_args), 947 [ 948 RUN_CMD.format( 949 serial='', 950 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 951 device_early_release=' --no-early-device-release', 952 tf_customize_template=( 953 '--template:map {}={} --template:map {}={}' 954 ), 955 ).format( 956 tf_tmplate_key1, 957 tf_tmplate_val1, 958 tf_tmplate_key2, 959 tf_tmplate_val2, 960 ) 961 ], 962 ) 963 964 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 965 def test_has_instant_app_config(self, mock_config): 966 """test _has_instant_app_config method.""" 967 no_instant_config = os.path.join( 968 uc.TEST_DATA_DIR, 'parameter_config', 'parameter.cfg' 969 ) 970 instant_config = os.path.join( 971 uc.TEST_DATA_DIR, 'parameter_config', 'instant_app_parameter.cfg' 972 ) 973 # Test find instant app config 974 mock_config.return_value = instant_config, '' 975 self.assertTrue( 976 atf_tr.AtestTradefedTestRunner._has_instant_app_config( 977 ['test_info'], 'module_info_obj' 978 ) 979 ) 980 # Test not find instant app config 981 mock_config.return_value = no_instant_config, '' 982 self.assertFalse( 983 atf_tr.AtestTradefedTestRunner._has_instant_app_config( 984 ['test_info'], 'module_info_obj' 985 ) 986 ) 987 988 @mock.patch.object( 989 atf_tr.AtestTradefedTestRunner, 990 '_is_all_tests_parameter_auto_enabled', 991 return_value=False, 992 ) 993 @mock.patch.object( 994 atf_tr.AtestTradefedTestRunner, 995 '_has_instant_app_config', 996 return_value=True, 997 ) 998 @mock.patch('os.environ.get', return_value=None) 999 @mock.patch('atest.atest_utils.get_result_server_args') 1000 def test_generate_run_commands_has_instant_app_config( 1001 self, mock_resultargs, _, _mock_has_config, _mock_is_all 1002 ): 1003 """Test generate_run_command method which has instant app config.""" 1004 # Basic Run Cmd 1005 mock_resultargs.return_value = [] 1006 extra_tf_arg = ( 1007 '{tf_test_arg} {tf_class}:{option_name}:{option_value}'.format( 1008 tf_test_arg=constants.TF_TEST_ARG, 1009 tf_class=constants.TF_AND_JUNIT_CLASS, 1010 option_name=constants.TF_EXCLUDE_ANNOTATE, 1011 option_value=constants.INSTANT_MODE_ANNOTATE, 1012 ) 1013 ) 1014 unittest_utils.assert_strict_equal( 1015 self, 1016 self.tr.generate_run_commands([], {}), 1017 [ 1018 RUN_CMD.format( 1019 serial='', 1020 template=self.tr._TF_DEVICE_TEST_TEMPLATE, 1021 tf_customize_template='', 1022 device_early_release=' --no-early-device-release ' 1023 + extra_tf_arg, 1024 ) 1025 ], 1026 ) 1027 1028 @mock.patch.object(atest_utils, 'get_config_parameter') 1029 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1030 def test_is_parameter_auto_enabled_cfg(self, mock_config, mock_cfg_para): 1031 """test _is_parameter_auto_enabled_cfg method.""" 1032 # Test if TF_PARA_INSTANT_APP is match 1033 mock_config.return_value = 'test_config', '' 1034 mock_cfg_para.return_value = { 1035 list(constants.DEFAULT_EXCLUDE_PARAS)[1], 1036 list(constants.DEFAULT_EXCLUDE_PARAS)[0], 1037 } 1038 self.assertFalse( 1039 atf_tr.AtestTradefedTestRunner._is_parameter_auto_enabled_cfg( 1040 ['test_info'], 'module_info_obj' 1041 ) 1042 ) 1043 # Test if DEFAULT_EXCLUDE_NOT_PARAS is match 1044 mock_cfg_para.return_value = { 1045 list(constants.DEFAULT_EXCLUDE_NOT_PARAS)[2], 1046 list(constants.DEFAULT_EXCLUDE_NOT_PARAS)[0], 1047 } 1048 self.assertFalse( 1049 atf_tr.AtestTradefedTestRunner._is_parameter_auto_enabled_cfg( 1050 ['test_info'], 'module_info_obj' 1051 ) 1052 ) 1053 # Test if have parameter not in default exclude paras 1054 mock_cfg_para.return_value = { 1055 'not match parameter', 1056 list(constants.DEFAULT_EXCLUDE_PARAS)[1], 1057 list(constants.DEFAULT_EXCLUDE_NOT_PARAS)[2], 1058 } 1059 self.assertTrue( 1060 atf_tr.AtestTradefedTestRunner._is_parameter_auto_enabled_cfg( 1061 ['test_info'], 'module_info_obj' 1062 ) 1063 ) 1064 1065 @mock.patch.object( 1066 atf_tr.AtestTradefedTestRunner, 1067 '_is_parameter_auto_enabled_cfg', 1068 return_value=True, 1069 ) 1070 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1071 def test_create_test_args_with_auto_enable_parameter( 1072 self, mock_config, _mock_is_enable 1073 ): 1074 """Test _create_test_args method with auto enabled parameter config.""" 1075 # Should have --m on args and should not have --include-filter. 1076 mock_config.return_value = '', '' 1077 args = self.tr._create_test_args([MOD_INFO], {}) 1078 self.assertTrue(constants.TF_MODULE_FILTER in args) 1079 self.assertFalse(constants.TF_INCLUDE_FILTER in args) 1080 1081 @mock.patch.object( 1082 atf_tr.AtestTradefedTestRunner, '_is_parameter_auto_enabled_cfg' 1083 ) 1084 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1085 def test_parse_extra_args(self, mock_config, _mock_is_enable): 1086 """Test _parse_extra_args .""" 1087 # If extra_arg enable instant_app or secondary users, should not have 1088 # --exclude-module-parameters even though test config parameter is auto 1089 # enabled. 1090 mock_config.return_value = '', '' 1091 _mock_is_enable.return_value = True 1092 args, _ = self.tr._parse_extra_args([MOD_INFO], {constants.INSTANT: ''}) 1093 self.assertFalse('--exclude-module-parameters' in args) 1094 1095 # If extra_arg not enable instant_app or secondary users, should have 1096 # --exclude-module-rameters if config parameter is auto enabled. 1097 _mock_is_enable.return_value = True 1098 args, _ = self.tr._parse_extra_args([MOD_INFO], {constants.ALL_ABI: ''}) 1099 self.assertTrue('--exclude-module-parameters' in args) 1100 1101 # If extra_arg not enable instant_app or secondary users, should not 1102 # have --exclude-module-rameters if config parameter is not auto enabled 1103 _mock_is_enable.return_value = False 1104 args, _ = self.tr._parse_extra_args([MOD_INFO], {constants.ALL_ABI: ''}) 1105 self.assertFalse('--exclude-module-parameters' in args) 1106 1107 @mock.patch.object( 1108 atf_tr.AtestTradefedTestRunner, 1109 '_is_parameter_auto_enabled_cfg', 1110 return_value=False, 1111 ) 1112 @mock.patch.object( 1113 atf_tr.AtestTradefedTestRunner, 1114 '_has_instant_app_config', 1115 return_value=False, 1116 ) 1117 def test_parse_extra_args_has_instant_app( 1118 self, _mock_has_instant, _mock_is_para 1119 ): 1120 """Test _parse_extra_args with instant app in customize flag.""" 1121 # If customize_arg has module-parameter should also include 1122 # --enable-parameterized-modules. 1123 args, _ = self.tr._parse_extra_args( 1124 [MOD_INFO], {constants.CUSTOM_ARGS: [constants.TF_MODULE_PARAMETER]} 1125 ) 1126 self.assertTrue(constants.TF_ENABLE_PARAMETERIZED_MODULES in args) 1127 1128 @mock.patch('atest.atest_utils.get_prebuilt_sdk_tools_dir') 1129 @mock.patch.object( 1130 atf_tr.AtestTradefedTestRunner, '_is_missing_exec', return_value=False 1131 ) 1132 def test_generate_env_vars_aapt_already_in_system_path( 1133 self, _mock_is_missing_exec, mock_prebuilt_sdk_dir 1134 ): 1135 """Test generate_env_vars if aapt already in system path.""" 1136 prebuilt_sdk_dir = Path('/my/test/sdk/dir') 1137 mock_prebuilt_sdk_dir.return_value = prebuilt_sdk_dir 1138 1139 env_vars = self.tr.generate_env_vars(extra_args={}) 1140 1141 self.assertFalse(str(prebuilt_sdk_dir) + ':' in env_vars.get('PATH', '')) 1142 1143 @mock.patch('os.path.exists', return_value=True) 1144 @mock.patch('atest.atest_utils.get_prebuilt_sdk_tools_dir') 1145 @mock.patch.object( 1146 atf_tr.AtestTradefedTestRunner, '_is_missing_exec', return_value=True 1147 ) 1148 def test_generate_env_vars_aapt_not_in_system_path( 1149 self, _mock_is_missing_exec, mock_prebuilt_sdk_dir, _mock_exist 1150 ): 1151 """Test generate_env_vars if aapt not in system path.""" 1152 prebuilt_sdk_dir = Path('/my/test/sdk/dir') 1153 mock_prebuilt_sdk_dir.return_value = prebuilt_sdk_dir 1154 1155 env_vars = self.tr.generate_env_vars(extra_args={}) 1156 1157 self.assertTrue(str(prebuilt_sdk_dir) + ':' in env_vars.get('PATH', '')) 1158 1159 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_handle_native_tests') 1160 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_parse_extra_args') 1161 @mock.patch.object(atf_tr.AtestTradefedTestRunner, '_create_test_args') 1162 @mock.patch('os.environ.get', return_value=None) 1163 @mock.patch('atest.atest_utils.get_result_server_args') 1164 def test_run_commands_for_aggregate_metric_result_with_manually_input( 1165 self, 1166 mock_resultargs, 1167 _mock_env, 1168 _mock_create, 1169 _mock_parse, 1170 _mock_handle_native, 1171 ): 1172 """Test generate_run_command method for test need aggregate metric.""" 1173 mock_resultargs.return_value = [] 1174 _mock_create.return_value = [] 1175 _mock_parse.return_value = [], [] 1176 test_info_with_aggregate_metrics = test_info.TestInfo( 1177 test_name='perf_test', test_runner='test_runner', build_targets=set() 1178 ) 1179 test_info_with_aggregate_metrics.aggregate_metrics_result = True 1180 1181 run_cmd = self.tr.generate_run_commands( 1182 [test_info_with_aggregate_metrics], 1183 extra_args={constants.TF_TEMPLATE: ['metric_post_processor=a/b/c']}, 1184 ) 1185 1186 self.assertTrue( 1187 str(run_cmd).find( 1188 'metric_post_processor=' 1189 'google/template/postprocessors/metric-file-aggregate-disabled' 1190 ) 1191 < 0 1192 ) 1193 1194 self.assertTrue(str(run_cmd).find('metric_post_processor=a/b/c') > 0) 1195 1196 @mock.patch.object( 1197 atf_tr.AtestTradefedTestRunner, 1198 '_is_all_tests_parameter_auto_enabled', 1199 return_value=False, 1200 ) 1201 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1202 def test_create_test_args_with_auto_enable_parameter_but_not_all( 1203 self, mock_config, _mock_is_all 1204 ): 1205 """Test _create_test_args method with not all configs are auto enabled 1206 1207 parameter. 1208 """ 1209 # Should not --m on args and should have --include-filter. 1210 mock_config.return_value = '', '' 1211 args = self.tr._create_test_args([MOD_INFO], {}) 1212 1213 self.assertFalse(constants.TF_MODULE_FILTER in args) 1214 self.assertTrue(constants.TF_INCLUDE_FILTER in args) 1215 1216 @mock.patch.object( 1217 atf_tr.AtestTradefedTestRunner, 1218 '_is_all_tests_parameter_auto_enabled', 1219 return_value=False, 1220 ) 1221 @mock.patch.object( 1222 atf_tr.AtestTradefedTestRunner, '_is_parameter_auto_enabled_cfg' 1223 ) 1224 @mock.patch.object(test_finder_utils, 'get_test_config_and_srcs') 1225 def test_parse_extra_args_not_all_cfg_auto_enable_parameter( 1226 self, mock_config, _mock_is_enable, _mock_is_all 1227 ): 1228 """Test _parse_extra_args without all config is auto parameter.""" 1229 # If not all test config is parameter auto enabled, should not find 1230 # --enable-parameterized-modules in test config. 1231 mock_config.return_value = '', '' 1232 _mock_is_enable.return_value = True 1233 1234 args, _ = self.tr._parse_extra_args([MOD_INFO], {}) 1235 self.assertFalse('--enable-parameterized-modules' in args) 1236 1237 def test_create_invocations_returns_invocations_for_device_and_deviceless_tests( 1238 self, 1239 ): 1240 self.tr.module_info = module_info.ModuleInfo( 1241 name_to_module_info={ 1242 'deviceless_test': ( 1243 module_info_unittest_base.robolectric_test_module( 1244 name='deviceless_test' 1245 ) 1246 ), 1247 'device_test': module_info_unittest_base.device_driven_test_module( 1248 name='device_test' 1249 ), 1250 } 1251 ) 1252 test_info_deviceless = test_info_of('deviceless_test') 1253 test_info_device = test_info_of('device_test') 1254 1255 invocations = self.tr.create_invocations( 1256 {}, [test_info_deviceless, test_info_device] 1257 ) 1258 expected_invocation_deviceless = TestRunnerInvocation( 1259 test_runner=self.tr, 1260 extra_args={constants.HOST: True}, 1261 test_infos=[test_info_deviceless], 1262 ) 1263 expected_invocation_device = TestRunnerInvocation( 1264 test_runner=self.tr, extra_args={}, test_infos=[test_info_device] 1265 ) 1266 1267 self.assertEqual( 1268 invocations, 1269 [expected_invocation_deviceless, expected_invocation_device], 1270 ) 1271 1272 def test_create_invocations_returns_invocation_only_for_device_tests(self): 1273 self.tr.module_info = module_info.ModuleInfo( 1274 name_to_module_info={ 1275 'device_test_1': ( 1276 module_info_unittest_base.device_driven_test_module( 1277 name='device_test_1' 1278 ) 1279 ), 1280 'device_test_2': ( 1281 module_info_unittest_base.host_driven_device_test_module( 1282 name='device_test_2' 1283 ) 1284 ), 1285 } 1286 ) 1287 test_info_device_1 = test_info_of('device_test_1') 1288 test_info_device_2 = test_info_of('device_test_2') 1289 1290 invocations = self.tr.create_invocations( 1291 {}, [test_info_device_1, test_info_device_2] 1292 ) 1293 expected_invocation = TestRunnerInvocation( 1294 test_runner=self.tr, 1295 extra_args={}, 1296 test_infos=[test_info_device_1, test_info_device_2], 1297 ) 1298 1299 self.assertEqual(invocations, [expected_invocation]) 1300 1301 def test_create_invocations_returns_invocations_for_device_tests_without_module_info( 1302 self, 1303 ): 1304 self.tr.module_info = module_info.ModuleInfo() 1305 1306 test_info_device = test_info_of('device_test_without_module_info') 1307 1308 invocations = self.tr.create_invocations({}, [test_info_device]) 1309 expected_invocation = TestRunnerInvocation( 1310 test_runner=self.tr, 1311 extra_args={}, 1312 test_infos=[test_info_device], 1313 ) 1314 1315 self.assertEqual(invocations, [expected_invocation]) 1316 1317 def assertTokensIn(self, expected_tokens, s): 1318 tokens = shlex.split(s) 1319 for token in expected_tokens: 1320 self.assertIn(token, tokens) 1321 1322 def assertTokensNotIn(self, unwanted_tokens, s): 1323 tokens = shlex.split(s) 1324 for token in unwanted_tokens: 1325 self.assertNotIn(token, tokens) 1326 1327 1328class ExtraArgsTest(AtestTradefedTestRunnerUnittests): 1329 """Unit tests for parsing extra args""" 1330 1331 def test_args_with_wait_for_debug_and_generate_in_run_cmd(self): 1332 extra_args = {constants.WAIT_FOR_DEBUGGER: None} 1333 1334 cmd = self.tr.generate_run_commands([], extra_args) 1335 1336 self.assertTokensIn(['--wait-for-debugger'], cmd[0]) 1337 1338 def test_args_with_disable_installed_and_generate_in_run_cmd(self): 1339 extra_args = {constants.DISABLE_INSTALL: None} 1340 1341 cmd = self.tr.generate_run_commands([], extra_args) 1342 1343 self.assertTokensIn(['--disable-target-preparers'], cmd[0]) 1344 1345 def test_multidevice_in_config_and_generate_in_run_cmd(self): 1346 self._global_args.device_count_config = 2 1347 cmd = self.tr.generate_run_commands([], {}) 1348 self.assertTokensIn( 1349 ['--replicate-parent-setup', '--multi-device-count', '2'], cmd[0] 1350 ) 1351 1352 self._global_args.device_count_config = 1 1353 cmd = self.tr.generate_run_commands([], {}) 1354 self.assertTokensNotIn( 1355 ['--replicate-parent-setup', '--multi-device-count'], cmd[0] 1356 ) 1357 1358 self._global_args.device_count_config = None 1359 cmd = self.tr.generate_run_commands([], {}) 1360 self.assertTokensNotIn( 1361 ['--replicate-parent-setup', '--multi-device-count'], cmd[0] 1362 ) 1363 1364 def test_args_with_serial_no_and_generate_in_run_cmd(self): 1365 extra_args = {constants.SERIAL: ['device1']} 1366 1367 cmd = self.tr.generate_run_commands([], extra_args) 1368 1369 self.assertTokensIn(['--serial', 'device1'], cmd[0]) 1370 1371 def test_args_with_multi_serial_no_and_generate_in_run_cmd(self): 1372 extra_args = {constants.SERIAL: ['device1', 'device2']} 1373 1374 cmd = self.tr.generate_run_commands([], extra_args) 1375 1376 self.assertIn('--serial device1 --serial device2', cmd[0]) 1377 1378 def test_args_with_sharding_and_generate_in_run_cmd(self): 1379 extra_args = {constants.SHARDING: 2} 1380 1381 cmd = self.tr.generate_run_commands([], extra_args) 1382 1383 self.assertIn('--shard-count 2', cmd[0]) 1384 1385 def test_args_with_disable_teardown_and_generate_in_run_cmd(self): 1386 extra_args = {constants.DISABLE_TEARDOWN: True} 1387 1388 cmd = self.tr.generate_run_commands([], extra_args) 1389 1390 self.assertTokensIn(['--disable-teardown'], cmd[0]) 1391 1392 def test_args_with_host_and_generate_in_run_cmd(self): 1393 extra_args = {constants.HOST: True} 1394 1395 cmd = self.tr.generate_run_commands([], extra_args) 1396 1397 self.assertTokensIn( 1398 ['-n', '--prioritize-host-config', '--skip-host-arch-check'], cmd[0] 1399 ) 1400 1401 def test_args_with_custom_args_and_generate_in_run_cmd(self): 1402 extra_args = {constants.CUSTOM_ARGS: ['--a=b']} 1403 1404 cmd = self.tr.generate_run_commands([], extra_args) 1405 1406 self.assertTokensIn(['--a=b'], cmd[0]) 1407 1408 def test_args_with_multi_custom_args_and_generate_in_run_cmd(self): 1409 extra_args = {constants.CUSTOM_ARGS: ['--a=b', '--c=d']} 1410 1411 cmd = self.tr.generate_run_commands([], extra_args) 1412 1413 self.assertTokensIn(['--a=b', '--c=d'], cmd[0]) 1414 1415 def test_args_with_all_abi_and_generate_in_run_cmd(self): 1416 extra_args = {constants.ALL_ABI: True} 1417 1418 cmd = self.tr.generate_run_commands([], extra_args) 1419 1420 self.assertTokensIn(['--all-abi'], cmd[0]) 1421 1422 def test_args_with_dry_run_but_not_generate_in_run_cmd(self): 1423 extra_args = {constants.DRY_RUN: True} 1424 1425 cmd = self.tr.generate_run_commands([], extra_args) 1426 1427 self.assertTokensNotIn(['--dry-run'], cmd[0]) 1428 1429 def test_args_with_instant_and_generate_in_run_cmd(self): 1430 extra_args = {constants.INSTANT: True} 1431 1432 cmd = self.tr.generate_run_commands([], extra_args) 1433 1434 self.assertTokensIn( 1435 ['--enable-parameterized-modules', '--module-parameter', 'instant_app'], 1436 cmd[0], 1437 ) 1438 1439 def test_args_with_user_type_and_generate_in_run_cmd(self): 1440 extra_args = {constants.USER_TYPE: 'hello_user'} 1441 1442 cmd = self.tr.generate_run_commands([], extra_args) 1443 1444 self.assertTokensIn( 1445 [ 1446 '--enable-parameterized-modules', 1447 '--enable-optional-parameterization', 1448 '--module-parameter', 1449 'hello_user', 1450 ], 1451 cmd[0], 1452 ) 1453 1454 def test_args_with_iterations_and_generate_in_run_cmd(self): 1455 extra_args = {constants.ITERATIONS: 2} 1456 1457 cmd = self.tr.generate_run_commands([], extra_args) 1458 1459 self.assertIn('--retry-strategy ITERATIONS', cmd[0]) 1460 self.assertIn('--max-testcase-run-count 2', cmd[0]) 1461 1462 def test_args_with_retry_until_failure_and_generate_in_run_cmd(self): 1463 extra_args = {constants.RERUN_UNTIL_FAILURE: 2} 1464 1465 cmd = self.tr.generate_run_commands([], extra_args) 1466 1467 self.assertIn('--retry-strategy RERUN_UNTIL_FAILURE', cmd[0]) 1468 self.assertIn('--max-testcase-run-count 2', cmd[0]) 1469 1470 def test_args_with_retry_any_failure_and_generate_in_run_cmd(self): 1471 extra_args = {constants.RETRY_ANY_FAILURE: 2} 1472 1473 cmd = self.tr.generate_run_commands([], extra_args) 1474 1475 self.assertIn('--retry-strategy RETRY_ANY_FAILURE', cmd[0]) 1476 self.assertIn('--max-testcase-run-count 2', cmd[0]) 1477 1478 def test_args_with_collect_test_only_and_generate_in_run_cmd(self): 1479 extra_args = {constants.COLLECT_TESTS_ONLY: True} 1480 1481 cmd = self.tr.generate_run_commands([], extra_args) 1482 1483 self.assertTokensIn(['--collect-tests-only'], cmd[0]) 1484 1485 def test_args_with_tf_template_but_not_generate_in_run_cmd(self): 1486 extra_args = {constants.TF_TEMPLATE: ['hello']} 1487 1488 cmd = self.tr.generate_run_commands([], extra_args) 1489 1490 self.assertTokensNotIn(['--tf-template'], cmd[0]) 1491 1492 def test_args_with_timeout_and_generate_in_run_cmd(self): 1493 extra_args = {constants.TEST_TIMEOUT: 10000} 1494 1495 cmd = self.tr.generate_run_commands([], extra_args) 1496 1497 self.assertTokensIn( 1498 [ 1499 '--test-arg', 1500 ( 1501 'com.android.tradefed.testtype.AndroidJUnitTest:' 1502 'shell-timeout:10000' 1503 ), 1504 '--test-arg', 1505 'com.android.tradefed.testtype.AndroidJUnitTest:test-timeout:10000', 1506 '--test-arg', 1507 'com.android.tradefed.testtype.HostGTest:native-test-timeout:10000', 1508 '--test-arg', 1509 'com.android.tradefed.testtype.GTest:native-test-timeout:10000', 1510 ], 1511 cmd[0], 1512 ) 1513 1514 1515def test_info_of(module_name): 1516 return test_info.TestInfo( 1517 module_name, atf_tr.AtestTradefedTestRunner.NAME, [] 1518 ) 1519 1520 1521class DeviceDrivenTestTest(module_info_unittest_base.ModuleInfoTest): 1522 """Tests for device driven test.""" 1523 1524 def test_multi_config_unit_test_without_host_arg(self): 1525 mod_info = self.create_module_info( 1526 modules=[ 1527 module_info_unittest_base.multi_variant_unit_test_module( 1528 name='hello_world_test' 1529 ) 1530 ] 1531 ) 1532 test_infos = [test_info_of('hello_world_test')] 1533 runner = atf_tr.AtestTradefedTestRunner( 1534 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1535 ) 1536 expect_deps = { 1537 'aapt2-host', 1538 'hello_world_test-target', 1539 'compatibility-tradefed-host', 1540 'adb-host', 1541 'atest-tradefed-host', 1542 'aapt-host', 1543 'atest_tradefed.sh-host', 1544 'tradefed-host', 1545 'atest_script_help.sh-host', 1546 } 1547 1548 deps = runner.get_test_runner_build_reqs(test_infos) 1549 1550 self.assertContainsSubset(expect_deps, deps) 1551 1552 @mock.patch.dict('os.environ', {'ANDROID_HOST_OUT': ANDROID_HOST_OUT}) 1553 def test_host_jar_env_device_driven_test_without_host_arg(self): 1554 tf_host_jar_path = os.path.join(ANDROID_HOST_OUT, 'tradefed.jar') 1555 atest_host_jar_path = os.path.join(ANDROID_HOST_OUT, 'atest-tradefed.jar') 1556 host_required_jar_path = os.path.join(ANDROID_HOST_OUT, 'host-required.jar') 1557 mod_info = self.create_module_info( 1558 modules=[ 1559 module_info_unittest_base.device_driven_test_module( 1560 name='hello_world_test', host_deps=['host-required'] 1561 ), 1562 module_info_unittest_base.host_jar_module( 1563 name='tradefed', installed=[tf_host_jar_path] 1564 ), 1565 module_info_unittest_base.host_jar_module( 1566 name='atest-tradefed', installed=[atest_host_jar_path] 1567 ), 1568 module_info_unittest_base.host_jar_module( 1569 name='host-required', installed=[host_required_jar_path] 1570 ), 1571 ] 1572 ) 1573 test_infos = [test_info_of('hello_world_test')] 1574 runner = atf_tr.AtestTradefedTestRunner( 1575 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1576 ) 1577 expect_path = { 1578 tf_host_jar_path, 1579 atest_host_jar_path, 1580 host_required_jar_path, 1581 } 1582 1583 runner.get_test_runner_build_reqs(test_infos) 1584 env = runner.generate_env_vars(dict()) 1585 1586 self.assertSetEqual(set(env['ATEST_HOST_JARS'].split(':')), expect_path) 1587 1588 def test_host_driven_device_test(self): 1589 mod_info = self.create_module_info( 1590 modules=[ 1591 module_info_unittest_base.host_driven_device_test_module( 1592 name='hello_world_test', libs=['lib'] 1593 ), 1594 module_info_unittest_base.module( 1595 name='lib', 1596 supported_variants=['HOST'], 1597 installed=[f'out/host/linux-x86/lib/lib.jar'], 1598 ), 1599 ] 1600 ) 1601 test_infos = [test_info_of('hello_world_test')] 1602 runner = atf_tr.AtestTradefedTestRunner( 1603 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1604 ) 1605 1606 deps = runner.get_test_runner_build_reqs(test_infos) 1607 1608 self.assertContainsSubset({'hello_world_test-host', 'lib-host'}, deps) 1609 1610 def test_device_driven_test_with_mainline_modules(self): 1611 mod_info = self.create_module_info( 1612 modules=[ 1613 module_info_unittest_base.device_driven_test_module( 1614 name='hello_world_test' 1615 ) 1616 ] 1617 ) 1618 t_info = test_info_of('hello_world_test') 1619 t_info.add_mainline_module('mainline_module_1') 1620 t_info.add_mainline_module('mainline_module_2') 1621 runner = atf_tr.AtestTradefedTestRunner( 1622 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1623 ) 1624 1625 deps = runner.get_test_runner_build_reqs([t_info]) 1626 1627 self.assertContainsSubset( 1628 {'hello_world_test-target', 'mainline_module_1', 'mainline_module_2'}, 1629 deps, 1630 ) 1631 1632 def test_device_driven_test_with_vts_suite(self): 1633 mod_info = self.create_module_info( 1634 modules=[ 1635 module_info_unittest_base.device_driven_test_module( 1636 name='hello_world_test', compatibility_suites=['vts'] 1637 ), 1638 ] 1639 ) 1640 test_infos = [test_info_of('hello_world_test')] 1641 runner = atf_tr.AtestTradefedTestRunner( 1642 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1643 ) 1644 1645 deps = runner.get_test_runner_build_reqs(test_infos) 1646 1647 self.assertIn('vts-core-tradefed-harness-host', deps) 1648 self.assertNotIn('compatibility-tradefed-host', deps) 1649 1650 def test_deps_contain_google_tradefed(self): 1651 mod_info = self.create_module_info( 1652 modules=[ 1653 module_info_unittest_base.multi_variant_unit_test_module( 1654 name='hello_world_test' 1655 ) 1656 ] 1657 ) 1658 test_infos = [test_info_of('hello_world_test')] 1659 runner = atf_tr.AtestTradefedTestRunner( 1660 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1661 ) 1662 gtf_target = set([str(t) + '-host' for t in constants.GTF_TARGETS]) 1663 1664 deps = runner.get_test_runner_build_reqs(test_infos) 1665 1666 self.assertContainsSubset(gtf_target, deps) 1667 1668 def test_java_device_test(self): 1669 mod_info = self.create_module_info( 1670 modules=[ 1671 module_info_unittest_base.device_driven_test_module( 1672 name='HelloWorldTest', 1673 installed=['out/product/vsoc_x86/testcases/HelloWorldTest.jar'], 1674 class_type=['JAVA_LIBRARIES'], 1675 ) 1676 ] 1677 ) 1678 t_info = test_info_of('HelloWorldTest') 1679 runner = atf_tr.AtestTradefedTestRunner( 1680 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1681 ) 1682 1683 deps = runner.get_test_runner_build_reqs([t_info]) 1684 1685 self.assertContainsSubset( 1686 { 1687 'cts-dalvik-device-test-runner-target', 1688 'cts-dalvik-host-test-runner-host', 1689 }, 1690 deps, 1691 ) 1692 1693 def test_requires_device_update_is_device_driven_test_returns_true(self): 1694 mod_info = self.create_module_info( 1695 modules=[ 1696 module_info_unittest_base.device_driven_test_module( 1697 name='hello_world_test', 1698 ), 1699 ] 1700 ) 1701 test_infos = [test_info_of('hello_world_test')] 1702 runner = atf_tr.AtestTradefedTestRunner( 1703 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1704 ) 1705 1706 requires_device_update = runner.requires_device_update(test_infos) 1707 1708 self.assertTrue(requires_device_update) 1709 1710 def test_requires_device_update_is_unit_test_returns_false(self): 1711 mod_info = self.create_module_info( 1712 modules=[ 1713 module_info_unittest_base.device_driven_test_module( 1714 name='hello_world_test', 1715 is_unit_test='true', 1716 ), 1717 ] 1718 ) 1719 test_infos = [test_info_of('hello_world_test')] 1720 runner = atf_tr.AtestTradefedTestRunner( 1721 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1722 ) 1723 1724 requires_device_update = runner.requires_device_update(test_infos) 1725 1726 self.assertFalse(requires_device_update) 1727 1728 def test_requires_device_update_no_module_info_returns_true(self): 1729 mod_info = self.create_module_info(modules=[]) 1730 test_infos = [test_info_of('hello_world_test')] 1731 runner = atf_tr.AtestTradefedTestRunner( 1732 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1733 ) 1734 1735 requires_device_update = runner.requires_device_update(test_infos) 1736 1737 self.assertTrue(requires_device_update) 1738 1739 1740class DevicelessTestTest(module_info_unittest_base.ModuleInfoTest): 1741 """Tests for deviceless test.""" 1742 1743 def test_multi_config_unit_test_with_host_arg(self): 1744 mod_info = self.create_module_info( 1745 modules=[ 1746 module_info_unittest_base.multi_variant_unit_test_module( 1747 name='hello_world_test' 1748 ) 1749 ] 1750 ) 1751 test_infos = [test_info_of('hello_world_test')] 1752 runner = atf_tr.AtestTradefedTestRunner( 1753 'result_dir', {constants.HOST: True}, mod_info, minimal_build=True 1754 ) 1755 expect_deps = { 1756 'hello_world_test-host', 1757 'adb-host', 1758 'atest-tradefed-host', 1759 'atest_tradefed.sh-host', 1760 'tradefed-host', 1761 'atest_script_help.sh-host', 1762 } 1763 1764 deps = runner.get_test_runner_build_reqs(test_infos) 1765 1766 self.assertContainsSubset(expect_deps, deps) 1767 1768 def test_robolectric_test(self): 1769 mod_info = self.create_module_info( 1770 modules=[ 1771 module_info_unittest_base.robolectric_test_module( 1772 name='hello_world_test' 1773 ) 1774 ] 1775 ) 1776 test_infos = [test_info_of('hello_world_test')] 1777 runner = atf_tr.AtestTradefedTestRunner( 1778 'result_dir', {constants.HOST: False}, mod_info, minimal_build=True 1779 ) 1780 expect_deps = { 1781 'hello_world_test-target', 1782 'adb-host', 1783 'atest-tradefed-host', 1784 'atest_tradefed.sh-host', 1785 'tradefed-host', 1786 'atest_script_help.sh-host', 1787 } 1788 1789 deps = runner.get_test_runner_build_reqs(test_infos) 1790 1791 self.assertContainsSubset(expect_deps, deps) 1792 1793 1794class TestExtraArgsToTfArgs(unittest.TestCase): 1795 """Tests for extra_args_to_tf_args function.""" 1796 1797 def test_supported_args(self): 1798 extra_args = { 1799 constants.WAIT_FOR_DEBUGGER: True, 1800 constants.SHARDING: 5, 1801 constants.SERIAL: ['device1', 'device2'], 1802 constants.CUSTOM_ARGS: ['arg1', 'arg2'], 1803 constants.ITERATIONS: 3, 1804 } 1805 expected_supported_args = [ 1806 '--wait-for-debugger', 1807 '--shard-count', 1808 '5', 1809 '--serial', 1810 'device1', 1811 '--serial', 1812 'device2', 1813 'arg1', 1814 'arg2', 1815 '--retry-strategy', 1816 constants.ITERATIONS, 1817 '--max-testcase-run-count', 1818 '3', 1819 ] 1820 1821 supported_args, _ = atf_tr.extra_args_to_tf_args(extra_args) 1822 1823 self.assertEqual(expected_supported_args, supported_args) 1824 1825 def test_unsupported_args(self): 1826 extra_args = { 1827 'invalid_arg': 'value', 1828 'tf_template': 'template', 1829 } 1830 expected_unsupported_args = ['invalid_arg', 'tf_template'] 1831 1832 _, unsupported_args = atf_tr.extra_args_to_tf_args(extra_args) 1833 1834 self.assertEqual(expected_unsupported_args, unsupported_args) 1835 1836 def test_empty_extra_args(self): 1837 extra_args = {} 1838 1839 supported_args, unsupported_args = atf_tr.extra_args_to_tf_args(extra_args) 1840 1841 self.assertEqual([], supported_args) 1842 self.assertEqual([], unsupported_args) 1843 1844 1845if __name__ == '__main__': 1846 unittest.main() 1847