147f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik#!/usr/bin/env python 247f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 347f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# Copyright (c) 2016 The Chromium Authors. All rights reserved. 447f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# Use of this source code is governed by a BSD-style license that can be 547f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# found in the LICENSE file. 647f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 77332cdb42368a904cbf7418de329868989e592daChris Craikimport functools 833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport inspect 97332cdb42368a904cbf7418de329868989e592daChris Craikimport os 107332cdb42368a904cbf7418de329868989e592daChris Craikimport sys 1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport time 12b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangimport platform 137332cdb42368a904cbf7418de329868989e592daChris Craik 147332cdb42368a904cbf7418de329868989e592daChris Craik 157332cdb42368a904cbf7418de329868989e592daChris Craikdef GetCatapultDir(): 167332cdb42368a904cbf7418de329868989e592daChris Craik return os.path.normpath( 177332cdb42368a904cbf7418de329868989e592daChris Craik os.path.join(os.path.dirname(__file__), '..', '..', '..')) 187332cdb42368a904cbf7418de329868989e592daChris Craik 197332cdb42368a904cbf7418de329868989e592daChris Craik 207332cdb42368a904cbf7418de329868989e592daChris Craikdef IsRunningOnCrosDevice(): 217332cdb42368a904cbf7418de329868989e592daChris Craik """Returns True if we're on a ChromeOS device.""" 227332cdb42368a904cbf7418de329868989e592daChris Craik lsb_release = '/etc/lsb-release' 237332cdb42368a904cbf7418de329868989e592daChris Craik if sys.platform.startswith('linux') and os.path.exists(lsb_release): 247332cdb42368a904cbf7418de329868989e592daChris Craik with open(lsb_release, 'r') as f: 257332cdb42368a904cbf7418de329868989e592daChris Craik res = f.read() 267332cdb42368a904cbf7418de329868989e592daChris Craik if res.count('CHROMEOS_RELEASE_NAME'): 277332cdb42368a904cbf7418de329868989e592daChris Craik return True 287332cdb42368a904cbf7418de329868989e592daChris Craik return False 297332cdb42368a904cbf7418de329868989e592daChris Craik 307332cdb42368a904cbf7418de329868989e592daChris Craik 31b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangdef GetHostOsName(): 32b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang if IsRunningOnCrosDevice(): 33b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang return 'chromeos' 34b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang elif sys.platform.startswith('linux'): 35b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang return 'linux' 36b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang elif sys.platform == 'darwin': 37b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang return 'mac' 38b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang elif sys.platform == 'win32': 39b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang return 'win' 40b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang 41b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang 42b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangdef GetHostArchName(): 43b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang return platform.machine() 44b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang 45b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang 467332cdb42368a904cbf7418de329868989e592daChris Craikdef _ExecutableExtensions(): 477332cdb42368a904cbf7418de329868989e592daChris Craik # pathext is, e.g. '.com;.exe;.bat;.cmd' 487332cdb42368a904cbf7418de329868989e592daChris Craik exts = os.getenv('PATHEXT').split(';') #e.g. ['.com','.exe','.bat','.cmd'] 497332cdb42368a904cbf7418de329868989e592daChris Craik return [x[1:].upper() for x in exts] #e.g. ['COM','EXE','BAT','CMD'] 507332cdb42368a904cbf7418de329868989e592daChris Craik 517332cdb42368a904cbf7418de329868989e592daChris Craik 527332cdb42368a904cbf7418de329868989e592daChris Craikdef IsExecutable(path): 537332cdb42368a904cbf7418de329868989e592daChris Craik if os.path.isfile(path): 547332cdb42368a904cbf7418de329868989e592daChris Craik if hasattr(os, 'name') and os.name == 'nt': 557332cdb42368a904cbf7418de329868989e592daChris Craik return path.split('.')[-1].upper() in _ExecutableExtensions() 567332cdb42368a904cbf7418de329868989e592daChris Craik else: 577332cdb42368a904cbf7418de329868989e592daChris Craik return os.access(path, os.X_OK) 587332cdb42368a904cbf7418de329868989e592daChris Craik else: 597332cdb42368a904cbf7418de329868989e592daChris Craik return False 607332cdb42368a904cbf7418de329868989e592daChris Craik 617332cdb42368a904cbf7418de329868989e592daChris Craik 627332cdb42368a904cbf7418de329868989e592daChris Craikdef _AddDirToPythonPath(*path_parts): 637332cdb42368a904cbf7418de329868989e592daChris Craik path = os.path.abspath(os.path.join(*path_parts)) 647332cdb42368a904cbf7418de329868989e592daChris Craik if os.path.isdir(path) and path not in sys.path: 657332cdb42368a904cbf7418de329868989e592daChris Craik # Some callsite that use telemetry assumes that sys.path[0] is the directory 667332cdb42368a904cbf7418de329868989e592daChris Craik # containing the script, so we add these extra paths to right after it. 677332cdb42368a904cbf7418de329868989e592daChris Craik sys.path.insert(1, path) 687332cdb42368a904cbf7418de329868989e592daChris Craik 697332cdb42368a904cbf7418de329868989e592daChris Craik_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'devil')) 707332cdb42368a904cbf7418de329868989e592daChris Craik_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'dependency_manager')) 717332cdb42368a904cbf7418de329868989e592daChris Craik_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mock')) 727332cdb42368a904cbf7418de329868989e592daChris Craik# mox3 is needed for pyfakefs usage, but not for pylint. 737332cdb42368a904cbf7418de329868989e592daChris Craik_AddDirToPythonPath(os.path.join(GetCatapultDir(), 'third_party', 'mox3')) 747332cdb42368a904cbf7418de329868989e592daChris Craik_AddDirToPythonPath( 757332cdb42368a904cbf7418de329868989e592daChris Craik os.path.join(GetCatapultDir(), 'third_party', 'pyfakefs')) 7647f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 7747f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craikfrom devil.utils import timeout_retry 7847f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craikfrom devil.utils import reraiser_thread 7947f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 807332cdb42368a904cbf7418de329868989e592daChris Craik 817332cdb42368a904cbf7418de329868989e592daChris Craik# Decorator that adds timeout functionality to a function. 8247f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craikdef Timeout(default_timeout): 837332cdb42368a904cbf7418de329868989e592daChris Craik return lambda func: TimeoutDeco(func, default_timeout) 8447f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 8547f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# Note: Even though the "timeout" keyword argument is the only 8647f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# keyword argument that will need to be given to the decorated function, 8747f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# we still have to use the **kwargs syntax, because we have to use 8847f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# the *args syntax here before (since the decorator decorates functions 8947f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# with different numbers of positional arguments) and Python doesn't allow 9047f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# a single named keyword argument after *args. 9147f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik# (e.g., 'def foo(*args, bar=42):' is a syntax error) 9247f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik 937332cdb42368a904cbf7418de329868989e592daChris Craikdef TimeoutDeco(func, default_timeout): 9447f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik @functools.wraps(func) 957332cdb42368a904cbf7418de329868989e592daChris Craik def RunWithTimeout(*args, **kwargs): 9647f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik if 'timeout' in kwargs: 9747f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik timeout = kwargs['timeout'] 9847f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik else: 9947f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik timeout = default_timeout 10047f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik try: 10147f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik return timeout_retry.Run(func, timeout, 0, args=args) 10247f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik except reraiser_thread.TimeoutError: 10347f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik print '%s timed out.' % func.__name__ 10447f0f1e200da8a481462f364f822c98fe1b1cd5bChris Craik return False 1057332cdb42368a904cbf7418de329868989e592daChris Craik return RunWithTimeout 10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckMIN_POLL_INTERVAL_IN_SECONDS = 0.1 10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckMAX_POLL_INTERVAL_IN_SECONDS = 5 11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John ReckOUTPUT_INTERVAL_IN_SECONDS = 300 11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef WaitFor(condition, timeout): 11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """Waits for up to |timeout| secs for the function |condition| to return True. 11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Polling frequency is (elapsed_time / 10), with a min of .1s and max of 5s. 11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Returns: 11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck Result of |condition| function (if present). 11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck def GetConditionString(): 12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if condition.__name__ == '<lambda>': 12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck try: 12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return inspect.getsource(condition).strip() 12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck except IOError: 12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck pass 12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return condition.__name__ 12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck # Do an initial check to see if its true. 12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck res = condition() 13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if res: 13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return res 13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck start_time = time.time() 13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_output_time = start_time 13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck elapsed_time = time.time() - start_time 13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck while elapsed_time < timeout: 13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck res = condition() 13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if res: 13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck return res 13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck now = time.time() 14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck elapsed_time = now - start_time 14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_output_elapsed_time = now - last_output_time 14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck if last_output_elapsed_time > OUTPUT_INTERVAL_IN_SECONDS: 14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck last_output_time = time.time() 14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck poll_interval = min(max(elapsed_time / 10., MIN_POLL_INTERVAL_IN_SECONDS), 14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck MAX_POLL_INTERVAL_IN_SECONDS) 14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck time.sleep(poll_interval) 14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck raise TimeoutException('Timed out while waiting %ds for %s.' % 14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck (timeout, GetConditionString())) 14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass TimeoutException(Exception): 15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """The operation failed to complete because of a timeout. 15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck 15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck It is possible that waiting for a longer period of time would result in a 15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck successful operation. 15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck """ 15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck pass 157