Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: build/android/pylib/linker/test_case.py

Issue 25525003: Add new Android test runner command to handle linker tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: formatting Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/android/pylib/linker/setup.py ('k') | build/android/pylib/linker/test_runner.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2013 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.
4
5 """Base class for linker-specific test cases.
6
7 The custom dynamic linker can only be tested through a custom test case
8 for various technical reasons:
9
10 - It's an 'invisible feature', i.e. it doesn't expose a new API or
11 behaviour, all it does is save RAM when loading native libraries.
12
13 - Checking that it works correctly requires several things that do not
14 fit the existing GTest-based and instrumentation-based tests:
15
16 - Native test code needs to be run in both the browser and renderer
17 process at the same time just after loading native libraries, in
18 a completely asynchronous way.
19
20 - Each test case requires restarting a whole new application process
21 with a different command-line.
22
23 - Enabling test support in the Linker code requires building a special
24 APK with a flag to activate special test-only support code in the
25 Linker code itself.
26
27 Host-driven tests have also been tried, but since they're really
28 sub-classes of instrumentation tests, they didn't work well either.
29
30 To build and run the linker tests, do the following:
31
32 ninja -C out/Debug content_linker_test_apk
33 build/android/test_runner.py linker
34
35 The core of the checks performed here are pretty simple:
36
37 - Clear the logcat and start recording with an appropriate set of filters.
38 - Create the command-line appropriate for the test-case.
39 - Start the activity (always forcing a cold start).
40 - Every second, look at the current content of the filtered logcat lines
41 and look for instances of the following:
42
43 BROWSER_LINKER_TEST: <status>
44 RENDERER_LINKER_TEST: <status>
45
46 where <status> can be either FAIL or SUCCESS. These lines can appear
47 in any order in the logcat. Once both browser and renderer status are
48 found, stop the loop. Otherwise timeout after 30 seconds.
49
50 Note that there can be other lines beginning with BROWSER_LINKER_TEST:
51 and RENDERER_LINKER_TEST:, but are not followed by a <status> code.
52
53 - The test case passes if the <status> for both the browser and renderer
54 process are SUCCESS. Otherwise its a fail.
55 """
56
57 import logging
58 import os
59 import re
60 import StringIO
61 import subprocess
62 import tempfile
63 import time
64
65 from pylib import android_commands
66 from pylib import flag_changer
67 from pylib.base import base_test_result
68
69
70 _PACKAGE_NAME='org.chromium.content_linker_test_apk'
71 _ACTIVITY_NAME='.ContentLinkerTestActivity'
72 _COMMAND_LINE_FILE='/data/local/tmp/content-linker-test-command-line'
73
74 # Logcat filters used during each test. Only the 'chromium' one is really
75 # needed, but the logs are added to the TestResult in case of error, and
76 # it is handy to have the 'content_android_linker' ones as well when
77 # troubleshooting.
78 _LOGCAT_FILTERS = [ '*:s', 'chromium:v', 'content_android_linker:v' ]
79
80 # Regular expression used to match status lines in logcat.
81 re_status_line = re.compile(r'(BROWSER|RENDERER)_LINKER_TEST: (FAIL|SUCCESS)')
82
83 def _CheckLinkerTestStatus(logcat):
84 """Parse the content of |logcat| and checks for both a browser and
85 renderer status line.
86
87 Args:
88 logcat: A string to parse. Can include line separators.
89
90 Returns:
91 A tuple, result[0] is True if there is a complete match, then
92 result[1] and result[2] will be True or False to reflect the
93 test status for the browser and renderer processes, respectively.
94 """
95 browser_found = False
96 renderer_found = False
97 for m in re_status_line.finditer(logcat):
98 process_type, status = m.groups()
99 if process_type == 'BROWSER':
100 browser_found = True
101 browser_success = (status == 'SUCCESS')
102 elif process_type == 'RENDERER':
103 renderer_found = True
104 renderer_success = (status == 'SUCCESS')
105 else:
106 assert False, 'Invalid process type ' + process_type
107
108 if browser_found and renderer_found:
109 return (True, browser_success, renderer_success)
110
111 # Didn't find anything.
112 return (False, None, None)
113
114
115 def _CreateCommandLineFileOnDevice(adb, flags):
116 changer = flag_changer.FlagChanger(adb, _COMMAND_LINE_FILE)
117 changer.Set(flags)
118
119
120 class LinkerTestCase(object):
121 """Base class for linker test cases."""
122
123 def __init__(self, test_name, is_low_memory=False):
124 """Create a test case initialized to run |test_name|.
125
126 Args:
127 test_name: The name of the method to run as the test.
128 is_low_memory: True to simulate a low-memory device, False otherwise.
129 """
130 self.test_name = test_name
131 class_name = self.__class__.__name__
132 self.qualified_name = '%s.%s' % (class_name, self.test_name)
133 self.tagged_name = self.qualified_name
134 self.is_low_memory = is_low_memory
135
136 def Run(self, device):
137 margin = 8
138 print '[ %-*s ] %s' % (margin, 'RUN', self.tagged_name)
139 logging.info('Running linker test: %s', self.tagged_name)
140 adb = android_commands.AndroidCommands(device)
141
142 # 1. Write command-line file with appropriate options.
143 command_line_flags = []
144 if self.is_low_memory:
145 command_line_flags.append('--low-memory-device')
146 _CreateCommandLineFileOnDevice(adb, command_line_flags)
147
148 # 2. Start recording logcat with appropriate filters.
149 adb.StartRecordingLogcat(clear=True, filters=_LOGCAT_FILTERS)
150
151 try:
152 # 3. Force-start activity.
153 adb.StartActivity(package=_PACKAGE_NAME,
154 activity=_ACTIVITY_NAME,
155 force_stop=True)
156
157 # 4. Wait up to 30 seconds until the linker test status is in the logcat.
158 max_tries = 30
159 num_tries = 0
160 found = False
161 logcat = None
162 while num_tries < max_tries:
163 time.sleep(1)
164 num_tries += 1
165 found, browser_ok, renderer_ok = _CheckLinkerTestStatus(
166 adb.GetCurrentRecordedLogcat())
167 if found:
168 break
169
170 finally:
171 # Ensure the ADB polling process is always killed when
172 # the script is interrupted by the user with Ctrl-C.
173 logs = adb.StopRecordingLogcat()
174
175 results = base_test_result.TestRunResults()
176
177 if num_tries >= max_tries:
178 # Timeout
179 print '[ %*s ] %s' % (margin, 'TIMEOUT', self.tagged_name)
180 results.AddResult(
181 base_test_result.BaseTestResult(
182 self.test_name,
183 base_test_result.ResultType.TIMEOUT,
184 logs))
185 elif browser_ok and renderer_ok:
186 # Passed
187 logging.info(
188 'Logcat start ---------------------------------\n%s' +
189 'Logcat end -----------------------------------', logs)
190 print '[ %*s ] %s' % (margin, 'OK', self.tagged_name)
191 results.AddResult(
192 base_test_result.BaseTestResult(
193 self.test_name,
194 base_test_result.ResultType.PASS))
195 else:
196 print '[ %*s ] %s' % (margin, 'FAILED', self.tagged_name)
197 # Failed
198 results.AddResult(
199 base_test_result.BaseTestResult(
200 self.test_name,
201 base_test_result.ResultType.FAIL,
202 logs))
203
204 return results
205
206 def __str__(self):
207 return self.tagged_name
208
209 def __repr__(self):
210 return self.tagged_name
OLDNEW
« no previous file with comments | « build/android/pylib/linker/setup.py ('k') | build/android/pylib/linker/test_runner.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698