• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4# Copyright (c) 2011 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
8"""Module of result cache unittest."""
9
10from __future__ import print_function
11
12import os
13import shutil
14import tempfile
15import unittest
16import unittest.mock as mock
17
18import image_checksummer
19import machine_manager
20import test_flag
21
22from label import MockLabel
23from results_cache import CacheConditions
24from results_cache import PerfDataReadError
25from results_cache import PidVerificationError
26from results_cache import Result
27from results_cache import ResultsCache
28from results_cache import TelemetryResult
29from cros_utils import command_executer
30from cros_utils import logger
31from cros_utils import misc
32
33# pylint: disable=line-too-long
34OUTPUT = """CMD (True): ./test_that.sh\
35 --remote=172.17.128.241  --board=lumpy   LibCBench
36CMD (None): cd /usr/local/google/home/yunlian/gd/src/build/images/lumpy/latest/../../../../..; cros_sdk  -- ./in_chroot_cmd6X7Cxu.sh
37Identity added: /tmp/test_that.PO1234567/autotest_key (/tmp/test_that.PO1234567/autotest_key)
38INFO    : Using emerged autotests already installed at /build/lumpy/usr/local/autotest.
39
40INFO    : Running the following control files 1 times:
41INFO    :  * 'client/site_tests/platform_LibCBench/control'
42
43INFO    : Running client test client/site_tests/platform_LibCBench/control
44./server/autoserv -m 172.17.128.241 --ssh-port 22 -c client/site_tests/platform_LibCBench/control -r /tmp/test_that.PO1234567/platform_LibCBench --test-retry=0 --args
45ERROR:root:import statsd failed, no stats will be reported.
4614:20:22 INFO | Results placed in /tmp/test_that.PO1234567/platform_LibCBench
4714:20:22 INFO | Processing control file
4814:20:23 INFO | Starting master ssh connection '/usr/bin/ssh -a -x -N -o ControlMaster=yes -o ControlPath=/tmp/_autotmp_VIIP67ssh-master/socket -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes -o ConnectTimeout=30 -o ServerAliveInterval=180 -o ServerAliveCountMax=3 -o ConnectionAttempts=4 -o Protocol=2 -l root -p 22 172.17.128.241'
4914:20:23 ERROR| [stderr] Warning: Permanently added '172.17.128.241' (RSA) to the list of known hosts.
5014:20:23 INFO | INFO	----	----	kernel=3.8.11	localtime=May 22 14:20:23	timestamp=1369257623
5114:20:23 INFO | Installing autotest on 172.17.128.241
5214:20:23 INFO | Using installation dir /usr/local/autotest
5314:20:23 WARNI| No job_repo_url for <remote host: 172.17.128.241>
5414:20:23 INFO | Could not install autotest using the packaging system: No repos to install an autotest client from. Trying other methods
5514:20:23 INFO | Installation of autotest completed
5614:20:24 WARNI| No job_repo_url for <remote host: 172.17.128.241>
5714:20:24 INFO | Executing /usr/local/autotest/bin/autotest /usr/local/autotest/control phase 0
5814:20:24 INFO | Entered autotestd_monitor.
5914:20:24 INFO | Finished launching tail subprocesses.
6014:20:24 INFO | Finished waiting on autotestd to start.
6114:20:26 INFO | START	----	----	timestamp=1369257625	localtime=May 22 14:20:25
6214:20:26 INFO | 	START	platform_LibCBench	platform_LibCBench	timestamp=1369257625	localtime=May 22 14:20:25
6314:20:30 INFO | 		GOOD	platform_LibCBench	platform_LibCBench	timestamp=1369257630	localtime=May 22 14:20:30	completed successfully
6414:20:30 INFO | 	END GOOD	platform_LibCBench	platform_LibCBench	timestamp=1369257630	localtime=May 22 14:20:30
6514:20:31 INFO | END GOOD	----	----	timestamp=1369257630	localtime=May 22 14:20:30
6614:20:31 INFO | Got lock of exit_code_file.
6714:20:31 INFO | Released lock of exit_code_file and closed it.
68OUTPUT: ==============================
69OUTPUT: Current time: 2013-05-22 14:20:32.818831 Elapsed: 0:01:30 ETA: Unknown
70Done: 0% [                                                  ]
71OUTPUT: Thread Status:
72RUNNING:  1 ('ttt: LibCBench (1)' 0:01:21)
73Machine Status:
74Machine                        Thread     Lock Status                    Checksum
75172.17.128.241                 ttt: LibCBench (1) True RUNNING                   3ba9f2ecbb222f20887daea5583d86ba
76
77OUTPUT: ==============================
7814:20:33 INFO | Killing child processes.
7914:20:33 INFO | Client complete
8014:20:33 INFO | Finished processing control file
8114:20:33 INFO | Starting master ssh connection '/usr/bin/ssh -a -x -N -o ControlMaster=yes -o ControlPath=/tmp/_autotmp_aVJUgmssh-master/socket -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes -o ConnectTimeout=30 -o ServerAliveInterval=180 -o ServerAliveCountMax=3 -o ConnectionAttempts=4 -o Protocol=2 -l root -p 22 172.17.128.241'
8214:20:33 ERROR| [stderr] Warning: Permanently added '172.17.128.241' (RSA) to the list of known hosts.
83
84INFO    : Test results:
85-------------------------------------------------------------------
86platform_LibCBench                                      [  PASSED  ]
87platform_LibCBench/platform_LibCBench                   [  PASSED  ]
88platform_LibCBench/platform_LibCBench                     b_malloc_big1__0_                                     0.00375231466667
89platform_LibCBench/platform_LibCBench                     b_malloc_big2__0_                                     0.002951359
90platform_LibCBench/platform_LibCBench                     b_malloc_bubble__0_                                   0.015066374
91platform_LibCBench/platform_LibCBench                     b_malloc_sparse__0_                                   0.015053784
92platform_LibCBench/platform_LibCBench                     b_malloc_thread_local__0_                             0.01138439
93platform_LibCBench/platform_LibCBench                     b_malloc_thread_stress__0_                            0.0367894733333
94platform_LibCBench/platform_LibCBench                     b_malloc_tiny1__0_                                    0.000768474333333
95platform_LibCBench/platform_LibCBench                     b_malloc_tiny2__0_                                    0.000581407333333
96platform_LibCBench/platform_LibCBench                     b_pthread_create_serial1__0_                          0.0291785246667
97platform_LibCBench/platform_LibCBench                     b_pthread_createjoin_serial1__0_                      0.031907936
98platform_LibCBench/platform_LibCBench                     b_pthread_createjoin_serial2__0_                      0.043485347
99platform_LibCBench/platform_LibCBench                     b_pthread_uselesslock__0_                             0.0294113346667
100platform_LibCBench/platform_LibCBench                     b_regex_compile____a_b_c__d_b__                       0.00529833933333
101platform_LibCBench/platform_LibCBench                     b_regex_search____a_b_c__d_b__                        0.00165455066667
102platform_LibCBench/platform_LibCBench                     b_regex_search___a_25_b__                             0.0496191923333
103platform_LibCBench/platform_LibCBench                     b_stdio_putcgetc__0_                                  0.100005711667
104platform_LibCBench/platform_LibCBench                     b_stdio_putcgetc_unlocked__0_                         0.0371443833333
105platform_LibCBench/platform_LibCBench                     b_string_memset__0_                                   0.00275405066667
106platform_LibCBench/platform_LibCBench                     b_string_strchr__0_                                   0.00456903
107platform_LibCBench/platform_LibCBench                     b_string_strlen__0_                                   0.044893587
108platform_LibCBench/platform_LibCBench                     b_string_strstr___aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac__ 0.118360778
109platform_LibCBench/platform_LibCBench                     b_string_strstr___aaaaaaaaaaaaaaaaaaaaaaaaac__        0.068957325
110platform_LibCBench/platform_LibCBench                     b_string_strstr___aaaaaaaaaaaaaacccccccccccc__        0.0135694476667
111platform_LibCBench/platform_LibCBench                     b_string_strstr___abcdefghijklmnopqrstuvwxyz__        0.0134553343333
112platform_LibCBench/platform_LibCBench                     b_string_strstr___azbycxdwevfugthsirjqkplomn__        0.0133123556667
113platform_LibCBench/platform_LibCBench                     b_utf8_bigbuf__0_                                     0.0473772253333
114platform_LibCBench/platform_LibCBench                     b_utf8_onebyone__0_                                   0.130938538333
115-------------------------------------------------------------------
116Total PASS: 2/2 (100%)
117
118INFO    : Elapsed time: 0m16s
119"""
120
121error = """
122ERROR: Identity added: /tmp/test_that.Z4Ld/autotest_key (/tmp/test_that.Z4Ld/autotest_key)
123INFO    : Using emerged autotests already installed at /build/lumpy/usr/local/autotest.
124INFO    : Running the following control files 1 times:
125INFO    :  * 'client/site_tests/platform_LibCBench/control'
126INFO    : Running client test client/site_tests/platform_LibCBench/control
127INFO    : Test results:
128INFO    : Elapsed time: 0m18s
129"""
130
131keyvals = {
132    '': 'PASS',
133    'b_stdio_putcgetc__0_': '0.100005711667',
134    'b_string_strstr___azbycxdwevfugthsirjqkplomn__': '0.0133123556667',
135    'b_malloc_thread_local__0_': '0.01138439',
136    'b_string_strlen__0_': '0.044893587',
137    'b_malloc_sparse__0_': '0.015053784',
138    'b_string_memset__0_': '0.00275405066667',
139    'platform_LibCBench': 'PASS',
140    'b_pthread_uselesslock__0_': '0.0294113346667',
141    'b_string_strchr__0_': '0.00456903',
142    'b_pthread_create_serial1__0_': '0.0291785246667',
143    'b_string_strstr___aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac__': '0.118360778',
144    'b_string_strstr___aaaaaaaaaaaaaacccccccccccc__': '0.0135694476667',
145    'b_pthread_createjoin_serial1__0_': '0.031907936',
146    'b_malloc_thread_stress__0_': '0.0367894733333',
147    'b_regex_search____a_b_c__d_b__': '0.00165455066667',
148    'b_malloc_bubble__0_': '0.015066374',
149    'b_malloc_big2__0_': '0.002951359',
150    'b_stdio_putcgetc_unlocked__0_': '0.0371443833333',
151    'b_pthread_createjoin_serial2__0_': '0.043485347',
152    'b_regex_search___a_25_b__': '0.0496191923333',
153    'b_utf8_bigbuf__0_': '0.0473772253333',
154    'b_malloc_big1__0_': '0.00375231466667',
155    'b_regex_compile____a_b_c__d_b__': '0.00529833933333',
156    'b_string_strstr___aaaaaaaaaaaaaaaaaaaaaaaaac__': '0.068957325',
157    'b_malloc_tiny2__0_': '0.000581407333333',
158    'b_utf8_onebyone__0_': '0.130938538333',
159    'b_malloc_tiny1__0_': '0.000768474333333',
160    'b_string_strstr___abcdefghijklmnopqrstuvwxyz__': '0.0134553343333'
161}
162
163PERF_DATA_HEADER = """
164# ========
165# captured on    : Thu Jan 01 00:00:00 1980
166# header version : 1
167# data offset    : 536
168# data size      : 737678672
169# feat offset    : 737679208
170# hostname : localhost
171# os release : 5.4.61
172# perf version :
173# arch : aarch64
174# nrcpus online : 8
175# nrcpus avail : 8
176# total memory : 5911496 kB
177# cmdline : /usr/bin/perf record -e instructions -p {pid}
178# event : name = instructions, , id = ( 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193 ), type = 8, size = 112
179# event : name = dummy:u, , id = ( 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204 ), type = 1, size = 112, config = 0x9
180# CPU_TOPOLOGY info available, use -I to display
181# pmu mappings: software = 1, uprobe = 6, cs_etm = 8, breakpoint = 5, tracepoint = 2, armv8_pmuv3 = 7
182# contains AUX area data (e.g. instruction trace)
183# time of first sample : 0.000000
184# time of last sample : 0.000000
185# sample duration :      0.000 ms
186# missing features: TRACING_DATA CPUDESC CPUID NUMA_TOPOLOGY BRANCH_STACK GROUP_DESC STAT CACHE MEM_TOPOLOGY CLOCKID DIR_FORMAT
187# ========
188#
189"""
190
191TURBOSTAT_LOG_OUTPUT = \
192"""CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
193-       329     12.13   2723    2393    10975   77
1940       336     12.41   2715    2393    6328    77
1952       323     11.86   2731    2393    4647    69
196CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
197-       1940    67.46   2884    2393    39920   83
1980       1827    63.70   2877    2393    21184   83
1992       2053    71.22   2891    2393    18736   67
200CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
201-       1927    66.02   2927    2393    48946   84
2020       1880    64.47   2925    2393    24457   84
2032       1973    67.57   2928    2393    24489   69
204CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
205-       1899    64.84   2937    2393    42540   72
2060       2135    72.82   2940    2393    23615   65
2072       1663    56.85   2934    2393    18925   72
208CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
209-       1908    65.24   2932    2393    43172   75
2100       1876    64.25   2928    2393    20743   75
2112       1939    66.24   2936    2393    22429   69
212CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
213-       1553    53.12   2933    2393    35488   46
2140       1484    50.80   2929    2393    18246   46
2152       1623    55.44   2936    2393    17242   45
216CPU     Avg_MHz Busy%   Bzy_MHz TSC_MHz IRQ     CoreTmp
217-       843     29.83   2832    2393    28161   47
2180       827     29.35   2826    2393    16093   47
2192       858     30.31   2838    2393    12068   46
220"""
221TURBOSTAT_DATA = {
222    'cpufreq': {
223        'all': [2723, 2884, 2927, 2937, 2932, 2933, 2832]
224    },
225    'cputemp': {
226        'all': [77, 83, 84, 72, 75, 46, 47]
227    },
228}
229
230TOP_LOG = \
231"""
232  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
233 4102 chronos   12  -8 3454472 238300 118188 R  41.8   6.1   0:08.37 chrome
234 4204 chronos   12  -8 2492716 205728 179016 S  11.8   5.3   0:03.89 chrome
235 4890 root      20   0    3396   2064   1596 R  11.8   0.1   0:00.03 top
236  375 root       0 -20       0      0      0 S   5.9   0.0   0:00.17 kworker/u13
237  617 syslog    20   0   25332   8372   7888 S   5.9   0.2   0:00.77 sys-journal
238
239  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
240 5745 chronos   20   0 5438580 139328  67988 R 122.8   3.6   0:04.26 chrome
241  912 root     -51   0       0      0      0 S   2.0   0.0   0:01.04 irq/cros-ec
242  121 root      20   0       0      0      0 S   1.0   0.0   0:00.45 spi5
243 4811 root      20   0    6808   4084   3492 S   1.0   0.1   0:00.02 sshd
244 4890 root      20   0    3364   2148   1596 R   1.0   0.1   0:00.36 top
245 5205 chronos   12  -8 3673780 240928 130864 S   1.0   6.2   0:07.30 chrome
246
247
248  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
249 5745 chronos   20   0 5434484 139432  63892 R 107.9   3.6   0:05.35 chrome
250 5713 chronos   20   0 5178652 103120  50372 S  17.8   2.6   0:01.13 chrome
251    7 root      20   0       0      0      0 S   1.0   0.0   0:00.73 rcu_preempt
252  855 root      20   0       0      0      0 S   1.0   0.0   0:00.01 kworker/4:2
253"""
254TOP_DATA = [
255    {
256        'cmd': 'chrome-5745',
257        'cpu_use_avg': 115.35,
258        'count': 2,
259        'top5_cpu_use': [122.8, 107.9],
260    },
261    {
262        'cmd': 'chrome-5713',
263        'cpu_use_avg': 8.9,
264        'count': 1,
265        'top5_cpu_use': [17.8]
266    },
267    {
268        'cmd': 'irq/cros-ec-912',
269        'cpu_use_avg': 1.0,
270        'count': 1,
271        'top5_cpu_use': [2.0],
272    },
273    {
274        'cmd': 'chrome-5205',
275        'cpu_use_avg': 0.5,
276        'count': 1,
277        'top5_cpu_use': [1.0]
278    },
279    {
280        'cmd': 'spi5-121',
281        'cpu_use_avg': 0.5,
282        'count': 1,
283        'top5_cpu_use': [1.0],
284    },
285    {
286        'cmd': 'sshd-4811',
287        'cpu_use_avg': 0.5,
288        'count': 1,
289        'top5_cpu_use': [1.0],
290    },
291    {
292        'cmd': 'rcu_preempt-7',
293        'cpu_use_avg': 0.5,
294        'count': 1,
295        'top5_cpu_use': [1.0],
296    },
297    {
298        'cmd': 'kworker/4:2-855',
299        'cpu_use_avg': 0.5,
300        'count': 1,
301        'top5_cpu_use': [1.0],
302    },
303]
304TOP_OUTPUT = \
305"""             COMMAND     AVG CPU%  SEEN   HIGHEST 5
306              chrome   128.250000     6   [122.8, 107.9, 17.8, 5.0, 2.0]
307     irq/230-cros-ec     1.000000     1   [2.0]
308                sshd     0.500000     1   [1.0]
309     irq/231-cros-ec     0.500000     1   [1.0]
310                spi5     0.500000     1   [1.0]
311         rcu_preempt     0.500000     1   [1.0]
312         kworker/4:2     0.500000     1   [1.0]
313"""
314
315CPUSTATS_UNIQ_OUTPUT = \
316"""
317/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 1512000
318/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq 1512000
319/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_cur_freq 2016000
320soc-thermal 44444
321little-cpu 41234
322big-cpu 51234
323/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 1500000
324/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq 1600000
325/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_cur_freq 2012000
326soc-thermal 45456
327little-cpu 42555
328big-cpu 61724
329"""
330CPUSTATS_UNIQ_DATA = {
331    'cpufreq': {
332        'cpu0': [1512, 1500],
333        'cpu1': [1512, 1600],
334        'cpu3': [2016, 2012]
335    },
336    'cputemp': {
337        'soc-thermal': [44.4, 45.5],
338        'little-cpu': [41.2, 42.6],
339        'big-cpu': [51.2, 61.7]
340    }
341}
342CPUSTATS_DUPL_OUTPUT = \
343"""
344/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 1512000
345/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq 1512000
346/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_cur_freq 1512000
347/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_cur_freq 2016000
348/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 1500000
349/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq 1500000
350/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_cur_freq 1500000
351/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_cur_freq 2016000
352/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 1614000
353/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_cur_freq 1614000
354/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_cur_freq 1614000
355/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_cur_freq 1982000
356"""
357CPUSTATS_DUPL_DATA = {
358    'cpufreq': {
359        'cpu0': [1512, 1500, 1614],
360        'cpu3': [2016, 2016, 1982]
361    },
362}
363
364TMP_DIR1 = '/tmp/tmpAbcXyz'
365
366HISTOGRAMSET = \
367"""
368[
369    {
370        "values": [
371            "cache_temperature_cold",
372            "typical",
373            "cache_temperature:cold"
374        ],
375        "guid": "db6d463b-7c07-4873-b839-db0652ccb97e",
376        "type": "GenericSet"
377    },
378    {
379        "values": [
380            "cache_temperature_warm",
381            "typical",
382            "cache_temperature:warm"
383        ],
384        "guid": "a270eb9d-3bb0-472a-951d-74ac3398b718",
385        "type": "GenericSet"
386    },
387    {
388        "sampleValues": [
389            1111.672
390        ],
391        "name": "timeToFirstContentfulPaint",
392        "diagnostics": {
393            "storyTags": "a270eb9d-3bb0-472a-951d-74ac3398b718"
394        },
395        "unit": "ms_smallerIsBetter"
396    },
397    {
398        "sampleValues": [
399            1146.459
400        ],
401        "name": "timeToFirstContentfulPaint",
402        "diagnostics": {
403            "storyTags": "db6d463b-7c07-4873-b839-db0652ccb97e"
404        },
405        "unit": "ms_smallerIsBetter"
406    },
407    {
408        "sampleValues": [
409            888.328
410        ],
411        "name": "timeToFirstContentfulPaint",
412        "diagnostics": {
413            "storyTags": "a270eb9d-3bb0-472a-951d-74ac3398b718"
414        },
415        "unit": "ms_smallerIsBetter"
416    },
417    {
418        "sampleValues": [
419            853.541
420        ],
421        "name": "timeToFirstContentfulPaint",
422        "diagnostics": {
423            "storyTags": "db6d463b-7c07-4873-b839-db0652ccb97e"
424        },
425        "unit": "ms_smallerIsBetter"
426    },
427    {
428        "sampleValues": [
429            400.000
430        ],
431        "name": "timeToFirstContentfulPaint",
432        "diagnostics": {
433            "storyTags": "a270eb9d-3bb0-472a-951d-74ac3398b718"
434        },
435        "unit": "ms_smallerIsBetter"
436    }
437
438]
439"""
440
441# pylint: enable=line-too-long
442
443
444class MockResult(Result):
445  """Mock result class."""
446
447  def __init__(self, mylogger, label, logging_level, machine):
448    super(MockResult, self).__init__(mylogger, label, logging_level, machine)
449
450  def FindFilesInResultsDir(self, find_args):
451    return ''
452
453  # pylint: disable=arguments-differ
454  def GetKeyvals(self, temp=False):
455    if temp:
456      pass
457    return keyvals
458
459
460class ResultTest(unittest.TestCase):
461  """Result test class."""
462
463  def __init__(self, *args, **kwargs):
464    super(ResultTest, self).__init__(*args, **kwargs)
465    self.callFakeProcessResults = False
466    self.fakeCacheReturnResult = None
467    self.callGetResultsDir = False
468    self.callProcessResults = False
469    self.callGetPerfReportFiles = False
470    self.kv_dict = None
471    self.tmpdir = ''
472    self.callGetNewKeyvals = False
473    self.callGetResultsFile = False
474    self.callGetPerfDataFiles = False
475    self.callGetTurbostatFile = False
476    self.callGetCpustatsFile = False
477    self.callGetTopFile = False
478    self.callGetCpuinfoFile = False
479    self.callGetWaitTimeFile = False
480    self.args = None
481    self.callGatherPerfResults = False
482    self.mock_logger = mock.Mock(spec=logger.Logger)
483    self.mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
484    self.mock_label = MockLabel('mock_label', 'build', 'chromeos_image',
485                                'autotest_dir', 'debug_dir', '/tmp', 'lumpy',
486                                'remote', 'image_args', 'cache_dir', 'average',
487                                'gcc', False, None)
488
489  def testCreateFromRun(self):
490    result = MockResult.CreateFromRun(logger.GetLogger(), 'average',
491                                      self.mock_label, 'remote1', OUTPUT, error,
492                                      0, True)
493    self.assertEqual(result.keyvals, keyvals)
494    self.assertEqual(result.chroot_results_dir,
495                     '/tmp/test_that.PO1234567/platform_LibCBench')
496    self.assertEqual(result.results_dir,
497                     '/tmp/chroot/tmp/test_that.PO1234567/platform_LibCBench')
498    self.assertEqual(result.retval, 0)
499
500  def setUp(self):
501    self.result = Result(self.mock_logger, self.mock_label, 'average',
502                         self.mock_cmd_exec)
503    self.result.chromeos_root = '/tmp/chromeos'
504
505  @mock.patch.object(os.path, 'isdir')
506  @mock.patch.object(command_executer.CommandExecuter, 'RunCommand')
507  @mock.patch.object(command_executer.CommandExecuter, 'CopyFiles')
508  def test_copy_files_to(self, mock_copyfiles, mock_runcmd, mock_isdir):
509
510    files = ['src_file_1', 'src_file_2', 'src_file_3']
511    dest_dir = '/tmp/test'
512    self.mock_cmd_exec.RunCommand = mock_runcmd
513    self.mock_cmd_exec.CopyFiles = mock_copyfiles
514
515    mock_copyfiles.return_value = 0
516
517    # test 1. dest_dir exists; CopyFiles returns 0.
518    mock_isdir.return_value = True
519    self.result.CopyFilesTo(dest_dir, files)
520    self.assertEqual(mock_runcmd.call_count, 0)
521    self.assertEqual(mock_copyfiles.call_count, 3)
522    first_args = mock_copyfiles.call_args_list[0][0]
523    second_args = mock_copyfiles.call_args_list[1][0]
524    third_args = mock_copyfiles.call_args_list[2][0]
525    self.assertEqual(first_args, ('src_file_1', '/tmp/test/src_file_1.0'))
526    self.assertEqual(second_args, ('src_file_2', '/tmp/test/src_file_2.0'))
527    self.assertEqual(third_args, ('src_file_3', '/tmp/test/src_file_3.0'))
528
529    mock_runcmd.reset_mock()
530    mock_copyfiles.reset_mock()
531    # test 2. dest_dir does not exist; CopyFiles returns 0.
532    mock_isdir.return_value = False
533    self.result.CopyFilesTo(dest_dir, files)
534    self.assertEqual(mock_runcmd.call_count, 3)
535    self.assertEqual(mock_copyfiles.call_count, 3)
536    self.assertEqual(mock_runcmd.call_args_list[0],
537                     mock_runcmd.call_args_list[1])
538    self.assertEqual(mock_runcmd.call_args_list[0],
539                     mock_runcmd.call_args_list[2])
540    self.assertEqual(mock_runcmd.call_args_list[0][0], ('mkdir -p /tmp/test',))
541
542    # test 3. CopyFiles returns 1 (fails).
543    mock_copyfiles.return_value = 1
544    self.assertRaises(Exception, self.result.CopyFilesTo, dest_dir, files)
545
546  @mock.patch.object(Result, 'CopyFilesTo')
547  def test_copy_results_to(self, mockCopyFilesTo):
548    results_file = [
549        '/tmp/result.json.0', '/tmp/result.json.1', '/tmp/result.json.2'
550    ]
551    perf_data_files = [
552        '/tmp/perf.data.0', '/tmp/perf.data.1', '/tmp/perf.data.2'
553    ]
554    perf_report_files = [
555        '/tmp/perf.report.0', '/tmp/perf.report.1', '/tmp/perf.report.2'
556    ]
557
558    self.result.results_file = results_file
559    self.result.perf_data_files = perf_data_files
560    self.result.perf_report_files = perf_report_files
561
562    self.result.CopyFilesTo = mockCopyFilesTo
563    self.result.CopyResultsTo('/tmp/results/')
564    self.assertEqual(mockCopyFilesTo.call_count, 3)
565    self.assertEqual(len(mockCopyFilesTo.call_args_list), 3)
566    self.assertEqual(mockCopyFilesTo.call_args_list[0][0],
567                     ('/tmp/results/', results_file))
568    self.assertEqual(mockCopyFilesTo.call_args_list[1][0],
569                     ('/tmp/results/', perf_data_files))
570    self.assertEqual(mockCopyFilesTo.call_args_list[2][0],
571                     ('/tmp/results/', perf_report_files))
572
573  def test_get_new_keyvals(self):
574    kv_dict = {}
575
576    def FakeGetDataMeasurementsFiles():
577      filename = os.path.join(os.getcwd(), 'unittest_keyval_file.txt')
578      return [filename]
579
580    self.result.GetDataMeasurementsFiles = FakeGetDataMeasurementsFiles
581    kv_dict2, udict = self.result.GetNewKeyvals(kv_dict)
582    self.assertEqual(
583        kv_dict2, {
584            u'Box2D__Box2D': 4775,
585            u'Mandreel__Mandreel': 6620,
586            u'Gameboy__Gameboy': 9901,
587            u'Crypto__Crypto': 8737,
588            u'telemetry_page_measurement_results__num_errored': 0,
589            u'telemetry_page_measurement_results__num_failed': 0,
590            u'PdfJS__PdfJS': 6455,
591            u'Total__Score': 7918,
592            u'EarleyBoyer__EarleyBoyer': 14340,
593            u'MandreelLatency__MandreelLatency': 5188,
594            u'CodeLoad__CodeLoad': 6271,
595            u'DeltaBlue__DeltaBlue': 14401,
596            u'Typescript__Typescript': 9815,
597            u'SplayLatency__SplayLatency': 7653,
598            u'zlib__zlib': 16094,
599            u'Richards__Richards': 10358,
600            u'RegExp__RegExp': 1765,
601            u'NavierStokes__NavierStokes': 9815,
602            u'Splay__Splay': 4425,
603            u'RayTrace__RayTrace': 16600
604        })
605    self.assertEqual(
606        udict, {
607            u'Box2D__Box2D': u'score',
608            u'Mandreel__Mandreel': u'score',
609            u'Gameboy__Gameboy': u'score',
610            u'Crypto__Crypto': u'score',
611            u'telemetry_page_measurement_results__num_errored': u'count',
612            u'telemetry_page_measurement_results__num_failed': u'count',
613            u'PdfJS__PdfJS': u'score',
614            u'Total__Score': u'score',
615            u'EarleyBoyer__EarleyBoyer': u'score',
616            u'MandreelLatency__MandreelLatency': u'score',
617            u'CodeLoad__CodeLoad': u'score',
618            u'DeltaBlue__DeltaBlue': u'score',
619            u'Typescript__Typescript': u'score',
620            u'SplayLatency__SplayLatency': u'score',
621            u'zlib__zlib': u'score',
622            u'Richards__Richards': u'score',
623            u'RegExp__RegExp': u'score',
624            u'NavierStokes__NavierStokes': u'score',
625            u'Splay__Splay': u'score',
626            u'RayTrace__RayTrace': u'score'
627        })
628
629  def test_append_telemetry_units(self):
630    kv_dict = {
631        u'Box2D__Box2D': 4775,
632        u'Mandreel__Mandreel': 6620,
633        u'Gameboy__Gameboy': 9901,
634        u'Crypto__Crypto': 8737,
635        u'PdfJS__PdfJS': 6455,
636        u'Total__Score': 7918,
637        u'EarleyBoyer__EarleyBoyer': 14340,
638        u'MandreelLatency__MandreelLatency': 5188,
639        u'CodeLoad__CodeLoad': 6271,
640        u'DeltaBlue__DeltaBlue': 14401,
641        u'Typescript__Typescript': 9815,
642        u'SplayLatency__SplayLatency': 7653,
643        u'zlib__zlib': 16094,
644        u'Richards__Richards': 10358,
645        u'RegExp__RegExp': 1765,
646        u'NavierStokes__NavierStokes': 9815,
647        u'Splay__Splay': 4425,
648        u'RayTrace__RayTrace': 16600
649    }
650    units_dict = {
651        u'Box2D__Box2D': u'score',
652        u'Mandreel__Mandreel': u'score',
653        u'Gameboy__Gameboy': u'score',
654        u'Crypto__Crypto': u'score',
655        u'PdfJS__PdfJS': u'score',
656        u'Total__Score': u'score',
657        u'EarleyBoyer__EarleyBoyer': u'score',
658        u'MandreelLatency__MandreelLatency': u'score',
659        u'CodeLoad__CodeLoad': u'score',
660        u'DeltaBlue__DeltaBlue': u'score',
661        u'Typescript__Typescript': u'score',
662        u'SplayLatency__SplayLatency': u'score',
663        u'zlib__zlib': u'score',
664        u'Richards__Richards': u'score',
665        u'RegExp__RegExp': u'score',
666        u'NavierStokes__NavierStokes': u'score',
667        u'Splay__Splay': u'score',
668        u'RayTrace__RayTrace': u'score'
669    }
670
671    results_dict = self.result.AppendTelemetryUnits(kv_dict, units_dict)
672    self.assertEqual(
673        results_dict, {
674            u'Box2D__Box2D': [4775, u'score'],
675            u'Splay__Splay': [4425, u'score'],
676            u'Gameboy__Gameboy': [9901, u'score'],
677            u'Crypto__Crypto': [8737, u'score'],
678            u'PdfJS__PdfJS': [6455, u'score'],
679            u'Total__Score': [7918, u'score'],
680            u'EarleyBoyer__EarleyBoyer': [14340, u'score'],
681            u'MandreelLatency__MandreelLatency': [5188, u'score'],
682            u'DeltaBlue__DeltaBlue': [14401, u'score'],
683            u'SplayLatency__SplayLatency': [7653, u'score'],
684            u'Mandreel__Mandreel': [6620, u'score'],
685            u'Richards__Richards': [10358, u'score'],
686            u'zlib__zlib': [16094, u'score'],
687            u'CodeLoad__CodeLoad': [6271, u'score'],
688            u'Typescript__Typescript': [9815, u'score'],
689            u'RegExp__RegExp': [1765, u'score'],
690            u'RayTrace__RayTrace': [16600, u'score'],
691            u'NavierStokes__NavierStokes': [9815, u'score']
692        })
693
694  @mock.patch.object(misc, 'GetInsideChrootPath')
695  @mock.patch.object(tempfile, 'mkdtemp')
696  @mock.patch.object(command_executer.CommandExecuter, 'RunCommand')
697  @mock.patch.object(command_executer.CommandExecuter,
698                     'ChrootRunCommandWOutput')
699  def test_get_keyvals(self, mock_chrootruncmd, mock_runcmd, mock_mkdtemp,
700                       mock_getpath):
701
702    self.kv_dict = {}
703    self.callGetNewKeyvals = False
704
705    def reset():
706      self.kv_dict = {}
707      self.callGetNewKeyvals = False
708      mock_chrootruncmd.reset_mock()
709      mock_runcmd.reset_mock()
710      mock_mkdtemp.reset_mock()
711      mock_getpath.reset_mock()
712
713    def FakeGetNewKeyvals(kv_dict):
714      self.kv_dict = kv_dict
715      self.callGetNewKeyvals = True
716      return_kvdict = {'first_time': 680, 'Total': 10}
717      return_udict = {'first_time': 'ms', 'Total': 'score'}
718      return return_kvdict, return_udict
719
720    mock_mkdtemp.return_value = TMP_DIR1
721    mock_chrootruncmd.return_value = [
722        '', ('%s,PASS\n%s/telemetry_Crosperf,PASS\n') % (TMP_DIR1, TMP_DIR1), ''
723    ]
724    mock_getpath.return_value = TMP_DIR1
725    self.result.ce.ChrootRunCommandWOutput = mock_chrootruncmd
726    self.result.ce.RunCommand = mock_runcmd
727    self.result.GetNewKeyvals = FakeGetNewKeyvals
728    self.result.suite = 'telemetry_Crosperf'
729    self.result.results_dir = '/tmp/test_that_resultsNmq'
730
731    # Test 1. no self.temp_dir.
732    res = self.result.GetKeyvals()
733    self.assertTrue(self.callGetNewKeyvals)
734    self.assertEqual(self.kv_dict, {'': 'PASS', 'telemetry_Crosperf': 'PASS'})
735    self.assertEqual(mock_runcmd.call_count, 1)
736    self.assertEqual(mock_runcmd.call_args_list[0][0],
737                     ('cp -r /tmp/test_that_resultsNmq/* %s' % TMP_DIR1,))
738    self.assertEqual(mock_chrootruncmd.call_count, 1)
739    self.assertEqual(
740        mock_chrootruncmd.call_args_list[0][0],
741        (self.result.chromeos_root,
742         ('./generate_test_report --no-color --csv %s') % TMP_DIR1))
743    self.assertEqual(mock_getpath.call_count, 1)
744    self.assertEqual(mock_mkdtemp.call_count, 1)
745    self.assertEqual(res, {'Total': [10, 'score'], 'first_time': [680, 'ms']})
746
747    # Test 2. self.temp_dir
748    reset()
749    mock_chrootruncmd.return_value = [
750        '', ('/tmp/tmpJCajRG,PASS\n/tmp/tmpJCajRG/'
751             'telemetry_Crosperf,PASS\n'), ''
752    ]
753    mock_getpath.return_value = '/tmp/tmpJCajRG'
754    self.result.temp_dir = '/tmp/tmpJCajRG'
755    res = self.result.GetKeyvals()
756    self.assertEqual(mock_runcmd.call_count, 0)
757    self.assertEqual(mock_mkdtemp.call_count, 0)
758    self.assertEqual(mock_chrootruncmd.call_count, 1)
759    self.assertTrue(self.callGetNewKeyvals)
760    self.assertEqual(self.kv_dict, {'': 'PASS', 'telemetry_Crosperf': 'PASS'})
761    self.assertEqual(res, {'Total': [10, 'score'], 'first_time': [680, 'ms']})
762
763    # Test 3. suite != telemetry_Crosperf.  Normally this would be for
764    # running non-Telemetry autotests, such as BootPerfServer.  In this test
765    # case, the keyvals we have set up were returned from a Telemetry test run;
766    # so this pass is basically testing that we don't append the units to the
767    # test results (which we do for Telemetry autotest runs).
768    reset()
769    self.result.suite = ''
770    res = self.result.GetKeyvals()
771    self.assertEqual(res, {'Total': 10, 'first_time': 680})
772
773  @mock.patch.object(misc, 'GetInsideChrootPath')
774  @mock.patch.object(command_executer.CommandExecuter,
775                     'ChrootRunCommandWOutput')
776  def test_get_samples(self, mock_chrootruncmd, mock_getpath):
777    fake_file = '/usr/chromeos/chroot/tmp/results/fake_file'
778    self.result.perf_data_files = ['/tmp/results/perf.data']
779    self.result.board = 'samus'
780    mock_getpath.return_value = fake_file
781    self.result.ce.ChrootRunCommandWOutput = mock_chrootruncmd
782    mock_chrootruncmd.return_value = ['', '45.42%        237210  chrome ', '']
783    samples = self.result.GetSamples()
784    self.assertEqual(samples, [237210, u'samples'])
785
786  def test_get_results_dir(self):
787
788    self.result.out = ''
789    self.assertRaises(Exception, self.result.GetResultsDir)
790
791    self.result.out = OUTPUT
792    resdir = self.result.GetResultsDir()
793    self.assertEqual(resdir, '/tmp/test_that.PO1234567/platform_LibCBench')
794
795  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandGeneric')
796  def test_find_files_in_results_dir(self, mock_runcmd):
797
798    self.result.results_dir = None
799    res = self.result.FindFilesInResultsDir('-name perf.data')
800    self.assertEqual(res, '')
801
802    self.result.ce.RunCommand = mock_runcmd
803    self.result.results_dir = '/tmp/test_results'
804    mock_runcmd.return_value = [0, '/tmp/test_results/perf.data', '']
805    res = self.result.FindFilesInResultsDir('-name perf.data')
806    self.assertEqual(mock_runcmd.call_count, 1)
807    self.assertEqual(mock_runcmd.call_args_list[0][0],
808                     ('find /tmp/test_results -name perf.data',))
809    self.assertEqual(res, '/tmp/test_results/perf.data')
810
811    mock_runcmd.reset_mock()
812    mock_runcmd.return_value = [1, '', '']
813    self.assertRaises(Exception, self.result.FindFilesInResultsDir,
814                      '-name perf.data')
815
816  @mock.patch.object(Result, 'FindFilesInResultsDir')
817  def test_get_perf_data_files(self, mock_findfiles):
818    self.args = None
819
820    mock_findfiles.return_value = 'line1\nline1\n'
821    self.result.FindFilesInResultsDir = mock_findfiles
822    res = self.result.GetPerfDataFiles()
823    self.assertEqual(res, ['line1', 'line1'])
824    self.assertEqual(mock_findfiles.call_args_list[0][0], ('-name perf.data',))
825
826  def test_get_perf_report_files(self):
827    self.args = None
828
829    def FakeFindFiles(find_args):
830      self.args = find_args
831      return 'line1\nline1\n'
832
833    self.result.FindFilesInResultsDir = FakeFindFiles
834    res = self.result.GetPerfReportFiles()
835    self.assertEqual(res, ['line1', 'line1'])
836    self.assertEqual(self.args, '-name perf.data.report')
837
838  def test_get_data_measurement_files(self):
839    self.args = None
840
841    def FakeFindFiles(find_args):
842      self.args = find_args
843      return 'line1\nline1\n'
844
845    self.result.FindFilesInResultsDir = FakeFindFiles
846    res = self.result.GetDataMeasurementsFiles()
847    self.assertEqual(res, ['line1', 'line1'])
848    self.assertEqual(self.args, '-name perf_measurements')
849
850  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
851  def test_get_turbostat_file_finds_single_log(self, mock_runcmd):
852    """Expected behavior when a single log file found."""
853    self.result.results_dir = '/tmp/test_results'
854    self.result.ce.RunCommandWOutput = mock_runcmd
855    mock_runcmd.return_value = (0, 'some/long/path/turbostat.log', '')
856    found_single_log = self.result.GetTurbostatFile()
857    self.assertEqual(found_single_log, 'some/long/path/turbostat.log')
858
859  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
860  def test_get_turbostat_file_finds_multiple_logs(self, mock_runcmd):
861    """Error case when multiple files found."""
862    self.result.results_dir = '/tmp/test_results'
863    self.result.ce.RunCommandWOutput = mock_runcmd
864    mock_runcmd.return_value = (0,
865                                'some/long/path/turbostat.log\nturbostat.log',
866                                '')
867    found_first_logs = self.result.GetTurbostatFile()
868    self.assertEqual(found_first_logs, 'some/long/path/turbostat.log')
869
870  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
871  def test_get_turbostat_file_finds_no_logs(self, mock_runcmd):
872    """Error case when no log file found."""
873    self.result.results_dir = '/tmp/test_results'
874    self.result.ce.RunCommandWOutput = mock_runcmd
875    mock_runcmd.return_value = (0, '', '')
876    found_no_logs = self.result.GetTurbostatFile()
877    self.assertEqual(found_no_logs, '')
878
879  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
880  def test_get_turbostat_file_with_failing_find(self, mock_runcmd):
881    """Error case when file search returns an error."""
882    self.result.results_dir = '/tmp/test_results'
883    mock_runcmd.return_value = (-1, '', 'error')
884    with self.assertRaises(RuntimeError):
885      self.result.GetTurbostatFile()
886
887  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
888  def test_get_top_file_finds_single_log(self, mock_runcmd):
889    """Expected behavior when a single top log file found."""
890    self.result.results_dir = '/tmp/test_results'
891    self.result.ce.RunCommandWOutput = mock_runcmd
892    mock_runcmd.return_value = (0, 'some/long/path/top.log', '')
893    found_single_log = self.result.GetTopFile()
894    self.assertEqual(found_single_log, 'some/long/path/top.log')
895
896  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
897  def test_get_top_file_finds_multiple_logs(self, mock_runcmd):
898    """The case when multiple top files found."""
899    self.result.results_dir = '/tmp/test_results'
900    self.result.ce.RunCommandWOutput = mock_runcmd
901    mock_runcmd.return_value = (0, 'some/long/path/top.log\ntop.log', '')
902    found_first_logs = self.result.GetTopFile()
903    self.assertEqual(found_first_logs, 'some/long/path/top.log')
904
905  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
906  def test_get_top_file_finds_no_logs(self, mock_runcmd):
907    """Error case when no log file found."""
908    self.result.results_dir = '/tmp/test_results'
909    self.result.ce.RunCommandWOutput = mock_runcmd
910    mock_runcmd.return_value = (0, '', '')
911    found_no_logs = self.result.GetTopFile()
912    self.assertEqual(found_no_logs, '')
913
914  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
915  def test_get_cpuinfo_file_finds_single_log(self, mock_runcmd):
916    """Expected behavior when a single cpuinfo file found."""
917    self.result.results_dir = '/tmp/test_results'
918    self.result.ce.RunCommandWOutput = mock_runcmd
919    mock_runcmd.return_value = (0, 'some/long/path/cpuinfo.log', '')
920    found_single_log = self.result.GetCpuinfoFile()
921    self.assertEqual(found_single_log, 'some/long/path/cpuinfo.log')
922
923  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
924  def test_get_cpustats_file_finds_single_log(self, mock_runcmd):
925    """Expected behavior when a single log file found."""
926    self.result.results_dir = '/tmp/test_results'
927    self.result.ce.RunCommandWOutput = mock_runcmd
928    mock_runcmd.return_value = (0, 'some/long/path/cpustats.log', '')
929    found_single_log = self.result.GetCpustatsFile()
930    self.assertEqual(found_single_log, 'some/long/path/cpustats.log')
931
932  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
933  def test_get_cpustats_file_finds_multiple_logs(self, mock_runcmd):
934    """The case when multiple files found."""
935    self.result.results_dir = '/tmp/test_results'
936    self.result.ce.RunCommandWOutput = mock_runcmd
937    mock_runcmd.return_value = (0, 'some/long/path/cpustats.log\ncpustats.log',
938                                '')
939    found_first_logs = self.result.GetCpustatsFile()
940    self.assertEqual(found_first_logs, 'some/long/path/cpustats.log')
941
942  @mock.patch.object(command_executer.CommandExecuter, 'RunCommandWOutput')
943  def test_get_cpustats_file_finds_no_logs(self, mock_runcmd):
944    """Error case when no log file found."""
945    self.result.results_dir = '/tmp/test_results'
946    self.result.ce.RunCommandWOutput = mock_runcmd
947    mock_runcmd.return_value = (0, '', '')
948    found_no_logs = self.result.GetCpustatsFile()
949    self.assertEqual(found_no_logs, '')
950
951  def test_verify_perf_data_pid_ok(self):
952    """Verify perf PID which is present in TOP_DATA."""
953    self.result.top_cmds = TOP_DATA
954    # pid is present in TOP_DATA.
955    with mock.patch.object(
956        Result, 'ReadPidFromPerfData', return_value=['5713']):
957      self.result.VerifyPerfDataPID()
958
959  def test_verify_perf_data_pid_fail(self):
960    """Test perf PID missing in top raises the error."""
961    self.result.top_cmds = TOP_DATA
962    # pid is not in the list of top processes.
963    with mock.patch.object(
964        Result, 'ReadPidFromPerfData', return_value=['9999']):
965      with self.assertRaises(PidVerificationError):
966        self.result.VerifyPerfDataPID()
967
968  @mock.patch.object(command_executer.CommandExecuter,
969                     'ChrootRunCommandWOutput')
970  def test_read_pid_from_perf_data_ok(self, mock_runcmd):
971    """Test perf header parser, normal flow."""
972    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
973    self.result.perf_data_files = ['/tmp/chromeos/chroot/tmp/results/perf.data']
974    exp_pid = '12345'
975    mock_runcmd.return_value = (0, PERF_DATA_HEADER.format(pid=exp_pid), '')
976    pids = self.result.ReadPidFromPerfData()
977    self.assertEqual(pids, [exp_pid])
978
979  @mock.patch.object(command_executer.CommandExecuter,
980                     'ChrootRunCommandWOutput')
981  def test_read_pid_from_perf_data_mult_profiles(self, mock_runcmd):
982    """Test multiple perf.data files with PID."""
983    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
984    # self.result.chromeos_root = '/tmp/chromeos'
985    self.result.perf_data_files = [
986        '/tmp/chromeos/chroot/tmp/results/perf.data.0',
987        '/tmp/chromeos/chroot/tmp/results/perf.data.1',
988    ]
989    # There is '-p <pid>' in command line but it's still system-wide: '-a'.
990    cmd_line = '# cmdline : /usr/bin/perf record -e instructions -p {pid}'
991    exp_perf_pids = ['1111', '2222']
992    mock_runcmd.side_effect = [
993        (0, cmd_line.format(pid=exp_perf_pids[0]), ''),
994        (0, cmd_line.format(pid=exp_perf_pids[1]), ''),
995    ]
996    pids = self.result.ReadPidFromPerfData()
997    self.assertEqual(pids, exp_perf_pids)
998
999  @mock.patch.object(command_executer.CommandExecuter,
1000                     'ChrootRunCommandWOutput')
1001  def test_read_pid_from_perf_data_no_pid(self, mock_runcmd):
1002    """Test perf.data without PID."""
1003    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
1004    self.result.perf_data_files = ['/tmp/chromeos/chroot/tmp/results/perf.data']
1005    cmd_line = '# cmdline : /usr/bin/perf record -e instructions'
1006    mock_runcmd.return_value = (0, cmd_line, '')
1007    pids = self.result.ReadPidFromPerfData()
1008    # pids is empty.
1009    self.assertEqual(pids, [])
1010
1011  @mock.patch.object(command_executer.CommandExecuter,
1012                     'ChrootRunCommandWOutput')
1013  def test_read_pid_from_perf_data_system_wide(self, mock_runcmd):
1014    """Test reading from system-wide profile with PID."""
1015    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
1016    self.result.perf_data_files = ['/tmp/chromeos/chroot/tmp/results/perf.data']
1017    # There is '-p <pid>' in command line but it's still system-wide: '-a'.
1018    cmd_line = '# cmdline : /usr/bin/perf record -e instructions -a -p 1234'
1019    mock_runcmd.return_value = (0, cmd_line, '')
1020    pids = self.result.ReadPidFromPerfData()
1021    # pids should be empty since it's not a per-process profiling.
1022    self.assertEqual(pids, [])
1023
1024  @mock.patch.object(command_executer.CommandExecuter,
1025                     'ChrootRunCommandWOutput')
1026  def test_read_pid_from_perf_data_read_fail(self, mock_runcmd):
1027    """Failure to read perf.data raises the error."""
1028    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
1029    self.result.perf_data_files = ['/tmp/chromeos/chroot/tmp/results/perf.data']
1030    # Error status of the profile read.
1031    mock_runcmd.return_value = (1, '', '')
1032    with self.assertRaises(PerfDataReadError):
1033      self.result.ReadPidFromPerfData()
1034
1035  @mock.patch.object(command_executer.CommandExecuter,
1036                     'ChrootRunCommandWOutput')
1037  def test_read_pid_from_perf_data_fail(self, mock_runcmd):
1038    """Failure to find cmdline in perf.data header raises the error."""
1039    self.result.ce.ChrootRunCommandWOutput = mock_runcmd
1040    self.result.perf_data_files = ['/tmp/chromeos/chroot/tmp/results/perf.data']
1041    # Empty output.
1042    mock_runcmd.return_value = (0, '', '')
1043    with self.assertRaises(PerfDataReadError):
1044      self.result.ReadPidFromPerfData()
1045
1046  def test_process_turbostat_results_with_valid_data(self):
1047    """Normal case when log exists and contains valid data."""
1048    self.result.turbostat_log_file = '/tmp/somelogfile.log'
1049    with mock.patch('builtins.open',
1050                    mock.mock_open(read_data=TURBOSTAT_LOG_OUTPUT)) as mo:
1051      cpustats = self.result.ProcessTurbostatResults()
1052      # Check that the log got opened and data were read/parsed.
1053      calls = [mock.call('/tmp/somelogfile.log')]
1054      mo.assert_has_calls(calls)
1055      self.assertEqual(cpustats, TURBOSTAT_DATA)
1056
1057  def test_process_turbostat_results_from_empty_file(self):
1058    """Error case when log exists but file is empty."""
1059    self.result.turbostat_log_file = '/tmp/emptylogfile.log'
1060    with mock.patch('builtins.open', mock.mock_open(read_data='')) as mo:
1061      cpustats = self.result.ProcessTurbostatResults()
1062      # Check that the log got opened and parsed successfully and empty data
1063      # returned.
1064      calls = [mock.call('/tmp/emptylogfile.log')]
1065      mo.assert_has_calls(calls)
1066      self.assertEqual(cpustats, {})
1067
1068  def test_process_turbostat_results_when_file_doesnt_exist(self):
1069    """Error case when file does not exist."""
1070    nonexistinglog = '/tmp/1'
1071    while os.path.exists(nonexistinglog):
1072      # Extend file path if it happens to exist.
1073      nonexistinglog = os.path.join(nonexistinglog, '1')
1074    self.result.turbostat_log_file = nonexistinglog
1075    # Allow the tested function to call a 'real' open and hopefully crash.
1076    with self.assertRaises(IOError):
1077      self.result.ProcessTurbostatResults()
1078
1079  def test_process_cpustats_results_with_uniq_data(self):
1080    """Process cpustats log which has freq unique to each core.
1081
1082    Testing normal case when frequency data vary between
1083    different cores.
1084    Expecting that data for all cores will be present in
1085    returned cpustats.
1086    """
1087    self.result.cpustats_log_file = '/tmp/somelogfile.log'
1088    with mock.patch('builtins.open',
1089                    mock.mock_open(read_data=CPUSTATS_UNIQ_OUTPUT)) as mo:
1090      cpustats = self.result.ProcessCpustatsResults()
1091      # Check that the log got opened and data were read/parsed.
1092      calls = [mock.call('/tmp/somelogfile.log')]
1093      mo.assert_has_calls(calls)
1094      self.assertEqual(cpustats, CPUSTATS_UNIQ_DATA)
1095
1096  def test_process_cpustats_results_with_dupl_data(self):
1097    """Process cpustats log where cores have duplicate freq.
1098
1099    Testing normal case when frequency data on some cores
1100    are duplicated.
1101    Expecting that duplicated data is discarded in
1102    returned cpustats.
1103    """
1104    self.result.cpustats_log_file = '/tmp/somelogfile.log'
1105    with mock.patch('builtins.open',
1106                    mock.mock_open(read_data=CPUSTATS_DUPL_OUTPUT)) as mo:
1107      cpustats = self.result.ProcessCpustatsResults()
1108      # Check that the log got opened and data were read/parsed.
1109      calls = [mock.call('/tmp/somelogfile.log')]
1110      mo.assert_has_calls(calls)
1111      self.assertEqual(cpustats, CPUSTATS_DUPL_DATA)
1112
1113  def test_process_cpustats_results_from_empty_file(self):
1114    """Error case when log exists but file is empty."""
1115    self.result.cpustats_log_file = '/tmp/emptylogfile.log'
1116    with mock.patch('builtins.open', mock.mock_open(read_data='')) as mo:
1117      cpustats = self.result.ProcessCpustatsResults()
1118      # Check that the log got opened and parsed successfully and empty data
1119      # returned.
1120      calls = [mock.call('/tmp/emptylogfile.log')]
1121      mo.assert_has_calls(calls)
1122      self.assertEqual(cpustats, {})
1123
1124  def test_process_top_results_with_valid_data(self):
1125    """Process top log with valid data."""
1126
1127    self.result.top_log_file = '/tmp/fakelogfile.log'
1128    with mock.patch('builtins.open', mock.mock_open(read_data=TOP_LOG)) as mo:
1129      topproc = self.result.ProcessTopResults()
1130      # Check that the log got opened and data were read/parsed.
1131      calls = [mock.call('/tmp/fakelogfile.log')]
1132      mo.assert_has_calls(calls)
1133      self.assertEqual(topproc, TOP_DATA)
1134
1135  def test_process_top_results_from_empty_file(self):
1136    """Error case when log exists but file is empty."""
1137    self.result.top_log_file = '/tmp/emptylogfile.log'
1138    with mock.patch('builtins.open', mock.mock_open(read_data='')) as mo:
1139      topcalls = self.result.ProcessTopResults()
1140      # Check that the log got opened and parsed successfully and empty data
1141      # returned.
1142      calls = [mock.call('/tmp/emptylogfile.log')]
1143      mo.assert_has_calls(calls)
1144      self.assertEqual(topcalls, [])
1145
1146  def test_format_string_top_cmds(self):
1147    """Test formatted string with top commands."""
1148    self.result.top_cmds = [
1149        {
1150            'cmd': 'chrome-111',
1151            'cpu_use_avg': 119.753453465,
1152            'count': 44444,
1153            'top5_cpu_use': [222.8, 217.9, 217.8, 191.0, 189.9],
1154        },
1155        {
1156            'cmd': 'chrome-222',
1157            'cpu_use_avg': 100,
1158            'count': 33333,
1159            'top5_cpu_use': [200.0, 195.0, 190.0, 185.0, 180.0],
1160        },
1161        {
1162            'cmd': 'irq/230-cros-ec',
1163            'cpu_use_avg': 10.000000000000001,
1164            'count': 1000,
1165            'top5_cpu_use': [11.5, 11.4, 11.3, 11.2, 11.1],
1166        },
1167        {
1168            'cmd': 'powerd',
1169            'cpu_use_avg': 2.0,
1170            'count': 2,
1171            'top5_cpu_use': [3.0, 1.0]
1172        },
1173        {
1174            'cmd': 'cmd3',
1175            'cpu_use_avg': 1.0,
1176            'count': 1,
1177            'top5_cpu_use': [1.0],
1178        },
1179        {
1180            'cmd': 'cmd4',
1181            'cpu_use_avg': 1.0,
1182            'count': 1,
1183            'top5_cpu_use': [1.0],
1184        },
1185        {
1186            'cmd': 'cmd5',
1187            'cpu_use_avg': 1.0,
1188            'count': 1,
1189            'top5_cpu_use': [1.0],
1190        },
1191        {
1192            'cmd': 'cmd6_not_for_print',
1193            'cpu_avg': 1.0,
1194            'count': 1,
1195            'top5': [1.0],
1196        },
1197    ]
1198    form_str = self.result.FormatStringTopCommands()
1199    self.assertEqual(
1200        form_str, '\n'.join([
1201            'Top commands with highest CPU usage:',
1202            '             COMMAND  AVG CPU%  COUNT   HIGHEST 5',
1203            '-' * 50,
1204            '          chrome-111    119.75  44444   '
1205            '[222.8, 217.9, 217.8, 191.0, 189.9]',
1206            '          chrome-222    100.00  33333   '
1207            '[200.0, 195.0, 190.0, 185.0, 180.0]',
1208            '     irq/230-cros-ec     10.00   1000   '
1209            '[11.5, 11.4, 11.3, 11.2, 11.1]',
1210            '              powerd      2.00      2   [3.0, 1.0]',
1211            '                cmd3      1.00      1   [1.0]',
1212            '                cmd4      1.00      1   [1.0]',
1213            '                cmd5      1.00      1   [1.0]',
1214            '-' * 50,
1215        ]))
1216
1217  def test_format_string_top_calls_no_data(self):
1218    """Test formatted string of top with no data."""
1219    self.result.top_cmds = []
1220    form_str = self.result.FormatStringTopCommands()
1221    self.assertEqual(
1222        form_str, '\n'.join([
1223            'Top commands with highest CPU usage:',
1224            '             COMMAND  AVG CPU%  COUNT   HIGHEST 5',
1225            '-' * 50,
1226            '[NO DATA FROM THE TOP LOG]',
1227            '-' * 50,
1228        ]))
1229
1230  @mock.patch.object(misc, 'GetInsideChrootPath')
1231  @mock.patch.object(command_executer.CommandExecuter, 'ChrootRunCommand')
1232  def test_generate_perf_report_files(self, mock_chrootruncmd, mock_getpath):
1233    fake_file = '/usr/chromeos/chroot/tmp/results/fake_file'
1234    self.result.perf_data_files = ['/tmp/results/perf.data']
1235    self.result.board = 'lumpy'
1236    mock_getpath.return_value = fake_file
1237    self.result.ce.ChrootRunCommand = mock_chrootruncmd
1238    mock_chrootruncmd.return_value = 0
1239    # Debug path not found
1240    self.result.label.debug_path = ''
1241    tmp = self.result.GeneratePerfReportFiles()
1242    self.assertEqual(tmp, ['/tmp/chromeos/chroot%s' % fake_file])
1243    self.assertEqual(mock_chrootruncmd.call_args_list[0][0],
1244                     (self.result.chromeos_root,
1245                      ('/usr/sbin/perf report -n    '
1246                       '-i %s --stdio > %s') % (fake_file, fake_file)))
1247
1248  @mock.patch.object(misc, 'GetInsideChrootPath')
1249  @mock.patch.object(command_executer.CommandExecuter, 'ChrootRunCommand')
1250  def test_generate_perf_report_files_debug(self, mock_chrootruncmd,
1251                                            mock_getpath):
1252    fake_file = '/usr/chromeos/chroot/tmp/results/fake_file'
1253    self.result.perf_data_files = ['/tmp/results/perf.data']
1254    self.result.board = 'lumpy'
1255    mock_getpath.return_value = fake_file
1256    self.result.ce.ChrootRunCommand = mock_chrootruncmd
1257    mock_chrootruncmd.return_value = 0
1258    # Debug path found
1259    self.result.label.debug_path = '/tmp/debug'
1260    tmp = self.result.GeneratePerfReportFiles()
1261    self.assertEqual(tmp, ['/tmp/chromeos/chroot%s' % fake_file])
1262    self.assertEqual(mock_chrootruncmd.call_args_list[0][0],
1263                     (self.result.chromeos_root,
1264                      ('/usr/sbin/perf report -n --symfs /tmp/debug '
1265                       '--vmlinux /tmp/debug/boot/vmlinux  '
1266                       '-i %s --stdio > %s') % (fake_file, fake_file)))
1267
1268  @mock.patch.object(misc, 'GetOutsideChrootPath')
1269  def test_populate_from_run(self, mock_getpath):
1270
1271    def FakeGetResultsDir():
1272      self.callGetResultsDir = True
1273      return '/tmp/results_dir'
1274
1275    def FakeGetResultsFile():
1276      self.callGetResultsFile = True
1277      return []
1278
1279    def FakeGetPerfDataFiles():
1280      self.callGetPerfDataFiles = True
1281      return []
1282
1283    def FakeGetPerfReportFiles():
1284      self.callGetPerfReportFiles = True
1285      return []
1286
1287    def FakeGetTurbostatFile():
1288      self.callGetTurbostatFile = True
1289      return []
1290
1291    def FakeGetCpustatsFile():
1292      self.callGetCpustatsFile = True
1293      return []
1294
1295    def FakeGetTopFile():
1296      self.callGetTopFile = True
1297      return []
1298
1299    def FakeGetCpuinfoFile():
1300      self.callGetCpuinfoFile = True
1301      return []
1302
1303    def FakeGetWaitTimeFile():
1304      self.callGetWaitTimeFile = True
1305      return []
1306
1307    def FakeProcessResults(show_results=False):
1308      if show_results:
1309        pass
1310      self.callProcessResults = True
1311
1312    if mock_getpath:
1313      pass
1314    mock.get_path = '/tmp/chromeos/tmp/results_dir'
1315
1316    self.callGetResultsDir = False
1317    self.callGetResultsFile = False
1318    self.callGetPerfDataFiles = False
1319    self.callGetPerfReportFiles = False
1320    self.callGetTurbostatFile = False
1321    self.callGetCpustatsFile = False
1322    self.callGetTopFile = False
1323    self.callGetCpuinfoFile = False
1324    self.callGetWaitTimeFile = False
1325    self.callProcessResults = False
1326
1327    self.result.GetResultsDir = FakeGetResultsDir
1328    self.result.GetResultsFile = FakeGetResultsFile
1329    self.result.GetPerfDataFiles = FakeGetPerfDataFiles
1330    self.result.GeneratePerfReportFiles = FakeGetPerfReportFiles
1331    self.result.GetTurbostatFile = FakeGetTurbostatFile
1332    self.result.GetCpustatsFile = FakeGetCpustatsFile
1333    self.result.GetTopFile = FakeGetTopFile
1334    self.result.GetCpuinfoFile = FakeGetCpuinfoFile
1335    self.result.GetWaitTimeFile = FakeGetWaitTimeFile
1336    self.result.ProcessResults = FakeProcessResults
1337
1338    self.result.PopulateFromRun(OUTPUT, '', 0, 'test', 'telemetry_Crosperf',
1339                                'chrome')
1340    self.assertTrue(self.callGetResultsDir)
1341    self.assertTrue(self.callGetResultsFile)
1342    self.assertTrue(self.callGetPerfDataFiles)
1343    self.assertTrue(self.callGetPerfReportFiles)
1344    self.assertTrue(self.callGetTurbostatFile)
1345    self.assertTrue(self.callGetCpustatsFile)
1346    self.assertTrue(self.callGetTopFile)
1347    self.assertTrue(self.callGetCpuinfoFile)
1348    self.assertTrue(self.callGetWaitTimeFile)
1349    self.assertTrue(self.callProcessResults)
1350
1351  def FakeGetKeyvals(self, show_all=False):
1352    if show_all:
1353      return {'first_time': 680, 'Total': 10}
1354    else:
1355      return {'Total': 10}
1356
1357  def test_process_results(self):
1358
1359    def FakeGatherPerfResults():
1360      self.callGatherPerfResults = True
1361
1362    def FakeGetSamples():
1363      return (1, 'samples')
1364
1365    # Test 1
1366    self.callGatherPerfResults = False
1367
1368    self.result.GetKeyvals = self.FakeGetKeyvals
1369    self.result.GatherPerfResults = FakeGatherPerfResults
1370
1371    self.result.retval = 0
1372    self.result.ProcessResults()
1373    self.assertTrue(self.callGatherPerfResults)
1374    self.assertEqual(len(self.result.keyvals), 2)
1375    self.assertEqual(self.result.keyvals, {'Total': 10, 'retval': 0})
1376
1377    # Test 2
1378    self.result.retval = 1
1379    self.result.ProcessResults()
1380    self.assertEqual(len(self.result.keyvals), 2)
1381    self.assertEqual(self.result.keyvals, {'Total': 10, 'retval': 1})
1382
1383    # Test 3
1384    self.result.cwp_dso = 'chrome'
1385    self.result.retval = 0
1386    self.result.GetSamples = FakeGetSamples
1387    self.result.ProcessResults()
1388    self.assertEqual(len(self.result.keyvals), 3)
1389    self.assertEqual(self.result.keyvals, {
1390        'Total': 10,
1391        'samples': (1, 'samples'),
1392        'retval': 0
1393    })
1394
1395    # Test 4. Parse output of benchmarks with multiple sotries in histogram
1396    # format
1397    self.result.suite = 'telemetry_Crosperf'
1398    self.result.results_file = [tempfile.mkdtemp() + '/histograms.json']
1399    with open(self.result.results_file[0], 'w') as f:
1400      f.write(HISTOGRAMSET)
1401    self.result.ProcessResults()
1402    shutil.rmtree(os.path.dirname(self.result.results_file[0]))
1403    # Verify the summary for the story is correct
1404    self.assertEqual(self.result.keyvals['timeToFirstContentfulPaint__typical'],
1405                     [880.000, u'ms_smallerIsBetter'])
1406    # Veirfy the summary for a certain stroy tag is correct
1407    self.assertEqual(
1408        self.result
1409        .keyvals['timeToFirstContentfulPaint__cache_temperature:cold'],
1410        [1000.000, u'ms_smallerIsBetter'])
1411    self.assertEqual(
1412        self.result
1413        .keyvals['timeToFirstContentfulPaint__cache_temperature:warm'],
1414        [800.000, u'ms_smallerIsBetter'])
1415
1416  @mock.patch.object(Result, 'ProcessCpustatsResults')
1417  @mock.patch.object(Result, 'ProcessTurbostatResults')
1418  def test_process_results_with_turbostat_log(self, mock_proc_turbo,
1419                                              mock_proc_cpustats):
1420    self.result.GetKeyvals = self.FakeGetKeyvals
1421
1422    self.result.retval = 0
1423    self.result.turbostat_log_file = '/tmp/turbostat.log'
1424    mock_proc_turbo.return_value = {
1425        'cpufreq': {
1426            'all': [1, 2, 3]
1427        },
1428        'cputemp': {
1429            'all': [5.0, 6.0, 7.0]
1430        }
1431    }
1432    self.result.ProcessResults()
1433    mock_proc_turbo.assert_has_calls([mock.call()])
1434    mock_proc_cpustats.assert_not_called()
1435    self.assertEqual(len(self.result.keyvals), 8)
1436    self.assertEqual(
1437        self.result.keyvals, {
1438            'Total': 10,
1439            'cpufreq_all_avg': 2,
1440            'cpufreq_all_max': 3,
1441            'cpufreq_all_min': 1,
1442            'cputemp_all_avg': 6.0,
1443            'cputemp_all_min': 5.0,
1444            'cputemp_all_max': 7.0,
1445            'retval': 0
1446        })
1447
1448  @mock.patch.object(Result, 'ProcessCpustatsResults')
1449  @mock.patch.object(Result, 'ProcessTurbostatResults')
1450  def test_process_results_with_cpustats_log(self, mock_proc_turbo,
1451                                             mock_proc_cpustats):
1452    self.result.GetKeyvals = self.FakeGetKeyvals
1453
1454    self.result.retval = 0
1455    self.result.cpustats_log_file = '/tmp/cpustats.log'
1456    mock_proc_cpustats.return_value = {
1457        'cpufreq': {
1458            'cpu0': [100, 100, 100],
1459            'cpu1': [4, 5, 6]
1460        },
1461        'cputemp': {
1462            'little': [20.2, 20.2, 20.2],
1463            'big': [55.2, 66.1, 77.3]
1464        }
1465    }
1466    self.result.ProcessResults()
1467    mock_proc_turbo.assert_not_called()
1468    mock_proc_cpustats.assert_has_calls([mock.call()])
1469    self.assertEqual(len(self.result.keyvals), 10)
1470    self.assertEqual(
1471        self.result.keyvals, {
1472            'Total': 10,
1473            'cpufreq_cpu0_avg': 100,
1474            'cpufreq_cpu1_avg': 5,
1475            'cpufreq_cpu1_max': 6,
1476            'cpufreq_cpu1_min': 4,
1477            'cputemp_big_avg': 66.2,
1478            'cputemp_big_max': 77.3,
1479            'cputemp_big_min': 55.2,
1480            'cputemp_little_avg': 20.2,
1481            'retval': 0
1482        })
1483
1484  @mock.patch.object(Result, 'ProcessCpustatsResults')
1485  @mock.patch.object(Result, 'ProcessTurbostatResults')
1486  def test_process_results_with_turbostat_and_cpustats_logs(
1487      self, mock_proc_turbo, mock_proc_cpustats):
1488    self.result.GetKeyvals = self.FakeGetKeyvals
1489
1490    self.result.retval = 0
1491    self.result.turbostat_log_file = '/tmp/turbostat.log'
1492    self.result.cpustats_log_file = '/tmp/cpustats.log'
1493    mock_proc_turbo.return_value = {
1494        'cpufreq': {
1495            'all': [1, 2, 3]
1496        },
1497        'cputemp': {
1498            'all': [5.0, 6.0, 7.0]
1499        }
1500    }
1501    self.result.ProcessResults()
1502    mock_proc_turbo.assert_has_calls([mock.call()])
1503    mock_proc_cpustats.assert_not_called()
1504    self.assertEqual(len(self.result.keyvals), 8)
1505    self.assertEqual(
1506        self.result.keyvals, {
1507            'Total': 10,
1508            'cpufreq_all_avg': 2,
1509            'cpufreq_all_max': 3,
1510            'cpufreq_all_min': 1,
1511            'cputemp_all_avg': 6.0,
1512            'cputemp_all_min': 5.0,
1513            'cputemp_all_max': 7.0,
1514            'retval': 0
1515        })
1516
1517  @mock.patch.object(Result, 'ProcessCpustatsResults')
1518  @mock.patch.object(Result, 'ProcessTurbostatResults')
1519  def test_process_results_without_cpu_data(self, mock_proc_turbo,
1520                                            mock_proc_cpustats):
1521    self.result.GetKeyvals = self.FakeGetKeyvals
1522
1523    self.result.retval = 0
1524    self.result.turbostat_log_file = ''
1525    self.result.cpustats_log_file = ''
1526    self.result.ProcessResults()
1527    mock_proc_turbo.assert_not_called()
1528    mock_proc_cpustats.assert_not_called()
1529    self.assertEqual(len(self.result.keyvals), 2)
1530    self.assertEqual(self.result.keyvals, {'Total': 10, 'retval': 0})
1531
1532  @mock.patch.object(misc, 'GetInsideChrootPath')
1533  @mock.patch.object(command_executer.CommandExecuter,
1534                     'ChrootRunCommandWOutput')
1535  def test_populate_from_cache_dir(self, mock_runchrootcmd, mock_getpath):
1536
1537    # pylint: disable=redefined-builtin
1538    def FakeMkdtemp(dir=None):
1539      if dir:
1540        pass
1541      return self.tmpdir
1542
1543    def FakeGetSamples():
1544      return [1, u'samples']
1545
1546    current_path = os.getcwd()
1547    cache_dir = os.path.join(current_path, 'test_cache/test_input')
1548    self.result.ce = command_executer.GetCommandExecuter(log_level='average')
1549    self.result.ce.ChrootRunCommandWOutput = mock_runchrootcmd
1550    mock_runchrootcmd.return_value = [
1551        '', ('%s,PASS\n%s/\telemetry_Crosperf,PASS\n') % (TMP_DIR1, TMP_DIR1),
1552        ''
1553    ]
1554    mock_getpath.return_value = TMP_DIR1
1555    self.tmpdir = tempfile.mkdtemp()
1556    save_real_mkdtemp = tempfile.mkdtemp
1557    tempfile.mkdtemp = FakeMkdtemp
1558
1559    self.result.PopulateFromCacheDir(cache_dir, 'sunspider',
1560                                     'telemetry_Crosperf', '')
1561    self.assertEqual(
1562        self.result.keyvals, {
1563            u'Total__Total': [444.0, u'ms'],
1564            u'regexp-dna__regexp-dna': [16.2, u'ms'],
1565            u'telemetry_page_measurement_results__num_failed': [0, u'count'],
1566            u'telemetry_page_measurement_results__num_errored': [0, u'count'],
1567            u'string-fasta__string-fasta': [23.2, u'ms'],
1568            u'crypto-sha1__crypto-sha1': [11.6, u'ms'],
1569            u'bitops-3bit-bits-in-byte__bitops-3bit-bits-in-byte': [3.2, u'ms'],
1570            u'access-nsieve__access-nsieve': [7.9, u'ms'],
1571            u'bitops-nsieve-bits__bitops-nsieve-bits': [9.4, u'ms'],
1572            u'string-validate-input__string-validate-input': [19.3, u'ms'],
1573            u'3d-raytrace__3d-raytrace': [24.7, u'ms'],
1574            u'3d-cube__3d-cube': [28.0, u'ms'],
1575            u'string-unpack-code__string-unpack-code': [46.7, u'ms'],
1576            u'date-format-tofte__date-format-tofte': [26.3, u'ms'],
1577            u'math-partial-sums__math-partial-sums': [22.0, u'ms'],
1578            '\telemetry_Crosperf': ['PASS', ''],
1579            u'crypto-aes__crypto-aes': [15.2, u'ms'],
1580            u'bitops-bitwise-and__bitops-bitwise-and': [8.4, u'ms'],
1581            u'crypto-md5__crypto-md5': [10.5, u'ms'],
1582            u'string-tagcloud__string-tagcloud': [52.8, u'ms'],
1583            u'access-nbody__access-nbody': [8.5, u'ms'],
1584            'retval': 0,
1585            u'math-spectral-norm__math-spectral-norm': [6.6, u'ms'],
1586            u'math-cordic__math-cordic': [8.7, u'ms'],
1587            u'access-binary-trees__access-binary-trees': [4.5, u'ms'],
1588            u'controlflow-recursive__controlflow-recursive': [4.4, u'ms'],
1589            u'access-fannkuch__access-fannkuch': [17.8, u'ms'],
1590            u'string-base64__string-base64': [16.0, u'ms'],
1591            u'date-format-xparb__date-format-xparb': [20.9, u'ms'],
1592            u'3d-morph__3d-morph': [22.1, u'ms'],
1593            u'bitops-bits-in-byte__bitops-bits-in-byte': [9.1, u'ms']
1594        })
1595
1596    self.result.GetSamples = FakeGetSamples
1597    self.result.PopulateFromCacheDir(cache_dir, 'sunspider',
1598                                     'telemetry_Crosperf', 'chrome')
1599    self.assertEqual(
1600        self.result.keyvals, {
1601            u'Total__Total': [444.0, u'ms'],
1602            u'regexp-dna__regexp-dna': [16.2, u'ms'],
1603            u'telemetry_page_measurement_results__num_failed': [0, u'count'],
1604            u'telemetry_page_measurement_results__num_errored': [0, u'count'],
1605            u'string-fasta__string-fasta': [23.2, u'ms'],
1606            u'crypto-sha1__crypto-sha1': [11.6, u'ms'],
1607            u'bitops-3bit-bits-in-byte__bitops-3bit-bits-in-byte': [3.2, u'ms'],
1608            u'access-nsieve__access-nsieve': [7.9, u'ms'],
1609            u'bitops-nsieve-bits__bitops-nsieve-bits': [9.4, u'ms'],
1610            u'string-validate-input__string-validate-input': [19.3, u'ms'],
1611            u'3d-raytrace__3d-raytrace': [24.7, u'ms'],
1612            u'3d-cube__3d-cube': [28.0, u'ms'],
1613            u'string-unpack-code__string-unpack-code': [46.7, u'ms'],
1614            u'date-format-tofte__date-format-tofte': [26.3, u'ms'],
1615            u'math-partial-sums__math-partial-sums': [22.0, u'ms'],
1616            '\telemetry_Crosperf': ['PASS', ''],
1617            u'crypto-aes__crypto-aes': [15.2, u'ms'],
1618            u'bitops-bitwise-and__bitops-bitwise-and': [8.4, u'ms'],
1619            u'crypto-md5__crypto-md5': [10.5, u'ms'],
1620            u'string-tagcloud__string-tagcloud': [52.8, u'ms'],
1621            u'access-nbody__access-nbody': [8.5, u'ms'],
1622            'retval': 0,
1623            u'math-spectral-norm__math-spectral-norm': [6.6, u'ms'],
1624            u'math-cordic__math-cordic': [8.7, u'ms'],
1625            u'access-binary-trees__access-binary-trees': [4.5, u'ms'],
1626            u'controlflow-recursive__controlflow-recursive': [4.4, u'ms'],
1627            u'access-fannkuch__access-fannkuch': [17.8, u'ms'],
1628            u'string-base64__string-base64': [16.0, u'ms'],
1629            u'date-format-xparb__date-format-xparb': [20.9, u'ms'],
1630            u'3d-morph__3d-morph': [22.1, u'ms'],
1631            u'bitops-bits-in-byte__bitops-bits-in-byte': [9.1, u'ms'],
1632            u'samples': [1, u'samples']
1633        })
1634
1635    # Clean up after test.
1636    tempfile.mkdtemp = save_real_mkdtemp
1637    command = 'rm -Rf %s' % self.tmpdir
1638    self.result.ce.RunCommand(command)
1639
1640  @mock.patch.object(misc, 'GetRoot')
1641  @mock.patch.object(command_executer.CommandExecuter, 'RunCommand')
1642  def test_cleanup(self, mock_runcmd, mock_getroot):
1643
1644    # Test 1. 'rm_chroot_tmp' is True; self.results_dir exists;
1645    # self.temp_dir exists; results_dir name contains 'test_that_results_'.
1646    mock_getroot.return_value = ['/tmp/tmp_AbcXyz', 'test_that_results_fake']
1647    self.result.ce.RunCommand = mock_runcmd
1648    self.result.results_dir = 'test_results_dir'
1649    self.result.temp_dir = 'testtemp_dir'
1650    self.result.CleanUp(True)
1651    self.assertEqual(mock_getroot.call_count, 1)
1652    self.assertEqual(mock_runcmd.call_count, 2)
1653    self.assertEqual(mock_runcmd.call_args_list[0][0],
1654                     ('rm -rf test_results_dir',))
1655    self.assertEqual(mock_runcmd.call_args_list[1][0], ('rm -rf testtemp_dir',))
1656
1657    # Test 2. Same, except ath results_dir name does not contain
1658    # 'test_that_results_'
1659    mock_getroot.reset_mock()
1660    mock_runcmd.reset_mock()
1661    mock_getroot.return_value = ['/tmp/tmp_AbcXyz', 'other_results_fake']
1662    self.result.ce.RunCommand = mock_runcmd
1663    self.result.results_dir = 'test_results_dir'
1664    self.result.temp_dir = 'testtemp_dir'
1665    self.result.CleanUp(True)
1666    self.assertEqual(mock_getroot.call_count, 1)
1667    self.assertEqual(mock_runcmd.call_count, 2)
1668    self.assertEqual(mock_runcmd.call_args_list[0][0],
1669                     ('rm -rf /tmp/tmp_AbcXyz',))
1670    self.assertEqual(mock_runcmd.call_args_list[1][0], ('rm -rf testtemp_dir',))
1671
1672    # Test 3. mock_getroot returns nothing; 'rm_chroot_tmp' is False.
1673    mock_getroot.reset_mock()
1674    mock_runcmd.reset_mock()
1675    self.result.CleanUp(False)
1676    self.assertEqual(mock_getroot.call_count, 0)
1677    self.assertEqual(mock_runcmd.call_count, 1)
1678    self.assertEqual(mock_runcmd.call_args_list[0][0], ('rm -rf testtemp_dir',))
1679
1680    # Test 4. 'rm_chroot_tmp' is True, but result_dir & temp_dir are None.
1681    mock_getroot.reset_mock()
1682    mock_runcmd.reset_mock()
1683    self.result.results_dir = None
1684    self.result.temp_dir = None
1685    self.result.CleanUp(True)
1686    self.assertEqual(mock_getroot.call_count, 0)
1687    self.assertEqual(mock_runcmd.call_count, 0)
1688
1689  @mock.patch.object(misc, 'GetInsideChrootPath')
1690  @mock.patch.object(command_executer.CommandExecuter, 'ChrootRunCommand')
1691  def test_store_to_cache_dir(self, mock_chrootruncmd, mock_getpath):
1692
1693    def FakeMkdtemp(directory=''):
1694      if directory:
1695        pass
1696      return self.tmpdir
1697
1698    if mock_chrootruncmd or mock_getpath:
1699      pass
1700    current_path = os.getcwd()
1701    cache_dir = os.path.join(current_path, 'test_cache/test_output')
1702
1703    self.result.ce = command_executer.GetCommandExecuter(log_level='average')
1704    self.result.out = OUTPUT
1705    self.result.err = error
1706    self.result.retval = 0
1707    self.tmpdir = tempfile.mkdtemp()
1708    if not os.path.exists(self.tmpdir):
1709      os.makedirs(self.tmpdir)
1710    self.result.results_dir = os.path.join(os.getcwd(), 'test_cache')
1711    save_real_mkdtemp = tempfile.mkdtemp
1712    tempfile.mkdtemp = FakeMkdtemp
1713
1714    mock_mm = machine_manager.MockMachineManager('/tmp/chromeos_root', 0,
1715                                                 'average', '')
1716    mock_mm.machine_checksum_string['mock_label'] = 'fake_machine_checksum123'
1717
1718    mock_keylist = ['key1', 'key2', 'key3']
1719    test_flag.SetTestMode(True)
1720    self.result.StoreToCacheDir(cache_dir, mock_mm, mock_keylist)
1721
1722    # Check that the correct things were written to the 'cache'.
1723    test_dir = os.path.join(os.getcwd(), 'test_cache/test_output')
1724    base_dir = os.path.join(os.getcwd(), 'test_cache/compare_output')
1725    self.assertTrue(os.path.exists(os.path.join(test_dir, 'autotest.tbz2')))
1726    self.assertTrue(os.path.exists(os.path.join(test_dir, 'machine.txt')))
1727    self.assertTrue(os.path.exists(os.path.join(test_dir, 'results.txt')))
1728
1729    f1 = os.path.join(test_dir, 'machine.txt')
1730    f2 = os.path.join(base_dir, 'machine.txt')
1731    cmd = 'diff %s %s' % (f1, f2)
1732    [_, out, _] = self.result.ce.RunCommandWOutput(cmd)
1733    self.assertEqual(len(out), 0)
1734
1735    f1 = os.path.join(test_dir, 'results.txt')
1736    f2 = os.path.join(base_dir, 'results.txt')
1737    cmd = 'diff %s %s' % (f1, f2)
1738    [_, out, _] = self.result.ce.RunCommandWOutput(cmd)
1739    self.assertEqual(len(out), 0)
1740
1741    # Clean up after test.
1742    tempfile.mkdtemp = save_real_mkdtemp
1743    command = 'rm %s/*' % test_dir
1744    self.result.ce.RunCommand(command)
1745
1746
1747TELEMETRY_RESULT_KEYVALS = {
1748    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1749    'math-cordic (ms)':
1750        '11.4',
1751    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1752    'access-nbody (ms)':
1753        '6.9',
1754    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1755    'access-fannkuch (ms)':
1756        '26.3',
1757    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1758    'math-spectral-norm (ms)':
1759        '6.3',
1760    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1761    'bitops-nsieve-bits (ms)':
1762        '9.3',
1763    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1764    'math-partial-sums (ms)':
1765        '32.8',
1766    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1767    'regexp-dna (ms)':
1768        '16.1',
1769    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1770    '3d-cube (ms)':
1771        '42.7',
1772    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1773    'crypto-md5 (ms)':
1774        '10.8',
1775    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1776    'crypto-sha1 (ms)':
1777        '12.4',
1778    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1779    'string-tagcloud (ms)':
1780        '47.2',
1781    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1782    'string-fasta (ms)':
1783        '36.3',
1784    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1785    'access-binary-trees (ms)':
1786        '7.3',
1787    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1788    'date-format-xparb (ms)':
1789        '138.1',
1790    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1791    'crypto-aes (ms)':
1792        '19.2',
1793    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1794    'Total (ms)':
1795        '656.5',
1796    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1797    'string-base64 (ms)':
1798        '17.5',
1799    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1800    'string-validate-input (ms)':
1801        '24.8',
1802    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1803    '3d-raytrace (ms)':
1804        '28.7',
1805    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1806    'controlflow-recursive (ms)':
1807        '5.3',
1808    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1809    'bitops-bits-in-byte (ms)':
1810        '9.8',
1811    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1812    '3d-morph (ms)':
1813        '50.2',
1814    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1815    'bitops-bitwise-and (ms)':
1816        '8.8',
1817    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1818    'access-nsieve (ms)':
1819        '8.6',
1820    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1821    'date-format-tofte (ms)':
1822        '31.2',
1823    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1824    'bitops-3bit-bits-in-byte (ms)':
1825        '3.5',
1826    'retval':
1827        0,
1828    'http://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html '
1829    'string-unpack-code (ms)':
1830        '45.0'
1831}
1832
1833PURE_TELEMETRY_OUTPUT = """
1834page_name,3d-cube (ms),3d-morph (ms),3d-raytrace (ms),Total (ms),access-binary-trees (ms),access-fannkuch (ms),access-nbody (ms),access-nsieve (ms),bitops-3bit-bits-in-byte (ms),bitops-bits-in-byte (ms),bitops-bitwise-and (ms),bitops-nsieve-bits (ms),controlflow-recursive (ms),crypto-aes (ms),crypto-md5 (ms),crypto-sha1 (ms),date-format-tofte (ms),date-format-xparb (ms),math-cordic (ms),math-partial-sums (ms),math-spectral-norm (ms),regexp-dna (ms),string-base64 (ms),string-fasta (ms),string-tagcloud (ms),string-unpack-code (ms),string-validate-input (ms)\r\nhttp://www.webkit.org/perf/sunspider-1.0.2/sunspider-1.0.2/driver.html,42.7,50.2,28.7,656.5,7.3,26.3,6.9,8.6,3.5,9.8,8.8,9.3,5.3,19.2,10.8,12.4,31.2,138.1,11.4,32.8,6.3,16.1,17.5,36.3,47.2,45.0,24.8\r
1835"""
1836
1837
1838class TelemetryResultTest(unittest.TestCase):
1839  """Telemetry result test."""
1840
1841  def __init__(self, *args, **kwargs):
1842    super(TelemetryResultTest, self).__init__(*args, **kwargs)
1843    self.callFakeProcessResults = False
1844    self.result = None
1845    self.mock_logger = mock.Mock(spec=logger.Logger)
1846    self.mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
1847    self.mock_label = MockLabel('mock_label', 'build', 'chromeos_image',
1848                                'autotest_dir', 'debug_dir', '/tmp', 'lumpy',
1849                                'remote', 'image_args', 'cache_dir', 'average',
1850                                'gcc', False, None)
1851    self.mock_machine = machine_manager.MockCrosMachine('falco.cros',
1852                                                        '/tmp/chromeos',
1853                                                        'average')
1854
1855  def test_populate_from_run(self):
1856
1857    def FakeProcessResults():
1858      self.callFakeProcessResults = True
1859
1860    self.callFakeProcessResults = False
1861    self.result = TelemetryResult(self.mock_logger, self.mock_label, 'average',
1862                                  self.mock_cmd_exec)
1863    self.result.ProcessResults = FakeProcessResults
1864    self.result.PopulateFromRun(OUTPUT, error, 3, 'fake_test',
1865                                'telemetry_Crosperf', '')
1866    self.assertTrue(self.callFakeProcessResults)
1867    self.assertEqual(self.result.out, OUTPUT)
1868    self.assertEqual(self.result.err, error)
1869    self.assertEqual(self.result.retval, 3)
1870
1871  def test_populate_from_cache_dir_and_process_results(self):
1872
1873    self.result = TelemetryResult(self.mock_logger, self.mock_label, 'average',
1874                                  self.mock_machine)
1875    current_path = os.getcwd()
1876    cache_dir = os.path.join(current_path,
1877                             'test_cache/test_puretelemetry_input')
1878    self.result.PopulateFromCacheDir(cache_dir, '', '', '')
1879    self.assertEqual(self.result.out.strip(), PURE_TELEMETRY_OUTPUT.strip())
1880    self.assertEqual(self.result.err, '')
1881    self.assertEqual(self.result.retval, 0)
1882    self.assertEqual(self.result.keyvals, TELEMETRY_RESULT_KEYVALS)
1883
1884
1885class ResultsCacheTest(unittest.TestCase):
1886  """Resultcache test class."""
1887
1888  def __init__(self, *args, **kwargs):
1889    super(ResultsCacheTest, self).__init__(*args, **kwargs)
1890    self.fakeCacheReturnResult = None
1891    self.mock_logger = mock.Mock(spec=logger.Logger)
1892    self.mock_label = MockLabel('mock_label', 'build', 'chromeos_image',
1893                                'autotest_dir', 'debug_dir', '/tmp', 'lumpy',
1894                                'remote', 'image_args', 'cache_dir', 'average',
1895                                'gcc', False, None)
1896
1897  def setUp(self):
1898    self.results_cache = ResultsCache()
1899
1900    mock_machine = machine_manager.MockCrosMachine('falco.cros',
1901                                                   '/tmp/chromeos', 'average')
1902
1903    mock_mm = machine_manager.MockMachineManager('/tmp/chromeos_root', 0,
1904                                                 'average', '')
1905    mock_mm.machine_checksum_string['mock_label'] = 'fake_machine_checksum123'
1906
1907    self.results_cache.Init(
1908        self.mock_label.chromeos_image,
1909        self.mock_label.chromeos_root,
1910        'sunspider',
1911        1,  # benchmark_run.iteration,
1912        '',  # benchmark_run.test_args,
1913        '',  # benchmark_run.profiler_args,
1914        mock_mm,
1915        mock_machine,
1916        self.mock_label.board,
1917        [CacheConditions.CACHE_FILE_EXISTS, CacheConditions.CHECKSUMS_MATCH],
1918        self.mock_logger,
1919        'average',
1920        self.mock_label,
1921        '',  # benchmark_run.share_cache
1922        'telemetry_Crosperf',
1923        True,  # benchmark_run.show_all_results
1924        False,  # benchmark_run.run_local
1925        '')  # benchmark_run.cwp_dso
1926
1927  @mock.patch.object(image_checksummer.ImageChecksummer, 'Checksum')
1928  def test_get_cache_dir_for_write(self, mock_checksum):
1929
1930    def FakeGetMachines(label):
1931      if label:
1932        pass
1933      m1 = machine_manager.MockCrosMachine('lumpy1.cros',
1934                                           self.results_cache.chromeos_root,
1935                                           'average')
1936      m2 = machine_manager.MockCrosMachine('lumpy2.cros',
1937                                           self.results_cache.chromeos_root,
1938                                           'average')
1939      return [m1, m2]
1940
1941    mock_checksum.return_value = 'FakeImageChecksumabc123'
1942    self.results_cache.machine_manager.GetMachines = FakeGetMachines
1943    self.results_cache.machine_manager.machine_checksum['mock_label'] = \
1944        'FakeMachineChecksumabc987'
1945    # Based on the label, benchmark and machines, get the directory in which
1946    # to store the cache information for this test run.
1947    result_path = self.results_cache.GetCacheDirForWrite()
1948    # Verify that the returned directory is correct (since the label
1949    # contained a cache_dir, named 'cache_dir', that's what is expected in
1950    # the result, rather than '~/cros_scratch').
1951    comp_path = os.path.join(
1952        os.getcwd(), 'cache_dir/54524606abaae4fdf7b02f49f7ae7127_'
1953        'sunspider_1_fda29412ceccb72977516c4785d08e2c_'
1954        'FakeImageChecksumabc123_FakeMachineChecksum'
1955        'abc987__6')
1956    self.assertEqual(result_path, comp_path)
1957
1958  def test_form_cache_dir(self):
1959    # This is very similar to the previous test (FormCacheDir is called
1960    # from GetCacheDirForWrite).
1961    cache_key_list = ('54524606abaae4fdf7b02f49f7ae7127', 'sunspider', '1',
1962                      '7215ee9c7d9dc229d2921a40e899ec5f',
1963                      'FakeImageChecksumabc123', '*', '*', '6')
1964    path = self.results_cache.FormCacheDir(cache_key_list)
1965    self.assertEqual(len(path), 1)
1966    path1 = path[0]
1967    test_dirname = ('54524606abaae4fdf7b02f49f7ae7127_sunspider_1_7215ee9'
1968                    'c7d9dc229d2921a40e899ec5f_FakeImageChecksumabc123_*_*_6')
1969    comp_path = os.path.join(os.getcwd(), 'cache_dir', test_dirname)
1970    self.assertEqual(path1, comp_path)
1971
1972  @mock.patch.object(image_checksummer.ImageChecksummer, 'Checksum')
1973  def test_get_cache_key_list(self, mock_checksum):
1974    # This tests the mechanism that generates the various pieces of the
1975    # cache directory name, based on various conditions.
1976
1977    def FakeGetMachines(label):
1978      if label:
1979        pass
1980      m1 = machine_manager.MockCrosMachine('lumpy1.cros',
1981                                           self.results_cache.chromeos_root,
1982                                           'average')
1983      m2 = machine_manager.MockCrosMachine('lumpy2.cros',
1984                                           self.results_cache.chromeos_root,
1985                                           'average')
1986      return [m1, m2]
1987
1988    mock_checksum.return_value = 'FakeImageChecksumabc123'
1989    self.results_cache.machine_manager.GetMachines = FakeGetMachines
1990    self.results_cache.machine_manager.machine_checksum['mock_label'] = \
1991        'FakeMachineChecksumabc987'
1992
1993    # Test 1. Generating cache name for reading (not writing).
1994    key_list = self.results_cache.GetCacheKeyList(True)
1995    self.assertEqual(key_list[0], '*')  # Machine checksum value, for read.
1996    self.assertEqual(key_list[1], 'sunspider')
1997    self.assertEqual(key_list[2], '1')
1998    self.assertEqual(key_list[3], 'fda29412ceccb72977516c4785d08e2c')
1999    self.assertEqual(key_list[4], 'FakeImageChecksumabc123')
2000    self.assertEqual(key_list[5], '*')
2001    self.assertEqual(key_list[6], '*')
2002    self.assertEqual(key_list[7], '6')
2003
2004    # Test 2. Generating cache name for writing, with local image type.
2005    key_list = self.results_cache.GetCacheKeyList(False)
2006    self.assertEqual(key_list[0], '54524606abaae4fdf7b02f49f7ae7127')
2007    self.assertEqual(key_list[1], 'sunspider')
2008    self.assertEqual(key_list[2], '1')
2009    self.assertEqual(key_list[3], 'fda29412ceccb72977516c4785d08e2c')
2010    self.assertEqual(key_list[4], 'FakeImageChecksumabc123')
2011    self.assertEqual(key_list[5], 'FakeMachineChecksumabc987')
2012    self.assertEqual(key_list[6], '')
2013    self.assertEqual(key_list[7], '6')
2014
2015    # Test 3. Generating cache name for writing, with trybot image type.
2016    self.results_cache.label.image_type = 'trybot'
2017    key_list = self.results_cache.GetCacheKeyList(False)
2018    self.assertEqual(key_list[0], '54524606abaae4fdf7b02f49f7ae7127')
2019    self.assertEqual(key_list[3], 'fda29412ceccb72977516c4785d08e2c')
2020    self.assertEqual(key_list[4], '54524606abaae4fdf7b02f49f7ae7127')
2021    self.assertEqual(key_list[5], 'FakeMachineChecksumabc987')
2022
2023    # Test 4. Generating cache name for writing, with official image type.
2024    self.results_cache.label.image_type = 'official'
2025    key_list = self.results_cache.GetCacheKeyList(False)
2026    self.assertEqual(key_list[0], '54524606abaae4fdf7b02f49f7ae7127')
2027    self.assertEqual(key_list[1], 'sunspider')
2028    self.assertEqual(key_list[2], '1')
2029    self.assertEqual(key_list[3], 'fda29412ceccb72977516c4785d08e2c')
2030    self.assertEqual(key_list[4], '*')
2031    self.assertEqual(key_list[5], 'FakeMachineChecksumabc987')
2032    self.assertEqual(key_list[6], '')
2033    self.assertEqual(key_list[7], '6')
2034
2035    # Test 5. Generating cache name for writing, with local image type, and
2036    # specifying that the image path must match the cached image path.
2037    self.results_cache.label.image_type = 'local'
2038    self.results_cache.cache_conditions.append(CacheConditions.IMAGE_PATH_MATCH)
2039    key_list = self.results_cache.GetCacheKeyList(False)
2040    self.assertEqual(key_list[0], '54524606abaae4fdf7b02f49f7ae7127')
2041    self.assertEqual(key_list[3], 'fda29412ceccb72977516c4785d08e2c')
2042    self.assertEqual(key_list[4], 'FakeImageChecksumabc123')
2043    self.assertEqual(key_list[5], 'FakeMachineChecksumabc987')
2044
2045  @mock.patch.object(command_executer.CommandExecuter, 'RunCommand')
2046  @mock.patch.object(os.path, 'isdir')
2047  @mock.patch.object(Result, 'CreateFromCacheHit')
2048  def test_read_result(self, mock_create, mock_isdir, mock_runcmd):
2049
2050    self.fakeCacheReturnResult = None
2051
2052    def FakeGetCacheDirForRead():
2053      return self.fakeCacheReturnResult
2054
2055    def FakeGetCacheDirForWrite():
2056      return self.fakeCacheReturnResult
2057
2058    mock_cmd_exec = mock.Mock(spec=command_executer.CommandExecuter)
2059    fake_result = Result(self.mock_logger, self.mock_label, 'average',
2060                         mock_cmd_exec)
2061    fake_result.retval = 0
2062
2063    # Set up results_cache _GetCacheDirFor{Read,Write} to return
2064    # self.fakeCacheReturnResult, which is initially None (see above).
2065    # So initially, no cache dir is returned.
2066    self.results_cache.GetCacheDirForRead = FakeGetCacheDirForRead
2067    self.results_cache.GetCacheDirForWrite = FakeGetCacheDirForWrite
2068
2069    mock_isdir.return_value = True
2070    save_cc = [
2071        CacheConditions.CACHE_FILE_EXISTS, CacheConditions.CHECKSUMS_MATCH
2072    ]
2073    self.results_cache.cache_conditions.append(CacheConditions.FALSE)
2074
2075    # Test 1. CacheCondition.FALSE, which means do not read from the cache.
2076    # (force re-running of test).  Result should be None.
2077    res = self.results_cache.ReadResult()
2078    self.assertIsNone(res)
2079    self.assertEqual(mock_runcmd.call_count, 1)
2080
2081    # Test 2. Remove CacheCondition.FALSE. Result should still be None,
2082    # because GetCacheDirForRead is returning None at the moment.
2083    mock_runcmd.reset_mock()
2084    self.results_cache.cache_conditions = save_cc
2085    res = self.results_cache.ReadResult()
2086    self.assertIsNone(res)
2087    self.assertEqual(mock_runcmd.call_count, 0)
2088
2089    # Test 3. Now set up cache dir to be returned by GetCacheDirForRead.
2090    # Since cache_dir is found, will call Result.CreateFromCacheHit, which
2091    # which will actually all our mock_create and should return fake_result.
2092    self.fakeCacheReturnResult = 'fake/cache/dir'
2093    mock_create.return_value = fake_result
2094    res = self.results_cache.ReadResult()
2095    self.assertEqual(mock_runcmd.call_count, 0)
2096    self.assertEqual(res, fake_result)
2097
2098    # Test 4. os.path.isdir(cache_dir) will now return false, so result
2099    # should be None again (no cache found).
2100    mock_isdir.return_value = False
2101    res = self.results_cache.ReadResult()
2102    self.assertEqual(mock_runcmd.call_count, 0)
2103    self.assertIsNone(res)
2104
2105    # Test 5. os.path.isdir returns true, but mock_create now returns None
2106    # (the call to CreateFromCacheHit returns None), so overal result is None.
2107    mock_isdir.return_value = True
2108    mock_create.return_value = None
2109    res = self.results_cache.ReadResult()
2110    self.assertEqual(mock_runcmd.call_count, 0)
2111    self.assertIsNone(res)
2112
2113    # Test 6. Everything works 'as expected', result should be fake_result.
2114    mock_create.return_value = fake_result
2115    res = self.results_cache.ReadResult()
2116    self.assertEqual(mock_runcmd.call_count, 0)
2117    self.assertEqual(res, fake_result)
2118
2119    # Test 7. The run failed; result should be None.
2120    mock_create.return_value = fake_result
2121    fake_result.retval = 1
2122    self.results_cache.cache_conditions.append(CacheConditions.RUN_SUCCEEDED)
2123    res = self.results_cache.ReadResult()
2124    self.assertEqual(mock_runcmd.call_count, 0)
2125    self.assertIsNone(res)
2126
2127
2128if __name__ == '__main__':
2129  unittest.main()
2130