Revert of [Android] Add zip pushing and refine push mode selection.
Broke telemetry_perf_unittests on Android Tests. TBR=craigdh@chromium.org,cjhopman@chromium.org,klundberg@chromium.org,tonyg@chromium.org NOTREECHECKS=true NOTRY=true BUG=400440 Review URL: https://codereview.chromium.org/645093002 Cr-Original-Commit-Position: refs/heads/master@{#299133} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 7eed7e0b28a56d5f18805cff73459115c4c31d5f
This commit is contained in:
Родитель
a498db7ac9
Коммит
0731401a45
|
@ -64,8 +64,7 @@ def TriggerSymlinkScript(options):
|
|||
mkdir_cmd = ('if [ ! -e %(dir)s ]; then mkdir -p %(dir)s; fi ' %
|
||||
{ 'dir': device_dir })
|
||||
RunShellCommand(device, mkdir_cmd)
|
||||
device.PushChangedFiles([(options.script_host_path,
|
||||
options.script_device_path)])
|
||||
device.PushChangedFiles(options.script_host_path, options.script_device_path)
|
||||
|
||||
trigger_cmd = (
|
||||
'APK_LIBRARIES_DIR=%(apk_libraries_dir)s; '
|
||||
|
|
|
@ -40,7 +40,7 @@ def DoPush(options):
|
|||
if needs_directory:
|
||||
device.RunShellCommand('mkdir -p ' + options.device_dir)
|
||||
needs_directory[:] = [] # = False
|
||||
device.PushChangedFiles([(host_path, device_path)])
|
||||
device.PushChangedFiles(host_path, device_path)
|
||||
|
||||
record_path = '%s.%s.push.md5.stamp' % (host_path, serial_number)
|
||||
md5_check.CallAndRecordIfStale(
|
||||
|
|
|
@ -72,7 +72,7 @@ def PushAndLaunchAdbReboot(device, target):
|
|||
logging.info(' Pushing adb_reboot ...')
|
||||
adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
|
||||
'out/%s/adb_reboot' % target)
|
||||
device.PushChangedFiles([(adb_reboot, '/data/local/tmp/')])
|
||||
device.PushChangedFiles(adb_reboot, '/data/local/tmp/')
|
||||
# Launch adb_reboot
|
||||
logging.info(' Launching adb_reboot ...')
|
||||
device.old_interface.GetAndroidToolStatusAndOutput(
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'chromium_commands',
|
||||
'type': 'none',
|
||||
'variables': {
|
||||
'java_in_dir': ['java'],
|
||||
},
|
||||
'includes': [
|
||||
'../../../../../build/java.gypi',
|
||||
],
|
||||
}
|
||||
],
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import os
|
||||
|
||||
from pylib import constants
|
||||
|
||||
BIN_DIR = '%s/bin' % constants.TEST_EXECUTABLE_DIR
|
||||
_FRAMEWORK_DIR = '%s/framework' % constants.TEST_EXECUTABLE_DIR
|
||||
|
||||
_COMMANDS = {
|
||||
'unzip': 'org.chromium.android.commands.unzip.Unzip',
|
||||
}
|
||||
|
||||
_SHELL_COMMAND_FORMAT = (
|
||||
"""#!/system/bin/sh
|
||||
base=%s
|
||||
export CLASSPATH=$base/framework/chromium_commands.jar
|
||||
exec app_process $base/bin %s $@
|
||||
""")
|
||||
|
||||
|
||||
def Installed(device):
|
||||
return all(device.FileExists('%s/%s' % (BIN_DIR, c)) for c in _COMMANDS)
|
||||
|
||||
|
||||
def InstallCommands(device):
|
||||
device.RunShellCommand(['mkdir', BIN_DIR, _FRAMEWORK_DIR])
|
||||
for command, main_class in _COMMANDS.iteritems():
|
||||
shell_command = _SHELL_COMMAND_FORMAT % (
|
||||
constants.TEST_EXECUTABLE_DIR, main_class)
|
||||
shell_file = '%s/%s' % (BIN_DIR, command)
|
||||
device.WriteTextFile(shell_file, shell_command)
|
||||
device.RunShellCommand(
|
||||
['chmod', '755', shell_file], check_return=True)
|
||||
|
||||
device.adb.Push(
|
||||
os.path.join(constants.GetOutDirectory(),
|
||||
constants.SDK_BUILD_JAVALIB_DIR,
|
||||
'chromium_commands.dex.jar'),
|
||||
'%s/chromium_commands.jar' % _FRAMEWORK_DIR)
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package org.chromium.android.commands.unzip;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* Minimal implementation of the command-line unzip utility for Android.
|
||||
*/
|
||||
public class Unzip {
|
||||
|
||||
private static final String TAG = "Unzip";
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
(new Unzip()).run(args);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, e.toString());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void showUsage(PrintStream s) {
|
||||
s.println("Usage:");
|
||||
s.println("unzip [zipfile]");
|
||||
}
|
||||
|
||||
private void unzip(String[] args) {
|
||||
ZipInputStream zis = null;
|
||||
try {
|
||||
String zipfile = args[0];
|
||||
zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipfile)));
|
||||
ZipEntry ze = null;
|
||||
|
||||
byte[] bytes = new byte[1024];
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
File outputFile = new File(ze.getName());
|
||||
if (ze.isDirectory()) {
|
||||
if (!outputFile.exists() && !outputFile.mkdirs()) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create directory: " + outputFile.toString());
|
||||
}
|
||||
} else {
|
||||
File parentDir = outputFile.getParentFile();
|
||||
if (!parentDir.exists() && !parentDir.mkdirs()) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create directory: " + parentDir.toString());
|
||||
}
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile));
|
||||
int actual_bytes = 0;
|
||||
int total_bytes = 0;
|
||||
while ((actual_bytes = zis.read(bytes)) != -1) {
|
||||
out.write(bytes, 0, actual_bytes);
|
||||
total_bytes += actual_bytes;
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
zis.closeEntry();
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error while unzipping: " + e.toString());
|
||||
} finally {
|
||||
try {
|
||||
if (zis != null) zis.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error while closing zip: " + e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void run(String[] args) {
|
||||
if (args.length != 1) {
|
||||
showUsage(System.err);
|
||||
throw new RuntimeException("Incorrect usage.");
|
||||
}
|
||||
|
||||
unzip(args);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,21 +8,15 @@ Eventually, this will be based on adb_wrapper.
|
|||
"""
|
||||
# pylint: disable=W0613
|
||||
|
||||
import multiprocessing
|
||||
import os
|
||||
import pipes
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
import pylib.android_commands
|
||||
from pylib.device import adb_wrapper
|
||||
from pylib.device import decorators
|
||||
from pylib.device import device_errors
|
||||
from pylib.device.commands import install_commands
|
||||
from pylib.utils import apk_helper
|
||||
from pylib.utils import host_utils
|
||||
from pylib.utils import parallelizer
|
||||
|
||||
_DEFAULT_TIMEOUT = 30
|
||||
|
@ -67,23 +61,17 @@ class DeviceUtils(object):
|
|||
operation should be retried on failure if no explicit
|
||||
value is provided.
|
||||
"""
|
||||
self.adb = None
|
||||
self.old_interface = None
|
||||
if isinstance(device, basestring):
|
||||
self.adb = adb_wrapper.AdbWrapper(device)
|
||||
self.old_interface = pylib.android_commands.AndroidCommands(device)
|
||||
elif isinstance(device, adb_wrapper.AdbWrapper):
|
||||
self.adb = device
|
||||
self.old_interface = pylib.android_commands.AndroidCommands(str(device))
|
||||
elif isinstance(device, pylib.android_commands.AndroidCommands):
|
||||
self.adb = adb_wrapper.AdbWrapper(device.GetDevice())
|
||||
self.old_interface = device
|
||||
elif not device:
|
||||
self.adb = adb_wrapper.AdbWrapper('')
|
||||
self.old_interface = pylib.android_commands.AndroidCommands()
|
||||
else:
|
||||
raise ValueError('Unsupported type passed for argument "device"')
|
||||
self._commands_installed = False
|
||||
self._default_timeout = default_timeout
|
||||
self._default_retries = default_retries
|
||||
assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR))
|
||||
|
@ -103,9 +91,6 @@ class DeviceUtils(object):
|
|||
Raises:
|
||||
CommandTimeoutError on timeout.
|
||||
"""
|
||||
return self._IsOnlineImpl()
|
||||
|
||||
def _IsOnlineImpl(self):
|
||||
return self.old_interface.IsOnline()
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
|
@ -126,6 +111,17 @@ class DeviceUtils(object):
|
|||
return self._HasRootImpl()
|
||||
|
||||
def _HasRootImpl(self):
|
||||
"""Implementation of HasRoot.
|
||||
|
||||
This is split from HasRoot to allow other DeviceUtils methods to call
|
||||
HasRoot without spawning a new timeout thread.
|
||||
|
||||
Returns:
|
||||
Same as for |HasRoot|.
|
||||
|
||||
Raises:
|
||||
Same as for |HasRoot|.
|
||||
"""
|
||||
return self.old_interface.IsRootEnabled()
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
|
@ -160,9 +156,6 @@ class DeviceUtils(object):
|
|||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._GetExternalStoragePathImpl()
|
||||
|
||||
def _GetExternalStoragePathImpl(self):
|
||||
try:
|
||||
return self.old_interface.GetExternalStorage()
|
||||
except AssertionError as e:
|
||||
|
@ -190,6 +183,21 @@ class DeviceUtils(object):
|
|||
self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout)
|
||||
|
||||
def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None):
|
||||
"""Implementation of WaitUntilFullyBooted.
|
||||
|
||||
This is split from WaitUntilFullyBooted to allow other DeviceUtils methods
|
||||
to call WaitUntilFullyBooted without spawning a new timeout thread.
|
||||
|
||||
TODO(jbudorick) Remove the timeout parameter once this is no longer
|
||||
implemented via AndroidCommands.
|
||||
|
||||
Args:
|
||||
wifi: Same as for |WaitUntilFullyBooted|.
|
||||
timeout: timeout in seconds
|
||||
|
||||
Raises:
|
||||
Same as for |WaitUntilFullyBooted|.
|
||||
"""
|
||||
if timeout is None:
|
||||
timeout = self._default_timeout
|
||||
self.old_interface.WaitForSystemBootCompleted(timeout)
|
||||
|
@ -273,8 +281,8 @@ class DeviceUtils(object):
|
|||
str(e), device=str(self)), None, sys.exc_info()[2]
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def RunShellCommand(self, cmd, check_return=False, as_root=False, cwd=None,
|
||||
env=None, timeout=None, retries=None):
|
||||
def RunShellCommand(self, cmd, check_return=False, as_root=False,
|
||||
timeout=None, retries=None):
|
||||
"""Run an ADB shell command.
|
||||
|
||||
TODO(jbudorick) Switch the default value of check_return to True after
|
||||
|
@ -286,8 +294,6 @@ class DeviceUtils(object):
|
|||
be checked.
|
||||
as_root: A boolean indicating whether the shell command should be run
|
||||
with root privileges.
|
||||
cwd: The device directory in which the command should be run.
|
||||
env: The environment variables with which the command should be run.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
|
||||
|
@ -299,23 +305,35 @@ class DeviceUtils(object):
|
|||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._RunShellCommandImpl(
|
||||
cmd, check_return=check_return, as_root=as_root, cwd=cwd, env=env,
|
||||
timeout=timeout)
|
||||
return self._RunShellCommandImpl(cmd, check_return=check_return,
|
||||
as_root=as_root, timeout=timeout)
|
||||
|
||||
def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False,
|
||||
cwd=None, env=None, timeout=None):
|
||||
# TODO(jbudorick): Remove the timeout parameter once this is no longer
|
||||
# backed by AndroidCommands.
|
||||
timeout=None):
|
||||
"""Implementation of RunShellCommand.
|
||||
|
||||
This is split from RunShellCommand to allow other DeviceUtils methods to
|
||||
call RunShellCommand without spawning a new timeout thread.
|
||||
|
||||
TODO(jbudorick) Remove the timeout parameter once this is no longer
|
||||
implemented via AndroidCommands.
|
||||
|
||||
Args:
|
||||
cmd: Same as for |RunShellCommand|.
|
||||
check_return: Same as for |RunShellCommand|.
|
||||
as_root: Same as for |RunShellCommand|.
|
||||
timeout: timeout in seconds
|
||||
|
||||
Raises:
|
||||
Same as for |RunShellCommand|.
|
||||
|
||||
Returns:
|
||||
Same as for |RunShellCommand|.
|
||||
"""
|
||||
if isinstance(cmd, list):
|
||||
cmd = ' '.join(cmd)
|
||||
if as_root and not self._HasRootImpl():
|
||||
if as_root and not self.HasRoot():
|
||||
cmd = 'su -c %s' % cmd
|
||||
if env:
|
||||
cmd = '%s %s' % (
|
||||
' '.join('%s=%s' % (k, v) for k, v in env.iteritems()), cmd)
|
||||
if cwd:
|
||||
cmd = 'cd %s && %s' % (cwd, cmd)
|
||||
if check_return:
|
||||
code, output = self.old_interface.GetShellCommandStatusAndOutput(
|
||||
cmd, timeout_time=timeout)
|
||||
|
@ -483,15 +501,15 @@ class DeviceUtils(object):
|
|||
@decorators.WithTimeoutAndRetriesDefaults(
|
||||
PUSH_CHANGED_FILES_DEFAULT_TIMEOUT,
|
||||
PUSH_CHANGED_FILES_DEFAULT_RETRIES)
|
||||
def PushChangedFiles(self, host_device_tuples, timeout=None,
|
||||
def PushChangedFiles(self, host_path, device_path, timeout=None,
|
||||
retries=None):
|
||||
"""Push files to the device, skipping files that don't need updating.
|
||||
|
||||
Args:
|
||||
host_device_tuples: A list of (host_path, device_path) tuples, where
|
||||
|host_path| is an absolute path of a file or directory on the host
|
||||
that should be minimially pushed to the device, and |device_path| is
|
||||
an absolute path of the destination on the device.
|
||||
host_path: A string containing the absolute path to the file or directory
|
||||
on the host that should be minimally pushed to the device.
|
||||
device_path: A string containing the absolute path of the destination on
|
||||
the device.
|
||||
timeout: timeout in seconds
|
||||
retries: number of retries
|
||||
|
||||
|
@ -500,125 +518,7 @@ class DeviceUtils(object):
|
|||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
|
||||
files = []
|
||||
for h, d in host_device_tuples:
|
||||
if os.path.isdir(h):
|
||||
self._RunShellCommandImpl(['mkdir', '-p', '"%s"' % d],
|
||||
check_return=True)
|
||||
files += self.old_interface.GetFilesChanged(h, d)
|
||||
|
||||
if not files:
|
||||
return
|
||||
|
||||
size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
|
||||
file_count = len(files)
|
||||
dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
|
||||
for h, _ in host_device_tuples)
|
||||
dir_file_count = 0
|
||||
for h, _ in host_device_tuples:
|
||||
if os.path.isdir(h):
|
||||
dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
|
||||
else:
|
||||
dir_file_count += 1
|
||||
|
||||
push_duration = self._ApproximateDuration(
|
||||
file_count, file_count, size, False)
|
||||
dir_push_duration = self._ApproximateDuration(
|
||||
len(host_device_tuples), dir_file_count, dir_size, False)
|
||||
zip_duration = self._ApproximateDuration(1, 1, size, True)
|
||||
|
||||
if dir_push_duration < push_duration and dir_push_duration < zip_duration:
|
||||
self._PushChangedFilesIndividually(host_device_tuples)
|
||||
elif push_duration < zip_duration:
|
||||
self._PushChangedFilesIndividually(files)
|
||||
else:
|
||||
self._PushChangedFilesZipped(files)
|
||||
self._RunShellCommandImpl(
|
||||
['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
|
||||
as_root=True)
|
||||
|
||||
@staticmethod
|
||||
def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
|
||||
# We approximate the time to push a set of files to a device as:
|
||||
# t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
|
||||
# t: total time (sec)
|
||||
# c1: adb call time delay (sec)
|
||||
# a: number of times adb is called (unitless)
|
||||
# c2: push time delay (sec)
|
||||
# f: number of files pushed via adb (unitless)
|
||||
# c3: zip time delay (sec)
|
||||
# c4: zip rate (bytes/sec)
|
||||
# b: total number of bytes (bytes)
|
||||
# c5: transfer rate (bytes/sec)
|
||||
# c6: compression ratio (unitless)
|
||||
|
||||
# All of these are approximations.
|
||||
ADB_CALL_PENALTY = 0.1 # seconds
|
||||
ADB_PUSH_PENALTY = 0.01 # seconds
|
||||
ZIP_PENALTY = 2.0 # seconds
|
||||
ZIP_RATE = 10000000.0 # bytes / second
|
||||
TRANSFER_RATE = 2000000.0 # bytes / second
|
||||
COMPRESSION_RATIO = 2.0 # unitless
|
||||
|
||||
adb_call_time = ADB_CALL_PENALTY * adb_calls
|
||||
adb_push_setup_time = ADB_PUSH_PENALTY * file_count
|
||||
if is_zipping:
|
||||
zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
|
||||
transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
|
||||
else:
|
||||
zip_time = 0
|
||||
transfer_time = byte_count / TRANSFER_RATE
|
||||
return (adb_call_time + adb_push_setup_time + zip_time + transfer_time)
|
||||
|
||||
def _PushChangedFilesIndividually(self, files):
|
||||
for h, d in files:
|
||||
self.adb.Push(h, d)
|
||||
|
||||
def _PushChangedFilesZipped(self, files):
|
||||
if not files:
|
||||
return
|
||||
|
||||
self._InstallCommands()
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
|
||||
zip_proc = multiprocessing.Process(
|
||||
target=DeviceUtils._CreateDeviceZip,
|
||||
args=(zip_file.name, files))
|
||||
zip_proc.start()
|
||||
zip_proc.join()
|
||||
|
||||
zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
|
||||
try:
|
||||
self.adb.Push(zip_file.name, zip_on_device)
|
||||
self._RunShellCommandImpl(
|
||||
['unzip', zip_on_device],
|
||||
as_root=True, check_return=True,
|
||||
env={'PATH': '$PATH:%s' % install_commands.BIN_DIR})
|
||||
finally:
|
||||
if zip_proc.is_alive():
|
||||
zip_proc.terminate()
|
||||
if self._IsOnlineImpl():
|
||||
self._RunShellCommandImpl(['rm', zip_on_device])
|
||||
|
||||
def _InstallCommands(self):
|
||||
if not self._commands_installed and not install_commands.Installed(self):
|
||||
install_commands.InstallCommands(self)
|
||||
self._commands_installed = True
|
||||
|
||||
@staticmethod
|
||||
def _CreateDeviceZip(zip_path, host_device_tuples):
|
||||
with zipfile.ZipFile(zip_path, 'w') as zip_file:
|
||||
for host_path, device_path in host_device_tuples:
|
||||
if os.path.isfile(host_path):
|
||||
zip_file.write(host_path, device_path, zipfile.ZIP_DEFLATED)
|
||||
else:
|
||||
for hd, _, files in os.walk(host_path):
|
||||
dd = '%s/%s' % (device_path, os.path.relpath(host_path, hd))
|
||||
zip_file.write(hd, dd, zipfile.ZIP_STORED)
|
||||
for f in files:
|
||||
zip_file.write(os.path.join(hd, f), '%s/%s' % (dd, f),
|
||||
zipfile.ZIP_DEFLATED)
|
||||
self.old_interface.PushIfNeeded(host_path, device_path)
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
def FileExists(self, device_path, timeout=None, retries=None):
|
||||
|
@ -637,6 +537,23 @@ class DeviceUtils(object):
|
|||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
return self._FileExistsImpl(device_path)
|
||||
|
||||
def _FileExistsImpl(self, device_path):
|
||||
"""Implementation of FileExists.
|
||||
|
||||
This is split from FileExists to allow other DeviceUtils methods to call
|
||||
FileExists without spawning a new timeout thread.
|
||||
|
||||
Args:
|
||||
device_path: Same as for |FileExists|.
|
||||
|
||||
Returns:
|
||||
True if the file exists on the device, False otherwise.
|
||||
|
||||
Raises:
|
||||
Same as for |FileExists|.
|
||||
"""
|
||||
return self.old_interface.FileExistsOnDevice(device_path)
|
||||
|
||||
@decorators.WithTimeoutAndRetriesFromInstance()
|
||||
|
@ -681,7 +598,7 @@ class DeviceUtils(object):
|
|||
CommandTimeoutError on timeout.
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
# TODO(jbudorick) Evaluate whether we want to return a list of lines after
|
||||
# TODO(jbudorick) Evaluate whether we awant to return a list of lines after
|
||||
# the implementation switch, and if file not found should raise exception.
|
||||
if as_root:
|
||||
if not self.old_interface.CanAccessProtectedFileContents():
|
||||
|
@ -838,6 +755,21 @@ class DeviceUtils(object):
|
|||
return self._GetPidsImpl(process_name)
|
||||
|
||||
def _GetPidsImpl(self, process_name):
|
||||
"""Implementation of GetPids.
|
||||
|
||||
This is split from GetPids to allow other DeviceUtils methods to call
|
||||
GetPids without spawning a new timeout thread.
|
||||
|
||||
Args:
|
||||
process_name: A string containing the process name to get the PIDs for.
|
||||
|
||||
Returns:
|
||||
A dict mapping process name to PID for each process that contained the
|
||||
provided |process_name|.
|
||||
|
||||
Raises:
|
||||
DeviceUnreachableError on missing device.
|
||||
"""
|
||||
procs_pids = {}
|
||||
for line in self._RunShellCommandImpl('ps'):
|
||||
try:
|
||||
|
|
|
@ -85,7 +85,6 @@ class MockFileSystem(object):
|
|||
st_size, st_atime, st_mtime, st_ctime)
|
||||
|
||||
MOCKED_FUNCTIONS = [
|
||||
('os.listdir', []),
|
||||
('os.path.abspath', ''),
|
||||
('os.path.dirname', ''),
|
||||
('os.path.exists', False),
|
||||
|
@ -118,23 +117,14 @@ class MockFileSystem(object):
|
|||
def addMockDirectory(self, path, **kw):
|
||||
self._addMockThing(path, True, **kw)
|
||||
|
||||
def _addMockThing(self, path, is_dir, listdir=None, size=0, stat=None,
|
||||
walk=None):
|
||||
if listdir is None:
|
||||
listdir = []
|
||||
def _addMockThing(self, path, is_dir, size=0, stat=None, walk=None):
|
||||
if stat is None:
|
||||
stat = self.osStatResult()
|
||||
if walk is None:
|
||||
walk = []
|
||||
|
||||
dirname = os.sep.join(path.rstrip(os.sep).split(os.sep)[:-1])
|
||||
if dirname and not dirname in self.mock_file_info:
|
||||
self._addMockThing(dirname, True)
|
||||
|
||||
self.mock_file_info[path] = {
|
||||
'os.listdir': listdir,
|
||||
'os.path.abspath': path,
|
||||
'os.path.dirname': dirname,
|
||||
'os.path.dirname': '/' + '/'.join(path.strip('/').split('/')[:-1]),
|
||||
'os.path.exists': True,
|
||||
'os.path.isdir': is_dir,
|
||||
'os.path.getsize': size,
|
||||
|
@ -218,24 +208,6 @@ class DeviceUtilsOldImplTest(unittest.TestCase):
|
|||
'0123456789abcdef', default_timeout=1, default_retries=0)
|
||||
|
||||
|
||||
class DeviceUtilsNewImplTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
test_serial = '0123456789abcdef'
|
||||
self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
|
||||
self.adb.__str__ = mock.Mock(return_value=test_serial)
|
||||
self.adb.GetDeviceSerial.return_value = test_serial
|
||||
self.device = device_utils.DeviceUtils(
|
||||
self.adb, default_timeout=1, default_retries=0)
|
||||
|
||||
|
||||
class DeviceUtilsHybridImplTest(DeviceUtilsOldImplTest):
|
||||
|
||||
def setUp(self):
|
||||
super(DeviceUtilsHybridImplTest, self).setUp()
|
||||
self.device.adb = self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
|
||||
|
||||
|
||||
class DeviceUtilsIsOnlineTest(DeviceUtilsOldImplTest):
|
||||
|
||||
def testIsOnline_true(self):
|
||||
|
@ -871,95 +843,132 @@ class DeviceUtilsSendKeyEventTest(DeviceUtilsOldImplTest):
|
|||
self.device.SendKeyEvent(66)
|
||||
|
||||
|
||||
class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsNewImplTest):
|
||||
|
||||
def testPushChangedFilesIndividually_empty(self):
|
||||
test_files = []
|
||||
self.device._PushChangedFilesIndividually(test_files)
|
||||
self.assertEqual(0, self.adb.Push.call_count)
|
||||
|
||||
def testPushChangedFilesIndividually_single(self):
|
||||
test_files = [('/test/host/path', '/test/device/path')]
|
||||
self.device._PushChangedFilesIndividually(test_files)
|
||||
self.adb.Push.assert_called_once_with(
|
||||
'/test/host/path', '/test/device/path')
|
||||
|
||||
def testPushChangedFilesIndividually_multiple(self):
|
||||
test_files = [
|
||||
('/test/host/path/file1', '/test/device/path/file1'),
|
||||
('/test/host/path/file2', '/test/device/path/file2')]
|
||||
self.device._PushChangedFilesIndividually(test_files)
|
||||
self.assertEqual(2, self.adb.Push.call_count)
|
||||
self.adb.Push.assert_any_call(
|
||||
'/test/host/path/file1', '/test/device/path/file1')
|
||||
self.adb.Push.assert_any_call(
|
||||
'/test/host/path/file2', '/test/device/path/file2')
|
||||
class DeviceUtilsPushChangedFilesTest(DeviceUtilsOldImplTest):
|
||||
|
||||
|
||||
class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsHybridImplTest):
|
||||
def testPushChangedFiles_noHostPath(self):
|
||||
with mock.patch('os.path.exists', return_value=False):
|
||||
with self.assertRaises(device_errors.CommandFailedError):
|
||||
self.device.PushChangedFiles('/test/host/path', '/test/device/path')
|
||||
|
||||
def setUp(self):
|
||||
super(DeviceUtilsPushChangedFilesZippedTest, self).setUp()
|
||||
self.original_install_commands = self.device._InstallCommands
|
||||
self.device._InstallCommands = mock.Mock()
|
||||
def testPushChangedFiles_file_noChange(self):
|
||||
self.device.old_interface._push_if_needed_cache = {}
|
||||
|
||||
def testPushChangedFilesZipped_empty(self):
|
||||
test_files = []
|
||||
self.device._PushChangedFilesZipped(test_files)
|
||||
self.assertEqual(0, self.adb.Push.call_count)
|
||||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
def testPushChangedFilesZipped_single(self):
|
||||
test_files = [('/test/host/path/file1', '/test/device/path/file1')]
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockFile(host_file_path, size=100)
|
||||
|
||||
self.device._GetExternalStoragePathImpl = mock.Mock(
|
||||
return_value='/test/device/external_dir')
|
||||
self.device._IsOnlineImpl = mock.Mock(return_value=True)
|
||||
self.device._RunShellCommandImpl = mock.Mock()
|
||||
mock_zip_temp = mock.mock_open()
|
||||
mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
|
||||
with mock.patch('multiprocessing.Process') as mock_zip_proc, (
|
||||
mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
|
||||
self.device._PushChangedFilesZipped(test_files)
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(return_value=[])
|
||||
|
||||
mock_zip_proc.assert_called_once_with(
|
||||
target=device_utils.DeviceUtils._CreateDeviceZip,
|
||||
args=('/test/temp/file/tmp.zip', test_files))
|
||||
self.adb.Push.assert_called_once_with(
|
||||
'/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
|
||||
self.assertEqual(2, self.device._RunShellCommandImpl.call_count)
|
||||
self.device._RunShellCommandImpl.assert_any_call(
|
||||
['unzip', '/test/device/external_dir/tmp.zip'],
|
||||
as_root=True, check_return=True,
|
||||
env={'PATH': '$PATH:/data/local/tmp/bin'})
|
||||
self.device._RunShellCommandImpl.assert_any_call(
|
||||
['rm', '/test/device/external_dir/tmp.zip'])
|
||||
with mock_fs:
|
||||
# GetFilesChanged is mocked, so its adb calls are omitted.
|
||||
with self.assertNoAdbCalls():
|
||||
self.device.PushChangedFiles(host_file_path, device_file_path)
|
||||
|
||||
def testPushChangedFilesZipped_multiple(self):
|
||||
test_files = [('/test/host/path/file1', '/test/device/path/file1'),
|
||||
('/test/host/path/file2', '/test/device/path/file2')]
|
||||
def testPushChangedFiles_file_changed(self):
|
||||
self.device.old_interface._push_if_needed_cache = {}
|
||||
|
||||
self.device._GetExternalStoragePathImpl = mock.Mock(
|
||||
return_value='/test/device/external_dir')
|
||||
self.device._IsOnlineImpl = mock.Mock(return_value=True)
|
||||
self.device._RunShellCommandImpl = mock.Mock()
|
||||
mock_zip_temp = mock.mock_open()
|
||||
mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
|
||||
with mock.patch('multiprocessing.Process') as mock_zip_proc, (
|
||||
mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
|
||||
self.device._PushChangedFilesZipped(test_files)
|
||||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_zip_proc.assert_called_once_with(
|
||||
target=device_utils.DeviceUtils._CreateDeviceZip,
|
||||
args=('/test/temp/file/tmp.zip', test_files))
|
||||
self.adb.Push.assert_called_once_with(
|
||||
'/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
|
||||
self.assertEqual(2, self.device._RunShellCommandImpl.call_count)
|
||||
self.device._RunShellCommandImpl.assert_any_call(
|
||||
['unzip', '/test/device/external_dir/tmp.zip'],
|
||||
as_root=True, check_return=True,
|
||||
env={'PATH': '$PATH:/data/local/tmp/bin'})
|
||||
self.device._RunShellCommandImpl.assert_any_call(
|
||||
['rm', '/test/device/external_dir/tmp.zip'])
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockFile(
|
||||
host_file_path, size=100,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path', '/test/device/path')])
|
||||
|
||||
with mock_fs:
|
||||
with self.assertCalls('adb -s 0123456789abcdef push '
|
||||
'/test/host/path /test/device/path', '100 B/s (100 B in 1.000s)\r\n'):
|
||||
self.device.PushChangedFiles(host_file_path, device_file_path)
|
||||
|
||||
def testPushChangedFiles_directory_nothingChanged(self):
|
||||
self.device.old_interface._push_if_needed_cache = {}
|
||||
|
||||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', size=251,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', size=252,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(return_value=[])
|
||||
|
||||
with mock_fs:
|
||||
with self.assertCallsSequence([
|
||||
("adb -s 0123456789abcdef shell 'mkdir -p \"/test/device/path\"'",
|
||||
'')]):
|
||||
self.device.PushChangedFiles(host_file_path, device_file_path)
|
||||
|
||||
def testPushChangedFiles_directory_somethingChanged(self):
|
||||
self.device.old_interface._push_if_needed_cache = {}
|
||||
|
||||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000),
|
||||
walk=[('/test/host/path', [], ['file1', 'file2'])])
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path/file1', '/test/device/path/file1')])
|
||||
|
||||
with mock_fs:
|
||||
with self.assertCallsSequence([
|
||||
("adb -s 0123456789abcdef shell 'mkdir -p \"/test/device/path\"'",
|
||||
''),
|
||||
('adb -s 0123456789abcdef push '
|
||||
'/test/host/path/file1 /test/device/path/file1',
|
||||
'256 B/s (256 B in 1.000s)\r\n')]):
|
||||
self.device.PushChangedFiles(host_file_path, device_file_path)
|
||||
|
||||
def testPushChangedFiles_directory_everythingChanged(self):
|
||||
self.device.old_interface._push_if_needed_cache = {}
|
||||
|
||||
host_file_path = '/test/host/path'
|
||||
device_file_path = '/test/device/path'
|
||||
|
||||
mock_fs = MockFileSystem()
|
||||
mock_fs.addMockDirectory(
|
||||
host_file_path, size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000000))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file1', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000001))
|
||||
mock_fs.addMockFile(
|
||||
host_file_path + '/file2', size=256,
|
||||
stat=MockFileSystem.osStatResult(st_mtime=1000000002))
|
||||
|
||||
self.device.old_interface.GetFilesChanged = mock.Mock(
|
||||
return_value=[('/test/host/path/file1', '/test/device/path/file1'),
|
||||
('/test/host/path/file2', '/test/device/path/file2')])
|
||||
|
||||
with mock_fs:
|
||||
with self.assertCallsSequence([
|
||||
("adb -s 0123456789abcdef shell 'mkdir -p \"/test/device/path\"'",
|
||||
''),
|
||||
('adb -s 0123456789abcdef push /test/host/path /test/device/path',
|
||||
'768 B/s (768 B in 1.000s)\r\n')]):
|
||||
self.device.PushChangedFiles(host_file_path, device_file_path)
|
||||
|
||||
|
||||
class DeviceUtilsFileExistsTest(DeviceUtilsOldImplTest):
|
||||
|
|
|
@ -288,9 +288,9 @@ class Forwarder(object):
|
|||
if device_serial in self._initialized_devices:
|
||||
return
|
||||
Forwarder._KillDeviceLocked(device, tool)
|
||||
device.PushChangedFiles([(
|
||||
device.PushChangedFiles(
|
||||
self._device_forwarder_path_on_host,
|
||||
Forwarder._DEVICE_FORWARDER_FOLDER)])
|
||||
Forwarder._DEVICE_FORWARDER_FOLDER)
|
||||
cmd = '%s %s' % (tool.GetUtilWrapper(), Forwarder._DEVICE_FORWARDER_PATH)
|
||||
(exit_code, output) = device.old_interface.GetAndroidToolStatusAndOutput(
|
||||
cmd, lib_path=Forwarder._DEVICE_FORWARDER_FOLDER)
|
||||
|
|
|
@ -44,9 +44,9 @@ class TestPackageApk(TestPackage):
|
|||
# GTest expects argv[0] to be the executable path.
|
||||
command_line_file.write(self.suite_name + ' ' + options)
|
||||
command_line_file.flush()
|
||||
device.PushChangedFiles([(
|
||||
device.PushChangedFiles(
|
||||
command_line_file.name,
|
||||
self._package_info.cmdline_file)])
|
||||
self._package_info.cmdline_file)
|
||||
|
||||
def _GetFifo(self):
|
||||
# The test.fifo path is determined by:
|
||||
|
|
|
@ -105,9 +105,9 @@ class TestPackageExecutable(TestPackage):
|
|||
TestPackageExecutable._TEST_RUNNER_RET_VAL_FILE))
|
||||
sh_script_file.flush()
|
||||
cmd_helper.RunCmd(['chmod', '+x', sh_script_file.name])
|
||||
device.PushChangedFiles([(
|
||||
device.PushChangedFiles(
|
||||
sh_script_file.name,
|
||||
constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh')])
|
||||
constants.TEST_EXECUTABLE_DIR + '/chrome_test_runner.sh')
|
||||
logging.info('Conents of the test runner script: ')
|
||||
for line in open(sh_script_file.name).readlines():
|
||||
logging.info(' ' + line.rstrip())
|
||||
|
@ -148,4 +148,4 @@ class TestPackageExecutable(TestPackage):
|
|||
self.suite_name + '_stripped'))
|
||||
|
||||
test_binary = constants.TEST_EXECUTABLE_DIR + '/' + self.suite_name
|
||||
device.PushChangedFiles([(target_name, test_binary)])
|
||||
device.PushChangedFiles(target_name, test_binary)
|
||||
|
|
|
@ -70,10 +70,10 @@ class TestRunner(base_test_runner.BaseTestRunner):
|
|||
device_dir = constants.TEST_EXECUTABLE_DIR
|
||||
else:
|
||||
device_dir = self.device.GetExternalStoragePath()
|
||||
self.device.PushChangedFiles(
|
||||
[(os.path.join(constants.ISOLATE_DEPS_DIR, p),
|
||||
for p in os.listdir(constants.ISOLATE_DEPS_DIR):
|
||||
self.device.PushChangedFiles(
|
||||
os.path.join(constants.ISOLATE_DEPS_DIR, p),
|
||||
os.path.join(device_dir, p))
|
||||
for p in os.listdir(constants.ISOLATE_DEPS_DIR)])
|
||||
|
||||
def _ParseTestOutput(self, p):
|
||||
"""Process the test output.
|
||||
|
|
|
@ -99,15 +99,14 @@ class TestRunner(base_test_runner.BaseTestRunner):
|
|||
str(self.device))
|
||||
return
|
||||
|
||||
host_device_file_tuples = []
|
||||
test_data = _GetDataFilesForTestSuite(self.test_pkg.GetApkName())
|
||||
if test_data:
|
||||
# Make sure SD card is ready.
|
||||
self.device.WaitUntilFullyBooted(timeout=20)
|
||||
host_device_file_tuples += [
|
||||
(os.path.join(constants.DIR_SOURCE_ROOT, p),
|
||||
os.path.join(self.device.GetExternalStoragePath(), p))
|
||||
for p in test_data]
|
||||
for p in test_data:
|
||||
self.device.PushChangedFiles(
|
||||
os.path.join(constants.DIR_SOURCE_ROOT, p),
|
||||
os.path.join(self.device.GetExternalStoragePath(), p))
|
||||
|
||||
# TODO(frankf): Specify test data in this file as opposed to passing
|
||||
# as command-line.
|
||||
|
@ -118,14 +117,12 @@ class TestRunner(base_test_runner.BaseTestRunner):
|
|||
host_test_files_path = os.path.join(constants.DIR_SOURCE_ROOT,
|
||||
host_src)
|
||||
if os.path.exists(host_test_files_path):
|
||||
host_device_file_tuples += [(
|
||||
self.device.PushChangedFiles(
|
||||
host_test_files_path,
|
||||
'%s/%s/%s' % (
|
||||
self.device.GetExternalStoragePath(),
|
||||
TestRunner._DEVICE_DATA_DIR,
|
||||
dst_layer))]
|
||||
if host_device_file_tuples:
|
||||
self.device.PushChangedFiles(host_device_file_tuples)
|
||||
dst_layer))
|
||||
self.tool.CopyFiles()
|
||||
TestRunner._DEVICE_HAS_TEST_FILES[str(self.device)] = True
|
||||
|
||||
|
|
|
@ -24,4 +24,4 @@ class TestPackage(test_jar.TestJar):
|
|||
|
||||
# Override.
|
||||
def Install(self, device):
|
||||
device.PushChangedFiles([(self._jar_path, constants.TEST_EXECUTABLE_DIR)])
|
||||
device.PushChangedFiles(self._jar_path, constants.TEST_EXECUTABLE_DIR)
|
||||
|
|
|
@ -172,10 +172,10 @@ class ValgrindTool(BaseTool):
|
|||
'rm -r %s; mkdir %s' % (ValgrindTool.VGLOGS_DIR,
|
||||
ValgrindTool.VGLOGS_DIR))
|
||||
files = self.GetFilesForTool()
|
||||
self._device.PushChangedFiles(
|
||||
[((os.path.join(DIR_SOURCE_ROOT, f),
|
||||
for f in files:
|
||||
self._device.PushChangedFiles(
|
||||
os.path.join(DIR_SOURCE_ROOT, f),
|
||||
os.path.join(ValgrindTool.VG_DIR, os.path.basename(f)))
|
||||
for f in files)])
|
||||
|
||||
def SetupEnvironment(self):
|
||||
"""Sets up device environment."""
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
{
|
||||
'dependencies': [
|
||||
'<(DEPTH)/base/base.gyp:base_java',
|
||||
'<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
|
||||
'<(DEPTH)/tools/android/android_tools.gyp:android_tools',
|
||||
],
|
||||
'conditions': [
|
||||
|
|
|
@ -551,7 +551,6 @@
|
|||
}],
|
||||
['is_test_apk == 1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands',
|
||||
'<(DEPTH)/tools/android/android_tools.gyp:android_tools',
|
||||
]
|
||||
}],
|
||||
|
|
Загрузка…
Ссылка в новой задаче