1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
9 from pylib
import constants
10 from pylib
import ports
11 from pylib
.base
import test_run
12 from pylib
.device
import device_errors
13 from pylib
.gtest
import gtest_test_instance
15 from pylib
.local
import local_test_server_spawner
16 from pylib
.local
.device
import local_device_environment
17 from pylib
.local
.device
import local_device_test_run
18 from pylib
.utils
import apk_helper
19 from pylib
.utils
import device_temp_file
21 _COMMAND_LINE_FLAGS_SUPPORTED
= True
23 _EXTRA_COMMAND_LINE_FILE
= (
24 'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile')
25 _EXTRA_COMMAND_LINE_FLAGS
= (
26 'org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags')
30 # TODO(jbudorick): Move this up to the test instance if the net test server is
31 # handled outside of the APK for the remote_device environment.
32 _SUITE_REQUIRES_TEST_SERVER_SPAWNER
= [
33 'content_unittests', 'content_browsertests', 'net_unittests', 'unit_tests'
36 class _ApkDelegate(object):
37 def __init__(self
, apk
):
39 self
._package
= apk_helper
.GetPackageName(self
._apk
)
40 self
._runner
= apk_helper
.GetInstrumentationName(self
._apk
)
41 self
._component
= '%s/%s' % (self
._package
, self
._runner
)
42 self
._enable
_test
_server
_spawner
= False
44 def Install(self
, device
):
45 device
.Install(self
._apk
)
47 def RunWithFlags(self
, device
, flags
, **kwargs
):
48 with device_temp_file
.DeviceTempFile(device
.adb
) as command_line_file
:
49 device
.WriteFile(command_line_file
.name
, '_ %s' % flags
)
52 _EXTRA_COMMAND_LINE_FILE
: command_line_file
.name
,
55 return device
.StartInstrumentation(
56 self
._component
, extras
=extras
, raw
=False, **kwargs
)
58 def Clear(self
, device
):
59 device
.ClearApplicationState(self
._package
)
62 class _ExeDelegate(object):
63 def __init__(self
, exe
, tr
):
64 self
._exe
_host
_path
= exe
65 self
._exe
_file
_name
= os
.path
.split(exe
)[-1]
66 self
._exe
_device
_path
= '%s/%s' % (
67 constants
.TEST_EXECUTABLE_DIR
, self
._exe
_file
_name
)
68 deps_host_path
= self
._exe
_host
_path
+ '_deps'
69 if os
.path
.exists(deps_host_path
):
70 self
._deps
_host
_path
= deps_host_path
71 self
._deps
_device
_path
= self
._exe
_device
_path
+ '_deps'
73 self
._deps
_host
_path
= None
76 def Install(self
, device
):
77 # TODO(jbudorick): Look into merging this with normal data deps pushing if
78 # executables become supported on nonlocal environments.
79 host_device_tuples
= [(self
._exe
_host
_path
, self
._exe
_device
_path
)]
80 if self
._deps
_host
_path
:
81 host_device_tuples
.append((self
._deps
_host
_path
, self
._deps
_device
_path
))
82 device
.PushChangedFiles(host_device_tuples
)
84 def RunWithFlags(self
, device
, flags
, **kwargs
):
86 self
._test
_run
.GetTool(device
).GetTestWrapper(),
87 self
._exe
_device
_path
,
90 cwd
= constants
.TEST_EXECUTABLE_DIR
94 '%s/%s_deps' % (constants
.TEST_EXECUTABLE_DIR
, self
._exe
_file
_name
),
97 gcov_strip_depth
= os
.environ
['NATIVE_COVERAGE_DEPTH_STRIP']
98 external
= device
.GetExternalStoragePath()
99 env
['GCOV_PREFIX'] = '%s/gcov' % external
100 env
['GCOV_PREFIX_STRIP'] = gcov_strip_depth
101 except (device_errors
.CommandFailedError
, KeyError):
104 # TODO(jbudorick): Switch to just RunShellCommand once perezju@'s CL
105 # for long shell commands lands.
106 with device_temp_file
.DeviceTempFile(device
.adb
) as script_file
:
107 script_contents
= ' '.join(cmd
)
108 logging
.info('script contents: %r' % script_contents
)
109 device
.WriteFile(script_file
.name
, script_contents
)
110 output
= device
.RunShellCommand(['sh', script_file
.name
], cwd
=cwd
,
114 def Clear(self
, device
):
116 device
.KillAll(self
._exe
_file
_name
, blocking
=True, timeout
=30, retries
=0)
117 except device_errors
.CommandFailedError
:
118 # Raised if there is no process with the given name, which in this case
119 # is all we care about.
123 class LocalDeviceGtestRun(local_device_test_run
.LocalDeviceTestRun
):
125 def __init__(self
, env
, test_instance
):
126 assert isinstance(env
, local_device_environment
.LocalDeviceEnvironment
)
127 assert isinstance(test_instance
, gtest_test_instance
.GtestTestInstance
)
128 super(LocalDeviceGtestRun
, self
).__init
__(env
, test_instance
)
130 if self
._test
_instance
.apk
:
131 self
._delegate
= _ApkDelegate(self
._test
_instance
.apk
)
132 elif self
._test
_instance
.exe
:
133 self
._delegate
= _ExeDelegate(self
, self
._test
_instance
.exe
)
138 def TestPackage(self
):
139 return self
._test
_instance
._suite
144 def individual_device_set_up(dev
, host_device_tuples
):
146 self
._delegate
.Install(dev
)
148 # Push data dependencies.
149 external_storage
= dev
.GetExternalStoragePath()
150 host_device_tuples
= [
151 (h
, d
if d
is not None else external_storage
)
152 for h
, d
in host_device_tuples
]
153 dev
.PushChangedFiles(host_device_tuples
)
155 self
._servers
[str(dev
)] = []
156 if self
.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER
:
157 self
._servers
[str(dev
)].append(
158 local_test_server_spawner
.LocalTestServerSpawner(
159 ports
.AllocateTestServerPort(), dev
, self
.GetTool(dev
)))
161 for s
in self
._servers
[str(dev
)]:
164 self
._env
.parallel_devices
.pMap(individual_device_set_up
,
165 self
._test
_instance
.GetDataDependencies())
168 def _ShouldShard(self
):
172 def _CreateShards(self
, tests
):
173 device_count
= len(self
._env
.devices
)
175 for i
in xrange(0, device_count
):
176 unbounded_shard
= tests
[i
::device_count
]
177 shards
+= [unbounded_shard
[j
:j
+_MAX_SHARD_SIZE
]
178 for j
in xrange(0, len(unbounded_shard
), _MAX_SHARD_SIZE
)]
179 return [':'.join(s
) for s
in shards
]
183 tests
= self
._delegate
.RunWithFlags(
184 self
._env
.devices
[0], '--gtest_list_tests')
185 tests
= gtest_test_instance
.ParseGTestListTests(tests
)
186 tests
= self
._test
_instance
.FilterTests(tests
)
190 def _RunTest(self
, device
, test
):
192 output
= self
._delegate
.RunWithFlags(device
, '--gtest_filter=%s' % test
,
193 timeout
=900, retries
=0)
194 for s
in self
._servers
[str(device
)]:
196 self
._delegate
.Clear(device
)
199 # TODO(jbudorick): Transition test scripts away from parsing stdout.
200 results
= self
._test
_instance
.ParseGTestOutput(output
)
205 def individual_device_tear_down(dev
):
206 for s
in self
._servers
[str(dev
)]:
209 self
._env
.parallel_devices
.pMap(individual_device_tear_down
)