blob: 32f5221daaa84acdeb3a7eff3a877c8d2636969b [file] [log] [blame]
Ang Li93420002016-05-10 19:11:44 -07001#!/usr/bin/env python3.4
2#
Keun Soo Yimb05f84e2016-10-31 09:29:42 -07003# Copyright (C) 2016 The Android Open Source Project
Ang Li93420002016-05-10 19:11:44 -07004#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
Keun Soo Yimb05f84e2016-10-31 09:29:42 -07009# http://www.apache.org/licenses/LICENSE-2.0
Ang Li93420002016-05-10 19:11:44 -070010#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
Keun Soo Yimb05f84e2016-10-31 09:29:42 -070016#
Ang Li93420002016-05-10 19:11:44 -070017
Ang Li64920272016-05-26 18:37:43 -070018import logging
Ang Li93420002016-05-10 19:11:44 -070019import os
20
21from vts.runners.host import asserts
22from vts.runners.host import errors
23from vts.runners.host import keys
24from vts.runners.host import logger
25from vts.runners.host import records
26from vts.runners.host import signals
Ang Li93420002016-05-10 19:11:44 -070027from vts.runners.host import utils
Yuexi Mab34e8c72016-09-16 20:58:08 +000028from vts.runners.host import const
29from vts.utils.python.common import list_utils
Ang Li93420002016-05-10 19:11:44 -070030
Ang Li93420002016-05-10 19:11:44 -070031# Macro strings for test result reporting
32TEST_CASE_TOKEN = "[Test Case]"
33RESULT_LINE_TEMPLATE = TEST_CASE_TOKEN + " %s %s"
Yuexi Maf87f2c62016-09-14 00:47:30 -070034STR_TEST = "test"
35STR_GENERATE = "generate"
Ang Li93420002016-05-10 19:11:44 -070036
37
38class BaseTestClass(object):
39 """Base class for all test classes to inherit from.
40
41 This class gets all the controller objects from test_runner and executes
42 the test cases requested within itself.
43
44 Most attributes of this class are set at runtime based on the configuration
45 provided.
46
47 Attributes:
48 tests: A list of strings, each representing a test case name.
49 TAG: A string used to refer to a test class. Default is the test class
50 name.
Ang Li93420002016-05-10 19:11:44 -070051 results: A records.TestResult object for aggregating test results from
52 the execution of test cases.
53 currentTestName: A string that's the name of the test case currently
54 being executed. If no test is executing, this should
55 be None.
Yuexi Mab34e8c72016-09-16 20:58:08 +000056 include_filer: A list of string, each representing a test case name to
57 include.
58 exclude_filer: A list of string, each representing a test case name to
59 exclude. Has no effect if include_filer is not empty.
Yuexi Mab5132a42016-11-10 14:59:30 -080060 abi_bitness: String, bitness of abi
Ang Li93420002016-05-10 19:11:44 -070061 """
62
63 TAG = None
64
65 def __init__(self, configs):
66 self.tests = []
67 if not self.TAG:
68 self.TAG = self.__class__.__name__
69 # Set all the controller objects and params.
70 for name, value in configs.items():
71 setattr(self, name, value)
72 self.results = records.TestResult()
73 self.currentTestName = None
74
Yuexi Maf3afb602016-09-30 16:18:23 -070075 # Setup test filters (optional)
76 if keys.ConfigKeys.KEY_TEST_SUITE in self.user_params:
77 test_suite = self.user_params[keys.ConfigKeys.KEY_TEST_SUITE]
78 filters = [keys.ConfigKeys.KEY_INCLUDE_FILTER,
79 keys.ConfigKeys.KEY_EXCLUDE_FILTER]
80 for filter in filters:
81 if filter in test_suite:
82 filter_expanded = list_utils.ExpandItemDelimiters(
83 test_suite[filter],
84 const.LIST_ITEM_DELIMITER,
85 strip=True)
86 setattr(self, filter, filter_expanded)
Yuexi Mab34e8c72016-09-16 20:58:08 +000087
Yuexi Mab5132a42016-11-10 14:59:30 -080088 # Set abi bitness (optional)
Yuexi Mac1396c02016-11-10 15:13:29 -080089 self.abi_bitness = self.getUserParam(keys.ConfigKeys.IKEY_ABI_BITNESS)
Yuexi Mab5132a42016-11-10 14:59:30 -080090
Ang Li93420002016-05-10 19:11:44 -070091 def __enter__(self):
92 return self
93
94 def __exit__(self, *args):
95 self._exec_func(self.cleanUp)
96
Ang Lie2139f12016-05-12 17:39:06 -070097 def getUserParams(self, req_param_names=[], opt_param_names=[], **kwargs):
Ang Li93420002016-05-10 19:11:44 -070098 """Unpacks user defined parameters in test config into individual
99 variables.
100
101 Instead of accessing the user param with self.user_params["xxx"], the
102 variable can be directly accessed with self.xxx.
103
104 A missing required param will raise an exception. If an optional param
105 is missing, an INFO line will be logged.
106
107 Args:
108 req_param_names: A list of names of the required user params.
109 opt_param_names: A list of names of the optional user params.
110 **kwargs: Arguments that provide default values.
111 e.g. getUserParams(required_list, opt_list, arg_a="hello")
112 self.arg_a will be "hello" unless it is specified again in
113 required_list or opt_list.
114
115 Raises:
116 BaseTestError is raised if a required user params is missing from
117 test config.
118 """
119 for k, v in kwargs.items():
120 setattr(self, k, v)
121 for name in req_param_names:
122 if name not in self.user_params:
Ang Li05f99ab2016-08-04 16:48:24 -0700123 raise errors.BaseTestError(("Missing required user param '%s' "
124 "in test configuration.") % name)
Ang Li93420002016-05-10 19:11:44 -0700125 setattr(self, name, self.user_params[name])
126 for name in opt_param_names:
127 if name not in self.user_params:
Yuexi Maf87f2c62016-09-14 00:47:30 -0700128 logging.info(("Missing optional user param '%s' in "
129 "configuration, continue."), name)
Ang Li93420002016-05-10 19:11:44 -0700130 else:
131 setattr(self, name, self.user_params[name])
132
Yuexi Mac1396c02016-11-10 15:13:29 -0800133 def getUserParam(self, param_name, error_if_not_found=False, default_value=None):
134 """Get the value of a single user parameter.
135
136 This method returns the value of specified user parameter.
137 Note: this method will not automatically set attribute using the parameter name and value.
138
139 Args:
140 param_name: string or list of string, denoting user parameter names. If provided
141 a single string, self.user_params["<param_name>"] will be accessed.
142 If provided multiple strings,
143 self.user_params["<param_name1>"]["<param_name2>"]["<param_name3>"]...
144 will be accessed.
145 error_if_not_found: bool, whether to raise error if parameter not exists. Default:
146 False
147 default_value: object, default value to return if not found. If error_if_not_found is
148 True, this parameter has no effect. Default: None
149
150 Returns:
151 object, value of the specified parameter name chain if exists;
152 <default_value> if not exists.
153 """
154 if not param_name:
155 if error_if_not_found:
156 raise errors.BaseTestError("empty param_name provided")
157 logging.error("empty param_name")
158 return default_value
159
160 if not isinstance(param_name, list):
161 param_name = [param_name]
162
163 curr_obj = self.user_params
164 for param in param_name:
165 if param not in curr_obj:
166 if error_if_not_found:
167 raise errors.BaseTestError(
168 ("Missing user param '%s' "
169 "in test configuration.") % name)
170 return default_value
171 curr_obj = curr_obj[param]
172
173 return curr_obj
174
Ang Li93420002016-05-10 19:11:44 -0700175 def _setUpClass(self):
176 """Proxy function to guarantee the base implementation of setUpClass
177 is called.
178 """
179 return self.setUpClass()
180
181 def setUpClass(self):
182 """Setup function that will be called before executing any test case in
183 the test class.
184
185 To signal setup failure, return False or raise an exception. If
186 exceptions were raised, the stack trace would appear in log, but the
187 exceptions would not propagate to upper levels.
188
189 Implementation is optional.
190 """
Keun Soo Yimbae361d2016-07-23 10:39:54 -0700191 pass
192
193 def _tearDownClass(self):
194 """Proxy function to guarantee the base implementation of tearDownClass
195 is called.
196 """
197 return self.tearDownClass()
Ang Li93420002016-05-10 19:11:44 -0700198
199 def tearDownClass(self):
200 """Teardown function that will be called after all the selected test
201 cases in the test class have been executed.
202
203 Implementation is optional.
204 """
Keun Soo Yimbae361d2016-07-23 10:39:54 -0700205 pass
Ang Li93420002016-05-10 19:11:44 -0700206
207 def _setUpTest(self, test_name):
208 """Proxy function to guarantee the base implementation of setUpTest is
209 called.
210 """
211 self.currentTestName = test_name
212 return self.setUpTest()
213
214 def setUpTest(self):
215 """Setup function that will be called every time before executing each
216 test case in the test class.
217
218 To signal setup failure, return False or raise an exception. If
219 exceptions were raised, the stack trace would appear in log, but the
220 exceptions would not propagate to upper levels.
221
222 Implementation is optional.
223 """
224
225 def _tearDownTest(self, test_name):
226 """Proxy function to guarantee the base implementation of tearDownTest
227 is called.
228 """
229 try:
230 self.tearDownTest()
231 finally:
232 self.currentTestName = None
233
234 def tearDownTest(self):
235 """Teardown function that will be called every time a test case has
236 been executed.
237
238 Implementation is optional.
239 """
240
241 def _onFail(self, record):
242 """Proxy function to guarantee the base implementation of onFail is
243 called.
244
245 Args:
246 record: The records.TestResultRecord object for the failed test
247 case.
248 """
249 test_name = record.test_name
Ang Li64920272016-05-26 18:37:43 -0700250 logging.error(record.details)
Ang Li93420002016-05-10 19:11:44 -0700251 begin_time = logger.epochToLogLineTimestamp(record.begin_time)
Ang Li64920272016-05-26 18:37:43 -0700252 logging.info(RESULT_LINE_TEMPLATE, test_name, record.result)
Ang Li93420002016-05-10 19:11:44 -0700253 self.onFail(test_name, begin_time)
254
255 def onFail(self, test_name, begin_time):
256 """A function that is executed upon a test case failure.
257
258 User implementation is optional.
259
260 Args:
261 test_name: Name of the test that triggered this function.
262 begin_time: Logline format timestamp taken when the test started.
263 """
264
265 def _onPass(self, record):
266 """Proxy function to guarantee the base implementation of onPass is
267 called.
268
269 Args:
270 record: The records.TestResultRecord object for the passed test
271 case.
272 """
273 test_name = record.test_name
274 begin_time = logger.epochToLogLineTimestamp(record.begin_time)
275 msg = record.details
276 if msg:
Ang Li64920272016-05-26 18:37:43 -0700277 logging.info(msg)
278 logging.info(RESULT_LINE_TEMPLATE, test_name, record.result)
Ang Li93420002016-05-10 19:11:44 -0700279 self.onPass(test_name, begin_time)
280
281 def onPass(self, test_name, begin_time):
282 """A function that is executed upon a test case passing.
283
284 Implementation is optional.
285
286 Args:
287 test_name: Name of the test that triggered this function.
288 begin_time: Logline format timestamp taken when the test started.
289 """
290
291 def _onSkip(self, record):
292 """Proxy function to guarantee the base implementation of onSkip is
293 called.
294
295 Args:
296 record: The records.TestResultRecord object for the skipped test
297 case.
298 """
299 test_name = record.test_name
300 begin_time = logger.epochToLogLineTimestamp(record.begin_time)
Ang Li64920272016-05-26 18:37:43 -0700301 logging.info(RESULT_LINE_TEMPLATE, test_name, record.result)
302 logging.info("Reason to skip: %s", record.details)
Ang Li93420002016-05-10 19:11:44 -0700303 self.onSkip(test_name, begin_time)
304
305 def onSkip(self, test_name, begin_time):
306 """A function that is executed upon a test case being skipped.
307
308 Implementation is optional.
309
310 Args:
311 test_name: Name of the test that triggered this function.
312 begin_time: Logline format timestamp taken when the test started.
313 """
314
315 def _onException(self, record):
316 """Proxy function to guarantee the base implementation of onException
317 is called.
318
319 Args:
320 record: The records.TestResultRecord object for the failed test
321 case.
322 """
323 test_name = record.test_name
Ang Li64920272016-05-26 18:37:43 -0700324 logging.exception(record.details)
Ang Li93420002016-05-10 19:11:44 -0700325 begin_time = logger.epochToLogLineTimestamp(record.begin_time)
Ang Li93420002016-05-10 19:11:44 -0700326 self.onException(test_name, begin_time)
327
328 def onException(self, test_name, begin_time):
329 """A function that is executed upon an unhandled exception from a test
330 case.
331
332 Implementation is optional.
333
334 Args:
335 test_name: Name of the test that triggered this function.
336 begin_time: Logline format timestamp taken when the test started.
337 """
338
339 def _exec_procedure_func(self, func, tr_record):
340 """Executes a procedure function like onPass, onFail etc.
341
342 This function will alternate the 'Result' of the test's record if
343 exceptions happened when executing the procedure function.
344
345 This will let signals.TestAbortAll through so abortAll works in all
346 procedure functions.
347
348 Args:
349 func: The procedure function to be executed.
350 tr_record: The TestResultRecord object associated with the test
351 case executed.
352 """
353 try:
354 func(tr_record)
355 except signals.TestAbortAll:
356 raise
357 except Exception as e:
Ang Li64920272016-05-26 18:37:43 -0700358 logging.exception("Exception happened when executing %s for %s.",
359 func.__name__, self.currentTestName)
Ang Li93420002016-05-10 19:11:44 -0700360 tr_record.addError(func.__name__, e)
361
Yuexi Maf3afb602016-09-30 16:18:23 -0700362 def filterOneTest(self, test_name):
Yuexi Mab5132a42016-11-10 14:59:30 -0800363 """Check test filters for a test name.
Yuexi Maf3afb602016-09-30 16:18:23 -0700364
Yuexi Mab5132a42016-11-10 14:59:30 -0800365 The first layer of filter is user defined test filters:
366 if a include filter is not empty, only tests in include filter will
Yuexi Maf3afb602016-09-30 16:18:23 -0700367 be executed regardless whether they are also in exclude filter. Else
368 if include filter is empty, only tests not in exclude filter will be
369 executed.
370
Yuexi Mab5132a42016-11-10 14:59:30 -0800371 The second layer of filter is checking abi bitness:
372 if a test has a suffix indicating the intended architecture bitness,
373 and the current abi bitness information is available, non matching tests
374 will be skipped. By our convention, this function will look for bitness in suffix
375 formated as "32bit", "32Bit", "32BIT", or 64 bit equivalents.
376
Yuexi Maf3afb602016-09-30 16:18:23 -0700377 Args:
378 test_name: string, name of a test
379
380 Raises:
381 signals.TestSilent if a test should not be executed
382 """
383 if (hasattr(self, keys.ConfigKeys.KEY_INCLUDE_FILTER) and
384 getattr(self, keys.ConfigKeys.KEY_INCLUDE_FILTER)):
385 if test_name not in getattr(self,
386 keys.ConfigKeys.KEY_INCLUDE_FILTER):
387 logging.info("Test case '%s' not in include filter." %
388 test_name)
389 raise signals.TestSilent(
390 "Test case '%s' not in include filter." % test_name)
391 elif (hasattr(self, keys.ConfigKeys.KEY_EXCLUDE_FILTER) and
392 test_name in getattr(self, keys.ConfigKeys.KEY_EXCLUDE_FILTER)):
393 logging.info("Test case '%s' in exclude filter." % test_name)
394 raise signals.TestSilent("Test case '%s' in exclude filter." %
395 test_name)
396
Yuexi Mab5132a42016-11-10 14:59:30 -0800397 if self.abi_bitness is not None:
398 asserts.skipIf(
399 (test_name[-len(const.SUFFIX_32BIT):].lower() ==
400 const.SUFFIX_32BIT and self.abi_bitness != "32") or
401 (test_name[-len(const.SUFFIX_64BIT):].lower() ==
402 const.SUFFIX_64BIT and self.abi_bitness != "64"),
403 "Test case '{}' excluded as abi bitness is {}.".format(
404 test_name, self.abi_bitness))
405
Ang Li93420002016-05-10 19:11:44 -0700406 def execOneTest(self, test_name, test_func, args, **kwargs):
407 """Executes one test case and update test results.
408
409 Executes one test case, create a records.TestResultRecord object with
410 the execution information, and add the record to the test class's test
411 results.
412
413 Args:
414 test_name: Name of the test.
415 test_func: The test function.
416 args: A tuple of params.
417 kwargs: Extra kwargs.
418 """
Yuexi Ma85941942016-09-14 00:49:24 -0700419 is_silenced = False
Ang Li93420002016-05-10 19:11:44 -0700420 tr_record = records.TestResultRecord(test_name, self.TAG)
421 tr_record.testBegin()
Ang Li64920272016-05-26 18:37:43 -0700422 logging.info("%s %s", TEST_CASE_TOKEN, test_name)
Ang Li93420002016-05-10 19:11:44 -0700423 verdict = None
424 try:
Yuexi Maf3afb602016-09-30 16:18:23 -0700425 self.filterOneTest(test_name)
Yuexi Mab34e8c72016-09-16 20:58:08 +0000426
Ang Li93420002016-05-10 19:11:44 -0700427 ret = self._setUpTest(test_name)
428 asserts.assertTrue(ret is not False,
Ang Lie2139f12016-05-12 17:39:06 -0700429 "Setup for %s failed." % test_name)
Ang Li93420002016-05-10 19:11:44 -0700430 try:
431 if args or kwargs:
432 verdict = test_func(*args, **kwargs)
433 else:
434 verdict = test_func()
435 finally:
436 self._tearDownTest(test_name)
437 except (signals.TestFailure, AssertionError) as e:
438 tr_record.testFail(e)
439 self._exec_procedure_func(self._onFail, tr_record)
440 except signals.TestSkip as e:
441 # Test skipped.
442 tr_record.testSkip(e)
443 self._exec_procedure_func(self._onSkip, tr_record)
444 except (signals.TestAbortClass, signals.TestAbortAll) as e:
445 # Abort signals, pass along.
446 tr_record.testFail(e)
447 raise e
448 except signals.TestPass as e:
449 # Explicit test pass.
450 tr_record.testPass(e)
451 self._exec_procedure_func(self._onPass, tr_record)
452 except signals.TestSilent as e:
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700453 # Suppress test reporting.
Yuexi Ma85941942016-09-14 00:49:24 -0700454 is_silenced = True
Ang Li93420002016-05-10 19:11:44 -0700455 self.results.requested.remove(test_name)
456 except Exception as e:
457 # Exception happened during test.
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700458 logging.exception(e)
Ang Li93420002016-05-10 19:11:44 -0700459 tr_record.testError(e)
460 self._exec_procedure_func(self._onException, tr_record)
461 self._exec_procedure_func(self._onFail, tr_record)
462 else:
463 # Keep supporting return False for now.
464 # TODO(angli): Deprecate return False support.
465 if verdict or (verdict is None):
466 # Test passed.
467 tr_record.testPass()
468 self._exec_procedure_func(self._onPass, tr_record)
469 return
470 # Test failed because it didn't return True.
471 # This should be removed eventually.
472 tr_record.testFail()
473 self._exec_procedure_func(self._onFail, tr_record)
474 finally:
Yuexi Ma85941942016-09-14 00:49:24 -0700475 if not is_silenced:
Ang Li93420002016-05-10 19:11:44 -0700476 self.results.addRecord(tr_record)
477
Ang Lie2139f12016-05-12 17:39:06 -0700478 def runGeneratedTests(self,
479 test_func,
480 settings,
481 args=None,
482 kwargs=None,
483 tag="",
484 name_func=None):
Ang Li93420002016-05-10 19:11:44 -0700485 """Runs generated test cases.
486
487 Generated test cases are not written down as functions, but as a list
488 of parameter sets. This way we reduce code repetition and improve
489 test case scalability.
490
491 Args:
492 test_func: The common logic shared by all these generated test
493 cases. This function should take at least one argument,
494 which is a parameter set.
495 settings: A list of strings representing parameter sets. These are
496 usually json strings that get loaded in the test_func.
497 args: Iterable of additional position args to be passed to
498 test_func.
499 kwargs: Dict of additional keyword args to be passed to test_func
500 tag: Name of this group of generated test cases. Ignored if
501 name_func is provided and operates properly.
502 name_func: A function that takes a test setting and generates a
503 proper test name. The test name should be shorter than
504 utils.MAX_FILENAME_LEN. Names over the limit will be
505 truncated.
506
507 Returns:
508 A list of settings that did not pass.
509 """
510 args = args or ()
511 kwargs = kwargs or {}
512 failed_settings = []
513 for s in settings:
514 test_name = "{} {}".format(tag, s)
515 if name_func:
516 try:
517 test_name = name_func(s, *args, **kwargs)
518 except:
Yuexi Maf87f2c62016-09-14 00:47:30 -0700519 logging.exception(("Failed to get test name from "
520 "test_func. Fall back to default %s"),
521 test_name)
Ang Li93420002016-05-10 19:11:44 -0700522 self.results.requested.append(test_name)
523 if len(test_name) > utils.MAX_FILENAME_LEN:
524 test_name = test_name[:utils.MAX_FILENAME_LEN]
525 previous_success_cnt = len(self.results.passed)
Ang Lie2139f12016-05-12 17:39:06 -0700526 self.execOneTest(test_name, test_func, (s, ) + args, **kwargs)
Ang Li93420002016-05-10 19:11:44 -0700527 if len(self.results.passed) - previous_success_cnt != 1:
528 failed_settings.append(s)
529 return failed_settings
530
531 def _exec_func(self, func, *args):
532 """Executes a function with exception safeguard.
533
534 This will let signals.TestAbortAll through so abortAll works in all
535 procedure functions.
536
537 Args:
538 func: Function to be executed.
539 args: Arguments to be passed to the function.
540
541 Returns:
542 Whatever the function returns, or False if unhandled exception
543 occured.
544 """
545 try:
546 return func(*args)
547 except signals.TestAbortAll:
548 raise
549 except:
Ang Li64920272016-05-26 18:37:43 -0700550 logging.exception("Exception happened when executing %s in %s.",
551 func.__name__, self.TAG)
Ang Li93420002016-05-10 19:11:44 -0700552 return False
553
554 def _get_all_test_names(self):
555 """Finds all the function names that match the test case naming
556 convention in this class.
557
558 Returns:
559 A list of strings, each is a test case name.
560 """
561 test_names = []
562 for name in dir(self):
Yuexi Maf87f2c62016-09-14 00:47:30 -0700563 if name.startswith(STR_TEST) or name.startswith(STR_GENERATE):
Ang Li64920272016-05-26 18:37:43 -0700564 attr_func = getattr(self, name)
565 if hasattr(attr_func, "__call__"):
566 test_names.append(name)
Ang Li93420002016-05-10 19:11:44 -0700567 return test_names
568
569 def _get_test_funcs(self, test_names):
570 """Obtain the actual functions of test cases based on test names.
571
572 Args:
573 test_names: A list of strings, each string is a test case name.
574
575 Returns:
576 A list of tuples of (string, function). String is the test case
577 name, function is the actual test case function.
578
579 Raises:
580 errors.USERError is raised if the test name does not follow
581 naming convention "test_*". This can only be caused by user input
582 here.
583 """
584 test_funcs = []
585 for test_name in test_names:
Yuexi Maf87f2c62016-09-14 00:47:30 -0700586 if not hasattr(self, test_name):
587 logging.warning("%s does not have test case %s.", self.TAG,
588 test_name)
589 elif (test_name.startswith(STR_TEST) or
590 test_name.startswith(STR_GENERATE)):
591 test_funcs.append((test_name, getattr(self, test_name)))
592 else:
Ang Li93420002016-05-10 19:11:44 -0700593 msg = ("Test case name %s does not follow naming convention "
Ang Li64920272016-05-26 18:37:43 -0700594 "test*, abort.") % test_name
Ang Li93420002016-05-10 19:11:44 -0700595 raise errors.USERError(msg)
Yuexi Maf87f2c62016-09-14 00:47:30 -0700596
Ang Li93420002016-05-10 19:11:44 -0700597 return test_funcs
598
599 def run(self, test_names=None):
600 """Runs test cases within a test class by the order they appear in the
601 execution list.
602
603 One of these test cases lists will be executed, shown here in priority
604 order:
605 1. The test_names list, which is passed from cmd line. Invalid names
606 are guarded by cmd line arg parsing.
607 2. The self.tests list defined in test class. Invalid names are
608 ignored.
609 3. All function that matches test case naming convention in the test
610 class.
611
612 Args:
613 test_names: A list of string that are test case names requested in
614 cmd line.
615
616 Returns:
617 The test results object of this class.
618 """
Ang Li64920272016-05-26 18:37:43 -0700619 logging.info("==========> %s <==========", self.TAG)
Ang Li93420002016-05-10 19:11:44 -0700620 # Devise the actual test cases to run in the test class.
621 if not test_names:
622 if self.tests:
623 # Specified by run list in class.
624 test_names = list(self.tests)
625 else:
626 # No test case specified by user, execute all in the test class
627 test_names = self._get_all_test_names()
Yuexi Maf87f2c62016-09-14 00:47:30 -0700628 self.results.requested = [test_name for test_name in test_names
629 if test_name.startswith(STR_TEST)]
Ang Li93420002016-05-10 19:11:44 -0700630 tests = self._get_test_funcs(test_names)
Yuexi Maf87f2c62016-09-14 00:47:30 -0700631
Ang Li93420002016-05-10 19:11:44 -0700632 # Setup for the class.
633 try:
634 if self._setUpClass() is False:
635 raise signals.TestFailure("Failed to setup %s." % self.TAG)
636 except Exception as e:
Ang Li64920272016-05-26 18:37:43 -0700637 logging.exception("Failed to setup %s.", self.TAG)
Ang Li93420002016-05-10 19:11:44 -0700638 self.results.failClass(self.TAG, e)
Keun Soo Yimbae361d2016-07-23 10:39:54 -0700639 self._exec_func(self._tearDownClass)
Ang Li93420002016-05-10 19:11:44 -0700640 return self.results
641 # Run tests in order.
642 try:
643 for test_name, test_func in tests:
Yuexi Maf87f2c62016-09-14 00:47:30 -0700644 if test_name.startswith(STR_GENERATE):
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700645 logging.info(
646 "Executing generated test trigger function '%s'",
647 test_name)
Yuexi Maf87f2c62016-09-14 00:47:30 -0700648 test_func()
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700649 logging.info("Finished '%s'", test_name)
Yuexi Maf87f2c62016-09-14 00:47:30 -0700650 else:
651 self.execOneTest(test_name, test_func, None)
Ang Li93420002016-05-10 19:11:44 -0700652 return self.results
653 except signals.TestAbortClass:
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700654 logging.info("Received TestAbortClass signal")
Ang Li93420002016-05-10 19:11:44 -0700655 return self.results
656 except signals.TestAbortAll as e:
Yuexi Maaeaacbc2016-09-15 21:28:44 -0700657 logging.info("Received TestAbortAll signal")
Ang Li93420002016-05-10 19:11:44 -0700658 # Piggy-back test results on this exception object so we don't lose
659 # results from this test class.
660 setattr(e, "results", self.results)
661 raise e
Yuexi Maf8d6e5b2016-10-12 21:57:53 -0700662 except Exception as e:
663 # Exception happened during test.
664 logging.exception(e)
665 raise e
Ang Li93420002016-05-10 19:11:44 -0700666 finally:
Keun Soo Yimbae361d2016-07-23 10:39:54 -0700667 self._exec_func(self._tearDownClass)
Ang Li64920272016-05-26 18:37:43 -0700668 logging.info("Summary for test class %s: %s", self.TAG,
669 self.results.summary())
Ang Li93420002016-05-10 19:11:44 -0700670
671 def cleanUp(self):
672 """A function that is executed upon completion of all tests cases
673 selected in the test class.
674
675 This function should clean up objects initialized in the constructor by
676 user.
677 """