• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python2
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
17import 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        logging.warning.assert_called_once_with(
155                'Command execution on DUT lumpy.cros2 failed.\n'
156                'Failing command: run command;\nreturned 1\n'
157                'Error message: Error!\n'
158                '(Failure is considered non-fatal. Continue.)')
159
160
161    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
162    def test_disable_aslr(self, mock_run_command):
163        mock_run_command.return_value = (0, '', '')
164        device_setup_utils.disable_aslr(self.dut)
165        # pyformat: disable
166        set_cpu_cmd = ('set -e; '
167                       'if [[ -e /proc/sys/kernel/randomize_va_space ]]; then '
168                       '  echo 0 > /proc/sys/kernel/randomize_va_space; '
169                       'fi')
170        mock_run_command.assert_called_once_with(self.dut, set_cpu_cmd)
171
172
173    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
174    def test_set_cpu_governor(self, mock_run_command):
175        mock_run_command.return_value = (0, '', '')
176        device_setup_utils.set_cpu_governor(
177                self.dut, 'new_governor', ignore_status=False)
178        set_cpu_cmd = (
179                'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do'
180                # Skip writing scaling_governor if cpu is offline.
181                '  [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} '
182                '   && continue; '
183                ' cd $f; '
184                ' if [[ -e scaling_governor ]]; then '
185                '  echo %s > scaling_governor; fi; '
186                'done; ')
187        mock_run_command.assert_called_once_with(
188                self.dut, set_cpu_cmd % 'new_governor', ignore_status=False)
189
190
191    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
192    def test_set_cpu_governor_propagate_error(self, mock_run_command):
193        mock_run_command.return_value = (1, '', 'Error.')
194        device_setup_utils.set_cpu_governor(self.dut, 'non-exist_governor')
195        set_cpu_cmd = (
196                'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do'
197                # Skip writing scaling_governor if cpu is not online.
198                '  [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} '
199                '   && continue; '
200                ' cd $f; '
201                ' if [[ -e scaling_governor ]]; then '
202                '  echo %s > scaling_governor; fi; '
203                'done; ')
204        # By default error status is fatal.
205        mock_run_command.assert_called_once_with(
206                self.dut,
207                set_cpu_cmd % 'non-exist_governor',
208                ignore_status=False)
209
210
211    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
212    def test_set_cpu_governor_ignore_status(self, mock_run_command):
213        mock_run_command.return_value = (1, '', 'Error.')
214        ret_code = device_setup_utils.set_cpu_governor(
215                self.dut, 'non-exist_governor', ignore_status=True)
216        set_cpu_cmd = (
217                'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do'
218                # Skip writing scaling_governor if cpu is not online.
219                '  [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} '
220                '   && continue; '
221                ' cd $f; '
222                ' if [[ -e scaling_governor ]]; then '
223                '  echo %s > scaling_governor; fi; '
224                'done; ')
225        mock_run_command.assert_called_once_with(
226                self.dut,
227                set_cpu_cmd % 'non-exist_governor',
228                ignore_status=True)
229        self.assertEqual(ret_code, 1)
230
231
232    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
233    def test_disable_turbo(self, mock_run_command):
234        mock_run_command.return_value = (0, '', '')
235        device_setup_utils.disable_turbo(self.dut)
236        set_cpu_cmd = (
237                # Disable Turbo the in Intel pstate driver.
238                'if [[ -e /sys/devices/system/cpu/intel_pstate/no_turbo ]]; then '
239                '  if grep -q 0 /sys/devices/system/cpu/intel_pstate/no_turbo;  then '
240                '    echo -n 1 > /sys/devices/system/cpu/intel_pstate/no_turbo; '
241                '  fi; '
242                'fi; '
243                # Disable Boost on AMD.
244                'if [[ -e /sys/devices/system/cpu/cpufreq/boost ]]; then '
245                '  if grep -q 1 /sys/devices/system/cpu/cpufreq/boost;  then '
246                '    echo -n 0 > /sys/devices/system/cpu/cpufreq/boost; '
247                '  fi; '
248                'fi; '
249        )
250        mock_run_command.assert_called_once_with(self.dut, set_cpu_cmd)
251
252
253    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
254    def test_get_cpu_online_two(self, mock_run_command):
255        """Test one digit CPU #."""
256        mock_run_command.return_value = (
257                0, '/sys/devices/system/cpu/cpu0/online 0\n'
258                '/sys/devices/system/cpu/cpu1/online 1\n', '')
259        cpu_online = device_setup_utils.get_cpu_online(self.dut)
260        self.assertEqual(cpu_online, {0: 0, 1: 1})
261
262
263    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
264    def test_get_cpu_online_twelve(self, mock_run_command):
265        """Test two digit CPU #."""
266        mock_run_command.return_value = (
267                0, '/sys/devices/system/cpu/cpu0/online 1\n'
268                '/sys/devices/system/cpu/cpu1/online 0\n'
269                '/sys/devices/system/cpu/cpu10/online 1\n'
270                '/sys/devices/system/cpu/cpu11/online 1\n'
271                '/sys/devices/system/cpu/cpu2/online 1\n'
272                '/sys/devices/system/cpu/cpu3/online 0\n'
273                '/sys/devices/system/cpu/cpu4/online 1\n'
274                '/sys/devices/system/cpu/cpu5/online 0\n'
275                '/sys/devices/system/cpu/cpu6/online 1\n'
276                '/sys/devices/system/cpu/cpu7/online 0\n'
277                '/sys/devices/system/cpu/cpu8/online 1\n'
278                '/sys/devices/system/cpu/cpu9/online 0\n', '')
279        cpu_online = device_setup_utils.get_cpu_online(self.dut)
280        self.assertEqual(
281                cpu_online, {
282                        0: 1,
283                        1: 0,
284                        2: 1,
285                        3: 0,
286                        4: 1,
287                        5: 0,
288                        6: 1,
289                        7: 0,
290                        8: 1,
291                        9: 0,
292                        10: 1,
293                        11: 1
294                })
295
296
297    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
298    def test_get_cpu_online_core0_not_exposed(self, mock_run_command):
299        """Test that not exposed cpu0/online will still be in the list."""
300
301        def run_command(dut, cmd):
302          """Helper function."""
303          if '/sys/devices/system/cpu/cpu' in cmd:
304              # Cpu0 online is not exposed.
305              return (0, '/sys/devices/system/cpu/cpu1/online 1\n', '')
306          elif '/sys/devices/system/cpu/online' in cmd:
307              # All online cores shows cpu0.
308              return (0, '0-1', '')
309          else:
310              return (1, '', '')
311
312        mock_run_command.side_effect = run_command
313        cpu_online = device_setup_utils.get_cpu_online(self.dut)
314        # Make sure core0 in the online list.
315        self.assertEqual(cpu_online, {0: 1, 1: 1})
316
317
318    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
319    def test_get_cpu_online_no_output(self, mock_run_command):
320        """Test error case, no output."""
321        mock_run_command.return_value = (0, '', '')
322        with self.assertRaises(AssertionError):
323            device_setup_utils.get_cpu_online(self.dut)
324
325
326    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
327    def test_get_cpu_online_command_error(self, mock_run_command):
328        """Test error case, command error."""
329        mock_run_command.side_effect = AssertionError
330        with self.assertRaises(AssertionError):
331            device_setup_utils.get_cpu_online(self.dut)
332
333
334    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
335    @mock.patch.object(device_setup_utils, 'setup_arm_cores')
336    def test_setup_cpu_usage_little_on_arm(self, mock_setup_arm,
337                                           mock_run_command):
338        device_setup_utils.setup_arm_cores = mock_setup_arm
339        mock_run_command.return_value = (0, 'armv7l', '')
340        cpu_usage = 'little_only'
341        device_setup_utils.setup_cpu_usage(self.dut, cpu_usage)
342        mock_setup_arm.assert_called_once()
343
344
345    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
346    @mock.patch.object(device_setup_utils, 'setup_arm_cores')
347    def test_setup_cpu_usage_big_on_aarch64(self, mock_setup_arm,
348                                            mock_run_command):
349        device_setup_utils.setup_arm_cores = mock_setup_arm
350        mock_run_command.return_value = (0, 'aarch64', '')
351        cpu_usage = 'big_only'
352        device_setup_utils.setup_cpu_usage(self.dut, cpu_usage)
353        mock_setup_arm.assert_called_once()
354
355
356    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
357    @mock.patch.object(device_setup_utils, 'setup_arm_cores')
358    def test_setup_cpu_usage_big_on_intel(self, mock_setup_arm,
359                                          mock_run_command):
360        device_setup_utils.setup_arm_cores = mock_setup_arm
361        mock_run_command.return_value = (0, 'x86_64', '')
362        cpu_usage = 'big_only'
363        device_setup_utils.setup_cpu_usage(self.dut, cpu_usage)
364        # Check that setup_arm_cores not called with invalid setup.
365        mock_setup_arm.assert_not_called()
366
367
368    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
369    @mock.patch.object(device_setup_utils, 'setup_arm_cores')
370    def test_setup_cpu_usage_all_on_intel(self, mock_setup_arm,
371                                          mock_run_command):
372        device_setup_utils.setup_arm_cores = mock_setup_arm
373        mock_run_command.return_value = (0, 'x86_64', '')
374        cpu_usage = 'all'
375        device_setup_utils.setup_cpu_usage(self.dut, cpu_usage)
376        # Check that setup_arm_cores not called in general case.
377        mock_setup_arm.assert_not_called()
378
379
380    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
381    def test_setup_arm_cores_big_on_big_little(self, mock_run_command):
382        mock_run_command.side_effect = [
383                (0, BIG_LITTLE_CPUINFO, ''),
384                (0, '', ''),
385        ]
386        cpu_usage = 'big_only'
387        device_setup_utils.setup_arm_cores(self.dut, cpu_usage)
388        mock_run_command.assert_called_with(
389                self.dut,
390                'echo 1 | tee /sys/devices/system/cpu/cpu{2}/online; '
391                'echo 0 | tee /sys/devices/system/cpu/cpu{0,1}/online')
392
393
394    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
395    def test_setup_arm_cores_little_on_big_little(self, mock_run_command):
396        mock_run_command.side_effect = [
397                (0, BIG_LITTLE_CPUINFO, ''),
398                (0, '', ''),
399        ]
400        cpu_usage = 'little_only'
401        device_setup_utils.setup_arm_cores(self.dut, cpu_usage)
402        mock_run_command.assert_called_with(
403                self.dut,
404                'echo 1 | tee /sys/devices/system/cpu/cpu{0,1}/online; '
405                'echo 0 | tee /sys/devices/system/cpu/cpu{2}/online')
406
407
408    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
409    def test_setup_arm_cores_invalid_config(self, mock_run_command):
410        mock_run_command.side_effect = [
411                (0, LITTLE_ONLY_CPUINFO, ''),
412                (0, '', ''),
413        ]
414        cpu_usage = 'big_only'
415        device_setup_utils.setup_arm_cores(self.dut, cpu_usage)
416        # Check that setup command is not sent when trying
417        # to use 'big_only' on a platform with all little cores.
418        mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo')
419
420
421    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
422    def test_setup_arm_cores_not_big_little(self, mock_run_command):
423        mock_run_command.side_effect = [
424                (0, NOT_BIG_LITTLE_CPUINFO, ''),
425                (0, '', ''),
426        ]
427        cpu_usage = 'big_only'
428        device_setup_utils.setup_arm_cores(self.dut, cpu_usage)
429        # Check that setup command is not sent when trying
430        # to use 'big_only' on a platform w/o support of big/little.
431        mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo')
432
433
434    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
435    def test_setup_arm_cores_unsupported_cpu_usage(self, mock_run_command):
436        mock_run_command.side_effect = [
437                (0, BIG_LITTLE_CPUINFO, ''),
438                (0, '', ''),
439        ]
440        cpu_usage = 'exclusive_cores'
441        device_setup_utils.setup_arm_cores(self.dut, cpu_usage)
442        # Check that setup command is not sent when trying to use
443        # 'exclusive_cores' on ARM CPU setup.
444        mock_run_command.assert_called_once_with(self.dut, 'cat /proc/cpuinfo')
445
446
447    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
448    def test_setup_cpu_freq_single_full(self, mock_run_command):
449        online = [0]
450        mock_run_command.side_effect = [
451                (0,
452                 '/sys/devices/system/cpu/cpu0/cpufreq/'
453                 'scaling_available_frequencies\n',
454                 ''),
455                (0, '1 2 3 4 5 6 7 8 9 10', ''),
456                (0, '', ''),
457        ]
458        cpu_frq_pct = 100
459        device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
460        self.assertGreaterEqual(mock_run_command.call_count, 3)
461        self.assertIn(
462                mock.call(
463                        self.dut, 'echo 10 | tee '
464                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq '
465                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq'
466                ),
467                mock_run_command.call_args_list)
468        # Check the fix of single core online.
469        # We expect to see cpu0 instead of cpu{0}.
470        self.assertIn(
471                mock.call(self.dut,
472                          'ls /sys/devices/system/cpu/cpu0/cpufreq/'
473                          'scaling_available_frequencies',
474                          ignore_status=True),
475                mock_run_command.call_args_list)
476
477
478    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
479    def test_setup_cpu_freq_middle(self, mock_run_command):
480        online = [0]
481        mock_run_command.side_effect = [
482                (0,
483                 '/sys/devices/system/cpu/cpu0/cpufreq/'
484                 'scaling_available_frequencies\n',
485                 ''),
486                (0, '1 2 3 4 5 6 7 8 9 10', ''),
487                (0, '', ''),
488        ]
489        cpu_frq_pct = 60
490        device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
491        self.assertGreaterEqual(mock_run_command.call_count, 2)
492        self.assertEqual(
493                mock_run_command.call_args,
494                mock.call(
495                        self.dut, 'echo 6 | tee '
496                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq '
497                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq'
498                ))
499
500
501    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
502    def test_setup_cpu_freq_lowest(self, mock_run_command):
503        online = [0]
504        mock_run_command.side_effect = [
505                (0,
506                 '/sys/devices/system/cpu/cpu0/cpufreq/'
507                 'scaling_available_frequencies\n',
508                 ''),
509                (0, '1 2 3 4 5 6 7 8 9 10', ''),
510                (0, '', ''),
511        ]
512        cpu_frq_pct = 0
513        device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
514        self.assertGreaterEqual(mock_run_command.call_count, 2)
515        self.assertEqual(
516                mock_run_command.call_args,
517                mock.call(
518                        self.dut, 'echo 1 | tee '
519                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq '
520                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq'
521                ))
522
523
524    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
525    def test_setup_cpu_freq_multiple_middle(self, mock_run_command):
526        online = [0, 1]
527        mock_run_command.side_effect = [
528                (0,
529                 '/sys/devices/system/cpu/cpu0/cpufreq/'
530                 'scaling_available_frequencies\n'
531                 '/sys/devices/system/cpu/cpu1/cpufreq/'
532                 'scaling_available_frequencies\n',
533                 ''),
534                (0, '1 2 3 4 5 6 7 8 9 10', ''),
535                (0, '', ''),
536                (0, '1 4 6 8 10 12 14 16 18 20', ''),
537                (0, '', ''),
538        ]
539        cpu_frq_pct = 70
540        device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
541        self.assertEqual(mock_run_command.call_count, 5)
542        self.assertIn(
543                mock.call(
544                        self.dut, 'echo 7 | tee '
545                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq '
546                        '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq'
547                ),
548                mock_run_command.call_args_list)
549        self.assertIn(
550                mock.call(
551                        self.dut, 'echo 14 | tee '
552                        '/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq '
553                        '/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq'
554                ),
555                mock_run_command.call_args_list)
556        # Check that setup_cpu_freq queries all online cores.
557        self.assertIn(
558                mock.call(self.dut,
559                          'ls /sys/devices/system/cpu/cpu{0,1}/cpufreq/'
560                          'scaling_available_frequencies',
561                          ignore_status=True),
562                mock_run_command.call_args_list)
563
564
565    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
566    def test_setup_cpu_freq_no_scaling_available(self, mock_run_command):
567        online = [0, 1]
568        mock_run_command.return_value = (2, '', 'No such file or directory')
569        cpu_frq_pct = 50
570        device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
571        mock_run_command.assert_called_once()
572        self.assertNotRegexpMatches(mock_run_command.call_args_list[0][0][1],
573                                    '^echo.*scaling_max_freq$')
574
575
576    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
577    def test_setup_cpu_freq_multiple_no_access(self, mock_run_command):
578        online = [0, 1]
579        mock_run_command.side_effect = [
580                (0,
581                 '/sys/devices/system/cpu/cpu0/cpufreq/'
582                 'scaling_available_frequencies\n'
583                 '/sys/devices/system/cpu/cpu1/cpufreq/'
584                 'scaling_available_frequencies\n',
585                 ''),
586                (0, '1 4 6 8 10 12 14 16 18 20', ''),
587                AssertionError(),
588        ]
589        cpu_frq_pct = 30
590        # Error status causes log fatal.
591        with self.assertRaises(AssertionError):
592            device_setup_utils.setup_cpu_freq(self.dut, cpu_frq_pct, online)
593
594
595    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
596    @mock.patch.object(time, 'sleep')
597    def test_wait_cooldown_nowait(self, mock_sleep, mock_run_command):
598        mock_sleep.return_value = 0
599        mock_run_command.return_value = (0, '39000', '')
600        cooldown_time = 10
601        cooldown_temp = 40
602        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
603                                                     cooldown_temp)
604        # Send command to DUT only once to check temperature
605        # and make sure it does not exceed the threshold.
606        mock_run_command.assert_called_once()
607        mock_sleep.assert_not_called()
608        self.assertEqual(wait_time, 0)
609
610
611    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
612    @mock.patch.object(time, 'sleep')
613    def test_wait_cooldown_needwait_once(self, mock_sleep, mock_run_command):
614        """
615        Wait one iteration for cooldown.
616
617        Set large enough timeout and changing temperature
618        output. Make sure it exits when expected value
619        received.
620        Expect that WaitCooldown check temp twice.
621
622        """
623        mock_sleep.return_value = 0
624        mock_run_command.side_effect = [(0, '41000', ''), (0, '39999', '')]
625        cooldown_time = 100
626        cooldown_temp = 40
627        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
628                                                     cooldown_temp)
629        mock_run_command.assert_called()
630        self.assertEqual(mock_run_command.call_count, 2)
631        mock_sleep.assert_called()
632        self.assertGreater(wait_time, 0)
633
634
635    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
636    @mock.patch.object(time, 'sleep')
637    def test_wait_cooldown_needwait(self, mock_sleep, mock_run_command):
638        """
639        Test exit by timeout.
640
641        Send command to DUT checking the temperature and
642        check repeatedly until timeout goes off.
643        Output from temperature sensor never changes.
644
645        """
646        mock_sleep.return_value = 0
647        mock_run_command.return_value = (0, '41000', '')
648        cooldown_time = 60
649        cooldown_temp = 40
650        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
651                                                     cooldown_temp)
652        mock_run_command.assert_called()
653        self.assertGreater(mock_run_command.call_count, 2)
654        mock_sleep.assert_called()
655        self.assertGreater(wait_time, 0)
656
657
658    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
659    @mock.patch.object(time, 'sleep')
660    def test_wait_cooldown_needwait_multtemp(self, mock_sleep,
661                                             mock_run_command):
662        """
663        Wait until all temps go down.
664
665        Set large enough timeout and changing temperature
666        output. Make sure it exits when expected value
667        for all temperatures received.
668        Expect 3 checks.
669
670        """
671        mock_sleep.return_value = 0
672        mock_run_command.side_effect = [
673                (0, '41000\n20000\n30000\n45000', ''),
674                (0, '39000\n20000\n30000\n41000', ''),
675                (0, '39000\n20000\n30000\n31000', ''),
676        ]
677        cooldown_time = 100
678        cooldown_temp = 40
679        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
680                                                     cooldown_temp)
681        mock_run_command.assert_called()
682        self.assertEqual(mock_run_command.call_count, 3)
683        mock_sleep.assert_called()
684        self.assertGreater(wait_time, 0)
685
686
687    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
688    @mock.patch.object(time, 'sleep')
689    def test_wait_cooldown_thermal_error(self, mock_sleep, mock_run_command):
690        """
691        Handle error status.
692
693        Any error should be considered non-fatal.
694
695        """
696        mock_sleep.return_value = 0
697        mock_run_command.side_effect = [
698                (1, '39000\n20000\n30000\n41000', 'Thermal error'),
699                (1, '39000\n20000\n30000\n31000', 'Thermal error'),
700        ]
701        cooldown_time = 10
702        cooldown_temp = 40
703        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
704                                                     cooldown_temp)
705        # Check that errors are ignored.
706        mock_run_command.assert_called_with(
707                self.dut,
708                'cat /sys/class/thermal/thermal_zone*/temp',
709                ignore_status=True)
710        self.assertEqual(mock_run_command.call_count, 2)
711        # Check that we are waiting even when an error is returned
712        # as soon as data is coming.
713        mock_sleep.assert_called()
714        self.assertGreater(wait_time, 0)
715
716
717    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
718    @mock.patch.object(time, 'sleep')
719    def test_wait_cooldown_thermal_no_output(self, mock_sleep,
720                                             mock_run_command):
721        """
722        Handle no output.
723
724        Check handling of empty stdout.
725
726        """
727        mock_sleep.return_value = 0
728        mock_run_command.side_effect = [(1, '', 'Thermal error')]
729        cooldown_time = 10
730        cooldown_temp = 40
731        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
732                                                     cooldown_temp)
733        # Check that errors are ignored.
734        mock_run_command.assert_called_once_with(
735                self.dut,
736                'cat /sys/class/thermal/thermal_zone*/temp',
737                ignore_status=True)
738        # No wait.
739        mock_sleep.assert_not_called()
740        self.assertEqual(wait_time, 0)
741
742
743    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
744    @mock.patch.object(time, 'sleep')
745    def test_wait_cooldown_thermal_ws_output(self, mock_sleep,
746                                             mock_run_command):
747        """
748        Handle whitespace output.
749
750        Check handling of whitespace only.
751
752        """
753        mock_sleep.return_value = 0
754        mock_run_command.side_effect = [(1, '\n', 'Thermal error')]
755        cooldown_time = 10
756        cooldown_temp = 40
757        wait_time = device_setup_utils.wait_cooldown(self.dut, cooldown_time,
758                                                     cooldown_temp)
759        # Check that errors are ignored.
760        mock_run_command.assert_called_once_with(
761                self.dut,
762                'cat /sys/class/thermal/thermal_zone*/temp',
763                ignore_status=True)
764        # No wait.
765        mock_sleep.assert_not_called()
766        self.assertEqual(wait_time, 0)
767
768
769    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
770    def test_stop_ui(self, mock_run_command):
771        mock_run_command.return_value = (0, '', '')
772        device_setup_utils.stop_ui(self.dut)
773        mock_run_command.assert_called_once_with(self.dut, 'stop ui')
774
775
776    @mock.patch.object(device_setup_utils, 'run_command_on_dut')
777    def test_start_ui(self, mock_run_command):
778        mock_run_command.return_value = (0, '', '')
779        device_setup_utils.start_ui(self.dut)
780        mock_run_command.assert_called_once_with(self.dut, 'start ui')
781
782
783    @mock.patch.object(device_setup_utils, 'kern_cmd_update_needed')
784    @mock.patch.object(device_setup_utils, 'update_kern_cmd_intel_pstate')
785    @mock.patch.object(device_setup_utils, 'disable_aslr')
786    @mock.patch.object(device_setup_utils, 'setup_cpu_usage')
787    @mock.patch.object(device_setup_utils, 'setup_cpu_freq')
788    @mock.patch.object(device_setup_utils, 'get_cpu_online')
789    @mock.patch.object(device_setup_utils, 'set_cpu_governor')
790    @mock.patch.object(device_setup_utils, 'disable_turbo')
791    @mock.patch.object(device_setup_utils, 'stop_ui')
792    @mock.patch.object(device_setup_utils, 'start_ui')
793    @mock.patch.object(device_setup_utils, 'wait_cooldown')
794    @mock.patch.object(device_setup_utils, 'decrease_wait_time')
795    def test_setup_device(self, mock_decrease_wait_time, mock_wait_cooldown,
796                          mock_start_ui, mock_stop_ui, mock_disable_turbo,
797                          mock_set_cpu_governor, mock_get_cpu_online,
798                          mock_setup_cpu_freq, mock_setup_cpu_usage,
799                          mock_disable_aslr, mock_update_kern_cmd_intel_pstate,
800                          mock_kern_cmd_update_needed):
801
802        def setup_mock_functions():
803            """
804            Reset mock functions.
805            """
806            mock_kern_cmd_update_needed.reset_mock()
807            mock_update_kern_cmd_intel_pstate.reset_mock()
808            mock_disable_aslr.reset_mock()
809            mock_setup_cpu_usage.reset_mock()
810            mock_setup_cpu_freq.reset_mock()
811            mock_get_cpu_online.reset_mock()
812            mock_set_cpu_governor.reset_mock()
813            mock_disable_turbo.reset_mock()
814            mock_stop_ui.reset_mock()
815            mock_start_ui.reset_mock()
816            mock_wait_cooldown.reset_mock()
817            mock_decrease_wait_time.reset_mock()
818
819            mock_kern_cmd_update_needed.return_value = True
820            mock_update_kern_cmd_intel_pstate.return_value = 0
821            mock_disable_aslr.return_value = 0
822            mock_setup_cpu_usage.return_value = 0
823            mock_setup_cpu_freq.return_value = 0
824            mock_get_cpu_online.return_value = {0: 1, 1: 1, 2: 0}
825            mock_set_cpu_governor.return_value = 0
826            mock_disable_turbo.return_value = 0
827            mock_stop_ui.return_value = 0
828            mock_start_ui.return_value = 0
829            mock_wait_cooldown.return_value = 0
830            mock_decrease_wait_time.return_value = 0
831
832        dut_config = {
833          'enable_aslr': False,
834          'cooldown_time': 0,
835          'cooldown_temp': 40,
836          'governor': 'fake_governor',
837          'cpu_freq_pct': 65,
838          'intel_pstate': 'no_hwp',
839        }
840
841        setup_mock_functions()
842        device_setup_utils.setup_device(self.dut, dut_config)
843
844        mock_kern_cmd_update_needed.assert_called_once()
845        mock_update_kern_cmd_intel_pstate.assert_called_once()
846        mock_disable_aslr.assert_called_once()
847        mock_setup_cpu_usage.assert_called_once()
848        mock_setup_cpu_freq.assert_called_once_with(
849                self.dut, dut_config['cpu_freq_pct'], [0, 1])
850        mock_get_cpu_online.assert_called_once()
851        mock_set_cpu_governor.assert_called_once_with(self.dut,
852                                                      'fake_governor')
853        mock_disable_turbo.assert_called_once()
854        mock_decrease_wait_time.assert_called_once()
855        mock_stop_ui.assert_called_once()
856        mock_start_ui.assert_called_once()
857        mock_wait_cooldown.assert_not_called()
858
859        # Test SetupDevice with cooldown
860        dut_config['cooldown_time'] = 10
861
862        setup_mock_functions()
863        mock_get_cpu_online.return_value = {0: 0, 1: 1}
864
865        device_setup_utils.setup_device(self.dut, dut_config)
866
867        mock_wait_cooldown.assert_called_once()
868        mock_disable_aslr.assert_called_once()
869        mock_disable_turbo.assert_called_once()
870        mock_setup_cpu_usage.assert_called_once()
871        mock_setup_cpu_freq.assert_called_once_with(
872                self.dut, dut_config['cpu_freq_pct'], [1])
873        mock_set_cpu_governor.assert_called()
874        mock_get_cpu_online.assert_called_once()
875        mock_stop_ui.assert_called_once()
876        mock_start_ui.assert_called_once()
877        self.assertGreater(mock_set_cpu_governor.call_count, 1)
878        self.assertEqual(mock_set_cpu_governor.call_args,
879                         mock.call(self.dut, 'fake_governor'))
880
881        # Test SetupDevice with cooldown
882        setup_mock_functions()
883        mock_setup_cpu_usage.side_effect = RuntimeError()
884
885        with self.assertRaises(RuntimeError):
886            device_setup_utils.setup_device(self.dut, dut_config)
887
888        # This call injected an exception.
889        mock_setup_cpu_usage.assert_called_once()
890        # Calls following the exception are skipped.
891        mock_wait_cooldown.assert_not_called()
892        mock_disable_turbo.assert_not_called()
893        mock_setup_cpu_freq.assert_not_called()
894        mock_set_cpu_governor.assert_not_called()
895        mock_get_cpu_online.assert_not_called()
896        # Check that Stop/Start UI are always called.
897        mock_stop_ui.assert_called_once()
898        mock_start_ui.assert_called_once()
899
900
901if __name__ == '__main__':
902    unittest.main()
903