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 'components_browsertests', 'content_unittests', 'content_browsertests',
34 'net_unittests', 'unit_tests'
37 class _ApkDelegate(object):
38 def __init__(self
, apk
):
40 self
._package
= apk_helper
.GetPackageName(self
._apk
)
41 self
._runner
= apk_helper
.GetInstrumentationName(self
._apk
)
42 self
._component
= '%s/%s' % (self
._package
, self
._runner
)
43 self
._enable
_test
_server
_spawner
= False
45 def Install(self
, device
):
46 device
.Install(self
._apk
)
48 def RunWithFlags(self
, device
, flags
, **kwargs
):
49 with device_temp_file
.DeviceTempFile(device
.adb
) as command_line_file
:
50 device
.WriteFile(command_line_file
.name
, '_ %s' % flags
)
53 _EXTRA_COMMAND_LINE_FILE
: command_line_file
.name
,
56 return device
.StartInstrumentation(
57 self
._component
, extras
=extras
, raw
=False, **kwargs
)
59 def Clear(self
, device
):
60 device
.ClearApplicationState(self
._package
)
63 class _ExeDelegate(object):
64 def __init__(self
, exe
, tr
):
65 self
._exe
_host
_path
= exe
66 self
._exe
_file
_name
= os
.path
.split(exe
)[-1]
67 self
._exe
_device
_path
= '%s/%s' % (
68 constants
.TEST_EXECUTABLE_DIR
, self
._exe
_file
_name
)
69 deps_host_path
= self
._exe
_host
_path
+ '_deps'
70 if os
.path
.exists(deps_host_path
):
71 self
._deps
_host
_path
= deps_host_path
72 self
._deps
_device
_path
= self
._exe
_device
_path
+ '_deps'
74 self
._deps
_host
_path
= None
77 def Install(self
, device
):
78 # TODO(jbudorick): Look into merging this with normal data deps pushing if
79 # executables become supported on nonlocal environments.
80 host_device_tuples
= [(self
._exe
_host
_path
, self
._exe
_device
_path
)]
81 if self
._deps
_host
_path
:
82 host_device_tuples
.append((self
._deps
_host
_path
, self
._deps
_device
_path
))
83 device
.PushChangedFiles(host_device_tuples
)
85 def RunWithFlags(self
, device
, flags
, **kwargs
):
87 self
._test
_run
.GetTool(device
).GetTestWrapper(),
88 self
._exe
_device
_path
,
91 cwd
= constants
.TEST_EXECUTABLE_DIR
95 '%s/%s_deps' % (constants
.TEST_EXECUTABLE_DIR
, self
._exe
_file
_name
),
98 gcov_strip_depth
= os
.environ
['NATIVE_COVERAGE_DEPTH_STRIP']
99 external
= device
.GetExternalStoragePath()
100 env
['GCOV_PREFIX'] = '%s/gcov' % external
101 env
['GCOV_PREFIX_STRIP'] = gcov_strip_depth
102 except (device_errors
.CommandFailedError
, KeyError):
105 # TODO(jbudorick): Switch to just RunShellCommand once perezju@'s CL
106 # for long shell commands lands.
107 with device_temp_file
.DeviceTempFile(device
.adb
) as script_file
:
108 script_contents
= ' '.join(cmd
)
109 logging
.info('script contents: %r' % script_contents
)
110 device
.WriteFile(script_file
.name
, script_contents
)
111 output
= device
.RunShellCommand(['sh', script_file
.name
], cwd
=cwd
,
115 def Clear(self
, device
):
116 device
.KillAll(self
._exe
_file
_name
, blocking
=True, timeout
=30, quiet
=True)
119 class LocalDeviceGtestRun(local_device_test_run
.LocalDeviceTestRun
):
121 def __init__(self
, env
, test_instance
):
122 assert isinstance(env
, local_device_environment
.LocalDeviceEnvironment
)
123 assert isinstance(test_instance
, gtest_test_instance
.GtestTestInstance
)
124 super(LocalDeviceGtestRun
, self
).__init
__(env
, test_instance
)
126 if self
._test
_instance
.apk
:
127 self
._delegate
= _ApkDelegate(self
._test
_instance
.apk
)
128 elif self
._test
_instance
.exe
:
129 self
._delegate
= _ExeDelegate(self
, self
._test
_instance
.exe
)
134 def TestPackage(self
):
135 return self
._test
_instance
._suite
140 def individual_device_set_up(dev
, host_device_tuples
):
142 self
._delegate
.Install(dev
)
144 # Push data dependencies.
145 external_storage
= dev
.GetExternalStoragePath()
146 host_device_tuples
= [
147 (h
, d
if d
is not None else external_storage
)
148 for h
, d
in host_device_tuples
]
149 dev
.PushChangedFiles(host_device_tuples
)
151 self
._servers
[str(dev
)] = []
152 if self
.TestPackage() in _SUITE_REQUIRES_TEST_SERVER_SPAWNER
:
153 self
._servers
[str(dev
)].append(
154 local_test_server_spawner
.LocalTestServerSpawner(
155 ports
.AllocateTestServerPort(), dev
, self
.GetTool(dev
)))
157 for s
in self
._servers
[str(dev
)]:
160 self
._env
.parallel_devices
.pMap(individual_device_set_up
,
161 self
._test
_instance
.GetDataDependencies())
164 def _ShouldShard(self
):
168 def _CreateShards(self
, tests
):
169 device_count
= len(self
._env
.devices
)
171 for i
in xrange(0, device_count
):
172 unbounded_shard
= tests
[i
::device_count
]
173 shards
+= [unbounded_shard
[j
:j
+_MAX_SHARD_SIZE
]
174 for j
in xrange(0, len(unbounded_shard
), _MAX_SHARD_SIZE
)]
175 return [':'.join(s
) for s
in shards
]
179 tests
= self
._delegate
.RunWithFlags(
180 self
._env
.devices
[0], '--gtest_list_tests')
181 tests
= gtest_test_instance
.ParseGTestListTests(tests
)
182 tests
= self
._test
_instance
.FilterTests(tests
)
186 def _RunTest(self
, device
, test
):
188 output
= self
._delegate
.RunWithFlags(device
, '--gtest_filter=%s' % test
,
189 timeout
=900, retries
=0)
190 for s
in self
._servers
[str(device
)]:
192 self
._delegate
.Clear(device
)
195 # TODO(jbudorick): Transition test scripts away from parsing stdout.
196 results
= self
._test
_instance
.ParseGTestOutput(output
)
201 def individual_device_tear_down(dev
):
202 for s
in self
._servers
[str(dev
)]:
205 self
._env
.parallel_devices
.pMap(individual_device_tear_down
)