1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# Copyright 2020 The Chromium OS Authors. All rights reserved. 5# Use of this source code is governed by a BSD-style license that can be 6# found in the LICENSE file. 7""" 8Unittest for device_setup_utils. 9 10""" 11 12from __future__ import print_function 13 14import logging 15import time 16import unittest 17from unittest import mock 18 19import common 20from autotest_lib.server import hosts 21from autotest_lib.server.cros.crosperf import device_setup_utils 22 23BIG_LITTLE_CPUINFO = """processor : 0 24model name : ARMv8 Processor rev 4 (v8l) 25BogoMIPS : 48.00 26Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 27CPU implementer : 0x41 28CPU architecture: 8 29CPU variant : 0x0 30CPU part : 0xd03 31CPU revision : 4 32 33processor : 1 34model name : ARMv8 Processor rev 4 (v8l) 35BogoMIPS : 48.00 36Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 37CPU implementer : 0x41 38CPU architecture: 8 39CPU variant : 0x0 40CPU part : 0xd03 41CPU revision : 4 42 43processor : 2 44model name : ARMv8 Processor rev 2 (v8l) 45BogoMIPS : 48.00 46Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 47CPU implementer : 0x41 48CPU architecture: 8 49CPU variant : 0x0 50CPU part : 0xd08 51CPU revision : 2 52""" 53LITTLE_ONLY_CPUINFO = """processor : 0 54model name : ARMv8 Processor rev 4 (v8l) 55BogoMIPS : 48.00 56Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 57CPU implementer : 0x41 58CPU architecture: 8 59CPU variant : 0x0 60CPU part : 0xd03 61CPU revision : 4 62 63processor : 1 64model name : ARMv8 Processor rev 4 (v8l) 65BogoMIPS : 48.00 66Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 67CPU implementer : 0x41 68CPU architecture: 8 69CPU variant : 0x0 70CPU part : 0xd03 71CPU revision : 4 72""" 73 74NOT_BIG_LITTLE_CPUINFO = """processor : 0 75model name : ARMv7 Processor rev 1 (v7l) 76Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 77CPU implementer : 0x41 78CPU architecture: 7 79CPU variant : 0x0 80CPU part : 0xc0d 81CPU revision : 1 82 83processor : 1 84model name : ARMv7 Processor rev 1 (v7l) 85Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 86CPU implementer : 0x41 87CPU architecture: 7 88CPU variant : 0x0 89CPU part : 0xc0d 90CPU revision : 1 91 92Hardware : Rockchip (Device Tree) 93Revision : 0000 94Serial : 0000000000000000 95""" 96 97 98class device_setup_utilsTest(unittest.TestCase): 99 """ 100 Class of device setup utils test. 101 """ 102 103 def __init__(self, *args, **kwargs): 104 super(device_setup_utilsTest, self).__init__(*args, **kwargs) 105 106 self.dut = mock.Mock(spec=hosts.create_host) 107 self.dut.hostname = 'lumpy.cros2' 108 self.dut.run = mock.Mock() 109 110 logging.error = mock.Mock() 111 logging.warning = mock.Mock() 112 113 114 def test_run_command_on_dut(self): 115 self.dut.run.return_value.exit_status = 0 116 self.dut.run.return_value.stdout = '' 117 self.dut.run.return_value.stderr = '' 118 119 self.dut.run.assert_not_called() 120 device_setup_utils.run_command_on_dut(self.dut, 'run command;') 121 self.dut.run.assert_called_once_with( 122 'run command;', ignore_status=False) 123 124 125 def test_run_command_on_dut_fatal_error(self): 126 # Command returns error 1. 127 self.dut.run.return_value.exit_status = 1 128 self.dut.run.return_value.stdout = '' 129 self.dut.run.return_value.stderr = 'Error!' 130 131 self.dut.run.assert_not_called() 132 device_setup_utils.run_command_on_dut(self.dut, 'run command;') 133 self.dut.run.assert_called_once_with( 134 'run command;', ignore_status=False) 135 # Error status causes log fatal. 136 logging.error.assert_called_once_with( 137 'Command execution on DUT lumpy.cros2 failed.\n' 138 'Failing command: run command;\nreturned 1\n' 139 'Error message: Error!') 140 141 142 def test_run_command_on_dut_ignore_error(self): 143 # Command returns error 1. 144 self.dut.run.return_value.exit_status = 1 145 self.dut.run.return_value.stdout = '' 146 self.dut.run.return_value.stderr = 'Error!' 147 148 self.dut.run.assert_not_called() 149 device_setup_utils.run_command_on_dut( 150 self.dut, 'run command;', ignore_status=True) 151 self.dut.run.assert_called_once_with( 152 'run command;', ignore_status=True) 153 # Error status causes log fatal. 154 calls = [ 155 mock.call('Command execution on DUT lumpy.cros2 failed.\n' 156 'Failing command: run command;\nreturned 1\n' 157 'Error message: Error!'), 158 mock.call('Failure is considered non-fatal. Continue.'), 159 ] 160 logging.warning.assert_has_calls(calls) 161 162 163 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 164 def test_disable_aslr(self, mock_run_command): 165 mock_run_command.return_value = (0, '', '') 166 device_setup_utils.disable_aslr(self.dut) 167 # pyformat: disable 168 set_cpu_cmd = ('set -e; ' 169 'if [[ -e /proc/sys/kernel/randomize_va_space ]]; then ' 170 ' echo 0 > /proc/sys/kernel/randomize_va_space; ' 171 'fi') 172 mock_run_command.assert_called_once_with(self.dut, set_cpu_cmd) 173 174 175 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 176 def test_set_cpu_governor(self, mock_run_command): 177 mock_run_command.return_value = (0, '', '') 178 device_setup_utils.set_cpu_governor( 179 self.dut, 'new_governor', ignore_status=False) 180 set_cpu_cmd = ( 181 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do' 182 # Skip writing scaling_governor if cpu is offline. 183 ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' 184 ' && continue; ' 185 ' cd $f; ' 186 ' if [[ -e scaling_governor ]]; then ' 187 ' echo %s > scaling_governor; fi; ' 188 'done; ') 189 mock_run_command.assert_called_once_with( 190 self.dut, set_cpu_cmd % 'new_governor', ignore_status=False) 191 192 193 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 194 def test_set_cpu_governor_propagate_error(self, mock_run_command): 195 mock_run_command.return_value = (1, '', 'Error.') 196 device_setup_utils.set_cpu_governor(self.dut, 'non-exist_governor') 197 set_cpu_cmd = ( 198 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do' 199 # Skip writing scaling_governor if cpu is not online. 200 ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' 201 ' && continue; ' 202 ' cd $f; ' 203 ' if [[ -e scaling_governor ]]; then ' 204 ' echo %s > scaling_governor; fi; ' 205 'done; ') 206 # By default error status is fatal. 207 mock_run_command.assert_called_once_with( 208 self.dut, 209 set_cpu_cmd % 'non-exist_governor', 210 ignore_status=False) 211 212 213 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 214 def test_set_cpu_governor_ignore_status(self, mock_run_command): 215 mock_run_command.return_value = (1, '', 'Error.') 216 ret_code = device_setup_utils.set_cpu_governor( 217 self.dut, 'non-exist_governor', ignore_status=True) 218 set_cpu_cmd = ( 219 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do' 220 # Skip writing scaling_governor if cpu is not online. 221 ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' 222 ' && continue; ' 223 ' cd $f; ' 224 ' if [[ -e scaling_governor ]]; then ' 225 ' echo %s > scaling_governor; fi; ' 226 'done; ') 227 mock_run_command.assert_called_once_with( 228 self.dut, 229 set_cpu_cmd % 'non-exist_governor', 230 ignore_status=True) 231 self.assertEqual(ret_code, 1) 232 233 234 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 235 def test_disable_turbo(self, mock_run_command): 236 mock_run_command.return_value = (0, '', '') 237 device_setup_utils.disable_turbo(self.dut) 238 set_cpu_cmd = ( 239 # Disable Turbo the in Intel pstate driver. 240 'if [[ -e /sys/devices/system/cpu/intel_pstate/no_turbo ]]; then ' 241 ' if grep -q 0 /sys/devices/system/cpu/intel_pstate/no_turbo; then ' 242 ' echo -n 1 > /sys/devices/system/cpu/intel_pstate/no_turbo; ' 243 ' fi; ' 244 'fi; ' 245 # Disable Boost on AMD. 246 'if [[ -e /sys/devices/system/cpu/cpufreq/boost ]]; then ' 247 ' if grep -q 1 /sys/devices/system/cpu/cpufreq/boost; then ' 248 ' echo -n 0 > /sys/devices/system/cpu/cpufreq/boost; ' 249 ' fi; ' 250 'fi; ' 251 ) 252 mock_run_command.assert_called_once_with(self.dut, set_cpu_cmd) 253 254 255 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 256 def test_get_cpu_online_two(self, mock_run_command): 257 """Test one digit CPU #.""" 258 mock_run_command.return_value = ( 259 0, '/sys/devices/system/cpu/cpu0/online 0\n' 260 '/sys/devices/system/cpu/cpu1/online 1\n', '') 261 cpu_online = device_setup_utils.get_cpu_online(self.dut) 262 self.assertEqual(cpu_online, {0: 0, 1: 1}) 263 264 265 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 266 def test_get_cpu_online_twelve(self, mock_run_command): 267 """Test two digit CPU #.""" 268 mock_run_command.return_value = ( 269 0, '/sys/devices/system/cpu/cpu0/online 1\n' 270 '/sys/devices/system/cpu/cpu1/online 0\n' 271 '/sys/devices/system/cpu/cpu10/online 1\n' 272 '/sys/devices/system/cpu/cpu11/online 1\n' 273 '/sys/devices/system/cpu/cpu2/online 1\n' 274 '/sys/devices/system/cpu/cpu3/online 0\n' 275 '/sys/devices/system/cpu/cpu4/online 1\n' 276 '/sys/devices/system/cpu/cpu5/online 0\n' 277 '/sys/devices/system/cpu/cpu6/online 1\n' 278 '/sys/devices/system/cpu/cpu7/online 0\n' 279 '/sys/devices/system/cpu/cpu8/online 1\n' 280 '/sys/devices/system/cpu/cpu9/online 0\n', '') 281 cpu_online = device_setup_utils.get_cpu_online(self.dut) 282 self.assertEqual( 283 cpu_online, { 284 0: 1, 285 1: 0, 286 2: 1, 287 3: 0, 288 4: 1, 289 5: 0, 290 6: 1, 291 7: 0, 292 8: 1, 293 9: 0, 294 10: 1, 295 11: 1 296 }) 297 298 299 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 300 def test_get_cpu_online_core0_not_exposed(self, mock_run_command): 301 """Test that not exposed cpu0/online will still be in the list.""" 302 303 def run_command(dut, cmd): 304 """Helper function.""" 305 if '/sys/devices/system/cpu/cpu' in cmd: 306 # Cpu0 online is not exposed. 307 return (0, '/sys/devices/system/cpu/cpu1/online 1\n', '') 308 elif '/sys/devices/system/cpu/online' in cmd: 309 # All online cores shows cpu0. 310 return (0, '0-1', '') 311 else: 312 return (1, '', '') 313 314 mock_run_command.side_effect = run_command 315 cpu_online = device_setup_utils.get_cpu_online(self.dut) 316 # Make sure core0 in the online list. 317 self.assertEqual(cpu_online, {0: 1, 1: 1}) 318 319 320 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 321 def test_get_cpu_online_no_output(self, mock_run_command): 322 """Test error case, no output.""" 323 mock_run_command.return_value = (0, '', '') 324 with self.assertRaises(AssertionError): 325 device_setup_utils.get_cpu_online(self.dut) 326 327 328 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 329 def test_get_cpu_online_command_error(self, mock_run_command): 330 """Test error case, command error.""" 331 mock_run_command.side_effect = AssertionError 332 with self.assertRaises(AssertionError): 333 device_setup_utils.get_cpu_online(self.dut) 334 335 336 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 337 @mock.patch.object(device_setup_utils, 'setup_arm_cores') 338 def test_setup_cpu_usage_little_on_arm(self, mock_setup_arm, 339 mock_run_command): 340 device_setup_utils.setup_arm_cores = mock_setup_arm 341 mock_run_command.return_value = (0, 'armv7l', '') 342 cpu_usage = 'little_only' 343 device_setup_utils.setup_cpu_usage(self.dut, cpu_usage) 344 mock_setup_arm.assert_called_once() 345 346 347 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 348 @mock.patch.object(device_setup_utils, 'setup_arm_cores') 349 def test_setup_cpu_usage_big_on_aarch64(self, mock_setup_arm, 350 mock_run_command): 351 device_setup_utils.setup_arm_cores = mock_setup_arm 352 mock_run_command.return_value = (0, 'aarch64', '') 353 cpu_usage = 'big_only' 354 device_setup_utils.setup_cpu_usage(self.dut, cpu_usage) 355 mock_setup_arm.assert_called_once() 356 357 358 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 359 @mock.patch.object(device_setup_utils, 'setup_arm_cores') 360 def test_setup_cpu_usage_big_on_intel(self, mock_setup_arm, 361 mock_run_command): 362 device_setup_utils.setup_arm_cores = mock_setup_arm 363 mock_run_command.return_value = (0, 'x86_64', '') 364 cpu_usage = 'big_only' 365 device_setup_utils.setup_cpu_usage(self.dut, cpu_usage) 366 # Check that setup_arm_cores not called with invalid setup. 367 mock_setup_arm.assert_not_called() 368 369 370 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 371 @mock.patch.object(device_setup_utils, 'setup_arm_cores') 372 def test_setup_cpu_usage_all_on_intel(self, mock_setup_arm, 373 mock_run_command): 374 device_setup_utils.setup_arm_cores = mock_setup_arm 375 mock_run_command.return_value = (0, 'x86_64', '') 376 cpu_usage = 'all' 377 device_setup_utils.setup_cpu_usage(self.dut, cpu_usage) 378 # Check that setup_arm_cores not called in general case. 379 mock_setup_arm.assert_not_called() 380 381 382 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 383 def test_setup_arm_cores_big_on_big_little(self, mock_run_command): 384 mock_run_command.side_effect = [ 385 (0, BIG_LITTLE_CPUINFO, ''), 386 (0, '', ''), 387 ] 388 cpu_usage = 'big_only' 389 device_setup_utils.setup_arm_cores(self.dut, cpu_usage) 390 mock_run_command.assert_called_with( 391 self.dut, 392 'echo 1 | tee /sys/devices/system/cpu/cpu{2}/online; ' 393 'echo 0 | tee /sys/devices/system/cpu/cpu{0,1}/online') 394 395 396 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 397 def test_setup_arm_cores_little_on_big_little(self, mock_run_command): 398 mock_run_command.side_effect = [ 399 (0, BIG_LITTLE_CPUINFO, ''), 400 (0, '', ''), 401 ] 402 cpu_usage = 'little_only' 403 device_setup_utils.setup_arm_cores(self.dut, cpu_usage) 404 mock_run_command.assert_called_with( 405 self.dut, 406 'echo 1 | tee /sys/devices/system/cpu/cpu{0,1}/online; ' 407 'echo 0 | tee /sys/devices/system/cpu/cpu{2}/online') 408 409 410 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 411 def test_setup_arm_cores_invalid_config(self, mock_run_command): 412 mock_run_command.side_effect = [ 413 (0, LITTLE_ONLY_CPUINFO, ''), 414 (0, '', ''), 415 ] 416 cpu_usage = 'big_only' 417 device_setup_utils.setup_arm_cores(self.dut, cpu_usage) 418 # Check that setup command is not sent when trying 419 # to use 'big_only' on a platform with all little cores. 420 mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo') 421 422 423 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 424 def test_setup_arm_cores_not_big_little(self, mock_run_command): 425 mock_run_command.side_effect = [ 426 (0, NOT_BIG_LITTLE_CPUINFO, ''), 427 (0, '', ''), 428 ] 429 cpu_usage = 'big_only' 430 device_setup_utils.setup_arm_cores(self.dut, cpu_usage) 431 # Check that setup command is not sent when trying 432 # to use 'big_only' on a platform w/o support of big/little. 433 mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo') 434 435 436 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 437 def test_setup_arm_cores_unsupported_cpu_usage(self, mock_run_command): 438 mock_run_command.side_effect = [ 439 (0, BIG_LITTLE_CPUINFO, ''), 440 (0, '', ''), 441 ] 442 cpu_usage = 'exclusive_cores' 443 device_setup_utils.setup_arm_cores(self.dut, cpu_usage) 444 # Check that setup command is not sent when trying to use 445 # 'exclusive_cores' on ARM CPU setup. 446 mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo') 447 448 449 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 450 def test_setup_cpu_freq_single_full(self, mock_run_command): 451 online = [0] 452 mock_run_command.side_effect = [ 453 (0, 454 '/sys/devices/system/cpu/cpu0/cpufreq/' 455 'scaling_available_frequencies\n', 456 ''), 457 (0, '1 2 3 4 5 6 7 8 9 10', ''), 458 (0, '', ''), 459 ] 460 cpu_frq_pct = 100 461 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 462 self.assertGreaterEqual(mock_run_command.call_count, 3) 463 self.assertIn( 464 mock.call( 465 self.dut, 'echo 10 | tee ' 466 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' 467 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq' 468 ), 469 mock_run_command.call_args_list) 470 # Check the fix of single core online. 471 # We expect to see cpu0 instead of cpu{0}. 472 self.assertIn( 473 mock.call(self.dut, 474 'ls /sys/devices/system/cpu/cpu0/cpufreq/' 475 'scaling_available_frequencies', 476 ignore_status=True), 477 mock_run_command.call_args_list) 478 479 480 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 481 def test_setup_cpu_freq_middle(self, mock_run_command): 482 online = [0] 483 mock_run_command.side_effect = [ 484 (0, 485 '/sys/devices/system/cpu/cpu0/cpufreq/' 486 'scaling_available_frequencies\n', 487 ''), 488 (0, '1 2 3 4 5 6 7 8 9 10', ''), 489 (0, '', ''), 490 ] 491 cpu_frq_pct = 60 492 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 493 self.assertGreaterEqual(mock_run_command.call_count, 2) 494 self.assertEqual( 495 mock_run_command.call_args, 496 mock.call( 497 self.dut, 'echo 6 | tee ' 498 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' 499 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq' 500 )) 501 502 503 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 504 def test_setup_cpu_freq_lowest(self, mock_run_command): 505 online = [0] 506 mock_run_command.side_effect = [ 507 (0, 508 '/sys/devices/system/cpu/cpu0/cpufreq/' 509 'scaling_available_frequencies\n', 510 ''), 511 (0, '1 2 3 4 5 6 7 8 9 10', ''), 512 (0, '', ''), 513 ] 514 cpu_frq_pct = 0 515 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 516 self.assertGreaterEqual(mock_run_command.call_count, 2) 517 self.assertEqual( 518 mock_run_command.call_args, 519 mock.call( 520 self.dut, 'echo 1 | tee ' 521 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' 522 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq' 523 )) 524 525 526 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 527 def test_setup_cpu_freq_multiple_middle(self, mock_run_command): 528 online = [0, 1] 529 mock_run_command.side_effect = [ 530 (0, 531 '/sys/devices/system/cpu/cpu0/cpufreq/' 532 'scaling_available_frequencies\n' 533 '/sys/devices/system/cpu/cpu1/cpufreq/' 534 'scaling_available_frequencies\n', 535 ''), 536 (0, '1 2 3 4 5 6 7 8 9 10', ''), 537 (0, '', ''), 538 (0, '1 4 6 8 10 12 14 16 18 20', ''), 539 (0, '', ''), 540 ] 541 cpu_frq_pct = 70 542 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 543 self.assertEqual(mock_run_command.call_count, 5) 544 self.assertIn( 545 mock.call( 546 self.dut, 'echo 7 | tee ' 547 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' 548 '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq' 549 ), 550 mock_run_command.call_args_list) 551 self.assertIn( 552 mock.call( 553 self.dut, 'echo 14 | tee ' 554 '/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq ' 555 '/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq' 556 ), 557 mock_run_command.call_args_list) 558 # Check that setup_cpu_freq queries all online cores. 559 self.assertIn( 560 mock.call(self.dut, 561 'ls /sys/devices/system/cpu/cpu{0,1}/cpufreq/' 562 'scaling_available_frequencies', 563 ignore_status=True), 564 mock_run_command.call_args_list) 565 566 567 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 568 def test_setup_cpu_freq_no_scaling_available(self, mock_run_command): 569 online = [0, 1] 570 mock_run_command.return_value = (2, '', 'No such file or directory') 571 cpu_frq_pct = 50 572 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 573 mock_run_command.assert_called_once() 574 self.assertNotRegexpMatches(mock_run_command.call_args_list[0][0][1], 575 '^echo.*scaling_max_freq$') 576 577 578 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 579 def test_setup_cpu_freq_multiple_no_access(self, mock_run_command): 580 online = [0, 1] 581 mock_run_command.side_effect = [ 582 (0, 583 '/sys/devices/system/cpu/cpu0/cpufreq/' 584 'scaling_available_frequencies\n' 585 '/sys/devices/system/cpu/cpu1/cpufreq/' 586 'scaling_available_frequencies\n', 587 ''), 588 (0, '1 4 6 8 10 12 14 16 18 20', ''), 589 AssertionError(), 590 ] 591 cpu_frq_pct = 30 592 # Error status causes log fatal. 593 with self.assertRaises(AssertionError): 594 device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online) 595 596 597 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 598 @mock.patch.object(time, 'sleep') 599 def test_wait_cooldown_nowait(self, mock_sleep, mock_run_command): 600 """ 601 No cooldown wait. 602 603 Don't wait when the temperature in uC does not exceed 40C. 604 """ 605 mock_sleep.return_value = 0 606 mock_run_command.side_effect = [ 607 (0, '/sys/class/thermal/thermal_zone0/temp', ''), 608 (0, 'cpu', ''), 609 (0, '39000', ''), 610 ] 611 cooldown_time = 10 612 cooldown_temp = 40 613 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 614 cooldown_temp) 615 mock_run_command.assert_called() 616 # Expect no wait time. 617 mock_sleep.assert_not_called() 618 self.assertEqual(wait_time, 0) 619 620 621 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 622 @mock.patch.object(time, 'sleep') 623 def test_wait_cooldown_needwait_once(self, mock_sleep, mock_run_command): 624 """ 625 Wait one iteration for cooldown. 626 627 Set large enough timeout and changing temperature output. 628 Make sure it exits when expected value received. 629 """ 630 mock_sleep.return_value = 0 631 mock_run_command.side_effect = [ 632 (0, '/sys/class/thermal/thermal_zone0/temp', ''), 633 (0, 'cpu', ''), 634 (0, '41000', ''), 635 (0, '39000', ''), 636 ] 637 cooldown_time = 100 638 cooldown_temp = 40 639 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 640 cooldown_temp) 641 mock_run_command.assert_called() 642 # Wait time is non-zero. 643 mock_sleep.assert_called() 644 self.assertGreater(wait_time, 0) 645 646 647 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 648 @mock.patch.object(time, 'sleep') 649 def test_wait_cooldown_space_in_thermal_name(self, mock_sleep, 650 mock_run_command): 651 """ 652 Wait one iteration for cooldown. 653 654 Make sure the cooldown is working properly when there is a space 655 in the sensor type name. 656 """ 657 mock_sleep.return_value = 0 658 mock_run_command.side_effect = [ 659 (0, '/sys/class/thermal/thermal_zone0/temp\n' 660 '/sys/class/thermal/thermal_zone1/temp', ''), 661 (0, 'cpu\ngpu thermal', ''), 662 (0, '39000', ''), 663 (0, '41000', ''), 664 (0, '38000', ''), 665 ] 666 cooldown_time = 10 667 cooldown_temp = 40 668 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 669 cooldown_temp) 670 mock_run_command.assert_called() 671 # Expect no wait time. 672 mock_sleep.assert_called_once() 673 self.assertGreater(wait_time, 0) 674 675 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 676 @mock.patch.object(time, 'sleep') 677 def test_wait_cooldown_wait_timeout(self, mock_sleep, mock_run_command): 678 """ 679 Test exit by timeout. 680 681 Send command to DUT checking the temperature and 682 check repeatedly until timeout goes off. 683 Output from temperature sensor never changes. 684 685 """ 686 687 def constant_temp(temp): 688 """Helper function returns gradually decreasing temperature.""" 689 yield (0, '/sys/class/thermal/thermal_zone0/temp', '') 690 yield (0, 'cpu', '') 691 while True: 692 yield (0, str(temp), '') 693 694 mock_sleep.return_value = 0 695 # Set the temperature higher than a default threshold 40k. 696 mock_run_command.side_effect = constant_temp(41000) 697 # Cooldown time - 5 minutes. 698 cooldown_time = 5 699 cooldown_temp = 40 700 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 701 cooldown_temp) 702 mock_run_command.assert_called() 703 mock_sleep.assert_called() 704 # Convert cooldown_time to seconds. 705 self.assertEqual(wait_time, cooldown_time * 60) 706 707 708 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 709 @mock.patch.object(time, 'sleep') 710 def test_wait_cooldown_needwait_multtemp(self, mock_sleep, 711 mock_run_command): 712 """ 713 Wait until all temps go down. 714 715 Set large enough timeout and changing temperature 716 output. Make sure it exits when expected value 717 for all temperatures received. 718 """ 719 mock_sleep.return_value = 0 720 mock_run_command.side_effect = [ 721 (0, '/sys/class/thermal/thermal_zone0/temp\n' 722 '/sys/class/thermal/thermal_zone1/temp\n' 723 '/sys/class/thermal/thermal_zone2/temp', ''), 724 (0, 'cpu0\ncpu1\ngpu', ''), 725 # Iteration 1 of monitoring. 726 (0, '45000', ''), 727 (0, '41000', ''), 728 (0, '20000', ''), 729 # Iteration 2 of monitoring. 730 (0, '42000', ''), 731 (0, '39000', ''), 732 # Iteration 3 of monitoring. 733 (0, '38000', ''), 734 # Monitoring ends. 735 ] 736 cooldown_time = 100 737 cooldown_temp = 40 738 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 739 cooldown_temp) 740 mock_run_command.assert_called() 741 # Wait time is non-zero. 742 mock_sleep.assert_called() 743 self.assertGreater(wait_time, 0) 744 745 746 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 747 @mock.patch.object(time, 'sleep') 748 def test_wait_cooldown_ignore_irrelevant_sensor(self, mock_sleep, 749 mock_run_command): 750 """ 751 Ignore non cpu/gpu sensors. 752 753 Set large temperature of a non-cpu sensor. 754 Make sure we don't wait if cpu temperature is low 755 regardless of other reports. 756 """ 757 mock_sleep.return_value = 0 758 mock_run_command.side_effect = [ 759 (0, '/sys/class/thermal/thermal_zone0/temp\n' 760 '/sys/class/thermal/thermal_zone1/temp', ''), 761 (0, 'cpu0\ncharger-sensor', ''), 762 # Iteration 1 of monitoring, check only cpu0. 763 # cpu0 764 (0, '39000', ''), 765 # Monitoring should stop at this point since the other 766 # sensor is irrelevant. 767 # If it doesn't, the test will fail since the function 768 # will continue monitoring until 50C drops but there is 769 # no more input. 770 (0, '50000', ''), 771 ] 772 cooldown_time = 100 773 cooldown_temp = 40 774 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 775 cooldown_temp) 776 mock_run_command.assert_called() 777 # Wait time is zero. 778 mock_sleep.assert_not_called() 779 self.assertEqual(wait_time, 0) 780 781 782 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 783 @mock.patch.object(time, 'sleep') 784 def test_wait_cooldown_thermal_error(self, mock_sleep, mock_run_command): 785 """ 786 Handle error status gracefully. 787 788 Sensor with an error is excluded from temperature monitoring. 789 But wait_cooldown still waits. 790 """ 791 mock_sleep.return_value = 0 792 # Error status and output with a high temperature. 793 mock_run_command.side_effect = [ 794 (0, '/sys/class/thermal/thermal_zone0/temp\n' 795 '/sys/class/thermal/thermal_zone1/temp', ''), 796 (0, 'cpu0\ncpu1', ''), 797 # Iteration 1 of monitoring. 798 # cpu0 799 (1, '', 'Thernal error'), 800 # Iteration 2 of monitoring. 801 # cpu1 802 (0, '45000', ''), 803 (0, '39000', ''), 804 ] 805 cooldown_time = 10 806 cooldown_temp = 40 807 wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time, 808 cooldown_temp) 809 # Wait time is greater than 0. 810 mock_sleep.assert_called() 811 self.assertGreater(wait_time, 0) 812 813 814 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 815 def test_stop_ui(self, mock_run_command): 816 mock_run_command.return_value = (0, '', '') 817 device_setup_utils.stop_ui(self.dut) 818 mock_run_command.assert_called_once_with(self.dut, 'stop ui') 819 820 821 @mock.patch.object(device_setup_utils, 'run_command_on_dut') 822 def test_start_ui(self, mock_run_command): 823 mock_run_command.return_value = (0, '', '') 824 device_setup_utils.start_ui(self.dut) 825 mock_run_command.assert_called_once_with(self.dut, 'start ui') 826 827 828 @mock.patch.object(device_setup_utils, 'kern_cmd_update_needed') 829 @mock.patch.object(device_setup_utils, 'update_kern_cmd_intel_pstate') 830 @mock.patch.object(device_setup_utils, 'disable_aslr') 831 @mock.patch.object(device_setup_utils, 'setup_cpu_usage') 832 @mock.patch.object(device_setup_utils, 'setup_cpu_freq') 833 @mock.patch.object(device_setup_utils, 'get_cpu_online') 834 @mock.patch.object(device_setup_utils, 'set_cpu_governor') 835 @mock.patch.object(device_setup_utils, 'disable_turbo') 836 @mock.patch.object(device_setup_utils, 'stop_ui') 837 @mock.patch.object(device_setup_utils, 'start_ui') 838 @mock.patch.object(device_setup_utils, 'wait_cooldown') 839 @mock.patch.object(device_setup_utils, 'decrease_wait_time') 840 def test_setup_device(self, mock_decrease_wait_time, mock_wait_cooldown, 841 mock_start_ui, mock_stop_ui, mock_disable_turbo, 842 mock_set_cpu_governor, mock_get_cpu_online, 843 mock_setup_cpu_freq, mock_setup_cpu_usage, 844 mock_disable_aslr, mock_update_kern_cmd_intel_pstate, 845 mock_kern_cmd_update_needed): 846 847 def setup_mock_functions(): 848 """ 849 Reset mock functions. 850 """ 851 mock_kern_cmd_update_needed.reset_mock() 852 mock_update_kern_cmd_intel_pstate.reset_mock() 853 mock_disable_aslr.reset_mock() 854 mock_setup_cpu_usage.reset_mock() 855 mock_setup_cpu_freq.reset_mock() 856 mock_get_cpu_online.reset_mock() 857 mock_set_cpu_governor.reset_mock() 858 mock_disable_turbo.reset_mock() 859 mock_stop_ui.reset_mock() 860 mock_start_ui.reset_mock() 861 mock_wait_cooldown.reset_mock() 862 mock_decrease_wait_time.reset_mock() 863 864 mock_kern_cmd_update_needed.return_value = True 865 mock_update_kern_cmd_intel_pstate.return_value = 0 866 mock_disable_aslr.return_value = 0 867 mock_setup_cpu_usage.return_value = 0 868 mock_setup_cpu_freq.return_value = 0 869 mock_get_cpu_online.return_value = {0: 1, 1: 1, 2: 0} 870 mock_set_cpu_governor.return_value = 0 871 mock_disable_turbo.return_value = 0 872 mock_stop_ui.return_value = 0 873 mock_start_ui.return_value = 0 874 mock_wait_cooldown.return_value = 0 875 mock_decrease_wait_time.return_value = 0 876 877 dut_config = { 878 'enable_aslr': False, 879 'cooldown_time': 0, 880 'cooldown_temp': 40, 881 'governor': 'fake_governor', 882 'cpu_freq_pct': 65, 883 'intel_pstate': 'no_hwp', 884 } 885 886 setup_mock_functions() 887 device_setup_utils.setup_device(self.dut, dut_config) 888 889 mock_kern_cmd_update_needed.assert_called_once() 890 mock_update_kern_cmd_intel_pstate.assert_called_once() 891 mock_disable_aslr.assert_called_once() 892 mock_setup_cpu_usage.assert_called_once() 893 mock_setup_cpu_freq.assert_called_once_with( 894 self.dut, dut_config['cpu_freq_pct'], [0, 1]) 895 mock_get_cpu_online.assert_called_once() 896 mock_set_cpu_governor.assert_called_once_with(self.dut, 897 'fake_governor') 898 mock_disable_turbo.assert_called_once() 899 mock_decrease_wait_time.assert_called_once() 900 mock_stop_ui.assert_called_once() 901 mock_start_ui.assert_called_once() 902 mock_wait_cooldown.assert_not_called() 903 904 # Test SetupDevice with cooldown 905 dut_config['cooldown_time'] = 10 906 907 setup_mock_functions() 908 mock_get_cpu_online.return_value = {0: 0, 1: 1} 909 910 device_setup_utils.setup_device(self.dut, dut_config) 911 912 mock_wait_cooldown.assert_called_once() 913 mock_disable_aslr.assert_called_once() 914 mock_disable_turbo.assert_called_once() 915 mock_setup_cpu_usage.assert_called_once() 916 mock_setup_cpu_freq.assert_called_once_with( 917 self.dut, dut_config['cpu_freq_pct'], [1]) 918 mock_set_cpu_governor.assert_called() 919 mock_get_cpu_online.assert_called_once() 920 mock_stop_ui.assert_called_once() 921 mock_start_ui.assert_called_once() 922 self.assertGreater(mock_set_cpu_governor.call_count, 1) 923 self.assertEqual(mock_set_cpu_governor.call_args, 924 mock.call(self.dut, 'fake_governor')) 925 926 # Test SetupDevice with cooldown 927 setup_mock_functions() 928 mock_setup_cpu_usage.side_effect = RuntimeError() 929 930 with self.assertRaises(RuntimeError): 931 device_setup_utils.setup_device(self.dut, dut_config) 932 933 # This call injected an exception. 934 mock_setup_cpu_usage.assert_called_once() 935 # Calls following the exception are skipped. 936 mock_wait_cooldown.assert_not_called() 937 mock_disable_turbo.assert_not_called() 938 mock_setup_cpu_freq.assert_not_called() 939 mock_set_cpu_governor.assert_not_called() 940 mock_get_cpu_online.assert_not_called() 941 # Check that Stop/Start UI are always called. 942 mock_stop_ui.assert_called_once() 943 mock_start_ui.assert_called_once() 944 945 946if __name__ == '__main__': 947 unittest.main() 948