diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5032e6f..24513cb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,6 @@ jobs: - name: Check formatting run: | - python -m pip install yapf - yapf -drp . + python -m pip install pyink + pyink --check . diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index 38ecc35e..00000000 --- a/.style.yapf +++ /dev/null @@ -1,5 +0,0 @@ -[style] -based_on_style = google -indent_width: 2 -spaces_before_comment = 2 - diff --git a/.yapfignore b/.yapfignore deleted file mode 100644 index 8347c8d6..00000000 --- a/.yapfignore +++ /dev/null @@ -1,2 +0,0 @@ -venv/* -.tox/* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f57bd26e..bca38c36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,16 +43,16 @@ mobly $ tox ``` ### Code style -Before pushing your changes, you need to lint the code style via `yapf` +Before pushing your changes, you need to lint the code style via `pyink` -To install `yapf`: +To install `pyink`: ```sh -$ pip3 install yapf +$ pip3 install pyink ``` To lint the code: ```sh -mobly $ yapf -irp . +mobly $ pyink . ``` diff --git a/docs/conf.py b/docs/conf.py index 314e4575..2a7e6a9f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,8 +31,10 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'sphinx.ext.autodoc', 'sphinx.ext.napoleon', 'sphinx.ext.todo', - 'sphinx.ext.viewcode' + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon', + 'sphinx.ext.todo', + 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. @@ -55,18 +57,18 @@ master_doc = 'index' # General information about the project. -project = u'Mobly' -copyright = u'Copyright 2016 Google Inc.' -author = u'Ang Li' +project = 'Mobly' +copyright = 'Copyright 2016 Google Inc.' +author = 'Ang Li' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = u'' +version = '' # The full version, including alpha/beta/rc tags. -release = u'' +release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -79,8 +81,12 @@ # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = [ - '_build', 'Thumbs.db', '.DS_Store', 'tutorial.md', - 'instrumentation_tutorial.md', 'android_device_service.md' + '_build', + 'Thumbs.db', + '.DS_Store', + 'tutorial.md', + 'instrumentation_tutorial.md', + 'android_device_service.md', ] # The name of the Pygments (syntax highlighting) style to use. @@ -118,15 +124,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -136,14 +139,14 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'Mobly.tex', u'Mobly Documentation', u'Ang Li', 'manual'), + (master_doc, 'Mobly.tex', 'Mobly Documentation', 'Ang Li', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, 'mobly', u'Mobly Documentation', [author], 1)] +man_pages = [(master_doc, 'mobly', 'Mobly Documentation', [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -151,9 +154,19 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'Mobly', u'Mobly Documentation', author, 'Mobly', - 'Mobly is a Python-based test framework that specializes in supporting tests that require multiple devices, complex environments, or custom hardware setups.', - 'Miscellaneous'), + ( + master_doc, + 'Mobly', + 'Mobly Documentation', + author, + 'Mobly', + ( + 'Mobly is a Python-based test framework that specializes in' + ' supporting tests that require multiple devices, complex' + ' environments, or custom hardware setups.' + ), + 'Miscellaneous', + ), ] # -- Options for Epub output ---------------------------------------------- diff --git a/mobly/asserts.py b/mobly/asserts.py index 70e1256d..e877e05f 100644 --- a/mobly/asserts.py +++ b/mobly/asserts.py @@ -23,11 +23,9 @@ _pyunit_proxy.maxDiff = None -def _call_unittest_assertion(assertion_method, - *args, - msg=None, - extras=None, - **kwargs): +def _call_unittest_assertion( + assertion_method, *args, msg=None, extras=None, **kwargs +): """Wrapper for converting a unittest assertion into a Mobly one. Args: @@ -65,28 +63,21 @@ def assert_equal(first, second, msg=None, extras=None): extras: An optional field for extra information to be included in test result. """ - _call_unittest_assertion(_pyunit_proxy.assertEqual, - first, - second, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertEqual, first, second, msg=msg, extras=extras + ) def assert_not_equal(first, second, msg=None, extras=None): """Asserts that first is not equal (!=) to second.""" - _call_unittest_assertion(_pyunit_proxy.assertNotEqual, - first, - second, - msg=msg, - extras=extras) - - -def assert_almost_equal(first, - second, - places=None, - msg=None, - delta=None, - extras=None): + _call_unittest_assertion( + _pyunit_proxy.assertNotEqual, first, second, msg=msg, extras=extras + ) + + +def assert_almost_equal( + first, second, places=None, msg=None, delta=None, extras=None +): """Asserts that first is almost equal to second. Fails if the two objects are unequal as determined by their difference @@ -107,21 +98,20 @@ def assert_almost_equal(first, extras: An optional field for extra information to be included in test result. """ - _call_unittest_assertion(_pyunit_proxy.assertAlmostEqual, - first, - second, - places=places, - msg=msg, - delta=delta, - extras=extras) - - -def assert_not_almost_equal(first, - second, - places=None, - msg=None, - delta=None, - extras=None): + _call_unittest_assertion( + _pyunit_proxy.assertAlmostEqual, + first, + second, + places=places, + msg=msg, + delta=delta, + extras=extras, + ) + + +def assert_not_almost_equal( + first, second, places=None, msg=None, delta=None, extras=None +): """Asserts that first is not almost equal to second. Args: @@ -135,49 +125,43 @@ def assert_not_almost_equal(first, extras: An optional field for extra information to be included in test result. """ - _call_unittest_assertion(_pyunit_proxy.assertNotAlmostEqual, - first, - second, - places=places, - msg=msg, - delta=delta, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertNotAlmostEqual, + first, + second, + places=places, + msg=msg, + delta=delta, + extras=extras, + ) def assert_in(member, container, msg=None, extras=None): """Asserts that member is in container.""" - _call_unittest_assertion(_pyunit_proxy.assertIn, - member, - container, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIn, member, container, msg=msg, extras=extras + ) def assert_not_in(member, container, msg=None, extras=None): """Asserts that member is not in container.""" - _call_unittest_assertion(_pyunit_proxy.assertNotIn, - member, - container, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertNotIn, member, container, msg=msg, extras=extras + ) def assert_is(expr1, expr2, msg=None, extras=None): """Asserts that expr1 is expr2.""" - _call_unittest_assertion(_pyunit_proxy.assertIs, - expr1, - expr2, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIs, expr1, expr2, msg=msg, extras=extras + ) def assert_is_not(expr1, expr2, msg=None, extras=None): """Asserts that expr1 is not expr2.""" - _call_unittest_assertion(_pyunit_proxy.assertIsNot, - expr1, - expr2, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIsNot, expr1, expr2, msg=msg, extras=extras + ) def assert_count_equal(first, second, msg=None, extras=None): @@ -197,99 +181,83 @@ def assert_count_equal(first, second, msg=None, extras=None): assert_count_equal([0, 1, 1], [1, 0, 1]) passes the assertion. assert_count_equal([0, 0, 1], [0, 1]) raises an assertion error. """ - _call_unittest_assertion(_pyunit_proxy.assertCountEqual, - first, - second, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertCountEqual, first, second, msg=msg, extras=extras + ) def assert_less(a, b, msg=None, extras=None): """Asserts that a < b.""" - _call_unittest_assertion(_pyunit_proxy.assertLess, - a, - b, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertLess, a, b, msg=msg, extras=extras + ) def assert_less_equal(a, b, msg=None, extras=None): """Asserts that a <= b.""" - _call_unittest_assertion(_pyunit_proxy.assertLessEqual, - a, - b, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertLessEqual, a, b, msg=msg, extras=extras + ) def assert_greater(a, b, msg=None, extras=None): """Asserts that a > b.""" - _call_unittest_assertion(_pyunit_proxy.assertGreater, - a, - b, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertGreater, a, b, msg=msg, extras=extras + ) def assert_greater_equal(a, b, msg=None, extras=None): """Asserts that a >= b.""" - _call_unittest_assertion(_pyunit_proxy.assertGreaterEqual, - a, - b, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertGreaterEqual, a, b, msg=msg, extras=extras + ) def assert_is_none(obj, msg=None, extras=None): """Asserts that obj is None.""" - _call_unittest_assertion(_pyunit_proxy.assertIsNone, - obj, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIsNone, obj, msg=msg, extras=extras + ) def assert_is_not_none(obj, msg=None, extras=None): """Asserts that obj is not None.""" - _call_unittest_assertion(_pyunit_proxy.assertIsNotNone, - obj, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIsNotNone, obj, msg=msg, extras=extras + ) def assert_is_instance(obj, cls, msg=None, extras=None): """Asserts that obj is an instance of cls.""" - _call_unittest_assertion(_pyunit_proxy.assertIsInstance, - obj, - cls, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertIsInstance, obj, cls, msg=msg, extras=extras + ) def assert_not_is_instance(obj, cls, msg=None, extras=None): """Asserts that obj is not an instance of cls.""" - _call_unittest_assertion(_pyunit_proxy.assertNotIsInstance, - obj, - cls, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertNotIsInstance, obj, cls, msg=msg, extras=extras + ) def assert_regex(text, expected_regex, msg=None, extras=None): """Fails the test unless the text matches the regular expression.""" - _call_unittest_assertion(_pyunit_proxy.assertRegex, - text, - expected_regex, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertRegex, text, expected_regex, msg=msg, extras=extras + ) def assert_not_regex(text, unexpected_regex, msg=None, extras=None): """Fails the test if the text matches the regular expression.""" - _call_unittest_assertion(_pyunit_proxy.assertNotRegex, - text, - unexpected_regex, - msg=msg, - extras=extras) + _call_unittest_assertion( + _pyunit_proxy.assertNotRegex, + text, + unexpected_regex, + msg=msg, + extras=extras, + ) def assert_raises(expected_exception, extras=None, *args, **kwargs): @@ -312,11 +280,9 @@ def assert_raises(expected_exception, extras=None, *args, **kwargs): return context -def assert_raises_regex(expected_exception, - expected_regex, - extras=None, - *args, - **kwargs): +def assert_raises_regex( + expected_exception, expected_regex, extras=None, *args, **kwargs +): """Assert that an exception is raised when a function is called. If no exception is raised, test fail. If an exception is raised but not @@ -334,9 +300,9 @@ def assert_raises_regex(expected_exception, extras: An optional field for extra information to be included in test result. """ - context = _AssertRaisesContext(expected_exception, - expected_regex, - extras=extras) + context = _AssertRaisesContext( + expected_exception, expected_regex, extras=extras + ) return context @@ -526,7 +492,9 @@ def __exit__(self, exc_type, exc_value, tb): if isinstance(expected_regexp, str): expected_regexp = re.compile(expected_regexp) if not expected_regexp.search(str(exc_value)): - raise signals.TestFailure('"%s" does not match "%s"' % - (expected_regexp.pattern, str(exc_value)), - extras=self.extras) + raise signals.TestFailure( + '"%s" does not match "%s"' + % (expected_regexp.pattern, str(exc_value)), + extras=self.extras, + ) return True diff --git a/mobly/base_instrumentation_test.py b/mobly/base_instrumentation_test.py index 9c24386a..f41a500a 100644 --- a/mobly/base_instrumentation_test.py +++ b/mobly/base_instrumentation_test.py @@ -302,10 +302,12 @@ class _InstrumentationBlock: unknown_keys: dict, arbitrary keys that are handled generically. """ - def __init__(self, - state=_InstrumentationBlockStates.UNKNOWN, - prefix=None, - previous_instrumentation_block=None): + def __init__( + self, + state=_InstrumentationBlockStates.UNKNOWN, + prefix=None, + previous_instrumentation_block=None, + ): self.state = state self.prefix = prefix self.previous_instrumentation_block = previous_instrumentation_block @@ -369,7 +371,7 @@ def _remove_structure_prefix(self, prefix, line): A string containing a key value pair descripting some property of the current instrumentation test method. """ - return line[len(prefix):].strip() + return line[len(prefix) :].strip() def set_status_code(self, status_code_line): """Sets the status code for the instrumentation test method, used in @@ -480,10 +482,12 @@ def __init__(self, instrumentation_block): self._unknown_keys = {} for key, value in instrumentation_block.known_keys.items(): self._known_keys[key] = '\n'.join( - instrumentation_block.known_keys[key]).rstrip() + instrumentation_block.known_keys[key] + ).rstrip() for key, value in instrumentation_block.unknown_keys.items(): self._unknown_keys[key] = '\n'.join( - instrumentation_block.unknown_keys[key]).rstrip() + instrumentation_block.unknown_keys[key] + ).rstrip() self._begin_time = instrumentation_block.begin_time def _get_name(self): @@ -510,7 +514,8 @@ def _get_class(self): name. """ class_parts = [ - self._prefix, self._known_keys[_InstrumentationKnownStatusKeys.CLASS] + self._prefix, + self._known_keys[_InstrumentationKnownStatusKeys.CLASS], ] return '.'.join(filter(None, class_parts)) @@ -549,16 +554,20 @@ def _get_extras(self): extra_parts.append(self._known_keys[_InstrumentationKnownStatusKeys.STREAM]) extra_parts.append( - self._known_keys[_InstrumentationKnownResultKeys.SHORTMSG]) + self._known_keys[_InstrumentationKnownResultKeys.SHORTMSG] + ) extra_parts.append( - self._known_keys[_InstrumentationKnownResultKeys.LONGMSG]) + self._known_keys[_InstrumentationKnownResultKeys.LONGMSG] + ) extra_parts.append(self._known_keys[_InstrumentationKnownStatusKeys.ERROR]) - if self._known_keys[ - _InstrumentationKnownStatusKeys.STACK] not in self._known_keys[ - _InstrumentationKnownStatusKeys.STREAM]: + if ( + self._known_keys[_InstrumentationKnownStatusKeys.STACK] + not in self._known_keys[_InstrumentationKnownStatusKeys.STREAM] + ): extra_parts.append( - self._known_keys[_InstrumentationKnownStatusKeys.STACK]) + self._known_keys[_InstrumentationKnownStatusKeys.STACK] + ) return '\n'.join(filter(None, extra_parts)) @@ -574,8 +583,10 @@ def _is_failed(self): """ if self._status_code in _InstrumentationStatusCodeCategories.FAIL: return True - elif (self._known_keys[_InstrumentationKnownStatusKeys.STACK] and - self._status_code != _InstrumentationStatusCodes.ASSUMPTION_FAILURE): + elif ( + self._known_keys[_InstrumentationKnownStatusKeys.STACK] + and self._status_code != _InstrumentationStatusCodes.ASSUMPTION_FAILURE + ): return True elif self._known_keys[_InstrumentationKnownStatusKeys.ERROR]: return True @@ -616,14 +627,16 @@ def create_test_record(self, mobly_test_class): elif self._status_code in _InstrumentationStatusCodeCategories.TIMING: if self._error_message: tr_record.test_error( - e=signals.TestError(details=details, extras=extras)) + e=signals.TestError(details=details, extras=extras) + ) else: tr_record = None else: tr_record.test_error(e=signals.TestError(details=details, extras=extras)) if self._known_keys[_InstrumentationKnownStatusKeys.STACK]: tr_record.termination_signal.stacktrace = self._known_keys[ - _InstrumentationKnownStatusKeys.STACK] + _InstrumentationKnownStatusKeys.STACK + ] return tr_record def has_completed_result_block_format(self, error_message): @@ -669,11 +682,13 @@ class InstrumentationTestMixin: """ DEFAULT_INSTRUMENTATION_OPTION_PREFIX = 'instrumentation_option_' - DEFAULT_INSTRUMENTATION_ERROR_MESSAGE = ('instrumentation run exited ' - 'unexpectedly') + DEFAULT_INSTRUMENTATION_ERROR_MESSAGE = ( + 'instrumentation run exited unexpectedly' + ) - def _previous_block_never_completed(self, current_block, previous_block, - new_state): + def _previous_block_never_completed( + self, current_block, previous_block, new_state + ): """Checks if the previous instrumentation method block completed. Args: @@ -691,11 +706,14 @@ def _previous_block_never_completed(self, current_block, previous_block, completed executing. """ if previous_block: - previously_timing_block = (previous_block.status_code - in _InstrumentationStatusCodeCategories.TIMING) - currently_new_block = (current_block.status_code - == _InstrumentationStatusCodes.START or - new_state == _InstrumentationBlockStates.RESULT) + previously_timing_block = ( + previous_block.status_code + in _InstrumentationStatusCodeCategories.TIMING + ) + currently_new_block = ( + current_block.status_code == _InstrumentationStatusCodes.START + or new_state == _InstrumentationBlockStates.RESULT + ) return all([previously_timing_block, currently_new_block]) else: return False @@ -718,21 +736,24 @@ def _create_formatters(self, instrumentation_block, new_state): if self._previous_block_never_completed( current_block=instrumentation_block, previous_block=instrumentation_block.previous_instrumentation_block, - new_state=new_state): + new_state=new_state, + ): instrumentation_block.previous_instrumentation_block.set_error_message( - self.DEFAULT_INSTRUMENTATION_ERROR_MESSAGE) + self.DEFAULT_INSTRUMENTATION_ERROR_MESSAGE + ) formatters.append( _InstrumentationBlockFormatter( - instrumentation_block.previous_instrumentation_block)) + instrumentation_block.previous_instrumentation_block + ) + ) if not instrumentation_block.is_empty: formatters.append(_InstrumentationBlockFormatter(instrumentation_block)) return formatters def _transition_instrumentation_block( - self, - instrumentation_block, - new_state=_InstrumentationBlockStates.UNKNOWN): + self, instrumentation_block, new_state=_InstrumentationBlockStates.UNKNOWN + ): """Transitions and finishes the current instrumentation block. Args: @@ -750,8 +771,9 @@ def _transition_instrumentation_block( test_record = formatter.create_test_record(self.TAG) if test_record: self.results.add_record(test_record) - self.summary_writer.dump(test_record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + test_record.to_dict(), records.TestSummaryEntryType.RECORD + ) return instrumentation_block.transition_state(new_state=new_state) def _parse_method_block_line(self, instrumentation_block, line): @@ -767,16 +789,18 @@ def _parse_method_block_line(self, instrumentation_block, line): parsing instrumentation output. """ if line.startswith(_InstrumentationStructurePrefixes.STATUS): - instrumentation_block.set_key(_InstrumentationStructurePrefixes.STATUS, - line) + instrumentation_block.set_key( + _InstrumentationStructurePrefixes.STATUS, line + ) return instrumentation_block elif line.startswith(_InstrumentationStructurePrefixes.STATUS_CODE): instrumentation_block.set_status_code(line) return self._transition_instrumentation_block(instrumentation_block) elif line.startswith(_InstrumentationStructurePrefixes.RESULT): # Unexpected transition from method block -> result block - instrumentation_block.set_key(_InstrumentationStructurePrefixes.RESULT, - line) + instrumentation_block.set_key( + _InstrumentationStructurePrefixes.RESULT, line + ) return self._parse_result_line( self._transition_instrumentation_block( instrumentation_block, @@ -828,8 +852,10 @@ def _parse_unknown_block_line(self, instrumentation_block, line): ), line, ) - elif (line.startswith(_InstrumentationStructurePrefixes.RESULT) or - _InstrumentationStructurePrefixes.FAILED in line): + elif ( + line.startswith(_InstrumentationStructurePrefixes.RESULT) + or _InstrumentationStructurePrefixes.FAILED in line + ): return self._parse_result_block_line( self._transition_instrumentation_block( instrumentation_block, @@ -882,7 +908,8 @@ def _finish_parsing(self, instrumentation_block): """ formatter = _InstrumentationBlockFormatter(instrumentation_block) return formatter.has_completed_result_block_format( - self.DEFAULT_INSTRUMENTATION_ERROR_MESSAGE) + self.DEFAULT_INSTRUMENTATION_ERROR_MESSAGE + ) def parse_instrumentation_options(self, parameters=None): """Returns the options for the instrumentation test from user_params. @@ -904,17 +931,15 @@ def parse_instrumentation_options(self, parameters=None): filtered_parameters = {} for parameter_key, parameter_value in parameters.items(): if parameter_key.startswith(self.DEFAULT_INSTRUMENTATION_OPTION_PREFIX): - option_key = parameter_key[len(self. - DEFAULT_INSTRUMENTATION_OPTION_PREFIX):] + option_key = parameter_key[ + len(self.DEFAULT_INSTRUMENTATION_OPTION_PREFIX) : + ] filtered_parameters[option_key] = parameter_value return filtered_parameters - def run_instrumentation_test(self, - device, - package, - options=None, - prefix=None, - runner=None): + def run_instrumentation_test( + self, device, package, options=None, prefix=None, runner=None + ): """Runs instrumentation tests on a device and creates test records. Args: @@ -942,19 +967,23 @@ def run_instrumentation_test(self, def parse_instrumentation(raw_line): line = raw_line.rstrip().decode('utf-8') logging.info(line) - instrumentation_block[0] = self._parse_line(instrumentation_block[0], - line) + instrumentation_block[0] = self._parse_line( + instrumentation_block[0], line + ) - device.adb.instrument(package=package, - options=options, - runner=runner, - handler=parse_instrumentation) + device.adb.instrument( + package=package, + options=options, + runner=runner, + handler=parse_instrumentation, + ) return self._finish_parsing(instrumentation_block[0]) -class BaseInstrumentationTestClass(InstrumentationTestMixin, - base_test.BaseTestClass): +class BaseInstrumentationTestClass( + InstrumentationTestMixin, base_test.BaseTestClass +): """Base class for all instrumentation test classes to inherit from. This class extends the BaseTestClass to add functionality to run and parse diff --git a/mobly/base_test.py b/mobly/base_test.py index 9bf4fcc4..ae8d0232 100644 --- a/mobly/base_test.py +++ b/mobly/base_test.py @@ -78,12 +78,14 @@ def repeat(count, max_consecutive_error=None): """ if count <= 1: raise ValueError( - f'The `count` for `repeat` must be larger than 1, got "{count}".') + f'The `count` for `repeat` must be larger than 1, got "{count}".' + ) if max_consecutive_error is not None and max_consecutive_error > count: raise ValueError( f'The `max_consecutive_error` ({max_consecutive_error}) for `repeat` ' - f'must be smaller than `count` ({count}).') + f'must be smaller than `count` ({count}).' + ) def _outer_decorator(func): setattr(func, ATTR_REPEAT_CNT, count) @@ -192,8 +194,10 @@ def __init__(self, configs): self.tests = [] class_identifier = self.__class__.__name__ if configs.test_class_name_suffix: - class_identifier = '%s_%s' % (class_identifier, - configs.test_class_name_suffix) + class_identifier = '%s_%s' % ( + class_identifier, + configs.test_class_name_suffix, + ) if self.TAG is None: self.TAG = class_identifier # Set params. @@ -208,13 +212,13 @@ def __init__(self, configs): self.summary_writer = configs.summary_writer self._generated_test_table = collections.OrderedDict() self._controller_manager = controller_manager.ControllerManager( - class_name=self.TAG, controller_configs=configs.controller_configs) + class_name=self.TAG, controller_configs=configs.controller_configs + ) self.controller_configs = self._controller_manager.controller_configs - def unpack_userparams(self, - req_param_names=None, - opt_param_names=None, - **kwargs): + def unpack_userparams( + self, req_param_names=None, opt_param_names=None, **kwargs + ): """An optional function that unpacks user defined parameters into individual variables. @@ -251,8 +255,9 @@ def unpack_userparams(self, if hasattr(self, name): continue if name not in self.user_params: - raise Error('Missing required user param "%s" in test ' - 'configuration.' % name) + raise Error( + 'Missing required user param "%s" in test configuration.' % name + ) setattr(self, name, self.user_params[name]) for name in opt_param_names: if hasattr(self, name): @@ -261,8 +266,8 @@ def unpack_userparams(self, setattr(self, name, self.user_params[name]) else: logging.warning( - 'Missing optional user param "%s" in ' - 'configuration, continue.', name) + 'Missing optional user param "%s" in configuration, continue.', name + ) def register_controller(self, module, required=True, min_number=1): """Loads a controller module and returns its loaded devices. @@ -337,15 +342,17 @@ def get_info(objects): * `required` is True and no corresponding config can be found. * Any other error occurred in the registration process. """ - return self._controller_manager.register_controller(module, required, - min_number) + return self._controller_manager.register_controller( + module, required, min_number + ) def _record_controller_info(self): # Collect controller information and write to test result. for record in self._controller_manager.get_controller_info_records(): self.results.add_controller_info_record(record) - self.summary_writer.dump(record.to_dict(), - records.TestSummaryEntryType.CONTROLLER_INFO) + self.summary_writer.dump( + record.to_dict(), records.TestSummaryEntryType.CONTROLLER_INFO + ) def _pre_run(self): """Proxy function to guarantee the base implementation of `pre_run` is @@ -358,7 +365,8 @@ def _pre_run(self): record = records.TestResultRecord(stage_name, self.TAG) record.test_begin() self.current_test_info = runtime_test_info.RuntimeTestInfo( - stage_name, self.log_path, record) + stage_name, self.log_path, record + ) try: with self._log_test_stage(stage_name): self.pre_run() @@ -371,8 +379,9 @@ def _pre_run(self): logging.exception('%s failed for %s.', stage_name, self.TAG) record.test_error(e) self.results.add_class_error(record) - self.summary_writer.dump(record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + record.to_dict(), records.TestSummaryEntryType.RECORD + ) return False def pre_run(self): @@ -411,7 +420,8 @@ def _setup_class(self): class_record = records.TestResultRecord(STAGE_NAME_SETUP_CLASS, self.TAG) class_record.test_begin() self.current_test_info = runtime_test_info.RuntimeTestInfo( - STAGE_NAME_SETUP_CLASS, self.log_path, class_record) + STAGE_NAME_SETUP_CLASS, self.log_path, class_record + ) expects.recorder.reset_internal_states(class_record) try: with self._log_test_stage(STAGE_NAME_SETUP_CLASS): @@ -427,16 +437,18 @@ def _setup_class(self): self.results.add_class_error(class_record) self._exec_procedure_func(self._on_fail, class_record) class_record.update_record() - self.summary_writer.dump(class_record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + class_record.to_dict(), records.TestSummaryEntryType.RECORD + ) self._skip_remaining_tests(e) return self.results if expects.recorder.has_error: self._exec_procedure_func(self._on_fail, class_record) class_record.test_error() class_record.update_record() - self.summary_writer.dump(class_record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + class_record.to_dict(), records.TestSummaryEntryType.RECORD + ) self.results.add_class_error(class_record) self._skip_remaining_tests(class_record.termination_signal.exception) return self.results @@ -460,7 +472,8 @@ def _teardown_class(self): record = records.TestResultRecord(stage_name, self.TAG) record.test_begin() self.current_test_info = runtime_test_info.RuntimeTestInfo( - stage_name, self.log_path, record) + stage_name, self.log_path, record + ) expects.recorder.reset_internal_states(record) try: with self._log_test_stage(stage_name): @@ -473,15 +486,17 @@ def _teardown_class(self): record.test_error(e) record.update_record() self.results.add_class_error(record) - self.summary_writer.dump(record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + record.to_dict(), records.TestSummaryEntryType.RECORD + ) else: if expects.recorder.has_error: record.test_error() record.update_record() self.results.add_class_error(record) - self.summary_writer.dump(record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + record.to_dict(), records.TestSummaryEntryType.RECORD + ) finally: self._clean_up() @@ -511,14 +526,18 @@ def _log_test_stage(self, stage_name): if parent_token == stage_name: parent_token = self.TAG logging.debug( - TEST_STAGE_BEGIN_LOG_TEMPLATE.format(parent_token=parent_token, - child_token=stage_name)) + TEST_STAGE_BEGIN_LOG_TEMPLATE.format( + parent_token=parent_token, child_token=stage_name + ) + ) try: yield finally: logging.debug( - TEST_STAGE_END_LOG_TEMPLATE.format(parent_token=parent_token, - child_token=stage_name)) + TEST_STAGE_END_LOG_TEMPLATE.format( + parent_token=parent_token, child_token=stage_name + ) + ) def _setup_test(self, test_name): """Proxy function to guarantee the base implementation of setup_test is @@ -647,8 +666,11 @@ def _exec_procedure_func(self, func, tr_record): except signals.TestAbortSignal: raise except Exception as e: - logging.exception('Exception happened when executing %s for %s.', - procedure_name, self.current_test_info.name) + logging.exception( + 'Exception happened when executing %s for %s.', + procedure_name, + self.current_test_info.name, + ) tr_record.add_error(procedure_name, e) def record_data(self, content): @@ -702,8 +724,9 @@ def should_retry(record): if not should_retry(previous_record): break - def _exec_one_test_with_repeat(self, test_name, test_method, repeat_count, - max_consecutive_error): + def _exec_one_test_with_repeat( + self, test_name, test_method, repeat_count, max_consecutive_error + ): """Repeatedly execute a test case. This method performs the action defined by the `repeat` decorator. @@ -739,8 +762,11 @@ def _exec_one_test_with_repeat(self, test_name, test_method, repeat_count, if consecutive_error_count == max_consecutive_error: logging.error( 'Repeated test case "%s" has consecutively failed %d iterations, ' - 'aborting the remaining %d iterations.', test_name, - consecutive_error_count, repeat_count - 1 - i) + 'aborting the remaining %d iterations.', + test_name, + consecutive_error_count, + repeat_count - 1 - i, + ) return def exec_one_test(self, test_name, test_method, record=None): @@ -768,7 +794,8 @@ def exec_one_test(self, test_name, test_method, record=None): tr_record.uid = getattr(test_method, 'uid', None) tr_record.test_begin() self.current_test_info = runtime_test_info.RuntimeTestInfo( - test_name, self.log_path, tr_record) + test_name, self.log_path, tr_record + ) expects.recorder.reset_internal_states(tr_record) logging.info('%s %s', TEST_CASE_TOKEN, test_name) # Did teardown_test throw an error. @@ -784,8 +811,9 @@ def exec_one_test(self, test_name, test_method, record=None): except (signals.TestPass, signals.TestAbortSignal, signals.TestSkip): raise except Exception: - logging.exception('Exception occurred in %s.', - self.current_test_info.name) + logging.exception( + 'Exception occurred in %s.', self.current_test_info.name + ) raise finally: before_count = expects.recorder.error_count @@ -794,9 +822,11 @@ def exec_one_test(self, test_name, test_method, record=None): except signals.TestAbortSignal: raise except Exception as e: - logging.exception('Exception occurred in %s of %s.', - STAGE_NAME_TEARDOWN_TEST, - self.current_test_info.name) + logging.exception( + 'Exception occurred in %s of %s.', + STAGE_NAME_TEARDOWN_TEST, + self.current_test_info.name, + ) tr_record.test_error() tr_record.add_error(STAGE_NAME_TEARDOWN_TEST, e) teardown_test_failed = True @@ -831,32 +861,37 @@ def exec_one_test(self, test_name, test_method, record=None): finally: tr_record.update_record() try: - if tr_record.result in (records.TestResultEnums.TEST_RESULT_ERROR, - records.TestResultEnums.TEST_RESULT_FAIL): + if tr_record.result in ( + records.TestResultEnums.TEST_RESULT_ERROR, + records.TestResultEnums.TEST_RESULT_FAIL, + ): self._exec_procedure_func(self._on_fail, tr_record) elif tr_record.result == records.TestResultEnums.TEST_RESULT_PASS: self._exec_procedure_func(self._on_pass, tr_record) elif tr_record.result == records.TestResultEnums.TEST_RESULT_SKIP: self._exec_procedure_func(self._on_skip, tr_record) finally: - logging.info(RESULT_LINE_TEMPLATE, tr_record.test_name, - tr_record.result) + logging.info( + RESULT_LINE_TEMPLATE, tr_record.test_name, tr_record.result + ) self.results.add_record(tr_record) - self.summary_writer.dump(tr_record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + tr_record.to_dict(), records.TestSummaryEntryType.RECORD + ) self.current_test_info = None return tr_record def _assert_function_names_in_stack(self, expected_func_names): - """Asserts that the current stack contains any of the given function names. - """ + """Asserts that the current stack contains any of the given function names.""" current_frame = inspect.currentframe() caller_frames = inspect.getouterframes(current_frame, 2) for caller_frame in caller_frames[2:]: if caller_frame[3] in expected_func_names: return - raise Error(f"'{caller_frames[1][3]}' cannot be called outside of the " - f"following functions: {expected_func_names}.") + raise Error( + f"'{caller_frames[1][3]}' cannot be called outside of the " + f'following functions: {expected_func_names}.' + ) def generate_tests(self, test_logic, name_func, arg_sets, uid_func=None): """Generates tests in the test class. @@ -884,20 +919,26 @@ def generate_tests(self, test_logic, name_func, arg_sets, uid_func=None): is the corresponding UID. """ self._assert_function_names_in_stack( - [STAGE_NAME_PRE_RUN, STAGE_NAME_SETUP_GENERATED_TESTS]) + [STAGE_NAME_PRE_RUN, STAGE_NAME_SETUP_GENERATED_TESTS] + ) root_msg = 'During test generation of "%s":' % test_logic.__name__ for args in arg_sets: test_name = name_func(*args) if test_name in self.get_existing_test_names(): - raise Error('%s Test name "%s" already exists, cannot be duplicated!' % - (root_msg, test_name)) + raise Error( + '%s Test name "%s" already exists, cannot be duplicated!' + % (root_msg, test_name) + ) test_func = functools.partial(test_logic, *args) # If the `test_logic` method is decorated by `retry` or `repeat` # decorators, copy the attributes added by the decorators to the # generated test methods as well, so the generated test methods # also have the retry/repeat behavior. - for attr_name in (ATTR_MAX_RETRY_CNT, ATTR_MAX_CONSEC_ERROR, - ATTR_REPEAT_CNT): + for attr_name in ( + ATTR_MAX_RETRY_CNT, + ATTR_MAX_CONSEC_ERROR, + ATTR_REPEAT_CNT, + ): attr = getattr(test_logic, attr_name, None) if attr is not None: setattr(test_func, attr_name, attr) @@ -927,8 +968,9 @@ def _safe_exec_func(self, func, *args): except signals.TestAbortAll: raise except Exception: - logging.exception('Exception happened when executing %s in %s.', - func.__name__, self.TAG) + logging.exception( + 'Exception happened when executing %s in %s.', func.__name__, self.TAG + ) def get_existing_test_names(self): """Gets the names of existing tests in the class. @@ -966,8 +1008,10 @@ def _get_test_methods(self, test_names): test_methods = [] for test_name in test_names: if not test_name.startswith('test_'): - raise Error('Test method name %s does not follow naming ' - 'convention test_*, abort.' % test_name) + raise Error( + 'Test method name %s does not follow naming ' + 'convention test_*, abort.' % test_name + ) if hasattr(self, test_name): test_method = getattr(self, test_name) elif test_name in self._generated_test_table: @@ -992,8 +1036,9 @@ def _skip_remaining_tests(self, exception): test_record = records.TestResultRecord(test_name, self.TAG) test_record.test_skip(exception) self.results.add_record(test_record) - self.summary_writer.dump(test_record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + test_record.to_dict(), records.TestSummaryEntryType.RECORD + ) def run(self, test_names=None): """Runs tests within a test class. @@ -1029,8 +1074,10 @@ def run(self, test_names=None): # No test method specified by user, execute all in test class. test_names = self.get_existing_test_names() self.results.requested = test_names - self.summary_writer.dump(self.results.requested_test_names_dict(), - records.TestSummaryEntryType.TEST_NAME_LIST) + self.summary_writer.dump( + self.results.requested_test_names_dict(), + records.TestSummaryEntryType.TEST_NAME_LIST, + ) tests = self._get_test_methods(test_names) try: setup_class_result = self._setup_class() @@ -1042,11 +1089,13 @@ def run(self, test_names=None): repeat_count = getattr(test_method, ATTR_REPEAT_CNT, 0) max_retry_count = getattr(test_method, ATTR_MAX_RETRY_CNT, 0) if max_retry_count: - self._exec_one_test_with_retry(test_name, test_method, - max_retry_count) + self._exec_one_test_with_retry( + test_name, test_method, max_retry_count + ) elif repeat_count: - self._exec_one_test_with_repeat(test_name, test_method, repeat_count, - max_consecutive_error) + self._exec_one_test_with_repeat( + test_name, test_method, repeat_count, max_consecutive_error + ) else: self.exec_one_test(test_name, test_method) return self.results @@ -1063,8 +1112,9 @@ def run(self, test_names=None): raise e finally: self._teardown_class() - logging.info('Summary for test class %s: %s', self.TAG, - self.results.summary_str()) + logging.info( + 'Summary for test class %s: %s', self.TAG, self.results.summary_str() + ) def _clean_up(self): """The final stage of a test class execution.""" @@ -1072,7 +1122,8 @@ def _clean_up(self): record = records.TestResultRecord(stage_name, self.TAG) record.test_begin() self.current_test_info = runtime_test_info.RuntimeTestInfo( - stage_name, self.log_path, record) + stage_name, self.log_path, record + ) expects.recorder.reset_internal_states(record) with self._log_test_stage(stage_name): # Write controller info and summary to summary file. @@ -1082,5 +1133,6 @@ def _clean_up(self): record.test_error() record.update_record() self.results.add_class_error(record) - self.summary_writer.dump(record.to_dict(), - records.TestSummaryEntryType.RECORD) + self.summary_writer.dump( + record.to_dict(), records.TestSummaryEntryType.RECORD + ) diff --git a/mobly/config_parser.py b/mobly/config_parser.py index 2f2da912..a9aae599 100644 --- a/mobly/config_parser.py +++ b/mobly/config_parser.py @@ -39,8 +39,9 @@ def _validate_test_config(test_config): """ required_key = keys.Config.key_testbed.value if required_key not in test_config: - raise MoblyConfigError('Required key %s missing in test config.' % - required_key) + raise MoblyConfigError( + 'Required key %s missing in test config.' % required_key + ) def _validate_testbed_name(name): @@ -60,8 +61,9 @@ def _validate_testbed_name(name): name = str(name) for char in name: if char not in utils.valid_filename_chars: - raise MoblyConfigError('Char "%s" is not allowed in test bed names.' % - char) + raise MoblyConfigError( + 'Char "%s" is not allowed in test bed names.' % char + ) def _validate_testbed_configs(testbed_configs): @@ -111,7 +113,8 @@ def load_test_config_file(test_config_path, tb_filters=None): if len(tbs) != len(tb_filters): raise MoblyConfigError( 'Expect to find %d test bed configs, found %d. Check if' - ' you have the correct test bed names.' % (len(tb_filters), len(tbs))) + ' you have the correct test bed names.' % (len(tb_filters), len(tbs)) + ) configs[keys.Config.key_testbed.value] = tbs mobly_params = configs.get(keys.Config.key_mobly_params.value, {}) # Decide log path. @@ -127,14 +130,17 @@ def load_test_config_file(test_config_path, tb_filters=None): for original_bed_config in configs[keys.Config.key_testbed.value]: test_run_config = TestRunConfig() test_run_config.testbed_name = original_bed_config[ - keys.Config.key_testbed_name.value] + keys.Config.key_testbed_name.value + ] # Deprecated, use testbed_name test_run_config.test_bed_name = test_run_config.testbed_name test_run_config.log_path = log_path test_run_config.controller_configs = original_bed_config.get( - keys.Config.key_testbed_controllers.value, {}) + keys.Config.key_testbed_controllers.value, {} + ) test_run_config.user_params = original_bed_config.get( - keys.Config.key_testbed_test_params.value, {}) + keys.Config.key_testbed_test_params.value, {} + ) test_configs.append(test_run_config) return test_configs @@ -186,8 +192,7 @@ def __init__(self): self.test_class_name_suffix = None def copy(self): - """Returns a deep copy of the current config. - """ + """Returns a deep copy of the current config.""" return copy.deepcopy(self) def __str__(self): diff --git a/mobly/controller_manager.py b/mobly/controller_manager.py index f19da27b..c4633e77 100644 --- a/mobly/controller_manager.py +++ b/mobly/controller_manager.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -""" Module for Mobly controller management.""" +"""Module for Mobly controller management.""" import collections import copy import logging @@ -41,12 +41,14 @@ def verify_controller_module(module): for attr in required_attributes: if not hasattr(module, attr): raise signals.ControllerError( - 'Module %s missing required controller module attribute' - ' %s.' % (module.__name__, attr)) + 'Module %s missing required controller module attribute %s.' + % (module.__name__, attr) + ) if not getattr(module, attr): raise signals.ControllerError( - 'Controller interface %s in %s cannot be null.' % - (attr, module.__name__)) + 'Controller interface %s in %s cannot be null.' + % (attr, module.__name__) + ) class ControllerManager: @@ -62,7 +64,8 @@ class ControllerManager: def __init__(self, class_name, controller_configs): # Controller object management. - self._controller_objects = collections.OrderedDict( + self._controller_objects = ( + collections.OrderedDict() ) # controller_name: objects self._controller_modules = {} # controller_name: module self._class_name = class_name @@ -102,16 +105,19 @@ def register_controller(self, module, required=True, min_number=1): if module_ref_name in self._controller_objects: raise signals.ControllerError( 'Controller module %s has already been registered. It cannot ' - 'be registered again.' % module_ref_name) + 'be registered again.' % module_ref_name + ) # Create controller objects. module_config_name = module.MOBLY_CONTROLLER_CONFIG_NAME if module_config_name not in self.controller_configs: if required: - raise signals.ControllerError('No corresponding config found for %s' % - module_config_name) + raise signals.ControllerError( + 'No corresponding config found for %s' % module_config_name + ) logging.warning( 'No corresponding config found for optional controller %s', - module_config_name) + module_config_name, + ) return None try: # Make a deep copy of the config to pass to the controller module, @@ -122,24 +128,28 @@ def register_controller(self, module, required=True, min_number=1): except Exception: logging.exception( 'Failed to initialize objects for controller %s, abort!', - module_config_name) + module_config_name, + ) raise if not isinstance(objects, list): raise signals.ControllerError( - 'Controller module %s did not return a list of objects, abort.' % - module_ref_name) + 'Controller module %s did not return a list of objects, abort.' + % module_ref_name + ) # Check we got enough controller objects to continue. actual_number = len(objects) if actual_number < min_number: module.destroy(objects) raise signals.ControllerError( - 'Expected to get at least %d controller objects, got %d.' % - (min_number, actual_number)) + 'Expected to get at least %d controller objects, got %d.' + % (min_number, actual_number) + ) # Save a shallow copy of the list for internal usage, so tests can't # affect internal registry by manipulating the object list. self._controller_objects[module_ref_name] = copy.copy(objects) - logging.debug('Found %d objects for controller %s', len(objects), - module_config_name) + logging.debug( + 'Found %d objects for controller %s', len(objects), module_config_name + ) self._controller_modules[module_ref_name] = module return objects @@ -174,22 +184,27 @@ def _create_controller_info_record(self, controller_module_name): controller_info = None try: controller_info = module.get_info( - copy.copy(self._controller_objects[controller_module_name])) + copy.copy(self._controller_objects[controller_module_name]) + ) except AttributeError: logging.warning( 'No optional debug info found for controller ' - '%s. To provide it, implement `get_info`.', controller_module_name) + '%s. To provide it, implement `get_info`.', + controller_module_name, + ) try: yaml.dump(controller_info) except TypeError: logging.warning( 'The info of controller %s in class "%s" is not ' - 'YAML serializable! Coercing it to string.', controller_module_name, - self._class_name) + 'YAML serializable! Coercing it to string.', + controller_module_name, + self._class_name, + ) controller_info = str(controller_info) - return records.ControllerInfoRecord(self._class_name, - module.MOBLY_CONTROLLER_CONFIG_NAME, - controller_info) + return records.ControllerInfoRecord( + self._class_name, module.MOBLY_CONTROLLER_CONFIG_NAME, controller_info + ) def get_controller_info_records(self): """Get the info records for all the controller objects in the manager. @@ -204,7 +219,8 @@ def get_controller_info_records(self): info_records = [] for controller_module_name in self._controller_objects.keys(): with expects.expect_no_raises( - 'Failed to collect controller info from %s' % controller_module_name): + 'Failed to collect controller info from %s' % controller_module_name + ): record = self._create_controller_info_record(controller_module_name) if record: info_records.append(record) diff --git a/mobly/controllers/android_device.py b/mobly/controllers/android_device.py index 0c2487df..981af276 100644 --- a/mobly/controllers/android_device.py +++ b/mobly/controllers/android_device.py @@ -149,12 +149,17 @@ def _validate_device_existence(serials): serials: list of strings, the serials of all the devices that are expected to exist. """ - valid_ad_identifiers = (list_adb_devices() + list_adb_devices_by_usb_id() + - list_fastboot_devices()) + valid_ad_identifiers = ( + list_adb_devices() + + list_adb_devices_by_usb_id() + + list_fastboot_devices() + ) for serial in serials: if serial not in valid_ad_identifiers: - raise Error(f'Android device serial "{serial}" is specified in ' - 'config but is not reachable.') + raise Error( + f'Android device serial "{serial}" is specified in ' + 'config but is not reachable.' + ) def _start_services_on_ads(ads): @@ -172,15 +177,18 @@ def _start_services_on_ads(ads): if start_logcat: ad.services.logcat.start() except Exception: - is_required = getattr(ad, KEY_DEVICE_REQUIRED, - DEFAULT_VALUE_DEVICE_REQUIRED) + is_required = getattr( + ad, KEY_DEVICE_REQUIRED, DEFAULT_VALUE_DEVICE_REQUIRED + ) if is_required: ad.log.exception('Failed to start some services, abort!') destroy(ads) raise else: - ad.log.exception('Skipping this optional device because some ' - 'services failed to start.') + ad.log.exception( + 'Skipping this optional device because some ' + 'services failed to start.' + ) def parse_device_list(device_list_str, key=None): @@ -201,7 +209,7 @@ def parse_device_list(device_list_str, key=None): try: clean_lines = str(device_list_str, 'utf-8').strip().split('\n') except UnicodeDecodeError: - logging.warning("unicode decode error, origin str: %s", device_list_str) + logging.warning('unicode decode error, origin str: %s', device_list_str) raise results = [] for line in clean_lines: @@ -291,7 +299,8 @@ def get_instances_with_configs(configs): serials.append(c['serial']) except KeyError: raise Error( - 'Required value "serial" is missing in AndroidDevice config %s.' % c) + 'Required value "serial" is missing in AndroidDevice config %s.' % c + ) _validate_device_existence(serials) results = [] for c in configs: @@ -373,8 +382,9 @@ def _get_device_filter(ad): filtered = filter_devices(ads, _get_device_filter) if not filtered: - raise Error('Could not find a target device that matches condition: %s.' % - kwargs) + raise Error( + 'Could not find a target device that matches condition: %s.' % kwargs + ) else: return filtered @@ -429,9 +439,9 @@ def take_bug_reports(ads, test_name=None, begin_time=None, destination=None): begin_time = mobly_logger.sanitize_filename(str(begin_time)) def take_br(test_name, begin_time, ad, destination): - ad.take_bug_report(test_name=test_name, - begin_time=begin_time, - destination=destination) + ad.take_bug_report( + test_name=test_name, begin_time=begin_time, destination=destination + ) args = [(test_name, begin_time, ad, destination) for ad in ads] utils.concurrent_exec(take_br, args) @@ -450,7 +460,10 @@ class BuildInfoConstants(enum.Enum): BUILD_TYPE = 'build_type', 'ro.build.type' BUILD_FINGERPRINT = 'build_fingerprint', 'ro.build.fingerprint' BUILD_VERSION_CODENAME = 'build_version_codename', 'ro.build.version.codename' - BUILD_VERSION_INCREMENTAL = 'build_version_incremental', 'ro.build.version.incremental' + BUILD_VERSION_INCREMENTAL = ( + 'build_version_incremental', + 'ro.build.version.incremental', + ) BUILD_VERSION_SDK = 'build_version_sdk', 'ro.build.version.sdk' BUILD_PRODUCT = 'build_product', 'ro.build.product' BUILD_CHARACTERISTICS = 'build_characteristics', 'ro.build.characteristics' @@ -494,11 +507,13 @@ def __init__(self, serial=''): self._serial = str(serial) # logging.log_path only exists when this is used in an Mobly test run. _log_path_base = utils.abs_path(getattr(logging, 'log_path', '/tmp/logs')) - self._log_path = os.path.join(_log_path_base, - 'AndroidDevice%s' % self._normalized_serial) + self._log_path = os.path.join( + _log_path_base, 'AndroidDevice%s' % self._normalized_serial + ) self._debug_tag = self._serial - self.log = AndroidDeviceLoggerAdapter(logging.getLogger(), - {'tag': self.debug_tag}) + self.log = AndroidDeviceLoggerAdapter( + logging.getLogger(), {'tag': self.debug_tag} + ) self._build_info = None self._is_rebooting = False self.adb = adb.AdbProxy(serial) @@ -506,11 +521,12 @@ def __init__(self, serial=''): if self.is_rootable: self.root_adb() self.services = service_manager.ServiceManager(self) - self.services.register(SERVICE_NAME_LOGCAT, - logcat.Logcat, - start_service=False) - self.services.register('snippets', - snippet_management_service.SnippetManagementService) + self.services.register( + SERVICE_NAME_LOGCAT, logcat.Logcat, start_service=False + ) + self.services.register( + 'snippets', snippet_management_service.SnippetManagementService + ) # Device info cache. self._user_added_device_info = {} @@ -544,7 +560,7 @@ def device_info(self): 'serial': self.serial, 'model': self.model, 'build_info': self.build_info, - 'user_added_info': self._user_added_device_info + 'user_added_info': self._user_added_device_info, } return info @@ -621,8 +637,7 @@ def has_active_service(self): @property def log_path(self): - """A string that is the path for all logs collected from this device. - """ + """A string that is the path for all logs collected from this device.""" if not os.path.exists(self._log_path): utils.create_dir(self._log_path) return self._log_path @@ -632,13 +647,15 @@ def log_path(self, new_path): """Setter for `log_path`, use with caution.""" if self.has_active_service: raise DeviceError( - self, 'Cannot change `log_path` when there is service running.') + self, 'Cannot change `log_path` when there is service running.' + ) old_path = self._log_path if new_path == old_path: return if os.listdir(new_path): - raise DeviceError(self, - 'Logs already exist at %s, cannot override.' % new_path) + raise DeviceError( + self, 'Logs already exist at %s, cannot override.' % new_path + ) if os.path.exists(old_path): # Remove new path so copytree doesn't complain. shutil.rmtree(new_path, ignore_errors=True) @@ -682,7 +699,8 @@ def update_serial(self, new_serial): if self.has_active_service: raise DeviceError( self, - 'Cannot change device serial number when there is service running.') + 'Cannot change device serial number when there is service running.', + ) if self._debug_tag == self.serial: self._debug_tag = new_serial self._serial = new_serial @@ -802,21 +820,20 @@ def build_info(self): build_info = self.adb.getprops(CACHED_SYSTEM_PROPS) for build_info_constant in BuildInfoConstants: info[build_info_constant.build_info_key] = build_info.get( - build_info_constant.system_prop_key, '') + build_info_constant.system_prop_key, '' + ) self._build_info = info return info return self._build_info @property def is_bootloader(self): - """True if the device is in bootloader mode. - """ + """True if the device is in bootloader mode.""" return self.serial in list_fastboot_devices() @property def is_adb_root(self): - """True if adb is running as root for this device. - """ + """True if adb is running as root for this device.""" try: return '0' == self.adb.shell('id -u').decode('utf-8').strip() except adb.AdbError: @@ -830,8 +847,7 @@ def is_rootable(self): @property def model(self): - """The Android code name for the device. - """ + """The Android code name for the device.""" # If device is in bootloader mode, get mode name from fastboot. if self.is_bootloader: out = self.fastboot.getvar('product').strip() @@ -886,8 +902,10 @@ def load_config(self, config): for k, v in config.items(): if hasattr(self, k) and k not in _ANDROID_DEVICE_SETTABLE_PROPS: raise DeviceError( - self, ('Attribute %s already exists with value %s, cannot set ' - 'again.') % (k, getattr(self, k))) + self, + 'Attribute %s already exists with value %s, cannot set again.' + % (k, getattr(self, k)), + ) setattr(self, k, v) def root_adb(self): @@ -928,7 +946,8 @@ class for supported configurations. if hasattr(self, name): raise SnippetError( self, - 'Attribute "%s" already exists, please use a different name.' % name) + 'Attribute "%s" already exists, please use a different name.' % name, + ) self.services.snippets.add_snippet_client(name, package, config=config) def unload_snippet(self, name): @@ -942,10 +961,9 @@ def unload_snippet(self, name): """ self.services.snippets.remove_snippet_client(name) - def generate_filename(self, - file_type, - time_identifier=None, - extension_name=None): + def generate_filename( + self, file_type, time_identifier=None, extension_name=None + ): """Generates a name for an output file related to this device. The name follows the pattern: @@ -982,11 +1000,9 @@ def generate_filename(self, self.log.debug('Generated filename: %s', filename_str) return filename_str - def take_bug_report(self, - test_name=None, - begin_time=None, - timeout=300, - destination=None): + def take_bug_report( + self, test_name=None, begin_time=None, timeout=300, destination=None + ): """Takes a bug report on the device and stores it in a file. Args: @@ -1054,8 +1070,9 @@ def take_screenshot(self, destination, prefix='screenshot'): """ filename = self.generate_filename(prefix, extension_name='png') device_path = os.path.join('/storage/emulated/0/', filename) - self.adb.shell(['screencap', '-p', device_path], - timeout=TAKE_SCREENSHOT_TIMEOUT_SECOND) + self.adb.shell( + ['screencap', '-p', device_path], timeout=TAKE_SCREENSHOT_TIMEOUT_SECOND + ) utils.create_dir(destination) self.adb.pull([device_path, destination]) pic_path = os.path.join(destination, filename) @@ -1084,8 +1101,9 @@ def run_iperf_client(self, server_host, extra_args=''): return False, clean_out return True, clean_out - def wait_for_boot_completion(self, - timeout=DEFAULT_TIMEOUT_BOOT_COMPLETION_SECOND): + def wait_for_boot_completion( + self, timeout=DEFAULT_TIMEOUT_BOOT_COMPLETION_SECOND + ): """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED. This function times out after 15 minutes. diff --git a/mobly/controllers/android_device_lib/adb.py b/mobly/controllers/android_device_lib/adb.py index 8b55b656..d8132450 100644 --- a/mobly/controllers/android_device_lib/adb.py +++ b/mobly/controllers/android_device_lib/adb.py @@ -33,7 +33,9 @@ ADB_ROOT_RETRY_ATTEMPT_INTERVAL_SEC = 10 # Qualified class name of the default instrumentation test runner. -DEFAULT_INSTRUMENTATION_RUNNER = 'com.android.common.support.test.runner.AndroidJUnitRunner' +DEFAULT_INSTRUMENTATION_RUNNER = ( + 'com.android.common.support.test.runner.AndroidJUnitRunner' +) # `adb shell getprop` can take surprisingly long, when the device is a # networked virtual device. @@ -43,7 +45,8 @@ # The regex pattern indicating the `adb connect` command did not fail. PATTERN_ADB_CONNECT_SUCCESS = re.compile( - r'^connected to .*|^already connected to .*') + r'^connected to .*|^already connected to .*' +) class Error(Exception): @@ -72,9 +75,12 @@ def __init__(self, cmd, stdout, stderr, ret_code, serial=''): self.serial = serial def __str__(self): - return ('Error executing adb cmd "%s". ret: %d, stdout: %s, stderr: %s') % ( - utils.cli_cmd_to_string( - self.cmd), self.ret_code, self.stdout, self.stderr) + return 'Error executing adb cmd "%s". ret: %d, stdout: %s, stderr: %s' % ( + utils.cli_cmd_to_string(self.cmd), + self.ret_code, + self.stdout, + self.stderr, + ) class AdbTimeoutError(Error): @@ -96,7 +102,9 @@ def __init__(self, cmd, timeout, serial=''): def __str__(self): return 'Timed out executing command "%s" after %ss.' % ( - utils.cli_cmd_to_string(self.cmd), self.timeout) + utils.cli_cmd_to_string(self.cmd), + self.timeout, + ) def is_adb_available(): @@ -190,16 +198,19 @@ def _exec_cmd(self, args, shell, timeout, stderr) -> bytes: if stderr: stderr.write(err) - logging.debug('cmd: %s, stdout: %s, stderr: %s, ret: %s', - utils.cli_cmd_to_string(args), out, err, ret) + logging.debug( + 'cmd: %s, stdout: %s, stderr: %s, ret: %s', + utils.cli_cmd_to_string(args), + out, + err, + ret, + ) if ret == 0: return out else: - raise AdbError(cmd=args, - stdout=out, - stderr=err, - ret_code=ret, - serial=self.serial) + raise AdbError( + cmd=args, stdout=out, stderr=err, ret_code=ret, serial=self.serial + ) def _execute_and_process_stdout(self, args, shell, handler) -> bytes: """Executes adb commands and processes the stdout with a handler. @@ -217,11 +228,13 @@ def _execute_and_process_stdout(self, args, shell, handler) -> bytes: Raises: AdbError: The adb command exit code is not 0. """ - proc = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=shell, - bufsize=1) + proc = subprocess.Popen( + args, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=shell, + bufsize=1, + ) out = '[elided, processed via handler]' try: # Even if the process dies, stdout.readline still works @@ -241,8 +254,13 @@ def _execute_and_process_stdout(self, args, shell, handler) -> bytes: handler(line) ret = proc.returncode - logging.debug('cmd: %s, stdout: %s, stderr: %s, ret: %s', - utils.cli_cmd_to_string(args), out, err, ret) + logging.debug( + 'cmd: %s, stdout: %s, stderr: %s, ret: %s', + utils.cli_cmd_to_string(args), + out, + err, + ret, + ) if ret == 0: return err else: @@ -291,12 +309,13 @@ def _exec_adb_cmd(self, name, args, shell, timeout, stderr) -> bytes: out = self._exec_cmd(adb_cmd, shell=shell, timeout=timeout, stderr=stderr) return out - def _execute_adb_and_process_stdout(self, name, args, shell, - handler) -> bytes: + def _execute_adb_and_process_stdout( + self, name, args, shell, handler + ) -> bytes: adb_cmd = self._construct_adb_cmd(name, args, shell=shell) - err = self._execute_and_process_stdout(adb_cmd, - shell=shell, - handler=handler) + err = self._execute_and_process_stdout( + adb_cmd, shell=shell, handler=handler + ) return err def _parse_getprop_output(self, output): @@ -357,16 +376,13 @@ def connect(self, address) -> bytes: Raises: AdbError: if the connection failed. """ - stdout = self._exec_adb_cmd('connect', - address, - shell=False, - timeout=None, - stderr=None) + stdout = self._exec_adb_cmd( + 'connect', address, shell=False, timeout=None, stderr=None + ) if PATTERN_ADB_CONNECT_SUCCESS.match(stdout.decode('utf-8')) is None: - raise AdbError(cmd=f'connect {address}', - stdout=stdout, - stderr='', - ret_code=0) + raise AdbError( + cmd=f'connect {address}', stdout=stdout, stderr='', ret_code=0 + ) return stdout def getprop(self, prop_name, timeout=DEFAULT_GETPROP_TIMEOUT_SEC): @@ -383,8 +399,11 @@ def getprop(self, prop_name, timeout=DEFAULT_GETPROP_TIMEOUT_SEC): A string that is the value of the property, or None if the property doesn't exist. """ - return self.shell(['getprop', prop_name], - timeout=timeout).decode('utf-8').strip() + return ( + self.shell(['getprop', prop_name], timeout=timeout) + .decode('utf-8') + .strip() + ) def getprops(self, prop_names): """Get multiple properties of the device. @@ -436,17 +455,13 @@ def has_shell_command(self, command) -> bool: def forward(self, args=None, shell=False) -> bytes: with ADB_PORT_LOCK: - return self._exec_adb_cmd('forward', - args, - shell, - timeout=None, - stderr=None) - - def instrument(self, - package, - options=None, - runner=None, - handler=None) -> bytes: + return self._exec_adb_cmd( + 'forward', args, shell, timeout=None, stderr=None + ) + + def instrument( + self, package, options=None, runner=None, handler=None + ) -> bytes: """Runs an instrumentation command on the device. This is a convenience wrapper to avoid parameter formatting. @@ -487,21 +502,28 @@ def instrument(self, options_list.append('-e %s %s' % (option_key, option_value)) options_string = ' '.join(options_list) - instrumentation_command = 'am instrument -r -w %s %s/%s' % (options_string, - package, runner) - logging.info('AndroidDevice|%s: Executing adb shell %s', self.serial, - instrumentation_command) + instrumentation_command = 'am instrument -r -w %s %s/%s' % ( + options_string, + package, + runner, + ) + logging.info( + 'AndroidDevice|%s: Executing adb shell %s', + self.serial, + instrumentation_command, + ) if handler is None: - return self._exec_adb_cmd('shell', - instrumentation_command, - shell=False, - timeout=None, - stderr=None) + return self._exec_adb_cmd( + 'shell', + instrumentation_command, + shell=False, + timeout=None, + stderr=None, + ) else: - return self._execute_adb_and_process_stdout('shell', - instrumentation_command, - shell=False, - handler=handler) + return self._execute_adb_and_process_stdout( + 'shell', instrumentation_command, shell=False, handler=handler + ) def root(self) -> bytes: """Enables ADB root mode on the device. @@ -520,16 +542,18 @@ def root(self) -> bytes: retry_interval = ADB_ROOT_RETRY_ATTEMPT_INTERVAL_SEC for attempt in range(ADB_ROOT_RETRY_ATTEMPTS): try: - return self._exec_adb_cmd('root', - args=None, - shell=False, - timeout=None, - stderr=None) + return self._exec_adb_cmd( + 'root', args=None, shell=False, timeout=None, stderr=None + ) except AdbError as e: if attempt + 1 < ADB_ROOT_RETRY_ATTEMPTS: - logging.debug('Retry the command "%s" since Error "%s" occurred.' % - (utils.cli_cmd_to_string( - e.cmd), e.stderr.decode('utf-8').strip())) + logging.debug( + 'Retry the command "%s" since Error "%s" occurred.' + % ( + utils.cli_cmd_to_string(e.cmd), + e.stderr.decode('utf-8').strip(), + ) + ) # Buffer between "adb root" commands. time.sleep(retry_interval) retry_interval *= 2 @@ -537,7 +561,6 @@ def root(self) -> bytes: raise e def __getattr__(self, name): - def adb_call(args=None, shell=False, timeout=None, stderr=None) -> bytes: """Wrapper for an ADB command. @@ -554,10 +577,8 @@ def adb_call(args=None, shell=False, timeout=None, stderr=None) -> bytes: Returns: The output of the adb command run if exit code is 0. """ - return self._exec_adb_cmd(name, - args, - shell=shell, - timeout=timeout, - stderr=stderr) + return self._exec_adb_cmd( + name, args, shell=shell, timeout=timeout, stderr=stderr + ) return adb_call diff --git a/mobly/controllers/android_device_lib/callback_handler.py b/mobly/controllers/android_device_lib/callback_handler.py index c783b717..711c92af 100644 --- a/mobly/controllers/android_device_lib/callback_handler.py +++ b/mobly/controllers/android_device_lib/callback_handler.py @@ -21,7 +21,8 @@ logging.warning( 'The module mobly.controllers.android_device_lib.callback_handler is ' 'deprecated and will be removed in a future version. Use module ' - 'mobly.controllers.android_device_lib.callback_handler_v2 instead.') + 'mobly.controllers.android_device_lib.callback_handler_v2 instead.' +) # The max timeout cannot be larger than the max time the socket waits for a # response message. Otherwise, the socket would timeout before the Rpc call @@ -91,8 +92,9 @@ def _callEventWaitAndGet(self, callback_id, event_name, timeout): """ # Convert to milliseconds for Java side. timeout_ms = int(timeout * 1000) - return self._event_client.eventWaitAndGet(callback_id, event_name, - timeout_ms) + return self._event_client.eventWaitAndGet( + callback_id, event_name, timeout_ms + ) def _callEventGetAll(self, callback_id, event_name): """Calls snippet lib's eventGetAll. @@ -128,15 +130,19 @@ def waitAndGet(self, event_name, timeout=DEFAULT_TIMEOUT): if timeout: if timeout > MAX_TIMEOUT: raise Error( - self._ad, 'Specified timeout %s is longer than max timeout %s.' % - (timeout, MAX_TIMEOUT)) + self._ad, + 'Specified timeout %s is longer than max timeout %s.' + % (timeout, MAX_TIMEOUT), + ) try: raw_event = self._callEventWaitAndGet(self._id, event_name, timeout) except Exception as e: if 'EventSnippetException: timeout.' in str(e): raise TimeoutError( - self._ad, 'Timed out after waiting %ss for event "%s" triggered by' - ' %s (%s).' % (timeout, event_name, self._method_name, self._id)) + self._ad, + 'Timed out after waiting %ss for event "%s" triggered by %s (%s).' + % (timeout, event_name, self._method_name, self._id), + ) raise return snippet_event.from_dict(raw_event) @@ -186,7 +192,8 @@ def waitForEvent(self, event_name, predicate, timeout=DEFAULT_TIMEOUT): raise TimeoutError( self._ad, 'Timed out after %ss waiting for an "%s" event that satisfies the ' - 'predicate "%s".' % (timeout, event_name, predicate.__name__)) + 'predicate "%s".' % (timeout, event_name, predicate.__name__), + ) def getAll(self, event_name): """Gets all the events of a certain name that have been received so diff --git a/mobly/controllers/android_device_lib/callback_handler_v2.py b/mobly/controllers/android_device_lib/callback_handler_v2.py index 5675f7ad..d1f9e8f7 100644 --- a/mobly/controllers/android_device_lib/callback_handler_v2.py +++ b/mobly/controllers/android_device_lib/callback_handler_v2.py @@ -42,14 +42,19 @@ def callEventWaitAndGetRpc(self, callback_id, event_name, timeout_sec): """ timeout_ms = int(timeout_sec * 1000) try: - return self._event_client.eventWaitAndGet(callback_id, event_name, - timeout_ms) + return self._event_client.eventWaitAndGet( + callback_id, event_name, timeout_ms + ) except Exception as e: if TIMEOUT_ERROR_MESSAGE in str(e): raise errors.CallbackHandlerTimeoutError( - self._device, (f'Timed out after waiting {timeout_sec}s for event ' - f'"{event_name}" triggered by {self._method_name} ' - f'({self.callback_id}).')) from e + self._device, + ( + f'Timed out after waiting {timeout_sec}s for event ' + f'"{event_name}" triggered by {self._method_name} ' + f'({self.callback_id}).' + ), + ) from e raise def callEventGetAllRpc(self, callback_id, event_name): diff --git a/mobly/controllers/android_device_lib/errors.py b/mobly/controllers/android_device_lib/errors.py index 9434cbc9..1f9156e5 100644 --- a/mobly/controllers/android_device_lib/errors.py +++ b/mobly/controllers/android_device_lib/errors.py @@ -42,6 +42,7 @@ class ServiceError(DeviceError): A service is inherently associated with a device instance, so the service error type is a subtype of `DeviceError`. """ + SERVICE_TYPE = None def __init__(self, device, msg): diff --git a/mobly/controllers/android_device_lib/event_dispatcher.py b/mobly/controllers/android_device_lib/event_dispatcher.py index 26db9111..80610eff 100644 --- a/mobly/controllers/android_device_lib/event_dispatcher.py +++ b/mobly/controllers/android_device_lib/event_dispatcher.py @@ -25,18 +25,15 @@ class EventDispatcherError(Exception): class IllegalStateError(EventDispatcherError): - """Raise when user tries to put event_dispatcher into an illegal state. - """ + """Raise when user tries to put event_dispatcher into an illegal state.""" class DuplicateError(EventDispatcherError): - """Raise when a duplicate is being created and it shouldn't. - """ + """Raise when a duplicate is being created and it shouldn't.""" class EventDispatcher: - """Class managing events for an sl4a connection. - """ + """Class managing events for an sl4a connection.""" DEFAULT_TIMEOUT = 60 @@ -69,11 +66,11 @@ def poll_events(self): raise if not event_obj: continue - elif 'name' not in event_obj: + elif "name" not in event_obj: print("Received Malformed event {}".format(event_obj)) continue else: - event_name = event_obj['name'] + event_name = event_obj["name"] # if handler registered, process event if event_name in self.handlers: self.handle_subscribed_event(event_obj, event_name) @@ -107,13 +104,13 @@ def register_handler(self, handler, event_name, args): handler for one type of event. """ if self.started: - raise IllegalStateError(("Can't register service after polling is" - " started")) + raise IllegalStateError("Can't register service after polling is started") self.lock.acquire() try: if event_name in self.handlers: raise DuplicateError( - 'A handler for {} already exists'.format(event_name)) + "A handler for {} already exists".format(event_name) + ) self.handlers[event_name] = (handler, args) finally: self.lock.release() @@ -194,15 +191,13 @@ def pop_event(self, event_name, timeout=DEFAULT_TIMEOUT): # Block forever on event wait return e_queue.get(True) except queue.Empty: - raise queue.Empty('Timeout after {}s waiting for event: {}'.format( - timeout, event_name)) - - def wait_for_event(self, - event_name, - predicate, - timeout=DEFAULT_TIMEOUT, - *args, - **kwargs): + raise queue.Empty( + "Timeout after {}s waiting for event: {}".format(timeout, event_name) + ) + + def wait_for_event( + self, event_name, predicate, timeout=DEFAULT_TIMEOUT, *args, **kwargs + ): """Wait for an event that satisfies a predicate to appear. Continuously pop events of a particular name and check against the @@ -238,8 +233,11 @@ def wait_for_event(self, return event if time.perf_counter() > deadline: - raise queue.Empty('Timeout after {}s waiting for event: {}'.format( - timeout, event_name)) + raise queue.Empty( + "Timeout after {}s waiting for event: {}".format( + timeout, event_name + ) + ) def pop_events(self, regex_pattern, timeout): """Pop events whose names match a regex pattern. @@ -275,10 +273,13 @@ def pop_events(self, regex_pattern, timeout): break time.sleep(1) if len(results) == 0: - raise queue.Empty('Timeout after {}s waiting for event: {}'.format( - timeout, regex_pattern)) + raise queue.Empty( + "Timeout after {}s waiting for event: {}".format( + timeout, regex_pattern + ) + ) - return sorted(results, key=lambda event: event['time']) + return sorted(results, key=lambda event: event["time"]) def _match_and_pop(self, regex_pattern): """Pop one event from each of the event queues whose names @@ -331,8 +332,15 @@ def handle_subscribed_event(self, event_obj, event_name): handler, args = self.handlers[event_name] self.executor.submit(handler, event_obj, *args) - def _handle(self, event_handler, event_name, user_args, event_timeout, cond, - cond_timeout): + def _handle( + self, + event_handler, + event_name, + user_args, + event_timeout, + cond, + cond_timeout, + ): """Pop an event of specified type and calls its handler on it. If condition is not None, block until condition is met or timeout. """ @@ -341,13 +349,15 @@ def _handle(self, event_handler, event_name, user_args, event_timeout, cond, event = self.pop_event(event_name, event_timeout) return event_handler(event, *user_args) - def handle_event(self, - event_handler, - event_name, - user_args, - event_timeout=None, - cond=None, - cond_timeout=None): + def handle_event( + self, + event_handler, + event_name, + user_args, + event_timeout=None, + cond=None, + cond_timeout=None, + ): """Handle events that don't have registered handlers In a new thread, poll one event of specified type from its queue and @@ -371,8 +381,15 @@ def handle_event(self, If blocking call worker.result() is triggered, the handler needs to return something to unblock. """ - worker = self.executor.submit(self._handle, event_handler, event_name, - user_args, event_timeout, cond, cond_timeout) + worker = self.executor.submit( + self._handle, + event_handler, + event_name, + user_args, + event_timeout, + cond, + cond_timeout, + ) return worker def pop_all(self, event_name): @@ -392,8 +409,7 @@ def pop_all(self, event_name): starts polling. """ if not self.started: - raise IllegalStateError(("Dispatcher needs to be started before " - "popping.")) + raise IllegalStateError("Dispatcher needs to be started before popping.") results = [] try: self.lock.acquire() diff --git a/mobly/controllers/android_device_lib/fastboot.py b/mobly/controllers/android_device_lib/fastboot.py index 1ef49695..cac08f1d 100644 --- a/mobly/controllers/android_device_lib/fastboot.py +++ b/mobly/controllers/android_device_lib/fastboot.py @@ -37,14 +37,19 @@ def exe_cmd(*cmds): proc = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) (out, err) = proc.communicate() ret = proc.returncode - logging.debug('cmd: %s, stdout: %s, stderr: %s, ret: %s', - utils.cli_cmd_to_string(cmds), out, err, ret) + logging.debug( + 'cmd: %s, stdout: %s, stderr: %s, ret: %s', + utils.cli_cmd_to_string(cmds), + out, + err, + ret, + ) if not err: return out return err -class FastbootProxy(): +class FastbootProxy: """Proxy class for fastboot. For syntactic reasons, the '-' in fastboot commands need to be replaced @@ -53,12 +58,12 @@ class FastbootProxy(): >> fb.devices() # will return the console output of "fastboot devices". """ - def __init__(self, serial=""): + def __init__(self, serial=''): self.serial = serial if serial: - self.fastboot_str = "fastboot -s {}".format(serial) + self.fastboot_str = 'fastboot -s {}'.format(serial) else: - self.fastboot_str = "fastboot" + self.fastboot_str = 'fastboot' def _exec_fastboot_cmd(self, name, arg_str): return exe_cmd(' '.join((self.fastboot_str, name, arg_str))) @@ -67,7 +72,6 @@ def args(self, *args): return exe_cmd(' '.join((self.fastboot_str,) + args)) def __getattr__(self, name): - def fastboot_call(*args): clean_name = name.replace('_', '-') arg_str = ' '.join(str(elem) for elem in args) diff --git a/mobly/controllers/android_device_lib/jsonrpc_client_base.py b/mobly/controllers/android_device_lib/jsonrpc_client_base.py index 7f27fa54..d272782d 100644 --- a/mobly/controllers/android_device_lib/jsonrpc_client_base.py +++ b/mobly/controllers/android_device_lib/jsonrpc_client_base.py @@ -86,6 +86,7 @@ class JsonRpcCommand: INIT: Initializes a new session. CONTINUE: Creates a connection. """ + INIT = 'initiate' CONTINUE = 'continue' @@ -203,16 +204,20 @@ def connect(self, uid=UNKNOWN_UID, cmd=JsonRpcCommand.INIT): """ self._counter = self._id_counter() try: - self._conn = socket.create_connection(('localhost', self.host_port), - _SOCKET_CONNECTION_TIMEOUT) + self._conn = socket.create_connection( + ('localhost', self.host_port), _SOCKET_CONNECTION_TIMEOUT + ) except ConnectionRefusedError as err: # Retry using '127.0.0.1' for IPv4 enabled machines that only resolve # 'localhost' to '[::1]'. self.log.debug( 'Failed to connect to localhost, trying 127.0.0.1: {}'.format( - str(err))) - self._conn = socket.create_connection(('127.0.0.1', self.host_port), - _SOCKET_CONNECTION_TIMEOUT) + str(err) + ) + ) + self._conn = socket.create_connection( + ('127.0.0.1', self.host_port), _SOCKET_CONNECTION_TIMEOUT + ) self._conn.settimeout(_SOCKET_READ_TIMEOUT) self._client = self._conn.makefile(mode='brw') @@ -248,8 +253,7 @@ def close_socket_connection(self): self._conn = None def clear_host_port(self): - """Stops the adb port forwarding of the host port used by this client. - """ + """Stops the adb port forwarding of the host port used by this client.""" if self.host_port: self._ad.adb.forward(['--remove', 'tcp:%d' % self.host_port]) self.host_port = None @@ -264,13 +268,14 @@ def _client_send(self, msg): Error: a socket error occurred during the send. """ try: - self._client.write(msg.encode("utf8") + b'\n') + self._client.write(msg.encode('utf8') + b'\n') self._client.flush() self.log.debug('Snippet sent %s.', msg) except socket.error as e: raise Error( self._ad, - 'Encountered socket error "%s" sending RPC message "%s"' % (e, msg)) + 'Encountered socket error "%s" sending RPC message "%s"' % (e, msg), + ) def _client_receive(self): """Receives the server's response of an Rpc message. @@ -289,13 +294,16 @@ def _client_receive(self): if _MAX_RPC_RESP_LOGGING_LENGTH >= len(response): self.log.debug('Snippet received: %s', response) else: - self.log.debug('Snippet received: %s... %d chars are truncated', - response[:_MAX_RPC_RESP_LOGGING_LENGTH], - len(response) - _MAX_RPC_RESP_LOGGING_LENGTH) + self.log.debug( + 'Snippet received: %s... %d chars are truncated', + response[:_MAX_RPC_RESP_LOGGING_LENGTH], + len(response) - _MAX_RPC_RESP_LOGGING_LENGTH, + ) return response except socket.error as e: - raise Error(self._ad, - 'Encountered socket error reading RPC response "%s"' % e) + raise Error( + self._ad, 'Encountered socket error reading RPC response "%s"' % e + ) def _cmd(self, command, uid=None): """Send a command to the server. @@ -342,11 +350,13 @@ def _rpc(self, method, *args): if result.get('callback') is not None: if self._event_client is None: self._event_client = self._start_event_client() - return callback_handler.CallbackHandler(callback_id=result['callback'], - event_client=self._event_client, - ret_value=result['result'], - method_name=method, - ad=self._ad) + return callback_handler.CallbackHandler( + callback_id=result['callback'], + event_client=self._event_client, + ret_value=result['result'], + method_name=method, + ad=self._ad, + ) return result['result'] def disable_hidden_api_blacklist(self): @@ -357,7 +367,8 @@ def disable_hidden_api_blacklist(self): # in development report sdk_version 27, but still enforce the blacklist. if self._ad.is_rootable and (sdk_version >= 28 or version_codename == 'P'): self._ad.adb.shell( - 'settings put global hidden_api_blacklist_exemptions "*"') + 'settings put global hidden_api_blacklist_exemptions "*"' + ) def __getattr__(self, name): """Wrapper for python magic to turn method calls into RPC calls.""" diff --git a/mobly/controllers/android_device_lib/jsonrpc_shell_base.py b/mobly/controllers/android_device_lib/jsonrpc_shell_base.py index 3129f59a..c6d395b2 100755 --- a/mobly/controllers/android_device_lib/jsonrpc_shell_base.py +++ b/mobly/controllers/android_device_lib/jsonrpc_shell_base.py @@ -59,8 +59,11 @@ def load_device(self, serial=None): elif len(serials) == 1: serial = serials[0] else: - raise Error('Expected one phone, but %d found. Use the -s flag or ' - 'specify ANDROID_SERIAL.' % len(serials)) + raise Error( + 'Expected one phone, but %d found. Use the -s flag or ' + 'specify ANDROID_SERIAL.' + % len(serials) + ) if serial not in serials: raise Error('Device "%s" is not found by adb.' % serial) ads = android_device.get_instances([serial]) diff --git a/mobly/controllers/android_device_lib/service_manager.py b/mobly/controllers/android_device_lib/service_manager.py index 983cff76..17d5a1f4 100644 --- a/mobly/controllers/android_device_lib/service_manager.py +++ b/mobly/controllers/android_device_lib/service_manager.py @@ -74,11 +74,15 @@ def register(self, alias, service_class, configs=None, start_service=True): if not inspect.isclass(service_class): raise Error(self._device, '"%s" is not a class!' % service_class) if not issubclass(service_class, base_service.BaseService): - raise Error(self._device, - 'Class %s is not a subclass of BaseService!' % service_class) + raise Error( + self._device, + 'Class %s is not a subclass of BaseService!' % service_class, + ) if alias in self._service_objects: - raise Error(self._device, - 'A service is already registered with alias "%s".' % alias) + raise Error( + self._device, + 'A service is already registered with alias "%s".' % alias, + ) service_obj = service_class(self._device, configs) service_obj.alias = alias if start_service: @@ -94,12 +98,14 @@ def unregister(self, alias): alias: string, the alias of the service instance to unregister. """ if alias not in self._service_objects: - raise Error(self._device, - 'No service is registered with alias "%s".' % alias) + raise Error( + self._device, 'No service is registered with alias "%s".' % alias + ) service_obj = self._service_objects.pop(alias) if service_obj.is_alive: - with expects.expect_no_raises('Failed to stop service instance "%s".' % - alias): + with expects.expect_no_raises( + 'Failed to stop service instance "%s".' % alias + ): service_obj.stop() def for_each(self, func): @@ -111,8 +117,9 @@ def for_each(self, func): """ aliases = list(self._service_objects.keys()) for alias in aliases: - with expects.expect_no_raises('Failed to execute "%s" for service "%s".' % - (func.__name__, alias)): + with expects.expect_no_raises( + 'Failed to execute "%s" for service "%s".' % (func.__name__, alias) + ): func(self._service_objects[alias]) def list_live_services(self): @@ -125,8 +132,11 @@ def list_live_services(self): list of strings, the aliases of the services that are running. """ aliases = [] - self.for_each(lambda service: aliases.append(service.alias) - if service.is_alive else None) + self.for_each( + lambda service: aliases.append(service.alias) + if service.is_alive + else None + ) return aliases def create_output_excerpts_all(self, test_info): @@ -185,8 +195,9 @@ def start_services(self, service_alises): if name not in self._service_objects: raise Error( self._device, - 'No service is registered under the name "%s", cannot start.' % - name) + 'No service is registered under the name "%s", cannot start.' + % name, + ) service = self._service_objects[name] if not service.is_alive: service.start() @@ -235,8 +246,9 @@ def resume_services(self, service_alises): if name not in self._service_objects: raise Error( self._device, - 'No service is registered under the name "%s", cannot resume.' % - name) + 'No service is registered under the name "%s", cannot resume.' + % name, + ) service = self._service_objects[name] service.resume() diff --git a/mobly/controllers/android_device_lib/services/base_service.py b/mobly/controllers/android_device_lib/services/base_service.py index 47397973..8706bf03 100644 --- a/mobly/controllers/android_device_lib/services/base_service.py +++ b/mobly/controllers/android_device_lib/services/base_service.py @@ -21,6 +21,7 @@ class BaseService(abc.ABC): This class defines the interface for Mobly's AndroidDevice service. """ + _alias = None def __init__(self, device, configs=None): diff --git a/mobly/controllers/android_device_lib/services/logcat.py b/mobly/controllers/android_device_lib/services/logcat.py index 37a84542..04dcf9da 100644 --- a/mobly/controllers/android_device_lib/services/logcat.py +++ b/mobly/controllers/android_device_lib/services/logcat.py @@ -27,6 +27,7 @@ class Error(errors.ServiceError): """Root error type for logcat service.""" + SERVICE_TYPE = 'Logcat' @@ -54,6 +55,7 @@ class Logcat(base_service.BaseService): adb_logcat_file_path: string, path to the file that the service writes adb logcat to by default. """ + OUTPUT_FILE_TYPE = 'logcat' def __init__(self, android_device, configs=None): @@ -73,8 +75,10 @@ def _enable_logpersist(self): if not self._ad.is_rootable: return - logpersist_warning = ('%s encountered an error enabling persistent' - ' logs, logs may not get saved.') + logpersist_warning = ( + '%s encountered an error enabling persistent' + ' logs, logs may not get saved.' + ) # Android L and older versions do not have logpersist installed, # so check that the logpersist scripts exists before trying to use # them. @@ -113,11 +117,13 @@ def create_output_excerpts(self, test_info): """ dest_path = test_info.output_path utils.create_dir(dest_path) - filename = self._ad.generate_filename(self.OUTPUT_FILE_TYPE, test_info, - 'txt') + filename = self._ad.generate_filename( + self.OUTPUT_FILE_TYPE, test_info, 'txt' + ) excerpt_file_path = os.path.join(dest_path, filename) - with io.open(excerpt_file_path, 'w', encoding='utf-8', - errors='replace') as out: + with io.open( + excerpt_file_path, 'w', encoding='utf-8', errors='replace' + ) as out: # Devices may accidentally go offline during test, # check not None before readline(). while self._adb_logcat_file_obj: @@ -153,7 +159,8 @@ def _assert_not_running(self): if self.is_alive: raise Error( self._ad, - 'Logcat thread is already running, cannot start another one.') + 'Logcat thread is already running, cannot start another one.', + ) def update_config(self, new_config): """Updates the configuration for the service. @@ -168,8 +175,11 @@ def update_config(self, new_config): new_config: Config, the new config to use. """ self._assert_not_running() - self._ad.log.info('[LogcatService] Changing config from %s to %s', - self._config, new_config) + self._ad.log.info( + '[LogcatService] Changing config from %s to %s', + self._config, + new_config, + ) self._config = new_config def _open_logcat_file(self): @@ -181,13 +191,13 @@ def _open_logcat_file(self): deadline = time.perf_counter() + CREATE_LOGCAT_FILE_TIMEOUT_SEC while not os.path.exists(self.adb_logcat_file_path): if time.perf_counter() > deadline: - raise Error(self._ad, - 'Timeout while waiting for logcat file to be created.') + raise Error( + self._ad, 'Timeout while waiting for logcat file to be created.' + ) time.sleep(1) - self._adb_logcat_file_obj = io.open(self.adb_logcat_file_path, - 'r', - encoding='utf-8', - errors='replace') + self._adb_logcat_file_obj = io.open( + self.adb_logcat_file_path, 'r', encoding='utf-8', errors='replace' + ) self._adb_logcat_file_obj.seek(0, os.SEEK_END) def _close_logcat_file(self): @@ -203,7 +213,8 @@ def start(self): """ if self._ad.is_bootloader: self._ad.log.warning( - 'Skip starting logcat because the device is in fastboot mode.') + 'Skip starting logcat because the device is in fastboot mode.' + ) return self._assert_not_running() if self._config.clear_log: @@ -218,8 +229,9 @@ def _start(self): self._close_logcat_file() self.adb_logcat_file_path = self._config.output_file_path if not self.adb_logcat_file_path: - f_name = self._ad.generate_filename(self.OUTPUT_FILE_TYPE, - extension_name='txt') + f_name = self._ad.generate_filename( + self.OUTPUT_FILE_TYPE, extension_name='txt' + ) logcat_file_path = os.path.join(self._ad.log_path, f_name) self.adb_logcat_file_path = logcat_file_path utils.create_dir(os.path.dirname(self.adb_logcat_file_path)) @@ -227,8 +239,11 @@ def _start(self): # double quotes in args if starting and ending with it. # Add spaces at beginning and at last to fix this issue. cmd = ' "%s" -s %s logcat -v threadtime -T 1 %s >> "%s" ' % ( - adb.ADB, self._ad.serial, self._config.logcat_params, - self.adb_logcat_file_path) + adb.ADB, + self._ad.serial, + self._config.logcat_params, + self.adb_logcat_file_path, + ) process = utils.start_standing_subprocess(cmd, shell=True) self._adb_logcat_process = process diff --git a/mobly/controllers/android_device_lib/services/snippet_management_service.py b/mobly/controllers/android_device_lib/services/snippet_management_service.py index 00253c7d..7da1b23d 100644 --- a/mobly/controllers/android_device_lib/services/snippet_management_service.py +++ b/mobly/controllers/android_device_lib/services/snippet_management_service.py @@ -21,6 +21,7 @@ class Error(errors.ServiceError): """Root error type for snippet management service.""" + SERVICE_TYPE = 'SnippetManagementService' @@ -73,14 +74,18 @@ class for supported configurations. # Should not load snippet with the same name more than once. if name in self._snippet_clients: raise Error( - self, 'Name "%s" is already registered with package "%s", it cannot ' - 'be used again.' % (name, self._snippet_clients[name].client.package)) + self, + 'Name "%s" is already registered with package "%s", it cannot ' + 'be used again.' % (name, self._snippet_clients[name].client.package), + ) # Should not load the same snippet package more than once. for snippet_name, client in self._snippet_clients.items(): if package == client.package: raise Error( - self, 'Snippet package "%s" has already been loaded under name' - ' "%s".' % (package, snippet_name)) + self, + 'Snippet package "%s" has already been loaded under name "%s".' + % (package, snippet_name), + ) client = snippet_client_v2.SnippetClientV2( package=package, @@ -113,7 +118,8 @@ def start(self): else: self._device.log.debug( 'Not startng SnippetClient<%s> because it is already alive.', - client.package) + client.package, + ) def stop(self): """Stops all the snippet clients under management.""" @@ -124,7 +130,8 @@ def stop(self): else: self._device.log.debug( 'Not stopping SnippetClient<%s> because it is not alive.', - client.package) + client.package, + ) def pause(self): """Pauses all the snippet clients under management. @@ -143,8 +150,9 @@ def resume(self): self._device.log.debug('Resuming SnippetClient<%s>.', client.package) client.restore_server_connection() else: - self._device.log.debug('Not resuming SnippetClient<%s>.', - client.package) + self._device.log.debug( + 'Not resuming SnippetClient<%s>.', client.package + ) def __getattr__(self, name): client = self.get_snippet_client(name) diff --git a/mobly/controllers/android_device_lib/sl4a_client.py b/mobly/controllers/android_device_lib/sl4a_client.py index 725a61cf..ac59f5b5 100644 --- a/mobly/controllers/android_device_lib/sl4a_client.py +++ b/mobly/controllers/android_device_lib/sl4a_client.py @@ -24,7 +24,8 @@ _LAUNCH_CMD = ( 'am start -a com.googlecode.android_scripting.action.LAUNCH_SERVER ' '--ei com.googlecode.android_scripting.extra.USE_SERVICE_PORT %s ' - 'com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher') + 'com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher' +) # Maximum time to wait for the app to start on the device (10 minutes). # TODO: This timeout is set high in order to allow for retries in # start_app_and_connect. Decrease it when the call to connect() has the option @@ -59,7 +60,8 @@ def start_app_and_connect(self): out = self._adb.shell('pm list package') if not utils.grep('com.googlecode.android_scripting', out): raise jsonrpc_client_base.AppStartError( - self._ad, '%s is not installed on %s' % (_APP_NAME, self._adb.serial)) + self._ad, '%s is not installed on %s' % (_APP_NAME, self._adb.serial) + ) self.disable_hidden_api_blacklist() # sl4a has problems connecting after disconnection, so kill the apk and @@ -108,8 +110,9 @@ def stop_app(self): try: self.closeSl4aSession() except Exception: - self.log.exception('Failed to gracefully shut down %s.', - self.app_name) + self.log.exception( + 'Failed to gracefully shut down %s.', self.app_name + ) # Close the socket connection. self.disconnect() @@ -141,23 +144,25 @@ def _retry_connect(self): started = True break except Exception: - self.log.debug('%s is not yet running, retrying', - self.app_name, - exc_info=True) + self.log.debug( + '%s is not yet running, retrying', self.app_name, exc_info=True + ) time.sleep(1) if not started: raise jsonrpc_client_base.AppRestoreConnectionError( - self._ad, '%s failed to connect for %s at host port %s, ' - 'device port %s' % - (self.app_name, self._adb.serial, self.host_port, self.device_port)) + self._ad, + '%s failed to connect for %s at host port %s, device port %s' + % (self.app_name, self._adb.serial, self.host_port, self.device_port), + ) def _start_event_client(self): # Start an EventDispatcher for the current sl4a session event_client = Sl4aClient(self._ad) event_client.host_port = self.host_port event_client.device_port = self.device_port - event_client.connect(uid=self.uid, - cmd=jsonrpc_client_base.JsonRpcCommand.CONTINUE) + event_client.connect( + uid=self.uid, cmd=jsonrpc_client_base.JsonRpcCommand.CONTINUE + ) ed = event_dispatcher.EventDispatcher(event_client) ed.start() return ed diff --git a/mobly/controllers/android_device_lib/snippet_client.py b/mobly/controllers/android_device_lib/snippet_client.py index 42ae1225..099f9c7b 100644 --- a/mobly/controllers/android_device_lib/snippet_client.py +++ b/mobly/controllers/android_device_lib/snippet_client.py @@ -23,13 +23,16 @@ from mobly.controllers.android_device_lib import jsonrpc_client_base from mobly.snippet import errors as snippet_errors -logging.warning('The module mobly.controllers.android_device_lib.snippet_client' - ' is deprecated and will be removed in a future version. Use' - ' module mobly.controllers.android_device_lib.snippet_client_v2' - ' instead.') +logging.warning( + 'The module mobly.controllers.android_device_lib.snippet_client' + ' is deprecated and will be removed in a future version. Use' + ' module mobly.controllers.android_device_lib.snippet_client_v2' + ' instead.' +) _INSTRUMENTATION_RUNNER_PACKAGE = ( - 'com.google.android.mobly.snippet.SnippetRunner') + 'com.google.android.mobly.snippet.SnippetRunner' +) # Major version of the launch and communication protocol being used by this # client. @@ -45,11 +48,14 @@ _PROTOCOL_MINOR_VERSION = 0 _LAUNCH_CMD = ( - '{shell_cmd} am instrument {user} -w -e action start {snippet_package}/' + - _INSTRUMENTATION_RUNNER_PACKAGE) + '{shell_cmd} am instrument {user} -w -e action start {snippet_package}/' + + _INSTRUMENTATION_RUNNER_PACKAGE +) -_STOP_CMD = ('am instrument {user} -w -e action stop {snippet_package}/' + - _INSTRUMENTATION_RUNNER_PACKAGE) +_STOP_CMD = ( + 'am instrument {user} -w -e action stop {snippet_package}/' + + _INSTRUMENTATION_RUNNER_PACKAGE +) # Test that uses UiAutomation requires the shell session to be maintained while # test is in progress. However, this requirement does not hold for the test that @@ -154,7 +160,8 @@ def start_app_and_connect(self): self.stop_app() except Exception: self._ad.log.exception( - 'Failed to stop app after failure to start and connect.') + 'Failed to stop app after failure to start and connect.' + ) # Explicitly raise the original error from starting app. raise e @@ -177,11 +184,17 @@ def _start_app_and_connect(self): # process. Starting snippets can be slow, especially if there are # multiple, and this avoids the perception that the framework is hanging # for a long time doing nothing. - self.log.info('Launching snippet apk %s with protocol %d.%d', self.package, - _PROTOCOL_MAJOR_VERSION, _PROTOCOL_MINOR_VERSION) - cmd = _LAUNCH_CMD.format(shell_cmd=persists_shell_cmd, - user=self._get_user_command_string(), - snippet_package=self.package) + self.log.info( + 'Launching snippet apk %s with protocol %d.%d', + self.package, + _PROTOCOL_MAJOR_VERSION, + _PROTOCOL_MINOR_VERSION, + ) + cmd = _LAUNCH_CMD.format( + shell_cmd=persists_shell_cmd, + user=self._get_user_command_string(), + snippet_package=self.package, + ) start_time = time.perf_counter() self._proc = self._do_start_app(cmd) @@ -203,9 +216,12 @@ def _start_app_and_connect(self): self.connect() # Yaaay! We're done! - self.log.debug('Snippet %s started after %.1fs on host port %s', - self.package, - time.perf_counter() - start_time, self.host_port) + self.log.debug( + 'Snippet %s started after %.1fs on host port %s', + self.package, + time.perf_counter() - start_time, + self.host_port, + ) def restore_app_connection(self, port=None): """Restores the app after device got reconnected. @@ -232,8 +248,12 @@ def restore_app_connection(self, port=None): self.log.exception('Failed to re-connect to app.') raise jsonrpc_client_base.AppRestoreConnectionError( self._ad, - ('Failed to restore app connection for %s at host port %s, ' - 'device port %s') % (self.package, self.host_port, self.device_port)) + ( + 'Failed to restore app connection for %s at host port %s, ' + 'device port %s' + ) + % (self.package, self.host_port, self.device_port), + ) # Because the previous connection was lost, update self._proc self._proc = None @@ -252,11 +272,14 @@ def stop_app(self): utils.stop_standing_subprocess(self._proc) self._proc = None out = self._adb.shell( - _STOP_CMD.format(snippet_package=self.package, - user=self._get_user_command_string())).decode('utf-8') + _STOP_CMD.format( + snippet_package=self.package, user=self._get_user_command_string() + ) + ).decode('utf-8') if 'OK (0 tests)' not in out: raise errors.DeviceError( - self._ad, 'Failed to stop existing apk. Unexpected output: %s' % out) + self._ad, 'Failed to stop existing apk. Unexpected output: %s' % out + ) self._stop_event_client() @@ -293,17 +316,21 @@ def _check_app_installed(self): out = self._adb.shell(f'pm list package --user {self.user_id}') if not utils.grep('^package:%s$' % self.package, out): raise AppStartPreCheckError( - self._ad, f'{self.package} is not installed for user {self.user_id}.') + self._ad, f'{self.package} is not installed for user {self.user_id}.' + ) # Check that the app is instrumented. out = self._adb.shell('pm list instrumentation') matched_out = utils.grep( f'^instrumentation:{self.package}/{_INSTRUMENTATION_RUNNER_PACKAGE}', - out) + out, + ) if not matched_out: raise AppStartPreCheckError( - self._ad, f'{self.package} is installed, but it is not instrumented.') - match = re.search(r'^instrumentation:(.*)\/(.*) \(target=(.*)\)$', - matched_out[0]) + self._ad, f'{self.package} is installed, but it is not instrumented.' + ) + match = re.search( + r'^instrumentation:(.*)\/(.*) \(target=(.*)\)$', matched_out[0] + ) target_name = match.group(3) # Check that the instrumentation target is installed if it's not the # same as the snippet package. @@ -313,7 +340,8 @@ def _check_app_installed(self): raise AppStartPreCheckError( self._ad, f'Instrumentation target {target_name} is not installed for user ' - f'{self.user_id}.') + f'{self.user_id}.', + ) def _do_start_app(self, launch_cmd): adb_cmd = [adb.ADB] @@ -339,14 +367,16 @@ def _read_protocol_line(self): line = self._proc.stdout.readline().decode('utf-8') if not line: raise jsonrpc_client_base.AppStartError( - self._ad, 'Unexpected EOF waiting for app to start') + self._ad, 'Unexpected EOF waiting for app to start' + ) # readline() uses an empty string to mark EOF, and a single newline # to mark regular empty lines in the output. Don't move the strip() # call above the truthiness check, or this method will start # considering any blank output line to be EOF. line = line.strip() - if (line.startswith('INSTRUMENTATION_RESULT:') or - line.startswith('SNIPPET ')): + if line.startswith('INSTRUMENTATION_RESULT:') or line.startswith( + 'SNIPPET ' + ): self.log.debug('Accepted line from instrumentation output: "%s"', line) return line self.log.debug('Discarded line from instrumentation output: "%s"', line) @@ -362,8 +392,10 @@ def _get_persist_command(self): self.log.warning( 'No %s and %s commands available to launch instrument ' 'persistently, tests that depend on UiAutomator and ' - 'at the same time performs USB disconnection may fail', _SETSID_COMMAND, - _NOHUP_COMMAND) + 'at the same time performs USB disconnection may fail', + _SETSID_COMMAND, + _NOHUP_COMMAND, + ) return '' def help(self, print_output=True): diff --git a/mobly/controllers/android_device_lib/snippet_client_v2.py b/mobly/controllers/android_device_lib/snippet_client_v2.py index ed944d69..32e73782 100644 --- a/mobly/controllers/android_device_lib/snippet_client_v2.py +++ b/mobly/controllers/android_device_lib/snippet_client_v2.py @@ -28,16 +28,22 @@ from mobly.snippet import errors # The package of the instrumentation runner used for mobly snippet -_INSTRUMENTATION_RUNNER_PACKAGE = 'com.google.android.mobly.snippet.SnippetRunner' +_INSTRUMENTATION_RUNNER_PACKAGE = ( + 'com.google.android.mobly.snippet.SnippetRunner' +) # The command template to start the snippet server _LAUNCH_CMD = ( - '{shell_cmd} am instrument {user} -w -e action start {instrument_options} ' - f'{{snippet_package}}/{_INSTRUMENTATION_RUNNER_PACKAGE}') + '{shell_cmd} am instrument {user} -w -e action start' + ' {instrument_options}' + f' {{snippet_package}}/{_INSTRUMENTATION_RUNNER_PACKAGE}' +) # The command template to stop the snippet server -_STOP_CMD = ('am instrument {user} -w -e action stop {snippet_package}/' - f'{_INSTRUMENTATION_RUNNER_PACKAGE}') +_STOP_CMD = ( + 'am instrument {user} -w -e action stop {snippet_package}/' + f'{_INSTRUMENTATION_RUNNER_PACKAGE}' +) # Major version of the launch and communication protocol being used by this # client. @@ -92,8 +98,9 @@ class Config: user_id: The user id under which to launch the snippet process. """ - am_instrument_options: Dict[str, - str] = dataclasses.field(default_factory=dict) + am_instrument_options: Dict[str, str] = dataclasses.field( + default_factory=dict + ) user_id: Union[int, None] = None @@ -108,6 +115,7 @@ class ConnectionHandshakeCommand(enum.Enum): INIT: Initiates a new session and makes a connection with this session. CONTINUE: Makes a connection with the current session. """ + INIT = 'initiate' CONTINUE = 'continue' @@ -207,19 +215,23 @@ def _validate_snippet_app_on_device(self): if not utils.grep(f'^package:{self.package}$', out): raise errors.ServerStartPreCheckError( self._device, - f'{self.package} is not installed for user {self.user_id}.') + f'{self.package} is not installed for user {self.user_id}.', + ) # Validate that the app is instrumented. out = self._adb.shell('pm list instrumentation') matched_out = utils.grep( f'^instrumentation:{self.package}/{_INSTRUMENTATION_RUNNER_PACKAGE}', - out) + out, + ) if not matched_out: raise errors.ServerStartPreCheckError( self._device, - f'{self.package} is installed, but it is not instrumented.') - match = re.search(r'^instrumentation:(.*)\/(.*) \(target=(.*)\)$', - matched_out[0]) + f'{self.package} is installed, but it is not instrumented.', + ) + match = re.search( + r'^instrumentation:(.*)\/(.*) \(target=(.*)\)$', matched_out[0] + ) target_name = match.group(3) # Validate that the instrumentation target is installed if it's not the # same as the snippet package. @@ -229,14 +241,16 @@ def _validate_snippet_app_on_device(self): raise errors.ServerStartPreCheckError( self._device, f'Instrumentation target {target_name} is not installed for user ' - f'{self.user_id}.') + f'{self.user_id}.', + ) def _disable_hidden_api_blocklist(self): """If necessary and possible, disables hidden api blocklist.""" sdk_version = int(self._device.build_info['build_version_sdk']) if self._device.is_rootable and sdk_version >= 28: self._device.adb.shell( - 'settings put global hidden_api_blacklist_exemptions "*"') + 'settings put global hidden_api_blacklist_exemptions "*"' + ) def start_server(self): """Starts the server on the remote device. @@ -252,14 +266,19 @@ def start_server(self): server output. """ persists_shell_cmd = self._get_persisting_command() - self.log.debug('Snippet server for package %s is using protocol %d.%d', - self.package, _PROTOCOL_MAJOR_VERSION, - _PROTOCOL_MINOR_VERSION) + self.log.debug( + 'Snippet server for package %s is using protocol %d.%d', + self.package, + _PROTOCOL_MAJOR_VERSION, + _PROTOCOL_MINOR_VERSION, + ) option_str = self._get_instrument_options_str() - cmd = _LAUNCH_CMD.format(shell_cmd=persists_shell_cmd, - user=self._get_user_command_string(), - snippet_package=self.package, - instrument_options=option_str) + cmd = _LAUNCH_CMD.format( + shell_cmd=persists_shell_cmd, + user=self._get_user_command_string(), + snippet_package=self.package, + instrument_options=option_str, + ) self._proc = self._run_adb_cmd(cmd) # Check protocol version and get the device port @@ -295,7 +314,9 @@ def _get_persisting_command(self): 'No %s and %s commands available to launch instrument ' 'persistently, tests that depend on UiAutomator and ' 'at the same time perform USB disconnections may fail.', - _SETSID_COMMAND, _NOHUP_COMMAND) + _SETSID_COMMAND, + _NOHUP_COMMAND, + ) return '' def _get_instrument_options_str(self): @@ -308,7 +329,8 @@ def _get_instrument_options_str(self): return '' return ' '.join( - f'-e {k} {v}' for k, v in self._config.am_instrument_options.items()) + f'-e {k} {v}' for k, v in self._config.am_instrument_options.items() + ) def _get_user_command_string(self): """Gets the appropriate command argument for specifying device user ID. @@ -344,15 +366,17 @@ def _read_protocol_line(self): line = self._proc.stdout.readline().decode('utf-8') if not line: raise errors.ServerStartError( - self._device, 'Unexpected EOF when waiting for server to start.') + self._device, 'Unexpected EOF when waiting for server to start.' + ) # readline() uses an empty string to mark EOF, and a single newline # to mark regular empty lines in the output. Don't move the strip() # call above the truthiness check, or this method will start # considering any blank output line to be EOF. line = line.strip() - if (line.startswith('INSTRUMENTATION_RESULT:') or - line.startswith('SNIPPET ')): + if line.startswith('INSTRUMENTATION_RESULT:') or line.startswith( + 'SNIPPET ' + ): self.log.debug('Accepted line from instrumentation output: "%s"', line) return line @@ -398,23 +422,29 @@ def create_socket_connection(self): try: self.log.debug( 'Snippet client is creating socket connection to the snippet server ' - 'of %s through host port %d.', self.package, self.host_port) - self._conn = socket.create_connection(('localhost', self.host_port), - _SOCKET_CONNECTION_TIMEOUT) + 'of %s through host port %d.', + self.package, + self.host_port, + ) + self._conn = socket.create_connection( + ('localhost', self.host_port), _SOCKET_CONNECTION_TIMEOUT + ) except ConnectionRefusedError as err: # Retry using '127.0.0.1' for IPv4 enabled machines that only resolve # 'localhost' to '[::1]'. - self.log.debug('Failed to connect to localhost, trying 127.0.0.1: %s', - str(err)) - self._conn = socket.create_connection(('127.0.0.1', self.host_port), - _SOCKET_CONNECTION_TIMEOUT) + self.log.debug( + 'Failed to connect to localhost, trying 127.0.0.1: %s', str(err) + ) + self._conn = socket.create_connection( + ('127.0.0.1', self.host_port), _SOCKET_CONNECTION_TIMEOUT + ) self._conn.settimeout(_SOCKET_READ_TIMEOUT) self._client = self._conn.makefile(mode='brw') - def send_handshake_request(self, - uid=UNKNOWN_UID, - cmd=ConnectionHandshakeCommand.INIT): + def send_handshake_request( + self, uid=UNKNOWN_UID, cmd=ConnectionHandshakeCommand.INIT + ): """Sends a handshake request to the server to prepare for the communication. Through the handshake response, this function checks whether the server @@ -439,7 +469,8 @@ def send_handshake_request(self, if not response: raise errors.ProtocolError( - self._device, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE) + self._device, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE + ) response = self._decode_socket_response_bytes(response) @@ -472,8 +503,9 @@ def send_rpc_request(self, request): self._client_send(request) response = self._client_receive() if not response: - raise errors.ProtocolError(self._device, - errors.ProtocolError.NO_RESPONSE_FROM_SERVER) + raise errors.ProtocolError( + self._device, errors.ProtocolError.NO_RESPONSE_FROM_SERVER + ) return self._decode_socket_response_bytes(response) def _client_send(self, message): @@ -491,7 +523,7 @@ def _client_send(self, message): except socket.error as e: raise errors.Error( self._device, - f'Encountered socket error "{e}" sending RPC message "{message}"' + f'Encountered socket error "{e}" sending RPC message "{message}"', ) from e def _client_receive(self): @@ -507,8 +539,8 @@ def _client_receive(self): return self._client.readline() except socket.error as e: raise errors.Error( - self._device, - f'Encountered socket error "{e}" reading RPC response') from e + self._device, f'Encountered socket error "{e}" reading RPC response' + ) from e def _decode_socket_response_bytes(self, response): """Returns a string decoded from the socket response bytes. @@ -526,8 +558,9 @@ def _decode_socket_response_bytes(self, response): return str(response, encoding='utf8') except UnicodeError: self.log.error( - 'Failed to decode socket response bytes using encoding ' - 'utf8: %s', response) + 'Failed to decode socket response bytes using encoding utf8: %s', + response, + ) raise def handle_callback(self, callback_id, ret_value, rpc_func_name): @@ -553,7 +586,8 @@ def handle_callback(self, callback_id, ret_value, rpc_func_name): method_name=rpc_func_name, device=self._device, rpc_max_timeout_sec=_SOCKET_READ_TIMEOUT, - default_timeout_sec=_CALLBACK_DEFAULT_TIMEOUT_SEC) + default_timeout_sec=_CALLBACK_DEFAULT_TIMEOUT_SEC, + ) def _create_event_client(self): """Creates a separate client to the same session for propagating events. @@ -564,14 +598,19 @@ def _create_event_client(self): """ self._event_client = SnippetClientV2(package=self.package, ad=self._device) self._event_client.make_connection_with_forwarded_port( - self.host_port, self.device_port, self.uid, - ConnectionHandshakeCommand.CONTINUE) - - def make_connection_with_forwarded_port(self, - host_port, - device_port, - uid=UNKNOWN_UID, - cmd=ConnectionHandshakeCommand.INIT): + self.host_port, + self.device_port, + self.uid, + ConnectionHandshakeCommand.CONTINUE, + ) + + def make_connection_with_forwarded_port( + self, + host_port, + device_port, + uid=UNKNOWN_UID, + cmd=ConnectionHandshakeCommand.INIT, + ): """Makes a connection to the server with the given forwarded port. This process assumes that a device port has already been forwarded to a @@ -654,13 +693,16 @@ def _stop_server(self): # Send the stop signal to the server running on the device side. out = self._adb.shell( - _STOP_CMD.format(snippet_package=self.package, - user=self._get_user_command_string())).decode('utf-8') + _STOP_CMD.format( + snippet_package=self.package, user=self._get_user_command_string() + ) + ).decode('utf-8') if 'OK (0 tests)' not in out: raise android_device_lib_errors.DeviceError( self._device, - f'Failed to stop existing apk. Unexpected output: {out}.') + f'Failed to stop existing apk. Unexpected output: {out}.', + ) def _destroy_event_client(self): """Releases all the resources acquired in `_create_event_client`.""" @@ -700,9 +742,11 @@ def restore_server_connection(self, port=None): self.log.error('Failed to re-connect to the server.') raise errors.ServerRestoreConnectionError( self._device, - (f'Failed to restore server connection for {self.package} at ' - f'host port {self.host_port}, device port {self.device_port}.' - )) from e + ( + f'Failed to restore server connection for {self.package} at ' + f'host port {self.host_port}, device port {self.device_port}.' + ), + ) from e # Because the previous connection was lost, update self._proc self._proc = None @@ -720,7 +764,8 @@ def _restore_event_client(self): """ if self._event_client: self._event_client.make_connection_with_forwarded_port( - self.host_port, self.device_port) + self.host_port, self.device_port + ) def help(self, print_output=True): """Calls the help RPC, which returns the list of RPC calls available. diff --git a/mobly/controllers/android_device_lib/snippet_event.py b/mobly/controllers/android_device_lib/snippet_event.py index 7ef75c11..860335bf 100644 --- a/mobly/controllers/android_device_lib/snippet_event.py +++ b/mobly/controllers/android_device_lib/snippet_event.py @@ -13,9 +13,11 @@ # limitations under the License. import logging -logging.warning('The module mobly.controllers.android_device_lib.snippet_event ' - 'is deprecated and will be removed in a future version. Use ' - 'module mobly.snippet.callback_event instead.') +logging.warning( + 'The module mobly.controllers.android_device_lib.snippet_event ' + 'is deprecated and will be removed in a future version. Use ' + 'module mobly.snippet.callback_event instead.' +) def from_dict(event_dict): @@ -29,10 +31,12 @@ def from_dict(event_dict): Returns: A SnippetEvent object. """ - return SnippetEvent(callback_id=event_dict['callbackId'], - name=event_dict['name'], - creation_time=event_dict['time'], - data=event_dict['data']) + return SnippetEvent( + callback_id=event_dict['callbackId'], + name=event_dict['name'], + creation_time=event_dict['time'], + data=event_dict['data'], + ) class SnippetEvent: @@ -55,6 +59,6 @@ def __init__(self, callback_id, name, creation_time, data): self.data = data def __repr__(self): - return ('SnippetEvent(callback_id: %s, name: %s, creation_time: %s, ' - 'data: %s)') % (self.callback_id, self.name, self.creation_time, - self.data) + return ( + 'SnippetEvent(callback_id: %s, name: %s, creation_time: %s, data: %s)' + ) % (self.callback_id, self.name, self.creation_time, self.data) diff --git a/mobly/controllers/attenuator.py b/mobly/controllers/attenuator.py index d666227d..70f1faaf 100644 --- a/mobly/controllers/attenuator.py +++ b/mobly/controllers/attenuator.py @@ -61,7 +61,8 @@ def create(configs): module = importlib.import_module(module_name) # Create each attenuation_device = module.AttenuatorDevice( - path_count=len(config[KEY_PATHS])) + path_count=len(config[KEY_PATHS]) + ) attenuation_device.model = attenuator_model instances = attenuation_device.open(config[KEY_ADDRESS], config[KEY_PORT]) for idx, path_name in enumerate(config[KEY_PATHS]): @@ -77,19 +78,19 @@ def destroy(objs): class Error(Exception): """This is the Exception class defined for all errors generated by - Attenuator-related modules. - """ + Attenuator-related modules. + """ def _validate_config(config): """Verifies that a config dict for an attenuator device is valid. - Args: - config: A dict that is the configuration for an attenuator device. + Args: + config: A dict that is the configuration for an attenuator device. - Raises: - attenuator.Error: A config is not valid. - """ + Raises: + attenuator.Error: A config is not valid. + """ required_keys = [KEY_ADDRESS, KEY_MODEL, KEY_PORT, KEY_PATHS] for key in required_keys: if key not in config: @@ -98,62 +99,62 @@ def _validate_config(config): class AttenuatorPath: """A convenience class that allows users to control each attenuator path - separately as different objects, as opposed to passing in an index number - to the functions of an attenuator device object. + separately as different objects, as opposed to passing in an index number + to the functions of an attenuator device object. - This decouples the test code from the actual attenuator device used in the - physical test bed. + This decouples the test code from the actual attenuator device used in the + physical test bed. - For example, if a test needs to attenuate four signal paths, this allows the - test to do: + For example, if a test needs to attenuate four signal paths, this allows the + test to do: - .. code-block:: python + .. code-block:: python - self.attenuation_paths[0].set_atten(50) - self.attenuation_paths[1].set_atten(40) + self.attenuation_paths[0].set_atten(50) + self.attenuation_paths[1].set_atten(40) - instead of: + instead of: - .. code-block:: python + .. code-block:: python - self.attenuators[0].set_atten(0, 50) - self.attenuators[0].set_atten(1, 40) + self.attenuators[0].set_atten(0, 50) + self.attenuators[0].set_atten(1, 40) - The benefit the former is that the physical test bed can use either four - single-channel attenuators, or one four-channel attenuators. Whereas the - latter forces the test bed to use a four-channel attenuator. - """ + The benefit the former is that the physical test bed can use either four + single-channel attenuators, or one four-channel attenuators. Whereas the + latter forces the test bed to use a four-channel attenuator. + """ def __init__(self, attenuation_device, idx=0, name=None): self.model = attenuation_device.model self.attenuation_device = attenuation_device self.idx = idx self.name = name - if (self.idx >= attenuation_device.path_count): + if self.idx >= attenuation_device.path_count: raise IndexError("Attenuator index out of range!") def set_atten(self, value): """This function sets the attenuation of Attenuator. - Args: - value: This is a floating point value for nominal attenuation to be - set. Unit is db. - """ + Args: + value: This is a floating point value for nominal attenuation to be + set. Unit is db. + """ self.attenuation_device.set_atten(self.idx, value) def get_atten(self): """Gets the current attenuation setting of Attenuator. - Returns: - A float that is the current attenuation value. Unit is db. - """ + Returns: + A float that is the current attenuation value. Unit is db. + """ return self.attenuation_device.get_atten(self.idx) def get_max_atten(self): """Gets the max attenuation supported by the Attenuator. - Returns: - A float that is the max attenuation value. - """ + Returns: + A float that is the max attenuation value. + """ return self.attenuation_device.max_atten diff --git a/mobly/controllers/attenuator_lib/minicircuits.py b/mobly/controllers/attenuator_lib/minicircuits.py index f33a5d1f..7234015b 100644 --- a/mobly/controllers/attenuator_lib/minicircuits.py +++ b/mobly/controllers/attenuator_lib/minicircuits.py @@ -24,75 +24,79 @@ class AttenuatorDevice: """This provides a specific telnet-controlled implementation of - AttenuatorDevice for Mini-Circuits RC-DAT attenuators. + AttenuatorDevice for Mini-Circuits RC-DAT attenuators. - Attributes: - path_count: The number of signal attenuation path this device has. - """ + Attributes: + path_count: The number of signal attenuation path this device has. + """ def __init__(self, path_count=1): self.path_count = path_count # The telnet client used to communicate with the attenuator device. self._telnet_client = telnet_scpi_client.TelnetScpiClient( - tx_cmd_separator="\r\n", rx_cmd_separator="\r\n", prompt="") + tx_cmd_separator="\r\n", rx_cmd_separator="\r\n", prompt="" + ) @property def is_open(self): """This function returns the state of the telnet connection to the - underlying AttenuatorDevice. + underlying AttenuatorDevice. - Returns: - True if there is a successfully open connection to the - AttenuatorDevice. - """ + Returns: + True if there is a successfully open connection to the + AttenuatorDevice. + """ return bool(self._telnet_client.is_open) def open(self, host, port=23): """Opens a telnet connection to the desired AttenuatorDevice and - queries basic information. + queries basic information. - Args: - host: A valid hostname (IP address or DNS-resolvable name) to an - MC-DAT attenuator instrument. - port: An optional port number (defaults to telnet default 23) - """ + Args: + host: A valid hostname (IP address or DNS-resolvable name) to an + MC-DAT attenuator instrument. + port: An optional port number (defaults to telnet default 23) + """ self._telnet_client.open(host, port) config_str = self._telnet_client.cmd("MN?") if config_str.startswith("MN="): - config_str = config_str[len("MN="):] + config_str = config_str[len("MN=") :] self.properties = dict( - zip(['model', 'max_freq', 'max_atten'], config_str.split("-", 2))) - self.max_atten = float(self.properties['max_atten']) + zip(["model", "max_freq", "max_atten"], config_str.split("-", 2)) + ) + self.max_atten = float(self.properties["max_atten"]) def close(self): """Closes a telnet connection to the desired attenuator device. - This should be called as part of any teardown procedure prior to the - attenuator instrument leaving scope. - """ + This should be called as part of any teardown procedure prior to the + attenuator instrument leaving scope. + """ if self.is_open: self._telnet_client.close() def set_atten(self, idx, value): """Sets the attenuation value for a particular signal path. - Args: - idx: Zero-based index int which is the identifier for a particular - signal path in an instrument. For instruments that only has one - channel, this is ignored by the device. - value: A float that is the attenuation value to set. - - Raises: - Error: The underlying telnet connection to the instrument is not - open. - IndexError: The index of the attenuator is greater than the maximum - index of the underlying instrument. - ValueError: The requested set value is greater than the maximum - attenuation value. - """ + Args: + idx: Zero-based index int which is the identifier for a particular + signal path in an instrument. For instruments that only has one + channel, this is ignored by the device. + value: A float that is the attenuation value to set. + + Raises: + Error: The underlying telnet connection to the instrument is not + open. + IndexError: The index of the attenuator is greater than the maximum + index of the underlying instrument. + ValueError: The requested set value is greater than the maximum + attenuation value. + """ if not self.is_open: - raise attenuator.Error("Connection to attenuator at %s is not open!" % - self._telnet_client.host) + raise attenuator.Error( + "Connection to attenuator at %s is not open!" + % self._telnet_client.host + ) if idx + 1 > self.path_count: raise IndexError("Attenuator index out of range!", self.path_count, idx) if value > self.max_atten: @@ -102,22 +106,24 @@ def set_atten(self, idx, value): def get_atten(self, idx=0): """This function returns the current attenuation from an attenuator at a - given index in the instrument. + given index in the instrument. - Args: - idx: This zero-based index is the identifier for a particular - attenuator in an instrument. + Args: + idx: This zero-based index is the identifier for a particular + attenuator in an instrument. - Raises: - Error: The underlying telnet connection to the instrument is not - open. + Raises: + Error: The underlying telnet connection to the instrument is not + open. - Returns: - A float that is the current attenuation value. - """ + Returns: + A float that is the current attenuation value. + """ if not self.is_open: - raise attenuator.Error("Connection to attenuator at %s is not open!" % - self._telnet_client.host) + raise attenuator.Error( + "Connection to attenuator at %s is not open!" + % self._telnet_client.host + ) if idx + 1 > self.path_count or idx < 0: raise IndexError("Attenuator index out of range!", self.path_count, idx) telnet_cmd = ":ATT?" if self.path_count == 1 else "CHAN:%s:ATT?" % (idx + 1) diff --git a/mobly/controllers/attenuator_lib/telnet_scpi_client.py b/mobly/controllers/attenuator_lib/telnet_scpi_client.py index 4dde387f..98ccccab 100644 --- a/mobly/controllers/attenuator_lib/telnet_scpi_client.py +++ b/mobly/controllers/attenuator_lib/telnet_scpi_client.py @@ -23,14 +23,14 @@ def _ascii_string(uc_string): - return str(uc_string).encode('ASCII') + return str(uc_string).encode("ASCII") class TelnetScpiClient: """This is an internal helper class for Telnet+SCPI command-based - instruments. It should only be used by those implemention control libraries - and not by any user code directly. - """ + instruments. It should only be used by those implemention control libraries + and not by any user code directly. + """ def __init__(self, tx_cmd_separator="\n", rx_cmd_separator="\n", prompt=""): self._tn = None @@ -70,13 +70,15 @@ def cmd(self, cmd_str, wait_ret=True): return None match_idx, match_val, ret_text = self._tn.expect( - [_ascii_string("\S+" + self.rx_cmd_separator)], 1) + [_ascii_string("\S+" + self.rx_cmd_separator)], 1 + ) if match_idx == -1: raise attenuator.Error("Telnet command failed to return valid data") ret_text = ret_text.decode() - ret_text = ret_text.strip(self.tx_cmd_separator + self.rx_cmd_separator + - self.prompt) + ret_text = ret_text.strip( + self.tx_cmd_separator + self.rx_cmd_separator + self.prompt + ) return ret_text diff --git a/mobly/controllers/iperf_server.py b/mobly/controllers/iperf_server.py index f8ebde94..e99b298a 100644 --- a/mobly/controllers/iperf_server.py +++ b/mobly/controllers/iperf_server.py @@ -19,7 +19,7 @@ from mobly import utils -MOBLY_CONTROLLER_CONFIG_NAME = "IPerfServer" +MOBLY_CONTROLLER_CONFIG_NAME = 'IPerfServer' def create(configs): @@ -56,16 +56,16 @@ def __init__(self, result_path): def _has_data(self): """Checks if the iperf result has valid throughput data. - Returns: - True if the result contains throughput data. False otherwise. - """ - return ('end' in self.result) and ('sum' in self.result["end"]) + Returns: + True if the result contains throughput data. False otherwise. + """ + return ('end' in self.result) and ('sum' in self.result['end']) def get_json(self): """ - Returns: - The raw json output from iPerf. - """ + Returns: + The raw json output from iPerf. + """ return self.result @property @@ -78,8 +78,8 @@ def error(self): def avg_rate(self): """Average receiving rate in MB/s over the entire run. - If the result is not from a success run, this property is None. - """ + If the result is not from a success run, this property is None. + """ if not self._has_data or 'sum' not in self.result['end']: return None bps = self.result['end']['sum']['bits_per_second'] @@ -88,10 +88,10 @@ def avg_rate(self): @property def avg_receive_rate(self): """Average receiving rate in MB/s over the entire run. This data may - not exist if iperf was interrupted. + not exist if iperf was interrupted. - If the result is not from a success run, this property is None. - """ + If the result is not from a success run, this property is None. + """ if not self._has_data or 'sum_received' not in self.result['end']: return None bps = self.result['end']['sum_received']['bits_per_second'] @@ -100,44 +100,44 @@ def avg_receive_rate(self): @property def avg_send_rate(self): """Average sending rate in MB/s over the entire run. This data may - not exist if iperf was interrupted. + not exist if iperf was interrupted. - If the result is not from a success run, this property is None. - """ + If the result is not from a success run, this property is None. + """ if not self._has_data or 'sum_sent' not in self.result['end']: return None bps = self.result['end']['sum_sent']['bits_per_second'] return bps / 8 / 1024 / 1024 -class IPerfServer(): - """Class that handles iperf3 operations. - """ +class IPerfServer: + """Class that handles iperf3 operations.""" def __init__(self, port, log_path): self.port = port - self.log_path = os.path.join(log_path, "iPerf{}".format(self.port)) - self.iperf_str = "iperf3 -s -J -p {}".format(port) + self.log_path = os.path.join(log_path, 'iPerf{}'.format(self.port)) + self.iperf_str = 'iperf3 -s -J -p {}'.format(port) self.iperf_process = None self.log_files = [] self.started = False - def start(self, extra_args="", tag=""): + def start(self, extra_args='', tag=''): """Starts iperf server on specified port. - Args: - extra_args: A string representing extra arguments to start iperf - server with. - tag: Appended to log file name to identify logs from different - iperf runs. - """ + Args: + extra_args: A string representing extra arguments to start iperf + server with. + tag: Appended to log file name to identify logs from different + iperf runs. + """ if self.started: return utils.create_dir(self.log_path) if tag: tag = tag + ',' - out_file_name = "IPerfServer,{},{}{}.log".format(self.port, tag, - len(self.log_files)) + out_file_name = 'IPerfServer,{},{}{}.log'.format( + self.port, tag, len(self.log_files) + ) full_out_path = os.path.join(self.log_path, out_file_name) cmd = '%s %s > %s' % (self.iperf_str, extra_args, full_out_path) self.iperf_process = utils.start_standing_subprocess(cmd, shell=True) diff --git a/mobly/controllers/sniffer.py b/mobly/controllers/sniffer.py index 91293b47..e1f3460b 100644 --- a/mobly/controllers/sniffer.py +++ b/mobly/controllers/sniffer.py @@ -20,18 +20,18 @@ def create(configs): """Initializes the sniffer structures based on the JSON configuration. The - expected keys are: - - * Type: A first-level type of sniffer. Planned to be 'local' for - sniffers running on the local machine, or 'remote' for sniffers - running remotely. - * SubType: The specific sniffer type to be used. - * Interface: The WLAN interface used to configure the sniffer. - * BaseConfigs: A dictionary specifying baseline configurations of - the sniffer. Configurations can be overridden when starting a - capture. The keys must be one of the Sniffer.CONFIG_KEY_* - values. - """ + expected keys are: + + * Type: A first-level type of sniffer. Planned to be 'local' for + sniffers running on the local machine, or 'remote' for sniffers + running remotely. + * SubType: The specific sniffer type to be used. + * Interface: The WLAN interface used to configure the sniffer. + * BaseConfigs: A dictionary specifying baseline configurations of + the sniffer. Configurations can be overridden when starting a + capture. The keys must be one of the Sniffer.CONFIG_KEY_* + values. + """ objs = [] for c in configs: sniffer_type = c["Type"] @@ -39,18 +39,19 @@ def create(configs): interface = c["Interface"] base_configs = c["BaseConfigs"] module_name = "mobly.controllers.sniffer_lib.{}.{}".format( - sniffer_type, sniffer_subtype) + sniffer_type, sniffer_subtype + ) module = importlib.import_module(module_name) objs.append( - module.Sniffer(interface, - logging.getLogger(), - base_configs=base_configs)) + module.Sniffer( + interface, logging.getLogger(), base_configs=base_configs + ) + ) return objs def destroy(objs): - """Destroys the sniffers and terminates any ongoing capture sessions. - """ + """Destroys the sniffers and terminates any ongoing capture sessions.""" for sniffer in objs: try: sniffer.stop_capture() @@ -60,221 +61,227 @@ def destroy(objs): class SnifferError(Exception): """This is the Exception class defined for all errors generated by - Sniffer-related modules. - """ + Sniffer-related modules. + """ + pass class InvalidDataError(Exception): """This exception is thrown when invalid configuration data is passed - to a method. - """ + to a method. + """ + pass class ExecutionError(SnifferError): """This exception is thrown when trying to configure the capture device - or when trying to execute the capture operation. + or when trying to execute the capture operation. + + When this exception is seen, it is possible that the sniffer module is run + without sudo (for local sniffers) or keys are out-of-date (for remote + sniffers). + """ - When this exception is seen, it is possible that the sniffer module is run - without sudo (for local sniffers) or keys are out-of-date (for remote - sniffers). - """ pass class InvalidOperationError(SnifferError): """Certain methods may only be accessed when the instance upon which they - are invoked is in a certain state. This indicates that the object is not - in the correct state for a method to be called. - """ + are invoked is in a certain state. This indicates that the object is not + in the correct state for a method to be called. + """ + pass class Sniffer: """This class defines an object representing a sniffer. - The object defines the generic behavior of sniffers - irrespective of how - they are implemented, or where they are located: on the local machine or on - the remote machine. - """ + The object defines the generic behavior of sniffers - irrespective of how + they are implemented, or where they are located: on the local machine or on + the remote machine. + """ CONFIG_KEY_CHANNEL = "channel" def __init__(self, interface, logger, base_configs=None): """The constructor for the Sniffer. It constructs a sniffer and - configures it to be ready for capture. - - Args: - interface: A string specifying the interface used to configure the - sniffer. - logger: Mobly logger object. - base_configs: A dictionary containing baseline configurations of the - sniffer. These can be overridden when staring a capture. The - keys are specified by Sniffer.CONFIG_KEY_*. - - Returns: - self: A configured sniffer. - - Raises: - InvalidDataError: if the config_path is invalid. - NoPermissionError: if an error occurs while configuring the - sniffer. - """ + configures it to be ready for capture. + + Args: + interface: A string specifying the interface used to configure the + sniffer. + logger: Mobly logger object. + base_configs: A dictionary containing baseline configurations of the + sniffer. These can be overridden when staring a capture. The + keys are specified by Sniffer.CONFIG_KEY_*. + + Returns: + self: A configured sniffer. + + Raises: + InvalidDataError: if the config_path is invalid. + NoPermissionError: if an error occurs while configuring the + sniffer. + """ raise NotImplementedError("Base class should not be called directly!") def get_descriptor(self): """This function returns a string describing the sniffer. The specific - string (and its format) is up to each derived sniffer type. + string (and its format) is up to each derived sniffer type. - Returns: - A string describing the sniffer. - """ + Returns: + A string describing the sniffer. + """ raise NotImplementedError("Base class should not be called directly!") def get_type(self): """This function returns the type of the sniffer. - Returns: - The type (string) of the sniffer. Corresponds to the 'Type' key of - the sniffer configuration. - """ + Returns: + The type (string) of the sniffer. Corresponds to the 'Type' key of + the sniffer configuration. + """ raise NotImplementedError("Base class should not be called directly!") def get_subtype(self): """This function returns the sub-type of the sniffer. - Returns: - The sub-type (string) of the sniffer. Corresponds to the 'SubType' - key of the sniffer configuration. - """ + Returns: + The sub-type (string) of the sniffer. Corresponds to the 'SubType' + key of the sniffer configuration. + """ raise NotImplementedError("Base class should not be called directly!") def get_interface(self): """This function returns The interface used to configure the sniffer, - e.g. 'wlan0'. + e.g. 'wlan0'. - Returns: - The interface (string) used to configure the sniffer. Corresponds to - the 'Interface' key of the sniffer configuration. - """ + Returns: + The interface (string) used to configure the sniffer. Corresponds to + the 'Interface' key of the sniffer configuration. + """ raise NotImplementedError("Base class should not be called directly!") def get_capture_file(self): """The sniffer places a capture in the logger directory. This function - enables the caller to obtain the path of that capture. + enables the caller to obtain the path of that capture. - Returns: - The full path of the current or last capture. - """ + Returns: + The full path of the current or last capture. + """ raise NotImplementedError("Base class should not be called directly!") - def start_capture(self, - override_configs=None, - additional_args=None, - duration=None, - packet_count=None): + def start_capture( + self, + override_configs=None, + additional_args=None, + duration=None, + packet_count=None, + ): """This function starts a capture which is saved to the specified file - path. - - Depending on the type/subtype and configuration of the sniffer the - capture may terminate on its own or may require an explicit call to the - stop_capture() function. - - This is a non-blocking function so a terminating function must be - called either explicitly or implicitly: - - * Explicitly: call either stop_capture() or wait_for_capture() - * Implicitly: use with a with clause. The wait_for_capture() - function will be called if a duration is specified (i.e. - is not None), otherwise a stop_capture() will be called. - - The capture is saved to a file in the log path of the logger. Use - the get_capture_file() to get the full path to the current or most - recent capture. - - Args: - override_configs: A dictionary which is combined with the - base_configs ("BaseConfigs" in the sniffer configuration). The - keys (specified by Sniffer.CONFIG_KEY_*) determine the - configuration of the sniffer for this specific capture. - additional_args: A string specifying additional raw - command-line arguments to pass to the underlying sniffer. The - interpretation of these flags is sniffer-dependent. - duration: An integer specifying the number of seconds over which to - capture packets. The sniffer will be terminated after this - duration. Used in implicit mode when using a 'with' clause. In - explicit control cases may have to be performed using a - sleep+stop or as the timeout argument to the wait function. - packet_count: An integer specifying the number of packets to capture - before terminating. Should be used with duration to guarantee - that capture terminates at some point (even if did not capture - the specified number of packets). - - Returns: - An ActiveCaptureContext process which can be used with a 'with' - clause. - - Raises: - InvalidDataError: for invalid configurations - NoPermissionError: if an error occurs while configuring and running - the sniffer. - """ + path. + + Depending on the type/subtype and configuration of the sniffer the + capture may terminate on its own or may require an explicit call to the + stop_capture() function. + + This is a non-blocking function so a terminating function must be + called either explicitly or implicitly: + + * Explicitly: call either stop_capture() or wait_for_capture() + * Implicitly: use with a with clause. The wait_for_capture() + function will be called if a duration is specified (i.e. + is not None), otherwise a stop_capture() will be called. + + The capture is saved to a file in the log path of the logger. Use + the get_capture_file() to get the full path to the current or most + recent capture. + + Args: + override_configs: A dictionary which is combined with the + base_configs ("BaseConfigs" in the sniffer configuration). The + keys (specified by Sniffer.CONFIG_KEY_*) determine the + configuration of the sniffer for this specific capture. + additional_args: A string specifying additional raw + command-line arguments to pass to the underlying sniffer. The + interpretation of these flags is sniffer-dependent. + duration: An integer specifying the number of seconds over which to + capture packets. The sniffer will be terminated after this + duration. Used in implicit mode when using a 'with' clause. In + explicit control cases may have to be performed using a + sleep+stop or as the timeout argument to the wait function. + packet_count: An integer specifying the number of packets to capture + before terminating. Should be used with duration to guarantee + that capture terminates at some point (even if did not capture + the specified number of packets). + + Returns: + An ActiveCaptureContext process which can be used with a 'with' + clause. + + Raises: + InvalidDataError: for invalid configurations + NoPermissionError: if an error occurs while configuring and running + the sniffer. + """ raise NotImplementedError("Base class should not be called directly!") def stop_capture(self): """This function stops a capture and guarantees that the capture is - saved to the capture file configured during the start_capture() method. - Depending on the type of the sniffer the file may previously contain - partial results (e.g. for a local sniffer) or may not exist until the - stop_capture() method is executed (e.g. for a remote sniffer). - - Depending on the type/subtype and configuration of the sniffer the - capture may terminate on its own without requiring a call to this - function. In such a case it is still necessary to call either this - function or the wait_for_capture() function to make sure that the - capture file is moved to the correct location. - - Raises: - NoPermissionError: No permission when trying to stop a capture - and save the capture file. - """ + saved to the capture file configured during the start_capture() method. + Depending on the type of the sniffer the file may previously contain + partial results (e.g. for a local sniffer) or may not exist until the + stop_capture() method is executed (e.g. for a remote sniffer). + + Depending on the type/subtype and configuration of the sniffer the + capture may terminate on its own without requiring a call to this + function. In such a case it is still necessary to call either this + function or the wait_for_capture() function to make sure that the + capture file is moved to the correct location. + + Raises: + NoPermissionError: No permission when trying to stop a capture + and save the capture file. + """ raise NotImplementedError("Base class should not be called directly!") def wait_for_capture(self, timeout=None): """This function waits for a capture to terminate and guarantees that - the capture is saved to the capture file configured during the - start_capture() method. Depending on the type of the sniffer the file - may previously contain partial results (e.g. for a local sniffer) or - may not exist until the stop_capture() method is executed (e.g. for a - remote sniffer). - - Depending on the type/subtype and configuration of the sniffer the - capture may terminate on its own without requiring a call to this - function. In such a case it is still necessary to call either this - function or the stop_capture() function to make sure that the capture - file is moved to the correct location. - - Args: - timeout: An integer specifying the number of seconds to wait for - the capture to terminate on its own. On expiration of the - timeout the sniffer is stopped explicitly using the - stop_capture() function. - - Raises: - NoPermissionError: No permission when trying to stop a capture and - save the capture file. - """ + the capture is saved to the capture file configured during the + start_capture() method. Depending on the type of the sniffer the file + may previously contain partial results (e.g. for a local sniffer) or + may not exist until the stop_capture() method is executed (e.g. for a + remote sniffer). + + Depending on the type/subtype and configuration of the sniffer the + capture may terminate on its own without requiring a call to this + function. In such a case it is still necessary to call either this + function or the stop_capture() function to make sure that the capture + file is moved to the correct location. + + Args: + timeout: An integer specifying the number of seconds to wait for + the capture to terminate on its own. On expiration of the + timeout the sniffer is stopped explicitly using the + stop_capture() function. + + Raises: + NoPermissionError: No permission when trying to stop a capture and + save the capture file. + """ raise NotImplementedError("Base class should not be called directly!") class ActiveCaptureContext: """This class defines an object representing an active sniffer capture. - The object is returned by a Sniffer.start_capture() command and terminates - the capture when the 'with' clause exits. It is syntactic sugar for - try/finally. - """ + The object is returned by a Sniffer.start_capture() command and terminates + the capture when the 'with' clause exits. It is syntactic sugar for + try/finally. + """ _sniffer = None _timeout = None diff --git a/mobly/controllers/sniffer_lib/local/local_base.py b/mobly/controllers/sniffer_lib/local/local_base.py index 8ccf517c..c81b1087 100644 --- a/mobly/controllers/sniffer_lib/local/local_base.py +++ b/mobly/controllers/sniffer_lib/local/local_base.py @@ -29,15 +29,14 @@ class SnifferLocalBase(sniffer.Sniffer): """This class defines the common behaviors of WLAN sniffers running on - WLAN interfaces of the local machine. + WLAN interfaces of the local machine. - Specific mechanisms to capture packets over the local WLAN interfaces are - implemented by sub-classes of this class - i.e. it is not a final class. - """ + Specific mechanisms to capture packets over the local WLAN interfaces are + implemented by sub-classes of this class - i.e. it is not a final class. + """ def __init__(self, interface, logger, base_configs=None): - """See base class documentation - """ + """See base class documentation""" self._base_configs = None self._capture_file_path = "" self._interface = "" @@ -51,20 +50,18 @@ def __init__(self, interface, logger, base_configs=None): self._base_configs = base_configs try: - subprocess.check_call(['ifconfig', self._interface, 'down']) - subprocess.check_call(['iwconfig', self._interface, 'mode', 'monitor']) - subprocess.check_call(['ifconfig', self._interface, 'up']) + subprocess.check_call(["ifconfig", self._interface, "down"]) + subprocess.check_call(["iwconfig", self._interface, "mode", "monitor"]) + subprocess.check_call(["ifconfig", self._interface, "up"]) except Exception as err: raise sniffer.ExecutionError(err) def get_interface(self): - """See base class documentation - """ + """See base class documentation""" return self._interface def get_type(self): - """See base class documentation - """ + """See base class documentation""" return "local" def get_capture_file(self): @@ -72,10 +69,10 @@ def get_capture_file(self): def _pre_capture_config(self, override_configs=None): """Utility function which configures the wireless interface per the - specified configurations. Operation is performed before every capture - start using baseline configurations (specified when sniffer initialized) - and override configurations specified here. - """ + specified configurations. Operation is performed before every capture + start using baseline configurations (specified when sniffer initialized) + and override configurations specified here. + """ final_configs = {} if self._base_configs: final_configs.update(self._base_configs) @@ -85,71 +82,78 @@ def _pre_capture_config(self, override_configs=None): if sniffer.Sniffer.CONFIG_KEY_CHANNEL in final_configs: try: subprocess.check_call([ - 'iwconfig', self._interface, 'channel', - str(final_configs[sniffer.Sniffer.CONFIG_KEY_CHANNEL]) + "iwconfig", + self._interface, + "channel", + str(final_configs[sniffer.Sniffer.CONFIG_KEY_CHANNEL]), ]) except Exception as err: raise sniffer.ExecutionError(err) - def _get_command_line(self, - additional_args=None, - duration=None, - packet_count=None): + def _get_command_line( + self, additional_args=None, duration=None, packet_count=None + ): """Utility function to be implemented by every child class - which - are the concrete sniffer classes. Each sniffer-specific class should - derive the command line to execute its sniffer based on the specified - arguments. - """ + are the concrete sniffer classes. Each sniffer-specific class should + derive the command line to execute its sniffer based on the specified + arguments. + """ raise NotImplementedError("Base class should not be called directly!") def _post_process(self): """Utility function which is executed after a capture is done. It - moves the capture file to the requested location. - """ + moves the capture file to the requested location. + """ self._process = None shutil.move(self._temp_capture_file_path, self._capture_file_path) - def start_capture(self, - override_configs=None, - additional_args=None, - duration=None, - packet_count=None): - """See base class documentation - """ + def start_capture( + self, + override_configs=None, + additional_args=None, + duration=None, + packet_count=None, + ): + """See base class documentation""" if self._process is not None: raise sniffer.InvalidOperationError( - "Trying to start a sniff while another is still running!") - capture_dir = os.path.join(self._logger.log_path, - "Sniffer-{}".format(self._interface)) + "Trying to start a sniff while another is still running!" + ) + capture_dir = os.path.join( + self._logger.log_path, "Sniffer-{}".format(self._interface) + ) os.makedirs(capture_dir, exist_ok=True) self._capture_file_path = os.path.join( - capture_dir, "capture_{}.pcap".format(logger.get_log_file_timestamp())) + capture_dir, "capture_{}.pcap".format(logger.get_log_file_timestamp()) + ) self._pre_capture_config(override_configs) _, self._temp_capture_file_path = tempfile.mkstemp(suffix=".pcap") - cmd = self._get_command_line(additional_args=additional_args, - duration=duration, - packet_count=packet_count) + cmd = self._get_command_line( + additional_args=additional_args, + duration=duration, + packet_count=packet_count, + ) self._process = utils.start_standing_subprocess(cmd) return sniffer.ActiveCaptureContext(self, duration) def stop_capture(self): - """See base class documentation - """ + """See base class documentation""" if self._process is None: raise sniffer.InvalidOperationError( - "Trying to stop a non-started process") + "Trying to stop a non-started process" + ) utils.stop_standing_subprocess(self._process) self._post_process() def wait_for_capture(self, timeout=None): - """See base class documentation - """ + """See base class documentation""" if self._process is None: raise sniffer.InvalidOperationError( - "Trying to wait on a non-started process") + "Trying to wait on a non-started process" + ) try: utils.wait_for_standing_subprocess(self._process, timeout) self._post_process() diff --git a/mobly/controllers/sniffer_lib/local/tcpdump.py b/mobly/controllers/sniffer_lib/local/tcpdump.py index 053d4eb6..4f54cdb6 100644 --- a/mobly/controllers/sniffer_lib/local/tcpdump.py +++ b/mobly/controllers/sniffer_lib/local/tcpdump.py @@ -18,12 +18,10 @@ class Sniffer(local_base.SnifferLocalBase): - """This class defines a sniffer which uses tcpdump as its back-end - """ + """This class defines a sniffer which uses tcpdump as its back-end""" def __init__(self, config_path, logger, base_configs=None): - """See base class documentation - """ + """See base class documentation""" self._executable_path = None super().__init__(config_path, logger, base_configs=base_configs) @@ -31,24 +29,23 @@ def __init__(self, config_path, logger, base_configs=None): self._executable_path = shutil.which("tcpdump") if self._executable_path is None: raise sniffer.SnifferError( - "Cannot find a path to the 'tcpdump' executable") + "Cannot find a path to the 'tcpdump' executable" + ) def get_descriptor(self): - """See base class documentation - """ + """See base class documentation""" return "local-tcpdump-{}".format(self._interface) def get_subtype(self): - """See base class documentation - """ + """See base class documentation""" return "tcpdump" - def _get_command_line(self, - additional_args=None, - duration=None, - packet_count=None): - cmd = "{} -i {} -w {}".format(self._executable_path, self._interface, - self._temp_capture_file_path) + def _get_command_line( + self, additional_args=None, duration=None, packet_count=None + ): + cmd = "{} -i {} -w {}".format( + self._executable_path, self._interface, self._temp_capture_file_path + ) if packet_count is not None: cmd = "{} -c {}".format(cmd, packet_count) if additional_args is not None: diff --git a/mobly/controllers/sniffer_lib/local/tshark.py b/mobly/controllers/sniffer_lib/local/tshark.py index a22d5f02..e48b1c6f 100644 --- a/mobly/controllers/sniffer_lib/local/tshark.py +++ b/mobly/controllers/sniffer_lib/local/tshark.py @@ -18,38 +18,37 @@ class Sniffer(local_base.SnifferLocalBase): - """This class defines a sniffer which uses tshark as its back-end - """ + """This class defines a sniffer which uses tshark as its back-end""" def __init__(self, config_path, logger, base_configs=None): - """See base class documentation - """ + """See base class documentation""" self._executable_path = None super().__init__(config_path, logger, base_configs=base_configs) - self._executable_path = (shutil.which("tshark") or - shutil.which("/usr/local/bin/tshark")) + self._executable_path = shutil.which("tshark") or shutil.which( + "/usr/local/bin/tshark" + ) if self._executable_path is None: - raise sniffer.SnifferError("Cannot find a path to the 'tshark' " - "executable (or to '/usr/local/bin/tshark')") + raise sniffer.SnifferError( + "Cannot find a path to the 'tshark' " + "executable (or to '/usr/local/bin/tshark')" + ) def get_descriptor(self): - """See base class documentation - """ + """See base class documentation""" return "local-tshark-{}-ch{}".format(self._interface) def get_subtype(self): - """See base class documentation - """ + """See base class documentation""" return "tshark" - def _get_command_line(self, - additional_args=None, - duration=None, - packet_count=None): - cmd = "{} -i {} -w {}".format(self._executable_path, self._interface, - self._temp_capture_file_path) + def _get_command_line( + self, additional_args=None, duration=None, packet_count=None + ): + cmd = "{} -i {} -w {}".format( + self._executable_path, self._interface, self._temp_capture_file_path + ) if duration is not None: cmd = "{} -a duration:{}".format(cmd, duration) if packet_count is not None: diff --git a/mobly/expects.py b/mobly/expects.py index 9475758c..ad7cb8af 100644 --- a/mobly/expects.py +++ b/mobly/expects.py @@ -129,8 +129,9 @@ def expect_equal(first, second, msg=None, extras=None): try: asserts.assert_equal(first, second, msg, extras) except signals.TestSignal as e: - logging.exception('Expected %s equals to %s, but they are not.', first, - second) + logging.exception( + 'Expected %s equals to %s, but they are not.', first, second + ) recorder.add_error(e) diff --git a/mobly/keys.py b/mobly/keys.py index b5617349..1987cdce 100644 --- a/mobly/keys.py +++ b/mobly/keys.py @@ -17,6 +17,7 @@ class Config(enum.Enum): """The reserved keywordss used in configurations.""" + # Keywords for params consumed by Mobly itself. key_mobly_params = 'MoblyParams' key_log_path = 'LogPath' diff --git a/mobly/logger.py b/mobly/logger.py index ea1de124..b792caef 100644 --- a/mobly/logger.py +++ b/mobly/logger.py @@ -30,34 +30,25 @@ # length seems to be lower. WINDOWS_MAX_FILENAME_LENGTH = 237 WINDOWS_RESERVED_CHARACTERS_REPLACEMENTS = { - '<': - '-', - '>': - '-', - ':': - '-', - '"': - '_', - '/': - '_', - '\\': - '_', - '|': - ',', - '?': - ',', - '*': - ',', + '<': '-', + '>': '-', + ':': '-', + '"': '_', + '/': '_', + '\\': '_', + '|': ',', + '?': ',', + '*': ',', # Integer zero (i.e. NUL) is not a valid character. # While integers 1-31 are also usually valid, they aren't sanitized because # they are situationally valid. - chr(0): - '0', + chr(0): '0', } # Note, although the documentation does not specify as such, COM0 and LPT0 are # also invalid/reserved filenames. WINDOWS_RESERVED_FILENAME_REGEX = re.compile( - r'^(CON|PRN|AUX|NUL|(COM|LPT)[0-9])(\.[^.]*)?$', re.IGNORECASE) + r'^(CON|PRN|AUX|NUL|(COM|LPT)[0-9])(\.[^.]*)?$', re.IGNORECASE +) WINDOWS_RESERVED_FILENAME_PREFIX = 'mobly_' log_line_format = '%(asctime)s.%(msecs).03d %(levelname)s %(message)s' @@ -201,11 +192,13 @@ def _setup_test_logger(log_path, console_level, prefix=None): f_formatter = logging.Formatter(log_line_format, log_line_time_format) # Write logger output to files fh_info = logging.FileHandler( - os.path.join(log_path, records.OUTPUT_FILE_INFO_LOG)) + os.path.join(log_path, records.OUTPUT_FILE_INFO_LOG) + ) fh_info.setFormatter(f_formatter) fh_info.setLevel(logging.INFO) fh_debug = logging.FileHandler( - os.path.join(log_path, records.OUTPUT_FILE_DEBUG_LOG)) + os.path.join(log_path, records.OUTPUT_FILE_DEBUG_LOG) + ) fh_debug.setFormatter(f_formatter) fh_debug.setLevel(logging.DEBUG) log.addHandler(ch) @@ -241,10 +234,9 @@ def create_latest_log_alias(actual_path, alias): utils.create_alias(actual_path, alias_path) -def setup_test_logger(log_path, - prefix=None, - alias='latest', - console_level=logging.INFO): +def setup_test_logger( + log_path, prefix=None, alias='latest', console_level=logging.INFO +): """Customizes the root logger for a test run. In addition to configuring the Mobly logging handlers, this also sets two @@ -294,7 +286,7 @@ def _truncate_filename(filename, max_length): # This is kind of a degrenerate case where the extension is # extremely long, in which case, just return the truncated filename. return filename[:max_length] - return '.'.join([filename[:max_length - len(extension) - 1], extension]) + return '.'.join([filename[: max_length - len(extension) - 1], extension]) else: return filename[:max_length] diff --git a/mobly/records.py b/mobly/records.py index 08ebe8e6..c5f41ef8 100644 --- a/mobly/records.py +++ b/mobly/records.py @@ -11,8 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""This module has classes for test result collection, and test result output. -""" +"""This module has classes for test result collection, and test result output.""" import collections import copy @@ -56,7 +55,6 @@ def uid(uid): raise ValueError('UID cannot be None.') def decorate(test_func): - @functools.wraps(test_func) def wrapper(*args, **kwargs): return test_func(*args, **kwargs) @@ -77,6 +75,7 @@ class TestSummaryEntryType(enum.Enum): The idea is similar to how `TestResult.json_str` categorizes different sections of a `TestResult` object in the serialized format. """ + # A list of all the tests requested for a test run. # This is dumped at the beginning of a summary file so we know what was # requested in case the test is interrupted and the final summary is not @@ -153,12 +152,14 @@ def dump(self, content, entry_type): with io.open(self._path, 'a', encoding='utf-8') as f: # Use safe_dump here to avoid language-specific tags in final # output. - yaml.safe_dump(new_content, - f, - explicit_start=True, - explicit_end=True, - allow_unicode=True, - indent=4) + yaml.safe_dump( + new_content, + f, + explicit_start=True, + explicit_end=True, + allow_unicode=True, + indent=4, + ) class TestResultEnums: @@ -240,7 +241,8 @@ def __init__(self, e, position=None): exc_traceback = e.__traceback__ if exc_traceback: self.stacktrace = ''.join( - traceback.format_exception(e.__class__, e, exc_traceback)) + traceback.format_exception(e.__class__, e, exc_traceback) + ) # Populate fields based on the type of the termination signal. if self.is_test_signal: self._set_details(e.details) @@ -358,8 +360,7 @@ def termination_signal_type(self): @property def stacktrace(self): - """The stacktrace string for the exception that terminated the test. - """ + """The stacktrace string for the exception that terminated the test.""" if self.termination_signal: return self.termination_signal.stacktrace @@ -468,8 +469,10 @@ def add_error(self, position, e): if self.result != TestResultEnums.TEST_RESULT_FAIL: self.result = TestResultEnums.TEST_RESULT_ERROR if position in self.extra_errors: - raise Error('An exception is already recorded with position "%s",' - ' cannot reuse.' % position) + raise Error( + 'An exception is already recorded with position "%s", cannot reuse.' + % position + ) if isinstance(e, ExceptionRecord): self.extra_errors[position] = e else: @@ -500,12 +503,14 @@ def to_dict(self): d[TestResultEnums.RECORD_RESULT] = self.result d[TestResultEnums.RECORD_UID] = self.uid d[TestResultEnums.RECORD_SIGNATURE] = self.signature - d[TestResultEnums. - RECORD_RETRY_PARENT] = self.retry_parent.signature if self.retry_parent else None + d[TestResultEnums.RECORD_RETRY_PARENT] = ( + self.retry_parent.signature if self.retry_parent else None + ) d[TestResultEnums.RECORD_EXTRAS] = self.extras d[TestResultEnums.RECORD_DETAILS] = self.details - d[TestResultEnums. - RECORD_TERMINATION_SIGNAL_TYPE] = self.termination_signal_type + d[TestResultEnums.RECORD_TERMINATION_SIGNAL_TYPE] = ( + self.termination_signal_type + ) d[TestResultEnums.RECORD_EXTRA_ERRORS] = { key: value.to_dict() for (key, value) in self.extra_errors.items() } @@ -551,8 +556,9 @@ def __add__(self, r): A TestResult instance that's the sum of two TestResult instances. """ if not isinstance(r, TestResult): - raise TypeError('Operand %s of type %s is not a TestResult.' % - (r, type(r))) + raise TypeError( + 'Operand %s of type %s is not a TestResult.' % (r, type(r)) + ) sum_result = TestResult() for name in sum_result.__dict__: r_value = getattr(r, name) @@ -646,8 +652,11 @@ def _count_eventually_passing_retries(self): @property def is_all_pass(self): """True if no tests failed or threw errors, False otherwise.""" - num_of_result_altering_errors = (len(self.failed) + len(self.error) - - self._count_eventually_passing_retries()) + num_of_result_altering_errors = ( + len(self.failed) + + len(self.error) + - self._count_eventually_passing_retries() + ) if num_of_result_altering_errors == 0: return True return False diff --git a/mobly/runtime_test_info.py b/mobly/runtime_test_info.py index ed691bcc..ca0eafdb 100644 --- a/mobly/runtime_test_info.py +++ b/mobly/runtime_test_info.py @@ -40,7 +40,8 @@ def __init__(self, test_name, log_path, record): self._name = test_name self._record = record self._output_dir_path = utils.abs_path( - os.path.join(log_path, self._record.signature)) + os.path.join(log_path, self._record.signature) + ) @property def name(self): diff --git a/mobly/signals.py b/mobly/signals.py index ef777d91..dc020f95 100644 --- a/mobly/signals.py +++ b/mobly/signals.py @@ -11,8 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""This module is where all the test signal classes and related utilities live. -""" +"""This module is where all the test signal classes and related utilities live.""" import json @@ -38,8 +37,9 @@ def __init__(self, details, extras=None): json.dumps(extras) self.extras = extras except TypeError: - raise TestSignalError('Extras must be json serializable. %s ' - 'is not.' % extras) + raise TestSignalError( + 'Extras must be json serializable. %s is not.' % extras + ) def __str__(self): return 'Details=%s, Extras=%s' % (self.details, self.extras) @@ -62,8 +62,7 @@ class TestSkip(TestSignal): class TestAbortSignal(TestSignal): - """Base class for abort signals. - """ + """Base class for abort signals.""" class TestAbortClass(TestAbortSignal): diff --git a/mobly/snippet/callback_event.py b/mobly/snippet/callback_event.py index 55471c72..ea8ee385 100644 --- a/mobly/snippet/callback_event.py +++ b/mobly/snippet/callback_event.py @@ -23,10 +23,12 @@ def from_dict(event_dict): Returns: A CallbackEvent object. """ - return CallbackEvent(callback_id=event_dict['callbackId'], - name=event_dict['name'], - creation_time=event_dict['time'], - data=event_dict['data']) + return CallbackEvent( + callback_id=event_dict['callbackId'], + name=event_dict['name'], + creation_time=event_dict['time'], + data=event_dict['data'], + ) class CallbackEvent: @@ -49,4 +51,5 @@ def __init__(self, callback_id, name, creation_time, data): def __repr__(self): return ( f'CallbackEvent(callback_id: {self.callback_id}, name: {self.name}, ' - f'creation_time: {self.creation_time}, data: {self.data})') + f'creation_time: {self.creation_time}, data: {self.data})' + ) diff --git a/mobly/snippet/callback_handler_base.py b/mobly/snippet/callback_handler_base.py index 50465d1a..95b5a4bc 100644 --- a/mobly/snippet/callback_handler_base.py +++ b/mobly/snippet/callback_handler_base.py @@ -45,14 +45,16 @@ class CallbackHandlerBase(abc.ABC): ret_value: any, the direct return value of the async RPC call. """ - def __init__(self, - callback_id, - event_client, - ret_value, - method_name, - device, - rpc_max_timeout_sec, - default_timeout_sec=120): + def __init__( + self, + callback_id, + event_client, + ret_value, + method_name, + device, + rpc_max_timeout_sec, + default_timeout_sec=120, + ): """Initializes a callback handler base object. Args: @@ -74,10 +76,12 @@ def __init__(self, self._method_name = method_name if rpc_max_timeout_sec < default_timeout_sec: - raise ValueError('The max timeout of a single RPC must be no smaller ' - 'than the default timeout of the callback handler. ' - f'Got rpc_max_timeout_sec={rpc_max_timeout_sec}, ' - f'default_timeout_sec={default_timeout_sec}.') + raise ValueError( + 'The max timeout of a single RPC must be no smaller ' + 'than the default timeout of the callback handler. ' + f'Got rpc_max_timeout_sec={rpc_max_timeout_sec}, ' + f'default_timeout_sec={default_timeout_sec}.' + ) self._rpc_max_timeout_sec = rpc_max_timeout_sec self._default_timeout_sec = default_timeout_sec @@ -168,7 +172,8 @@ def waitAndGet(self, event_name, timeout=None): raise errors.CallbackHandlerBaseError( self._device, f'Specified timeout {timeout} is longer than max timeout ' - f'{self.rpc_max_timeout_sec}.') + f'{self.rpc_max_timeout_sec}.', + ) raw_event = self.callEventWaitAndGetRpc(self._id, event_name, timeout) return callback_event.from_dict(raw_event) @@ -223,7 +228,8 @@ def waitForEvent(self, event_name, predicate, timeout=None): raise errors.CallbackHandlerTimeoutError( self._device, f'Timed out after {timeout}s waiting for an "{event_name}" event that ' - f'satisfies the predicate "{predicate.__name__}".') + f'satisfies the predicate "{predicate.__name__}".', + ) def getAll(self, event_name): """Gets all existing events in the server with the specified identifier. diff --git a/mobly/snippet/client_base.py b/mobly/snippet/client_base.py index 3e046df9..3a24a20a 100644 --- a/mobly/snippet/client_base.py +++ b/mobly/snippet/client_base.py @@ -127,26 +127,34 @@ def initialize(self): self.log.debug('Starting the snippet server of %s.', self.package) self.start_server() - self.log.debug('Making a connection to the snippet server of %s.', - self.package) + self.log.debug( + 'Making a connection to the snippet server of %s.', self.package + ) self._make_connection() except Exception: self.log.error( 'Error occurred trying to start and connect to the snippet server ' - 'of %s.', self.package) + 'of %s.', + self.package, + ) try: self.stop() except Exception: # pylint: disable=broad-except # Only prints this exception and re-raises the original exception self.log.exception( 'Failed to stop the snippet package %s after failure to start ' - 'and connect.', self.package) + 'and connect.', + self.package, + ) raise - self.log.debug('Snippet package %s initialized after %.1fs.', self.package, - time.perf_counter() - start_time) + self.log.debug( + 'Snippet package %s initialized after %.1fs.', + self.package, + time.perf_counter() - start_time, + ) @abc.abstractmethod def before_starting_server(self): @@ -271,7 +279,8 @@ def _rpc(self, rpc_func_name, *args, **kwargs): except Exception: self.log.error( 'Server process running check failed, skip sending RPC method(%s).', - rpc_func_name) + rpc_func_name, + ) raise with self._lock: @@ -285,12 +294,15 @@ def _rpc(self, rpc_func_name, *args, **kwargs): if self.verbose_logging or _MAX_RPC_RESP_LOGGING_LENGTH >= len(response): self.log.debug('Snippet received: %s', response) else: - self.log.debug('Snippet received: %s... %d chars are truncated', - response[:_MAX_RPC_RESP_LOGGING_LENGTH], - len(response) - _MAX_RPC_RESP_LOGGING_LENGTH) + self.log.debug( + 'Snippet received: %s... %d chars are truncated', + response[:_MAX_RPC_RESP_LOGGING_LENGTH], + len(response) - _MAX_RPC_RESP_LOGGING_LENGTH, + ) response_decoded = self._decode_response_string_and_validate_format( - rpc_id, response) + rpc_id, response + ) return self._handle_rpc_response(rpc_func_name, response_decoded) @abc.abstractmethod @@ -360,19 +372,22 @@ def _decode_response_string_and_validate_format(self, rpc_id, response): errors.ProtocolError: if the response format is invalid. """ if not response: - raise errors.ProtocolError(self._device, - errors.ProtocolError.NO_RESPONSE_FROM_SERVER) + raise errors.ProtocolError( + self._device, errors.ProtocolError.NO_RESPONSE_FROM_SERVER + ) result = json.loads(response) for field_name in RPC_RESPONSE_REQUIRED_FIELDS: if field_name not in result: raise errors.ProtocolError( self._device, - errors.ProtocolError.RESPONSE_MISSING_FIELD % field_name) + errors.ProtocolError.RESPONSE_MISSING_FIELD % field_name, + ) if result['id'] != rpc_id: - raise errors.ProtocolError(self._device, - errors.ProtocolError.MISMATCHED_API_ID) + raise errors.ProtocolError( + self._device, errors.ProtocolError.MISMATCHED_API_ID + ) return result @@ -399,8 +414,9 @@ def _handle_rpc_response(self, rpc_func_name, response): if response['error']: raise errors.ApiError(self._device, response['error']) if response['callback'] is not None: - return self.handle_callback(response['callback'], response['result'], - rpc_func_name) + return self.handle_callback( + response['callback'], response['result'], rpc_func_name + ) return response['result'] @abc.abstractmethod diff --git a/mobly/snippet/errors.py b/mobly/snippet/errors.py index 4d41adb1..6ca71978 100644 --- a/mobly/snippet/errors.py +++ b/mobly/snippet/errors.py @@ -51,9 +51,11 @@ class ApiError(Error): class ProtocolError(Error): """Raised when there was an error in exchanging data with server.""" + NO_RESPONSE_FROM_HANDSHAKE = 'No response from handshake.' - NO_RESPONSE_FROM_SERVER = ('No response from server. ' - 'Check the device logcat for crashes.') + NO_RESPONSE_FROM_SERVER = ( + 'No response from server. Check the device logcat for crashes.' + ) MISMATCHED_API_ID = 'RPC request-response ID mismatch.' RESPONSE_MISSING_FIELD = 'Missing required field in the RPC response: %s.' diff --git a/mobly/suite_runner.py b/mobly/suite_runner.py index aed0d3dd..b0b064ca 100644 --- a/mobly/suite_runner.py +++ b/mobly/suite_runner.py @@ -93,35 +93,45 @@ def _parse_cli_args(argv): """ parser = argparse.ArgumentParser(description='Mobly Suite Executable.') group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-c', - '--config', - type=str, - metavar='', - help='Path to the test configuration file.') + group.add_argument( + '-c', + '--config', + type=str, + metavar='', + help='Path to the test configuration file.', + ) group.add_argument( '-l', '--list_tests', action='store_true', - help='Print the names of the tests defined in a script without ' - 'executing them.') + help=( + 'Print the names of the tests defined in a script without ' + 'executing them.' + ), + ) parser.add_argument( '--tests', '--test_case', nargs='+', type=str, metavar='[ClassA[.test_a] ClassB[.test_b] ...]', - help='A list of test classes and optional tests to execute.') - parser.add_argument('-tb', - '--test_bed', - nargs='+', - type=str, - metavar='[ ...]', - help='Specify which test beds to run tests on.') - - parser.add_argument('-v', - '--verbose', - action='store_true', - help='Set console logger level to DEBUG') + help='A list of test classes and optional tests to execute.', + ) + parser.add_argument( + '-tb', + '--test_bed', + nargs='+', + type=str, + metavar='[ ...]', + help='Specify which test beds to run tests on.', + ) + + parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='Set console logger level to DEBUG', + ) if not argv: argv = sys.argv[1:] return parser.parse_known_args(argv)[0] @@ -143,8 +153,10 @@ def _find_suite_class(): if issubclass(module_member, base_suite.BaseSuite): test_suites.append(module_member) if len(test_suites) != 1: - logging.error('Expected 1 test class per file, found %s.', - [t.__name__ for t in test_suites]) + logging.error( + 'Expected 1 test class per file, found %s.', + [t.__name__ for t in test_suites], + ) sys.exit(1) return test_suites[0] @@ -173,7 +185,7 @@ def _print_test_names(test_classes): cls._clean_up() print('==========> %s <==========' % cls.TAG) for name in test_names: - print(f"{cls.TAG}.{name}") + print(f'{cls.TAG}.{name}') def run_suite_class(argv=None): @@ -187,14 +199,16 @@ def run_suite_class(argv=None): if cli_args.list_tests: _print_test_names([suite_class]) sys.exit(0) - test_configs = config_parser.load_test_config_file(cli_args.config, - cli_args.test_bed) + test_configs = config_parser.load_test_config_file( + cli_args.config, cli_args.test_bed + ) config_count = len(test_configs) if config_count != 1: logging.error('Expect exactly one test config, found %d', config_count) config = test_configs[0] - runner = test_runner.TestRunner(log_dir=config.log_path, - testbed_name=config.testbed_name) + runner = test_runner.TestRunner( + log_dir=config.log_path, testbed_name=config.testbed_name + ) suite = suite_class(runner, config) console_level = logging.DEBUG if cli_args.verbose else logging.INFO ok = False @@ -230,8 +244,9 @@ def run_suite(test_classes, argv=None): for test_class in test_classes: if not issubclass(test_class, base_test.BaseTestClass): logging.error( - 'Test class %s does not extend ' - 'mobly.base_test.BaseTestClass', test_class) + 'Test class %s does not extend mobly.base_test.BaseTestClass', + test_class, + ) sys.exit(1) if args.list_tests: @@ -249,7 +264,7 @@ def run_suite(test_classes, argv=None): for config in test_configs: runner = test_runner.TestRunner(config.log_path, config.testbed_name) with runner.mobly_logger(console_level=console_level): - for (test_class, tests) in selected_tests.items(): + for test_class, tests in selected_tests.items(): runner.add_test_class(config, test_class, tests) try: runner.run() diff --git a/mobly/test_runner.py b/mobly/test_runner.py index 529035f9..5c97113d 100644 --- a/mobly/test_runner.py +++ b/mobly/test_runner.py @@ -70,8 +70,9 @@ def main(argv=None): # Execute the test class with configs. ok = True for config in test_configs: - runner = TestRunner(log_dir=config.log_path, - testbed_name=config.testbed_name) + runner = TestRunner( + log_dir=config.log_path, testbed_name=config.testbed_name + ) with runner.mobly_logger(console_level=console_level): runner.add_test_class(config, test_class, tests) try: @@ -104,34 +105,45 @@ def parse_mobly_cli_args(argv): """ parser = argparse.ArgumentParser(description='Mobly Test Executable.') group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-c', - '--config', - type=str, - metavar='', - help='Path to the test configuration file.') + group.add_argument( + '-c', + '--config', + type=str, + metavar='', + help='Path to the test configuration file.', + ) group.add_argument( '-l', '--list_tests', action='store_true', - help='Print the names of the tests defined in a script without ' - 'executing them.') - parser.add_argument('--tests', - '--test_case', - nargs='+', - type=str, - metavar='[test_a test_b...]', - help='A list of tests in the test class to execute.') - parser.add_argument('-tb', - '--test_bed', - nargs='+', - type=str, - metavar='[ ...]', - help='Specify which test beds to run tests on.') - - parser.add_argument('-v', - '--verbose', - action='store_true', - help='Set console logger level to DEBUG') + help=( + 'Print the names of the tests defined in a script without ' + 'executing them.' + ), + ) + parser.add_argument( + '--tests', + '--test_case', + nargs='+', + type=str, + metavar='[test_a test_b...]', + help='A list of tests in the test class to execute.', + ) + parser.add_argument( + '-tb', + '--test_bed', + nargs='+', + type=str, + metavar='[ ...]', + help='Specify which test beds to run tests on.', + ) + + parser.add_argument( + '-v', + '--verbose', + action='store_true', + help='Set console logger level to DEBUG', + ) if not argv: argv = sys.argv[1:] return parser.parse_known_args(argv)[0] @@ -150,11 +162,14 @@ def _find_test_class(): SystemExit: Raised if the number of test classes is not exactly one. """ try: - return utils.find_subclass_in_module(base_test.BaseTestClass, - sys.modules['__main__']) + return utils.find_subclass_in_module( + base_test.BaseTestClass, sys.modules['__main__'] + ) except ValueError: - logging.exception('Exactly one subclass of `base_test.BaseTestClass`' - ' should be in the main file.') + logging.exception( + 'Exactly one subclass of `base_test.BaseTestClass`' + ' should be in the main file.' + ) sys.exit(1) @@ -206,11 +221,9 @@ class _TestRunInfo: run it with. """ - def __init__(self, - config, - test_class, - tests=None, - test_class_name_suffix=None): + def __init__( + self, config, test_class, tests=None, test_class_name_suffix=None + ): self.config = config self.test_class = test_class self.test_class_name_suffix = test_class_name_suffix @@ -255,8 +268,9 @@ def generate_test_run_log_path(self): String, the generated log path. """ self._logger_start_time = logger.get_log_file_timestamp() - self.root_output_path = os.path.join(self._log_dir, self._testbed_name, - self._logger_start_time) + self.root_output_path = os.path.join( + self._log_dir, self._testbed_name, self._logger_start_time + ) return self.root_output_path @property @@ -323,10 +337,12 @@ def mobly_logger(self, alias='latest', console_level=logging.INFO): """ # Refresh the log path at the beginning of the logger context. root_output_path = self._test_run_metadata.generate_test_run_log_path() - logger.setup_test_logger(root_output_path, - self._testbed_name, - alias=alias, - console_level=console_level) + logger.setup_test_logger( + root_output_path, + self._testbed_name, + alias=alias, + console_level=console_level, + ) try: yield self._test_run_metadata.root_output_path finally: @@ -351,18 +367,25 @@ class to execute. constructor. """ if self._log_dir != config.log_path: - raise Error('TestRunner\'s log folder is "%s", but a test config with a ' - 'different log folder ("%s") was added.' % - (self._log_dir, config.log_path)) + raise Error( + 'TestRunner\'s log folder is "%s", but a test config with a ' + 'different log folder ("%s") was added.' + % (self._log_dir, config.log_path) + ) if self._testbed_name != config.testbed_name: - raise Error('TestRunner\'s test bed is "%s", but a test config with a ' - 'different test bed ("%s") was added.' % - (self._testbed_name, config.testbed_name)) + raise Error( + 'TestRunner\'s test bed is "%s", but a test config with a ' + 'different test bed ("%s") was added.' + % (self._testbed_name, config.testbed_name) + ) self._test_run_infos.append( - TestRunner._TestRunInfo(config=config, - test_class=test_class, - tests=tests, - test_class_name_suffix=name_suffix)) + TestRunner._TestRunInfo( + config=config, + test_class=test_class, + tests=tests, + test_class_name_suffix=name_suffix, + ) + ) def _run_test_class(self, config, test_class, tests=None): """Instantiates and executes a test class. @@ -377,8 +400,9 @@ def _run_test_class(self, config, test_class, tests=None): tests: Optional list of test names within the class to execute. """ test_instance = test_class(config) - logging.debug('Executing test class "%s" with config: %s', - test_class.__name__, config) + logging.debug( + 'Executing test class "%s" with config: %s', test_class.__name__, config + ) try: cls_result = test_instance.run(tests) self.results += cls_result @@ -412,7 +436,8 @@ def run(self): utils.create_dir(self._test_run_metadata.root_output_path) summary_writer = records.TestSummaryWriter( - self._test_run_metadata.summary_file_path) + self._test_run_metadata.summary_file_path + ) # When a SIGTERM is received during the execution of a test, the Mobly test # immediately terminates without executing any of the finally blocks. This @@ -432,24 +457,35 @@ def sigterm_handler(*args): test_config = test_run_info.config.copy() test_config.log_path = self._test_run_metadata.root_output_path test_config.summary_writer = summary_writer - test_config.test_class_name_suffix = test_run_info.test_class_name_suffix + test_config.test_class_name_suffix = ( + test_run_info.test_class_name_suffix + ) try: - self._run_test_class(config=test_config, - test_class=test_run_info.test_class, - tests=test_run_info.tests) + self._run_test_class( + config=test_config, + test_class=test_run_info.test_class, + tests=test_run_info.tests, + ) except signals.TestAbortAll as e: logging.warning('Abort all subsequent test classes. Reason: %s', e) raise finally: - summary_writer.dump(self.results.summary_dict(), - records.TestSummaryEntryType.SUMMARY) + summary_writer.dump( + self.results.summary_dict(), records.TestSummaryEntryType.SUMMARY + ) self._test_run_metadata.set_end_point() # Show the test run summary. summary_lines = [ f'Summary for test run {self._test_run_metadata.run_id}:', f'Total time elapsed {self._test_run_metadata.time_elapsed_sec}s', - f'Artifacts are saved in "{self._test_run_metadata.root_output_path}"', - f'Test summary saved in "{self._test_run_metadata.summary_file_path}"', - f'Test results: {self.results.summary_str()}' + ( + 'Artifacts are saved in' + f' "{self._test_run_metadata.root_output_path}"' + ), + ( + 'Test summary saved in' + f' "{self._test_run_metadata.summary_file_path}"' + ), + f'Test results: {self.results.summary_str()}', ] logging.info('\n'.join(summary_lines)) diff --git a/mobly/utils.py b/mobly/utils.py index 9d777d83..dca925d4 100644 --- a/mobly/utils.py +++ b/mobly/utils.py @@ -75,7 +75,7 @@ 'GMT+12': 'Pacific/Fiji', 'GMT+13': 'Pacific/Tongatapu', 'GMT-11': 'Pacific/Midway', - 'GMT-10': 'Pacific/Honolulu' + 'GMT-10': 'Pacific/Honolulu', } @@ -127,6 +127,7 @@ def create_alias(target_path, alias_path): os.remove(alias_path) if platform.system() == 'Windows': from win32com import client + shell = client.Dispatch('WScript.Shell') shortcut = shell.CreateShortCut(alias_path) shortcut.Targetpath = target_path @@ -280,14 +281,18 @@ def _collect_process_tree(starting_pid): while stack: pid = stack.pop() try: - ps_results = subprocess.check_output([ - 'ps', - '-o', - 'pid', - '--ppid', - str(pid), - '--noheaders', - ]).decode().strip() + ps_results = ( + subprocess.check_output([ + 'ps', + '-o', + 'pid', + '--ppid', + str(pid), + '--noheaders', + ]) + .decode() + .strip() + ) except subprocess.CalledProcessError: # Ignore if there is not child process. continue @@ -358,7 +363,8 @@ def concurrent_exec(func, param_list, max_workers=30, raise_on_exception=False): `raise_on_exception` is True. """ with concurrent.futures.ThreadPoolExecutor( - max_workers=max_workers) as executor: + max_workers=max_workers + ) as executor: # Start the load operations and mark each future with its params future_to_params = {executor.submit(func, *p): p for p in param_list} return_vals = [] @@ -368,16 +374,21 @@ def concurrent_exec(func, param_list, max_workers=30, raise_on_exception=False): try: return_vals.append(future.result()) except Exception as exc: # pylint: disable=broad-except - logging.exception('%s generated an exception: %s', params, - traceback.format_exc()) + logging.exception( + '%s generated an exception: %s', params, traceback.format_exc() + ) return_vals.append(exc) exceptions.append(exc) if raise_on_exception and exceptions: error_messages = [] for exception in exceptions: - error_messages.append(''.join( - traceback.format_exception(exception.__class__, exception, - exception.__traceback__))) + error_messages.append( + ''.join( + traceback.format_exception( + exception.__class__, exception, exception.__traceback__ + ) + ) + ) raise RuntimeError('\n\n'.join(error_messages)) return return_vals @@ -392,7 +403,8 @@ def run_command( timeout=..., cwd=..., env=..., - universal_newlines: Literal[False] = ...) -> Tuple[int, bytes, bytes]: + universal_newlines: Literal[False] = ..., +) -> Tuple[int, bytes, bytes]: ... @@ -405,18 +417,21 @@ def run_command( timeout=..., cwd=..., env=..., - universal_newlines: Literal[True] = ...) -> Tuple[int, str, str]: + universal_newlines: Literal[True] = ..., +) -> Tuple[int, str, str]: ... -def run_command(cmd, - stdout=None, - stderr=None, - shell=False, - timeout=None, - cwd=None, - env=None, - universal_newlines=False): +def run_command( + cmd, + stdout=None, + stderr=None, + shell=False, + timeout=None, + cwd=None, + env=None, + universal_newlines=False, +): """Runs a command in a subprocess. This function is very similar to subprocess.check_output. The main @@ -457,13 +472,15 @@ def run_command(cmd, stdout = subprocess.PIPE if stderr is None: stderr = subprocess.PIPE - process = subprocess.Popen(cmd, - stdout=stdout, - stderr=stderr, - shell=shell, - cwd=cwd, - env=env, - universal_newlines=universal_newlines) + process = subprocess.Popen( + cmd, + stdout=stdout, + stderr=stderr, + shell=shell, + cwd=cwd, + env=env, + universal_newlines=universal_newlines, + ) timer = None timer_triggered = threading.Event() if timeout and timeout > 0: @@ -482,10 +499,9 @@ def timeout_expired(): if timer is not None: timer.cancel() if timer_triggered.is_set(): - raise subprocess.TimeoutExpired(cmd=cmd, - timeout=timeout, - output=out, - stderr=err) + raise subprocess.TimeoutExpired( + cmd=cmd, timeout=timeout, output=out, stderr=err + ) return process.returncode, out, err @@ -510,12 +526,14 @@ def start_standing_subprocess(cmd, shell=False, env=None): The subprocess that was started. """ logging.debug('Starting standing subprocess with: %s', cmd) - proc = subprocess.Popen(cmd, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - shell=shell, - env=env) + proc = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=shell, + env=env, + ) # Leaving stdin open causes problems for input, e.g. breaking the # code.inspect() shell (http://stackoverflow.com/a/25512460/1612937), so # explicitly close it assuming it is not needed for standing subprocesses. @@ -594,6 +612,7 @@ def get_available_host_port(): """ # Only import adb module if needed. from mobly.controllers.android_device_lib import adb + port = portpicker.pick_unused_port() if not adb.is_adb_available(): return port @@ -603,8 +622,11 @@ def get_available_host_port(): if port not in adb.list_occupied_adb_ports(): return port port = portpicker.pick_unused_port() - raise Error('Failed to find available port after {} retries'.format( - MAX_PORT_ALLOCATION_RETRY)) + raise Error( + 'Failed to find available port after {} retries'.format( + MAX_PORT_ALLOCATION_RETRY + ) + ) def grep(regex, output): @@ -696,6 +718,7 @@ def find_subclass_in_module(base_class, module): subclasses = find_subclasses_in_module([base_class], module) if len(subclasses) != 1: raise ValueError( - 'Expected 1 subclass of %s per module, found %s.' % - (base_class.__name__, [subclass.__name__ for subclass in subclasses])) + 'Expected 1 subclass of %s per module, found %s.' + % (base_class.__name__, [subclass.__name__ for subclass in subclasses]) + ) return subclasses[0] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..ecf4aa7c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,6 @@ +[tool.pyink] +line-length = 80 +preview = true +pyink-indentation = 2 +pyink-use-majority-quotes = true +extend-exclude = '.*\/venv/.*|.*\/\.tox\/.*' \ No newline at end of file diff --git a/setup.py b/setup.py index e99a054f..3a37ddcf 100755 --- a/setup.py +++ b/setup.py @@ -34,11 +34,12 @@ class PyTest(test.test): def finalize_options(self): test.test.finalize_options(self) - self.test_args = ['-x', "tests/mobly"] + self.test_args = ['-x', 'tests/mobly'] self.test_suite = True def run_tests(self): import pytest + errno = pytest.main(self.test_args) sys.exit(errno) diff --git a/tests/lib/integration_test.py b/tests/lib/integration_test.py index 0a1cf87f..905caa68 100755 --- a/tests/lib/integration_test.py +++ b/tests/lib/integration_test.py @@ -28,13 +28,16 @@ def setup_class(self): def test_hello_world(self): asserts.assert_equal(self.user_params['icecream'], 42) asserts.assert_equal(self.user_params['extra_param'], 'haha') - logging.info('This is a bare minimal test to make sure the basic MOBLY' - ' test flow works.') + logging.info( + 'This is a bare minimal test to make sure the basic MOBLY' + ' test flow works.' + ) asserts.explicit_pass( 'Hello World', # Use a unicode string here to make sure the full log pipeline # works with unicode. - extras=u'\u2022') + extras='\u2022', + ) if __name__ == '__main__': diff --git a/tests/lib/jsonrpc_client_test_base.py b/tests/lib/jsonrpc_client_test_base.py index 3124630a..7ea0eeb8 100755 --- a/tests/lib/jsonrpc_client_test_base.py +++ b/tests/lib/jsonrpc_client_test_base.py @@ -26,21 +26,26 @@ class JsonRpcClientTestBase(unittest.TestCase): MOCK_RESP = ( b'{"id": 0, "result": 123, "error": null, "status": 1, "uid": 1, ' - b'"callback": null}') + b'"callback": null}' + ) MOCK_RESP_WITHOUT_CALLBACK = ( - b'{"id": 0, "result": 123, "error": null, "status": 1, "uid": 1}') + b'{"id": 0, "result": 123, "error": null, "status": 1, "uid": 1}' + ) MOCK_RESP_TEMPLATE = ( '{"id": %d, "result": 123, "error": null, "status": 1, "uid": 1, ' - '"callback": null}') + '"callback": null}' + ) MOCK_RESP_UNKNOWN_STATUS = ( - b'{"id": 0, "result": 123, "error": null, "status": 0, ' - b'"callback": null}') + b'{"id": 0, "result": 123, "error": null, "status": 0, "callback": null}' + ) MOCK_RESP_WITH_CALLBACK = ( b'{"id": 0, "result": 123, "error": null, "status": 1, "uid": 1, ' - b'"callback": "1-0"}') + b'"callback": "1-0"}' + ) MOCK_RESP_WITH_ERROR = b'{"id": 0, "error": 1, "status": 1, "uid": 1}' MOCK_RESP_FLEXIABLE_RESULT_LENGTH = ( - '{"id": 0, "result": "%s", "error": null, "status": 0, "callback": null}') + '{"id": 0, "result": "%s", "error": null, "status": 0, "callback": null}' + ) class MockSocketFile: diff --git a/tests/lib/mock_android_device.py b/tests/lib/mock_android_device.py index 9d149914..c383c182 100755 --- a/tests/lib/mock_android_device.py +++ b/tests/lib/mock_android_device.py @@ -29,7 +29,7 @@ 'ro.build.version.sdk': '28', 'ro.product.name': 'FakeModel', 'ro.debuggable': '1', - 'sys.boot_completed': "1", + 'sys.boot_completed': '1', 'ro.build.characteristics': 'emulator,phone', 'ro.hardware': 'marlin', } @@ -50,7 +50,7 @@ def get_mock_ads(num): """ ads = [] for i in range(num): - ad = mock.MagicMock(name="AndroidDevice", serial=str(i), h_port=None) + ad = mock.MagicMock(name='AndroidDevice', serial=str(i), h_port=None) ad.skip_logcat = False ads.append(ad) return ads @@ -63,7 +63,7 @@ def get_all_instances(): def get_instances(serials): ads = [] for serial in serials: - ad = mock.MagicMock(name="AndroidDevice", serial=serial, h_port=None) + ad = mock.MagicMock(name='AndroidDevice', serial=serial, h_port=None) ads.append(ad) return ads @@ -79,13 +79,15 @@ def list_adb_devices(): class MockAdbProxy: """Mock class that swaps out calls to adb with mock calls.""" - def __init__(self, - serial='', - fail_br=False, - fail_br_before_N=False, - mock_properties=None, - installed_packages=None, - instrumented_packages=None): + def __init__( + self, + serial='', + fail_br=False, + fail_br_before_N=False, + mock_properties=None, + installed_packages=None, + instrumented_packages=None, + ): self.serial = serial self.fail_br = fail_br self.fail_br_before_N = fail_br_before_N @@ -103,28 +105,34 @@ def __init__(self, self.instrumented_packages = instrumented_packages def shell(self, params, timeout=None): - if params == "id -u": - return b"root" - elif params == "bugreportz": + if params == 'id -u': + return b'root' + elif params == 'bugreportz': if self.fail_br: - return b"OMG I died!\n" + return b'OMG I died!\n' return b'OK:/path/bugreport.zip\n' - elif params == "bugreportz -v": + elif params == 'bugreportz -v': if self.fail_br_before_N: - return b"/system/bin/sh: bugreportz: not found" + return b'/system/bin/sh: bugreportz: not found' return b'1.1' elif 'pm list package' in params: packages = self.installed_packages + [ package for package, _, _ in self.instrumented_packages ] - return bytes('\n'.join(['package:%s' % package for package in packages]), - 'utf-8') + return bytes( + '\n'.join(['package:%s' % package for package in packages]), 'utf-8' + ) elif 'pm list instrumentation' in params: return bytes( - '\n'.join([ - 'instrumentation:%s/%s (target=%s)' % (package, runner, target) - for package, runner, target in self.instrumented_packages - ]), 'utf-8') + '\n'.join( + [ + 'instrumentation:%s/%s (target=%s)' + % (package, runner, target) + for package, runner, target in self.instrumented_packages + ] + ), + 'utf-8', + ) elif 'which' in params: return b'' @@ -138,8 +146,11 @@ def getprops(self, params): def bugreport(self, args, shell=False, timeout=None): expected = os.path.join( - logging.log_path, 'AndroidDevice%s' % self.serial, 'BugReports', - 'bugreport,test_something,%s,fakemodel,sometime' % self.serial) + logging.log_path, + 'AndroidDevice%s' % self.serial, + 'BugReports', + 'bugreport,test_something,%s,fakemodel,sometime' % self.serial, + ) if expected not in args: raise Error('"Expected "%s", got "%s"' % (expected, args)) @@ -162,10 +173,9 @@ def __init__(self, serial): self.serial = serial def devices(self): - return b"xxxx device\nyyyy device" + return b'xxxx device\nyyyy device' def __getattr__(self, name): - def fastboot_call(*args): arg_str = ' '.join(str(elem) for elem in args) return arg_str diff --git a/tests/lib/mock_instrumentation_test.py b/tests/lib/mock_instrumentation_test.py index be3d90ec..ee1ee6a2 100644 --- a/tests/lib/mock_instrumentation_test.py +++ b/tests/lib/mock_instrumentation_test.py @@ -24,7 +24,8 @@ class MockInstrumentationTest( - base_instrumentation_test.BaseInstrumentationTestClass): + base_instrumentation_test.BaseInstrumentationTestClass +): def __init__(self, tmp_dir, user_params={}): mock_test_run_configs = config_parser.TestRunConfig() @@ -35,7 +36,6 @@ def __init__(self, tmp_dir, user_params={}): super().__init__(mock_test_run_configs) def run_mock_instrumentation_test(self, instrumentation_output, prefix): - def fake_instrument(package, options=None, runner=None, handler=None): for line in instrumentation_output.splitlines(): handler(line) @@ -44,6 +44,6 @@ def fake_instrument(package, options=None, runner=None, handler=None): mock_device = mock.Mock(spec=android_device.AndroidDevice) mock_device.adb = mock.Mock(spec=adb.AdbProxy) mock_device.adb.instrument = fake_instrument - return self.run_instrumentation_test(mock_device, - MOCK_TEST_PACKAGE, - prefix=prefix) + return self.run_instrumentation_test( + mock_device, MOCK_TEST_PACKAGE, prefix=prefix + ) diff --git a/tests/lib/mock_second_controller.py b/tests/lib/mock_second_controller.py index 3f323493..aef70b3f 100644 --- a/tests/lib/mock_second_controller.py +++ b/tests/lib/mock_second_controller.py @@ -54,7 +54,7 @@ def get_magic(self): return self.magic def set_magic(self, extra_magic): - self.magic['extra_magic'] = extra_magic + self.magic["extra_magic"] = extra_magic def who_am_i(self): return {"MyOtherMagic": self.magic} diff --git a/tests/lib/utils.py b/tests/lib/utils.py index 904459cd..3bbe43cf 100644 --- a/tests/lib/utils.py +++ b/tests/lib/utils.py @@ -34,5 +34,6 @@ def validate_test_result(result): for bucket_list, expected_enum in buckets: for record in bucket_list: if record.result != expected_enum: - raise AssertionError('Expected result %s, got %s.' % - (expected_enum, record.result)) + raise AssertionError( + 'Expected result %s, got %s.' % (expected_enum, record.result) + ) diff --git a/tests/mobly/asserts_test.py b/tests/mobly/asserts_test.py index 662173f9..37131856 100755 --- a/tests/mobly/asserts_test.py +++ b/tests/mobly/asserts_test.py @@ -58,11 +58,9 @@ def test_assert_almost_equal_fail(self): def test_assert_almost_equal_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: - asserts.assert_almost_equal(1, - 2, - delta=0.1, - msg='Message', - extras='Extras') + asserts.assert_almost_equal( + 1, 2, delta=0.1, msg='Message', extras='Extras' + ) self.assertRegex(cm.exception.details, r'1 != 2 within 0\.1 delta.*Message') self.assertEqual(cm.exception.extras, 'Extras') @@ -77,11 +75,9 @@ def test_assert_not_almost_equal_fail(self): def test_assert_not_almost_equal_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: - asserts.assert_not_almost_equal(1, - 2, - delta=1, - msg='Message', - extras='Extras') + asserts.assert_not_almost_equal( + 1, 2, delta=1, msg='Message', extras='Extras' + ) self.assertRegex(cm.exception.details, r'1 == 2 within 1 delta.*Message') self.assertEqual(cm.exception.extras, 'Extras') @@ -116,8 +112,9 @@ def test_assert_not_in_fail(self): def test_assert_not_in_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_not_in(1, [1, 2, 3], msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - '1 unexpectedly found in [1, 2, 3] Message') + self.assertEqual( + cm.exception.details, '1 unexpectedly found in [1, 2, 3] Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_is_pass(self): @@ -131,8 +128,9 @@ def test_assert_is_fail(self): def test_assert_is_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_is(_OBJECT_1, _OBJECT_2, msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - f'{_OBJECT_1} is not {_OBJECT_2} Message') + self.assertEqual( + cm.exception.details, f'{_OBJECT_1} is not {_OBJECT_2} Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_is_not_pass(self): @@ -141,17 +139,18 @@ def test_assert_is_not_pass(self): def test_assert_is_not_fail(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_is_not(_OBJECT_1, _OBJECT_1) - self.assertEqual(cm.exception.details, - f'unexpectedly identical: {_OBJECT_1}') + self.assertEqual( + cm.exception.details, f'unexpectedly identical: {_OBJECT_1}' + ) def test_assert_is_not_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: - asserts.assert_is_not(_OBJECT_1, - _OBJECT_1, - msg='Message', - extras='Extras') - self.assertEqual(cm.exception.details, - f'unexpectedly identical: {_OBJECT_1} Message') + asserts.assert_is_not( + _OBJECT_1, _OBJECT_1, msg='Message', extras='Extras' + ) + self.assertEqual( + cm.exception.details, f'unexpectedly identical: {_OBJECT_1} Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_count_equal_pass(self): @@ -162,15 +161,20 @@ def test_assert_count_equal_fail(self): asserts.assert_count_equal([3, 3], [3]) self.assertEqual( cm.exception.details, - 'Element counts were not equal:\nFirst has 2, Second has 1: 3') + 'Element counts were not equal:\nFirst has 2, Second has 1: 3', + ) def test_assert_count_equal_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_count_equal((3, 3), (4, 4), msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - ('Element counts were not equal:\n' - 'First has 2, Second has 0: 3\n' - 'First has 0, Second has 2: 4 Message')) + self.assertEqual( + cm.exception.details, + ( + 'Element counts were not equal:\n' + 'First has 2, Second has 0: 3\n' + 'First has 0, Second has 2: 4 Message' + ), + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_less_pass(self): @@ -199,8 +203,9 @@ def test_assert_less_equal_fail(self): def test_assert_less_equal_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_less_equal(2, 1, msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - '2 not less than or equal to 1 Message') + self.assertEqual( + cm.exception.details, '2 not less than or equal to 1 Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_greater_pass(self): @@ -229,8 +234,9 @@ def test_assert_greater_equal_fail(self): def test_assert_greater_equal_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_greater_equal(1, 2, msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - '1 not greater than or equal to 2 Message') + self.assertEqual( + cm.exception.details, '1 not greater than or equal to 2 Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_is_none_pass(self): @@ -274,8 +280,9 @@ def test_assert_is_instance_fail(self): def test_assert_is_instance_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_is_instance(1.0, int, msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - f'1.0 is not an instance of {int} Message') + self.assertEqual( + cm.exception.details, f'1.0 is not an instance of {int} Message' + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_not_is_instance_pass(self): @@ -291,8 +298,9 @@ def test_assert_not_is_instance_fail(self): def test_assert_not_is_instance_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: asserts.assert_not_is_instance('foo', str, msg='Message', extras='Extras') - self.assertEqual(cm.exception.details, - f"'foo' is an instance of {str} Message") + self.assertEqual( + cm.exception.details, f"'foo' is an instance of {str} Message" + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_regex_pass(self): @@ -303,18 +311,18 @@ def test_assert_regex_fail(self): asserts.assert_regex('Big socks', r'(r|m)ocks') self.assertEqual( cm.exception.details, - "Regex didn't match: '(r|m)ocks' not found in 'Big socks'") + "Regex didn't match: '(r|m)ocks' not found in 'Big socks'", + ) def test_assert_regex_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: - asserts.assert_regex('Big socks', - r'(r|m)ocks', - msg='Message', - extras='Extras') + asserts.assert_regex( + 'Big socks', r'(r|m)ocks', msg='Message', extras='Extras' + ) self.assertEqual( cm.exception.details, - ("Regex didn't match: '(r|m)ocks' not found in 'Big socks' " - 'Message')) + "Regex didn't match: '(r|m)ocks' not found in 'Big socks' Message", + ) self.assertEqual(cm.exception.extras, 'Extras') def test_assert_not_regex_pass(self): @@ -325,18 +333,18 @@ def test_assert_not_regex_fail(self): asserts.assert_not_regex('Big rocks', r'(r|m)ocks') self.assertEqual( cm.exception.details, - "Regex matched: 'rocks' matches '(r|m)ocks' in 'Big rocks'") + "Regex matched: 'rocks' matches '(r|m)ocks' in 'Big rocks'", + ) def test_assert_not_regex_fail_with_msg_and_extras(self): with self.assertRaises(signals.TestFailure) as cm: - asserts.assert_not_regex('Big mocks', - r'(r|m)ocks', - msg='Message', - extras='Extras') + asserts.assert_not_regex( + 'Big mocks', r'(r|m)ocks', msg='Message', extras='Extras' + ) self.assertEqual( cm.exception.details, - ("Regex matched: 'mocks' matches '(r|m)ocks' in 'Big mocks' " - 'Message')) + "Regex matched: 'mocks' matches '(r|m)ocks' in 'Big mocks' Message", + ) self.assertEqual(cm.exception.extras, 'Extras') diff --git a/tests/mobly/base_instrumentation_test_test.py b/tests/mobly/base_instrumentation_test_test.py index c336b90d..fcf52fb4 100755 --- a/tests/mobly/base_instrumentation_test_test.py +++ b/tests/mobly/base_instrumentation_test_test.py @@ -57,10 +57,12 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.tmp_dir) - def assert_parse_instrumentation_options(self, user_params, - expected_instrumentation_options): + def assert_parse_instrumentation_options( + self, user_params, expected_instrumentation_options + ): mit = mock_instrumentation_test.MockInstrumentationTest( - self.tmp_dir, user_params) + self.tmp_dir, user_params + ) instrumentation_options = mit.parse_instrumentation_options(mit.user_params) self.assertEqual(instrumentation_options, expected_instrumentation_options) @@ -82,10 +84,7 @@ def test_parse_instrumentation_options_with_only_instrumentation_params(self): 'instrumentation_option_key1': 'value1', 'instrumentation_option_key2': 'value2', }, - { - 'key1': 'value1', - 'key2': 'value2' - }, + {'key1': 'value1', 'key2': 'value2'}, ) def test_parse_instrumentation_options_with_mixed_user_params(self): @@ -96,10 +95,7 @@ def test_parse_instrumentation_options_with_mixed_user_params(self): 'instrumentation_option_key1': 'value1', 'instrumentation_option_key2': 'value2', }, - { - 'key1': 'value1', - 'key2': 'value2' - }, + {'key1': 'value1', 'key2': 'value2'}, ) def run_instrumentation_test(self, instrumentation_output, prefix=None): @@ -107,7 +103,8 @@ def run_instrumentation_test(self, instrumentation_output, prefix=None): result = InstrumentationResult() try: result.completed_and_passed = mit.run_mock_instrumentation_test( - instrumentation_output, prefix=prefix) + instrumentation_output, prefix=prefix + ) except signals.TestError as e: result.error = e result.executed = mit.results.executed @@ -116,29 +113,34 @@ def run_instrumentation_test(self, instrumentation_output, prefix=None): def assert_equal_test(self, actual_test, expected_test): (expected_test_name, expected_signal) = expected_test - self.assertEqual(actual_test.test_class, - MOCK_INSTRUMENTATION_TEST_CLASS_NAME) + self.assertEqual( + actual_test.test_class, MOCK_INSTRUMENTATION_TEST_CLASS_NAME + ) self.assertEqual(actual_test.test_name, expected_test_name) - self.assertIsInstance(actual_test.termination_signal.exception, - expected_signal) - - def assert_run_instrumentation_test(self, - instrumentation_output, - expected_executed=[], - expected_skipped=[], - expected_completed_and_passed=False, - expected_has_error=False, - prefix=None, - expected_executed_times=[]): - result = self.run_instrumentation_test(bytes(instrumentation_output, - 'utf-8'), - prefix=prefix) + self.assertIsInstance( + actual_test.termination_signal.exception, expected_signal + ) + + def assert_run_instrumentation_test( + self, + instrumentation_output, + expected_executed=[], + expected_skipped=[], + expected_completed_and_passed=False, + expected_has_error=False, + prefix=None, + expected_executed_times=[], + ): + result = self.run_instrumentation_test( + bytes(instrumentation_output, 'utf-8'), prefix=prefix + ) if expected_has_error: self.assertIsInstance(result.error, signals.TestError) else: self.assertIsNone(result.error) - self.assertEqual(result.completed_and_passed, - expected_completed_and_passed) + self.assertEqual( + result.completed_and_passed, expected_completed_and_passed + ) self.assertEqual(len(result.executed), len(expected_executed)) for actual_test, expected_test in zip(result.executed, expected_executed): self.assert_equal_test(actual_test, expected_test) @@ -146,8 +148,9 @@ def assert_run_instrumentation_test(self, for actual_test, expected_test in zip(result.skipped, expected_skipped): self.assert_equal_test(actual_test, expected_test) if expected_executed_times: - for actual_test, expected_time in zip(result.executed, - expected_executed_times): + for actual_test, expected_time in zip( + result.executed, expected_executed_times + ): (expected_begin_time, expected_end_time) = expected_time self.assertEqual(actual_test.begin_time, expected_begin_time) self.assertEqual(actual_test.end_time, expected_end_time) @@ -173,14 +176,16 @@ def test_run_instrumentation_test_with_invalid_syntax(self): Error: Bad component name: / """ - self.assert_run_instrumentation_test(instrumentation_output, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_has_error=True + ) def test_run_instrumentation_test_with_no_output(self): instrumentation_output = """\ """ - self.assert_run_instrumentation_test(instrumentation_output, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_has_error=True + ) def test_run_instrumentation_test_with_missing_test_package(self): instrumentation_output = """\ @@ -194,8 +199,9 @@ def test_run_instrumentation_test_with_missing_test_package(self): INSTRUMENTATION_STATUS: id=ActivityManagerService INSTRUMENTATION_STATUS: Error=Unable to find instrumentation info for: ComponentInfo{com.my.package.test/com.my.package.test.runner.MyRunner} INSTRUMENTATION_STATUS_CODE: -1""" - self.assert_run_instrumentation_test(instrumentation_output, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_has_error=True + ) def test_run_instrumentation_test_with_missing_runner(self): instrumentation_output = """\ @@ -209,19 +215,22 @@ def test_run_instrumentation_test_with_missing_runner(self): at com.android.commands.am.Am.main(Am.java:124) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:262)""" - self.assert_run_instrumentation_test(instrumentation_output, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_has_error=True + ) def test_run_instrumentation_test_with_no_tests(self): instrumentation_output = MOCK_EMPTY_INSTRUMENTATION_TEST - self.assert_run_instrumentation_test(instrumentation_output, - expected_completed_and_passed=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_completed_and_passed=True + ) @mock.patch('logging.info') def test_run_instrumentation_test_logs_correctly(self, mock_info_logger): instrumentation_output = MOCK_EMPTY_INSTRUMENTATION_TEST - self.assert_run_instrumentation_test(instrumentation_output, - expected_completed_and_passed=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_completed_and_passed=True + ) for mock_call in mock_info_logger.mock_calls: logged_format = mock_call[1][0] self.assertIsInstance(logged_format, str) @@ -257,10 +266,12 @@ def test_run_instrumentation_test_with_passing_test(self, mock_get_time): ('com.my.package.test.BasicTest#basicTest', signals.TestPass), ] mock_get_time.side_effect = [13, 51] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_completed_and_passed=True, - expected_executed_times=[(13, 51)]) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_completed_and_passed=True, + expected_executed_times=[(13, 51)], + ) def test_run_instrumentation_test_with_random_whitespace(self): instrumentation_output = """\ @@ -312,9 +323,11 @@ def test_run_instrumentation_test_with_random_whitespace(self): expected_executed = [ ('com.my.package.test.BasicTest#basicTest', signals.TestPass), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_completed_and_passed=True) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_completed_and_passed=True, + ) def test_run_instrumentation_test_with_prefix_test(self): instrumentation_output = """\ @@ -343,13 +356,17 @@ def test_run_instrumentation_test_with_prefix_test(self): INSTRUMENTATION_CODE: -1 """ expected_executed = [ - ('%s.com.my.package.test.BasicTest#basicTest' % MOCK_PREFIX, - signals.TestPass), + ( + '%s.com.my.package.test.BasicTest#basicTest' % MOCK_PREFIX, + signals.TestPass, + ), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_completed_and_passed=True, - prefix=MOCK_PREFIX) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_completed_and_passed=True, + prefix=MOCK_PREFIX, + ) def test_run_instrumentation_test_with_failing_test(self): instrumentation_output = """\ @@ -535,8 +552,9 @@ def test_run_instrumentation_test_with_failing_test(self): expected_executed = [ ('com.my.package.test.BasicTest#failingTest', signals.TestFailure), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed) + self.assert_run_instrumentation_test( + instrumentation_output, expected_executed=expected_executed + ) def test_run_instrumentation_test_with_assumption_failure_test(self): instrumentation_output = """\ @@ -618,12 +636,16 @@ def test_run_instrumentation_test_with_assumption_failure_test(self): INSTRUMENTATION_CODE: -1""" expected_skipped = [ - ('com.my.package.test.BasicTest#assumptionFailureTest', - signals.TestSkip), + ( + 'com.my.package.test.BasicTest#assumptionFailureTest', + signals.TestSkip, + ), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_skipped=expected_skipped, - expected_completed_and_passed=True) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_skipped=expected_skipped, + expected_completed_and_passed=True, + ) def test_run_instrumentation_test_with_ignored_test(self): instrumentation_output = """\ @@ -654,9 +676,11 @@ def test_run_instrumentation_test_with_ignored_test(self): expected_skipped = [ ('com.my.package.test.BasicTest#ignoredTest', signals.TestSkip), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_skipped=expected_skipped, - expected_completed_and_passed=True) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_skipped=expected_skipped, + expected_completed_and_passed=True, + ) @mock.patch('mobly.utils.get_current_epoch_time') def test_run_instrumentation_test_with_crashed_test(self, mock_get_time): @@ -675,10 +699,12 @@ def test_run_instrumentation_test_with_crashed_test(self, mock_get_time): ('com.my.package.test.BasicTest#crashTest', signals.TestError), ] mock_get_time.side_effect = [67, 942] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_has_error=True, - expected_executed_times=[(67, 942)]) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_has_error=True, + expected_executed_times=[(67, 942)], + ) @mock.patch('mobly.utils.get_current_epoch_time') def test_run_instrumentation_test_with_crashing_test(self, mock_get_time): @@ -708,25 +734,31 @@ def test_run_instrumentation_test_with_crashing_test(self, mock_get_time): INSTRUMENTATION_CODE: -1""" expected_executed = [ - ('com.my.package.test.BasicTest#crashAndRecover1Test', - signals.TestError), - ('com.my.package.test.BasicTest#crashAndRecover2Test', - signals.TestError), + ( + 'com.my.package.test.BasicTest#crashAndRecover1Test', + signals.TestError, + ), + ( + 'com.my.package.test.BasicTest#crashAndRecover2Test', + signals.TestError, + ), ] mock_get_time.side_effect = [16, 412, 4143, 6547] # TODO(winterfrosts): Fix this issue with overlapping timing - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_completed_and_passed=True, - expected_executed_times=[(16, 4143), - (412, 6547)]) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_completed_and_passed=True, + expected_executed_times=[(16, 4143), (412, 6547)], + ) def test_run_instrumentation_test_with_runner_setup_crash(self): instrumentation_output = """\ INSTRUMENTATION_RESULT: shortMsg=Process crashed. INSTRUMENTATION_CODE: 0""" - self.assert_run_instrumentation_test(instrumentation_output, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, expected_has_error=True + ) def test_run_instrumentation_test_with_runner_teardown_crash(self): instrumentation_output = """\ @@ -751,9 +783,11 @@ def test_run_instrumentation_test_with_runner_teardown_crash(self): expected_executed = [ ('com.my.package.test.BasicTest#basicTest', signals.TestPass), ] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_has_error=True) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_has_error=True, + ) @mock.patch('mobly.utils.get_current_epoch_time') def test_run_instrumentation_test_with_multiple_tests(self, mock_get_time): @@ -1036,24 +1070,28 @@ def test_run_instrumentation_test_with_multiple_tests(self, mock_get_time): ('com.my.package.test.BasicTest#passingTest', signals.TestPass), ] expected_skipped = [ - ('com.my.package.test.BasicTest#assumptionFailureTest', - signals.TestSkip), + ( + 'com.my.package.test.BasicTest#assumptionFailureTest', + signals.TestSkip, + ), ('com.my.package.test.BasicTest#ignoredTest', signals.TestSkip), ] mock_get_time.side_effect = [54, 64, -1, -1, -1, -1, 89, 94] - self.assert_run_instrumentation_test(instrumentation_output, - expected_executed=expected_executed, - expected_skipped=expected_skipped, - expected_executed_times=[(54, 64), - (89, 94)]) + self.assert_run_instrumentation_test( + instrumentation_output, + expected_executed=expected_executed, + expected_skipped=expected_skipped, + expected_executed_times=[(54, 64), (89, 94)], + ) def test__Instrumentation_block_set_key_on_multiple_equals_sign(self): - value = "blah=blah, blah2=blah2, blah=2=1=2" - parsed_line = "INSTRUMENTATION_STATUS: stack=%s" % value + value = 'blah=blah, blah2=blah2, blah=2=1=2' + parsed_line = 'INSTRUMENTATION_STATUS: stack=%s' % value block = _InstrumentationBlock() block.set_key(_InstrumentationStructurePrefixes.STATUS, parsed_line) - self.assertIn(value, - block.known_keys[_InstrumentationKnownStatusKeys.STACK]) + self.assertIn( + value, block.known_keys[_InstrumentationKnownStatusKeys.STACK] + ) if __name__ == '__main__': diff --git a/tests/mobly/base_test_test.py b/tests/mobly/base_test_test.py index b1663577..630bd820 100755 --- a/tests/mobly/base_test_test.py +++ b/tests/mobly/base_test_test.py @@ -33,11 +33,11 @@ from tests.lib import mock_second_controller import yaml -MSG_EXPECTED_EXCEPTION = "This is an expected exception." -MSG_EXPECTED_TEST_FAILURE = "This is an expected test failure." -MSG_UNEXPECTED_EXCEPTION = "Unexpected exception!" +MSG_EXPECTED_EXCEPTION = 'This is an expected exception.' +MSG_EXPECTED_TEST_FAILURE = 'This is an expected test failure.' +MSG_UNEXPECTED_EXCEPTION = 'Unexpected exception!' -MOCK_EXTRA = {"key": "value", "answer_to_everything": 42} +MOCK_EXTRA = {'key': 'value', 'answer_to_everything': 42} def never_call(): @@ -55,18 +55,19 @@ def setUp(self): self.mock_test_cls_configs = config_parser.TestRunConfig() self.summary_file = os.path.join(self.tmp_dir, 'summary.yaml') self.mock_test_cls_configs.summary_writer = records.TestSummaryWriter( - self.summary_file) + self.summary_file + ) self.mock_test_cls_configs.controller_configs = {} self.mock_test_cls_configs.log_path = self.tmp_dir - self.mock_test_cls_configs.user_params = {"some_param": "hahaha"} + self.mock_test_cls_configs.user_params = {'some_param': 'hahaha'} self.mock_test_cls_configs.reporter = mock.MagicMock() - self.mock_test_name = "test_something" + self.mock_test_name = 'test_something' def tearDown(self): shutil.rmtree(self.tmp_dir) def test_paths(self): - '''Checks the output paths set in `BaseTestClass`.''' + """Checks the output paths set in `BaseTestClass`.""" path_checker = mock.MagicMock() class MockBaseTest(base_test.BaseTestClass): @@ -76,7 +77,7 @@ def test_func(self): path_checker.root_output_path = self.root_output_path bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) self.assertEqual(path_checker.root_output_path, self.tmp_dir) self.assertTrue(os.path.exists(path_checker.root_output_path)) expected_log_path = os.path.join(self.tmp_dir, 'MockBaseTest') @@ -84,33 +85,33 @@ def test_func(self): self.assertTrue(os.path.exists(path_checker.log_path)) def test_current_test_name(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): - asserts.assert_true(self.current_test_info.name == "test_func", - ("Got " - "unexpected test name %s.") % - self.current_test_info.name) + asserts.assert_true( + self.current_test_info.name == 'test_func', + 'Got unexpected test name %s.' % self.current_test_info.name, + ) bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) def test_current_test_info(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): asserts.assert_true( self.current_test_info.name == 'test_func', - 'Got unexpected test name %s.' % self.current_test_info.name) + 'Got unexpected test name %s.' % self.current_test_info.name, + ) output_path = self.current_test_info.output_path - asserts.assert_true(os.path.exists(output_path), - 'test output path missing') + asserts.assert_true( + os.path.exists(output_path), 'test output path missing' + ) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run(test_names=['test_func']) @@ -120,16 +121,17 @@ def test_func(self): self.assertIsNone(actual_record.extras) def test_current_test_info_in_setup_class(self): - class MockBaseTest(base_test.BaseTestClass): def setup_class(self): asserts.assert_true( self.current_test_info.name == 'setup_class', - 'Got unexpected test name %s.' % self.current_test_info.name) + 'Got unexpected test name %s.' % self.current_test_info.name, + ) output_path = self.current_test_info.output_path - asserts.assert_true(os.path.exists(output_path), - 'test output path missing') + asserts.assert_true( + os.path.exists(output_path), 'test output path missing' + ) raise Exception(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) @@ -140,12 +142,11 @@ def setup_class(self): self.assertIsNone(actual_record.extras) def test_self_tests_list(self): - class MockBaseTest(base_test.BaseTestClass): def __init__(self, controllers): super().__init__(controllers) - self.tests = ("test_something",) + self.tests = ('test_something',) def test_something(self): pass @@ -157,15 +158,14 @@ def test_never(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_something") + self.assertEqual(actual_record.test_name, 'test_something') def test_self_tests_list_fail_by_convention(self): - class MockBaseTest(base_test.BaseTestClass): def __init__(self, controllers): super().__init__(controllers) - self.tests = ("not_a_test_something",) + self.tests = ('not_a_test_something',) def not_a_test_something(self): pass @@ -175,18 +175,19 @@ def test_never(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - expected_msg = (r'Test method name not_a_test_something does not follow ' - r'naming convention test_\*, abort.') + expected_msg = ( + r'Test method name not_a_test_something does not follow ' + r'naming convention test_\*, abort.' + ) with self.assertRaisesRegex(base_test.Error, expected_msg): bt_cls.run() def test_cli_test_selection_override_self_tests_list(self): - class MockBaseTest(base_test.BaseTestClass): def __init__(self, controllers): super().__init__(controllers) - self.tests = ("test_never",) + self.tests = ('test_never',) def test_something(self): pass @@ -196,17 +197,16 @@ def test_never(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_something"]) + bt_cls.run(test_names=['test_something']) actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_something") + self.assertEqual(actual_record.test_name, 'test_something') def test_cli_test_selection_fail_by_convention(self): - class MockBaseTest(base_test.BaseTestClass): def __init__(self, controllers): super().__init__(controllers) - self.tests = ("not_a_test_something",) + self.tests = ('not_a_test_something',) def not_a_test_something(self): pass @@ -216,13 +216,14 @@ def test_never(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - expected_msg = (r'Test method name not_a_test_something does not follow ' - r'naming convention test_\*, abort.') + expected_msg = ( + r'Test method name not_a_test_something does not follow ' + r'naming convention test_\*, abort.' + ) with self.assertRaisesRegex(base_test.Error, expected_msg): - bt_cls.run(test_names=["not_a_test_something"]) + bt_cls.run(test_names=['not_a_test_something']) def test_default_execution_of_all_tests(self): - class MockBaseTest(base_test.BaseTestClass): def test_something(self): @@ -236,7 +237,7 @@ def not_a_test(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_something") + self.assertEqual(actual_record.test_name, 'test_something') def test_default_execution_skip_noncallable_tests(self): mock_decorated = mock.MagicMock() @@ -268,13 +269,13 @@ def test_undecorated(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - self.assertNotIn('test_noncallable', - [test.test_name for test in bt_cls.results.executed]) + self.assertNotIn( + 'test_noncallable', [test.test_name for test in bt_cls.results.executed] + ) mock_decorated.assert_called_once_with('test_decorated') mock_undecorated.assert_called_once_with('test_undecorated') def test_get_existing_tests_do_not_call_properties(self): - class MockBaseTest(base_test.BaseTestClass): def test_something(self): @@ -289,14 +290,13 @@ def not_a_test(self): bt_cls.run() def test_missing_requested_test_func(self): - class MockBaseTest(base_test.BaseTestClass): pass bt_cls = MockBaseTest(self.mock_test_cls_configs) - expected_msg = ".* does not have test method test_something" + expected_msg = '.* does not have test method test_something' with self.assertRaisesRegex(base_test.Error, expected_msg): - bt_cls.run(test_names=["test_something"]) + bt_cls.run(test_names=['test_something']) self.assertFalse(bt_cls.results.executed) def test_setup_class_fail_by_exception(self): @@ -320,10 +320,10 @@ def teardown_class(self): # This should execute because the setup_class failure should # have already been recorded. if not self.results.is_all_pass: - teardown_class_call_check("heehee") + teardown_class_call_check('heehee') def on_fail(self, record): - on_fail_call_check("haha") + on_fail_call_check('haha') bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() @@ -332,23 +332,27 @@ def on_fail(self, record): self.assertIsNone(skipped_record.begin_time) self.assertIsNone(skipped_record.end_time) utils.validate_test_result(bt_cls.results) - self.assertEqual(actual_record.test_name, "setup_class") + self.assertEqual(actual_record.test_name, 'setup_class') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 0, Failed 0, Passed 0, " - "Requested 2, Skipped 2") + expected_summary = ( + 'Error 1, Executed 0, Failed 0, Passed 0, Requested 2, Skipped 2' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) - teardown_class_call_check.assert_called_once_with("heehee") - on_fail_call_check.assert_called_once_with("haha") + teardown_class_call_check.assert_called_once_with('heehee') + on_fail_call_check.assert_called_once_with('haha') def test_teardown_class_fail_by_exception(self): mock_test_config = self.mock_test_cls_configs.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - mock_ctrlr_2_config_name = mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + mock_ctrlr_2_config_name = ( + mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + ) my_config = [{'serial': 'xxxx', 'magic': 'Magic'}] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs[mock_ctrlr_2_config_name] = copy.copy( - my_config) + my_config + ) class MockBaseTest(base_test.BaseTestClass): @@ -371,8 +375,9 @@ def teardown_class(self): self.assertIsNotNone(class_record.begin_time) self.assertIsNotNone(class_record.end_time) self.assertIsNone(class_record.extras) - expected_summary = ('Error 1, Executed 1, Failed 0, Passed 1, ' - 'Requested 1, Skipped 0') + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 1, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) # Verify the controller info is recorded correctly. info = bt_cls.results.controller_info[0] @@ -383,11 +388,14 @@ def teardown_class(self): def test_teardown_class_raise_abort_all(self): mock_test_config = self.mock_test_cls_configs.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - mock_ctrlr_2_config_name = mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + mock_ctrlr_2_config_name = ( + mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + ) my_config = [{'serial': 'xxxx', 'magic': 'Magic'}] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs[mock_ctrlr_2_config_name] = copy.copy( - my_config) + my_config + ) class MockBaseTest(base_test.BaseTestClass): @@ -405,8 +413,9 @@ def teardown_class(self): bt_cls.run() test_record = bt_cls.results.passed[0] self.assertTrue(bt_cls.results.is_all_pass) - expected_summary = ('Error 0, Executed 1, Failed 0, Passed 1, ' - 'Requested 1, Skipped 0') + expected_summary = ( + 'Error 0, Executed 1, Failed 0, Passed 1, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) # Verify the controller info is recorded correctly. info = bt_cls.results.controller_info[0] @@ -430,7 +439,7 @@ def test_something(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_something"]) + bt_cls.run(test_names=['test_something']) mock_on_fail.assert_called_once_with('on_fail') actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, self.mock_test_name) @@ -438,14 +447,16 @@ def test_something(self): self.assertIn( 'in setup_test\n ' 'raise Exception(MSG_EXPECTED_EXCEPTION)\n' - 'Exception: This is an expected exception.\n', actual_record.stacktrace) + 'Exception: This is an expected exception.\n', + actual_record.stacktrace, + ) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_setup_test_fail_by_test_signal(self): - class MockBaseTest(base_test.BaseTestClass): def setup_test(self): @@ -456,7 +467,7 @@ def test_something(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_something"]) + bt_cls.run(test_names=['test_something']) actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) @@ -464,12 +475,12 @@ def test_something(self): self.assertTrue('self.setup_test()' in actual_record.stacktrace) self.assertIsNone(actual_record.extras) self.assertTrue(actual_record.end_time) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_assert_fail(self): - class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): @@ -485,12 +496,12 @@ def test_something(self): self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertTrue(actual_record.end_time) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_raise_exception(self): - class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): @@ -506,12 +517,12 @@ def test_something(self): self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) self.assertFalse(actual_record.extra_errors) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_expects_error(self): - class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): @@ -528,8 +539,9 @@ def test_something(self): self.assertIsNone(actual_record.extras) self.assertFalse(actual_record.extra_errors) self.assertTrue(actual_record.end_time) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_executed_if_test_pass(self): @@ -538,7 +550,7 @@ def test_teardown_test_executed_if_test_pass(self): class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): - my_mock("teardown_test") + my_mock('teardown_test') def test_something(self): pass @@ -546,13 +558,14 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - my_mock.assert_called_once_with("teardown_test") + my_mock.assert_called_once_with('teardown_test') self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) self.assertTrue(actual_record.end_time) - expected_summary = ("Error 0, Executed 1, Failed 0, Passed 1, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 0, Executed 1, Failed 0, Passed 1, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_executed_if_setup_test_fails(self): @@ -564,7 +577,7 @@ def setup_test(self): raise Exception(MSG_EXPECTED_EXCEPTION) def teardown_test(self): - my_mock("teardown_test") + my_mock('teardown_test') def test_something(self): pass @@ -572,13 +585,14 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - my_mock.assert_called_once_with("teardown_test") + my_mock.assert_called_once_with('teardown_test') self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) self.assertTrue(actual_record.end_time) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_teardown_test_executed_if_test_fails(self): @@ -587,7 +601,7 @@ def test_teardown_test_executed_if_test_fails(self): class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): - my_mock("teardown_test") + my_mock('teardown_test') def on_pass(self, record): never_call() @@ -598,12 +612,13 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - my_mock.assert_called_once_with("teardown_test") + my_mock.assert_called_once_with('teardown_test') self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_executed_if_teardown_test_fails(self): @@ -612,7 +627,7 @@ def test_on_fail_executed_if_teardown_test_fails(self): class MockBaseTest(base_test.BaseTestClass): def on_fail(self, record): - my_mock("on_fail") + my_mock('on_fail') def on_pass(self, record): never_call() @@ -630,8 +645,9 @@ def test_something(self): self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_executed_if_test_fails(self): @@ -641,7 +657,7 @@ class MockBaseTest(base_test.BaseTestClass): def on_fail(self, record): assert self.current_test_info.name == 'test_something' - my_mock("on_fail") + my_mock('on_fail') def on_pass(self, record): never_call() @@ -651,13 +667,14 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - my_mock.assert_called_once_with("on_fail") + my_mock.assert_called_once_with('on_fail') actual_record = bt_cls.results.failed[0] self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_procedure_function_gets_correct_record(self): @@ -680,13 +697,13 @@ def test_something(self): self.assertEqual(on_fail_mock.record.end_time, actual_record.end_time) self.assertEqual(on_fail_mock.record.stacktrace, actual_record.stacktrace) self.assertEqual(on_fail_mock.record.extras, actual_record.extras) - self.assertEqual(on_fail_mock.record.extra_errors, - actual_record.extra_errors) + self.assertEqual( + on_fail_mock.record.extra_errors, actual_record.extra_errors + ) # But they are not the same object. self.assertIsNot(on_fail_mock.record, actual_record) def test_on_fail_cannot_modify_original_record(self): - class MockBaseTest(base_test.BaseTestClass): def on_fail(self, record): @@ -706,7 +723,7 @@ def test_on_fail_executed_if_both_test_and_teardown_test_fails(self): class MockBaseTest(base_test.BaseTestClass): def on_fail(self, record): - on_fail_mock("on_fail") + on_fail_mock('on_fail') def on_pass(self, record): never_call() @@ -719,15 +736,18 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - on_fail_mock.assert_called_once_with("on_fail") + on_fail_mock.assert_called_once_with('on_fail') actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) - self.assertEqual(actual_record.extra_errors['teardown_test'].details, - 'This is an expected exception.ha') + self.assertEqual( + actual_record.extra_errors['teardown_test'].details, + 'This is an expected exception.ha', + ) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_executed_if_setup_test_fails_by_exception(self): @@ -739,20 +759,21 @@ def setup_test(self): raise Exception(MSG_EXPECTED_EXCEPTION) def on_fail(self, record): - my_mock("on_fail") + my_mock('on_fail') def test_something(self): pass bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - my_mock.assert_called_once_with("on_fail") + my_mock.assert_called_once_with('on_fail') actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_executed_if_setup_class_fails_by_exception(self): @@ -764,20 +785,21 @@ def setup_class(self): raise Exception(MSG_EXPECTED_EXCEPTION) def on_fail(self, record): - my_mock("on_fail") + my_mock('on_fail') def test_something(self): pass bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - my_mock.assert_called_once_with("on_fail") + my_mock.assert_called_once_with('on_fail') actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, 'setup_class') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 0, Failed 0, Passed 0, " - "Requested 1, Skipped 1") + expected_summary = ( + 'Error 1, Executed 0, Failed 0, Passed 0, Requested 1, Skipped 1' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_triggered_by_setup_class_failure_then_fail_too(self): @@ -799,14 +821,16 @@ def test_something(self): setup_class_record = bt_cls.results.error[0] self.assertEqual(setup_class_record.test_name, 'setup_class') self.assertEqual(setup_class_record.details, MSG_EXPECTED_EXCEPTION) - self.assertEqual(setup_class_record.extra_errors['on_fail'].details, - 'Failure in on_fail.') - expected_summary = ("Error 1, Executed 0, Failed 0, Passed 0, " - "Requested 1, Skipped 1") + self.assertEqual( + setup_class_record.extra_errors['on_fail'].details, + 'Failure in on_fail.', + ) + expected_summary = ( + 'Error 1, Executed 0, Failed 0, Passed 0, Requested 1, Skipped 1' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_failure_to_call_procedure_function_is_recorded(self): - class MockBaseTest(base_test.BaseTestClass): def on_fail(self): @@ -822,12 +846,13 @@ def test_something(self): self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_failure_in_procedure_functions_is_recorded(self): - expected_msg = "Something failed in on_pass." + expected_msg = 'Something failed in on_pass.' class MockBaseTest(base_test.BaseTestClass): @@ -840,41 +865,44 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - self.assertEqual(actual_record.extra_errors['on_pass'].details, - expected_msg) + self.assertEqual( + actual_record.extra_errors['on_pass'].details, expected_msg + ) self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_both_teardown_and_test_body_raise_exceptions(self): - class MockBaseTest(base_test.BaseTestClass): def teardown_test(self): asserts.assert_true(False, MSG_EXPECTED_EXCEPTION) def test_something(self): - raise Exception("Test Body Exception.") + raise Exception('Test Body Exception.') bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] self.assertEqual(actual_record.test_name, self.mock_test_name) - self.assertEqual(actual_record.details, "Test Body Exception.") + self.assertEqual(actual_record.details, 'Test Body Exception.') self.assertIsNone(actual_record.extras) - self.assertEqual(actual_record.extra_errors['teardown_test'].details, - MSG_EXPECTED_EXCEPTION) + self.assertEqual( + actual_record.extra_errors['teardown_test'].details, + MSG_EXPECTED_EXCEPTION, + ) self.assertIsNone(actual_record.extra_errors['teardown_test'].extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_exception_objects_in_record(self): - """Checks that the exception objects are correctly tallied. - """ + """Checks that the exception objects are correctly tallied.""" expected_termination_signal = Exception('Test Body Exception.') expected_extra_error = Exception('teardown_test Exception.') @@ -889,8 +917,9 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - self.assertIs(actual_record.termination_signal.exception, - expected_termination_signal) + self.assertIs( + actual_record.termination_signal.exception, expected_termination_signal + ) self.assertIsNotNone(actual_record.termination_signal.stacktrace) self.assertEqual(len(actual_record.extra_errors), 1) extra_error = actual_record.extra_errors['teardown_test'] @@ -920,8 +949,7 @@ def test_something(self): self.assertIsNotNone(actual_record.stacktrace) def test_explicit_pass_but_teardown_test_raises_an_exception(self): - """Test record result should be marked as ERROR as opposed to PASS. - """ + """Test record result should be marked as ERROR as opposed to PASS.""" class MockBaseTest(base_test.BaseTestClass): @@ -937,15 +965,17 @@ def test_something(self): self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, 'Test Passed!') self.assertIsNone(actual_record.extras) - self.assertEqual(actual_record.extra_errors['teardown_test'].details, - MSG_EXPECTED_EXCEPTION) + self.assertEqual( + actual_record.extra_errors['teardown_test'].details, + MSG_EXPECTED_EXCEPTION, + ) self.assertIsNone(actual_record.extra_errors['teardown_test'].extras) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_pass_cannot_modify_original_record(self): - class MockBaseTest(base_test.BaseTestClass): def on_pass(self, record): @@ -960,7 +990,6 @@ def test_something(self): self.assertEqual(actual_record.test_name, 'test_something') def test_on_pass_raise_exception(self): - class MockBaseTest(base_test.BaseTestClass): def on_pass(self, record): @@ -975,14 +1004,15 @@ def test_something(self): self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) - self.assertEqual(actual_record.extra_errors['on_pass'].details, - MSG_EXPECTED_EXCEPTION) - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + self.assertEqual( + actual_record.extra_errors['on_pass'].details, MSG_EXPECTED_EXCEPTION + ) + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_on_fail_raise_exception(self): - class MockBaseTest(base_test.BaseTestClass): def on_fail(self, record): @@ -997,10 +1027,12 @@ def test_something(self): self.assertEqual(actual_record.test_name, self.mock_test_name) self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) - self.assertEqual(actual_record.extra_errors['on_fail'].details, - MSG_EXPECTED_EXCEPTION) - expected_summary = ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 1, Skipped 0") + self.assertEqual( + actual_record.extra_errors['on_fail'].details, MSG_EXPECTED_EXCEPTION + ) + expected_summary = ( + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_abort_class_setup_class(self): @@ -1026,14 +1058,14 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertEqual(len(bt_cls.results.skipped), 3) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 0, Failed 0, Passed 0, " - "Requested 3, Skipped 3")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 0, Failed 0, Passed 0, Requested 3, Skipped 3', + ) def test_abort_class_in_setup_test(self): - class MockBaseTest(base_test.BaseTestClass): def setup_test(self): @@ -1049,14 +1081,14 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertEqual(len(bt_cls.results.skipped), 2) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 3, Skipped 2")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 3, Skipped 2', + ) def test_abort_class_in_on_fail(self): - class MockBaseTest(base_test.BaseTestClass): def test_1(self): @@ -1072,14 +1104,14 @@ def on_fail(self, record): asserts.abort_class(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertEqual(len(bt_cls.results.skipped), 2) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 3, Skipped 2")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 3, Skipped 2', + ) def test_setup_and_teardown_execution_count(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1100,7 +1132,6 @@ def test_func2(self): self.assertEqual(bt_cls.teardown_test.call_count, 2) def test_abort_class_in_test(self): - class MockBaseTest(base_test.BaseTestClass): def test_1(self): @@ -1114,15 +1145,15 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) - self.assertEqual(bt_cls.results.passed[0].test_name, "test_1") + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) + self.assertEqual(bt_cls.results.passed[0].test_name, 'test_1') self.assertEqual(bt_cls.results.failed[0].details, MSG_EXPECTED_EXCEPTION) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 2, Failed 1, Passed 1, " - "Requested 3, Skipped 1")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 2, Failed 1, Passed 1, Requested 3, Skipped 1', + ) def test_abort_all_in_setup_class(self): - class MockBaseTest(base_test.BaseTestClass): def setup_class(self): @@ -1138,16 +1169,17 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 0, Failed 0, Passed 0, " - "Requested 3, Skipped 3")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 0, Failed 0, Passed 0, Requested 3, Skipped 3', + ) def test_abort_all_in_teardown_class(self): - class MockBaseTest(base_test.BaseTestClass): def test_1(self): @@ -1160,16 +1192,17 @@ def teardown_class(self): asserts.abort_all(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2']) self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 2, Failed 0, Passed 2, " - "Requested 2, Skipped 0")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 2, Failed 0, Passed 2, Requested 2, Skipped 0', + ) def test_abort_all_in_setup_test(self): - class MockBaseTest(base_test.BaseTestClass): def setup_test(self): @@ -1185,16 +1218,17 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 3, Skipped 2")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 3, Skipped 2', + ) def test_abort_all_in_on_fail(self): - class MockBaseTest(base_test.BaseTestClass): def test_1(self): @@ -1210,16 +1244,17 @@ def on_fail(self, record): asserts.abort_all(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 1, Failed 1, Passed 0, " - "Requested 3, Skipped 2")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 1, Failed 1, Passed 0, Requested 3, Skipped 2', + ) def test_abort_all_in_on_fail_from_setup_class(self): - class MockBaseTest(base_test.BaseTestClass): def setup_class(self): @@ -1238,18 +1273,19 @@ def on_fail(self, record): asserts.abort_all(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) setup_class_record = bt_cls.results.error[0] self.assertEqual(setup_class_record.test_name, 'setup_class') self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 1, Executed 0, Failed 0, Passed 0, " - "Requested 3, Skipped 3")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 1, Executed 0, Failed 0, Passed 0, Requested 3, Skipped 3', + ) def test_abort_all_in_test(self): - class MockBaseTest(base_test.BaseTestClass): def test_1(self): @@ -1263,18 +1299,19 @@ def test_3(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - with self.assertRaisesRegex(signals.TestAbortAll, - MSG_EXPECTED_EXCEPTION) as context: - bt_cls.run(test_names=["test_1", "test_2", "test_3"]) + with self.assertRaisesRegex( + signals.TestAbortAll, MSG_EXPECTED_EXCEPTION + ) as context: + bt_cls.run(test_names=['test_1', 'test_2', 'test_3']) self.assertTrue(hasattr(context.exception, 'results')) - self.assertEqual(bt_cls.results.passed[0].test_name, "test_1") + self.assertEqual(bt_cls.results.passed[0].test_name, 'test_1') self.assertEqual(bt_cls.results.failed[0].details, MSG_EXPECTED_EXCEPTION) - self.assertEqual(bt_cls.results.summary_str(), - ("Error 0, Executed 2, Failed 1, Passed 1, " - "Requested 3, Skipped 1")) + self.assertEqual( + bt_cls.results.summary_str(), + 'Error 0, Executed 2, Failed 1, Passed 1, Requested 3, Skipped 1', + ) def test_uncaught_exception(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1282,20 +1319,21 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.error[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) # Stacktraces can vary. Just check for key words self.assertIn('test_method()', actual_record.stacktrace) - self.assertIn('raise Exception(MSG_EXPECTED_EXCEPTION)', - actual_record.stacktrace) - self.assertIn('Exception: This is an expected exception.', - actual_record.stacktrace) + self.assertIn( + 'raise Exception(MSG_EXPECTED_EXCEPTION)', actual_record.stacktrace + ) + self.assertIn( + 'Exception: This is an expected exception.', actual_record.stacktrace + ) def test_fail(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1303,14 +1341,13 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_true(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1318,14 +1355,13 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_equal_pass(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1334,12 +1370,11 @@ def test_func(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) def test_assert_equal_fail(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1348,30 +1383,27 @@ def test_func(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") - self.assertEqual(actual_record.details, "1 != 2") + self.assertEqual(actual_record.test_name, 'test_func') + self.assertEqual(actual_record.details, '1 != 2') self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_equal_fail_with_msg(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): - asserts.assert_equal(1, - 2, - msg=MSG_EXPECTED_EXCEPTION, - extras=MOCK_EXTRA) + asserts.assert_equal( + 1, 2, msg=MSG_EXPECTED_EXCEPTION, extras=MOCK_EXTRA + ) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") - expected_msg = "1 != 2 " + MSG_EXPECTED_EXCEPTION + self.assertEqual(actual_record.test_name, 'test_func') + expected_msg = '1 != 2 ' + MSG_EXPECTED_EXCEPTION self.assertEqual(actual_record.details, expected_msg) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_raises_pass(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1381,12 +1413,11 @@ def test_func(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) def test_assert_raises_fail_with_noop(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1396,12 +1427,11 @@ def test_func(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") - self.assertEqual(actual_record.details, "SomeError not raised") + self.assertEqual(actual_record.test_name, 'test_func') + self.assertEqual(actual_record.details, 'SomeError not raised') self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_raises_fail_with_wrong_error(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1411,83 +1441,80 @@ def test_func(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_UNEXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) def test_assert_raises_regex_pass(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): - with asserts.assert_raises_regex(SomeError, - expected_regex=MSG_EXPECTED_EXCEPTION, - extras=MOCK_EXTRA): + with asserts.assert_raises_regex( + SomeError, expected_regex=MSG_EXPECTED_EXCEPTION, extras=MOCK_EXTRA + ): raise SomeError(MSG_EXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) def test_assert_raises_regex_fail_with_noop(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): - with asserts.assert_raises_regex(SomeError, - expected_regex=MSG_EXPECTED_EXCEPTION, - extras=MOCK_EXTRA): + with asserts.assert_raises_regex( + SomeError, expected_regex=MSG_EXPECTED_EXCEPTION, extras=MOCK_EXTRA + ): pass bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") - self.assertEqual(actual_record.details, "SomeError not raised") + self.assertEqual(actual_record.test_name, 'test_func') + self.assertEqual(actual_record.details, 'SomeError not raised') self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_raises_fail_with_wrong_regex(self): - wrong_msg = "ha" + wrong_msg = 'ha' class MockBaseTest(base_test.BaseTestClass): def test_func(self): - with asserts.assert_raises_regex(SomeError, - expected_regex=MSG_EXPECTED_EXCEPTION, - extras=MOCK_EXTRA): + with asserts.assert_raises_regex( + SomeError, expected_regex=MSG_EXPECTED_EXCEPTION, extras=MOCK_EXTRA + ): raise SomeError(wrong_msg) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.failed[0] - self.assertEqual(actual_record.test_name, "test_func") - expected_details = ('"This is an expected exception." does not match ' - '"%s"') % wrong_msg + self.assertEqual(actual_record.test_name, 'test_func') + expected_details = ( + '"This is an expected exception." does not match "%s"' + ) % wrong_msg self.assertEqual(actual_record.details, expected_details) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_assert_raises_regex_fail_with_wrong_error(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): - with asserts.assert_raises_regex(SomeError, - expected_regex=MSG_EXPECTED_EXCEPTION, - extras=MOCK_EXTRA): + with asserts.assert_raises_regex( + SomeError, expected_regex=MSG_EXPECTED_EXCEPTION, extras=MOCK_EXTRA + ): raise AttributeError(MSG_UNEXPECTED_EXCEPTION) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_UNEXPECTED_EXCEPTION) self.assertIsNone(actual_record.extras) def test_explicit_pass(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1495,28 +1522,26 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_implicit_pass(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): pass bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertIsNone(actual_record.details) self.assertIsNone(actual_record.extras) def test_skip(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1524,16 +1549,15 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.skipped[0] self.assertIsNotNone(actual_record.begin_time) self.assertIsNotNone(actual_record.end_time) - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_skip_if(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -1542,16 +1566,15 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.skipped[0] self.assertIsNotNone(actual_record.begin_time) self.assertIsNotNone(actual_record.end_time) - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_skip_in_setup_test(self): - class MockBaseTest(base_test.BaseTestClass): def setup_test(self): @@ -1561,11 +1584,11 @@ def test_func(self): never_call() bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_func"]) + bt_cls.run(test_names=['test_func']) actual_record = bt_cls.results.skipped[0] self.assertIsNotNone(actual_record.begin_time) self.assertIsNotNone(actual_record.end_time) - self.assertEqual(actual_record.test_name, "test_func") + self.assertEqual(actual_record.test_name, 'test_func') self.assertEqual(actual_record.details, MSG_EXPECTED_EXCEPTION) self.assertEqual(actual_record.extras, MOCK_EXTRA) @@ -1619,8 +1642,7 @@ def on_fail(self, record): self.assertEqual(second_error.extras, '2') def test_expect_two_tests(self): - """Errors in `expect` should not leak across tests. - """ + """Errors in `expect` should not leak across tests.""" must_call = mock.Mock() class MockBaseTest(base_test.BaseTestClass): @@ -1643,8 +1665,7 @@ def test_2(self): self.assertEqual(another_record.test_name, 'test_2') def test_expect_no_op(self): - """Tests don't fail when expect is not triggered. - """ + """Tests don't fail when expect is not triggered.""" must_call = mock.Mock() class MockBaseTest(base_test.BaseTestClass): @@ -1851,8 +1872,10 @@ def test_func(self): must_call.assert_called_once_with('ha') actual_record = bt_cls.results.failed[0] self.assertEqual(actual_record.test_name, 'test_func') - self.assertEqual(actual_record.details, - 'Got an unexpected exception: %s' % MSG_EXPECTED_EXCEPTION) + self.assertEqual( + actual_record.details, + 'Got an unexpected exception: %s' % MSG_EXPECTED_EXCEPTION, + ) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_expect_no_raises_custom_msg(self): @@ -1871,13 +1894,13 @@ def test_func(self): must_call.assert_called_once_with('ha') actual_record = bt_cls.results.failed[0] self.assertEqual(actual_record.test_name, 'test_func') - self.assertEqual(actual_record.details, - '%s: %s' % (msg, MSG_EXPECTED_EXCEPTION)) + self.assertEqual( + actual_record.details, '%s: %s' % (msg, MSG_EXPECTED_EXCEPTION) + ) self.assertEqual(actual_record.extras, MOCK_EXTRA) def test_expect_true_and_assert_true(self): - """Error thrown by assert_true should be considered the termination. - """ + """Error thrown by assert_true should be considered the termination.""" must_call = mock.Mock() class MockBaseTest(base_test.BaseTestClass): @@ -1897,18 +1920,19 @@ def test_func(self): def test_unpack_userparams_required(self): """Missing a required param should raise an error.""" - required = ["some_param"] + required = ['some_param'] bc = base_test.BaseTestClass(self.mock_test_cls_configs) bc.unpack_userparams(required) - expected_value = self.mock_test_cls_configs.user_params["some_param"] + expected_value = self.mock_test_cls_configs.user_params['some_param'] self.assertEqual(bc.some_param, expected_value) def test_unpack_userparams_required_missing(self): """Missing a required param should raise an error.""" - required = ["something"] + required = ['something'] bc = base_test.BaseTestClass(self.mock_test_cls_configs) - expected_msg = ('Missing required user param "%s" in test ' - 'configuration.') % required[0] + expected_msg = ( + 'Missing required user param "%s" in test configuration.' + ) % required[0] with self.assertRaisesRegex(base_test.Error, expected_msg): bc.unpack_userparams(required) @@ -1916,10 +1940,10 @@ def test_unpack_userparams_optional(self): """If an optional param is specified, the value should be what's in the config. """ - opt = ["some_param"] + opt = ['some_param'] bc = base_test.BaseTestClass(self.mock_test_cls_configs) bc.unpack_userparams(opt_param_names=opt) - expected_value = self.mock_test_cls_configs.user_params["some_param"] + expected_value = self.mock_test_cls_configs.user_params['some_param'] self.assertEqual(bc.some_param, expected_value) def test_unpack_userparams_optional_with_default(self): @@ -1927,16 +1951,16 @@ def test_unpack_userparams_optional_with_default(self): param is not in the config, the value should be the default value. """ bc = base_test.BaseTestClass(self.mock_test_cls_configs) - bc.unpack_userparams(optional_thing="whatever") - self.assertEqual(bc.optional_thing, "whatever") + bc.unpack_userparams(optional_thing='whatever') + self.assertEqual(bc.optional_thing, 'whatever') def test_unpack_userparams_default_overwrite_by_optional_param_list(self): """If an optional param is specified in kwargs, and the param is in the config, the value should be the one in the config. """ bc = base_test.BaseTestClass(self.mock_test_cls_configs) - bc.unpack_userparams(some_param="whatever") - expected_value = self.mock_test_cls_configs.user_params["some_param"] + bc.unpack_userparams(some_param='whatever') + expected_value = self.mock_test_cls_configs.user_params['some_param'] self.assertEqual(bc.some_param, expected_value) def test_unpack_userparams_default_overwrite_by_required_param_list(self): @@ -1946,32 +1970,33 @@ def test_unpack_userparams_default_overwrite_by_required_param_list(self): thrown. """ bc = base_test.BaseTestClass(self.mock_test_cls_configs) - bc.unpack_userparams(req_param_names=['a_kwarg_param'], - a_kwarg_param="whatever") - self.assertEqual(bc.a_kwarg_param, "whatever") + bc.unpack_userparams( + req_param_names=['a_kwarg_param'], a_kwarg_param='whatever' + ) + self.assertEqual(bc.a_kwarg_param, 'whatever') def test_unpack_userparams_optional_missing(self): """Missing an optional param should not raise an error.""" - opt = ["something"] + opt = ['something'] bc = base_test.BaseTestClass(self.mock_test_cls_configs) bc.unpack_userparams(opt_param_names=opt) def test_unpack_userparams_basic(self): """Required and optional params are unpacked properly.""" - required = ["something"] - optional = ["something_else"] + required = ['something'] + optional = ['something_else'] configs = self.mock_test_cls_configs.copy() - configs.user_params["something"] = 42 - configs.user_params["something_else"] = 53 + configs.user_params['something'] = 42 + configs.user_params['something_else'] = 53 bc = base_test.BaseTestClass(configs) bc.unpack_userparams(req_param_names=required, opt_param_names=optional) self.assertEqual(bc.something, 42) self.assertEqual(bc.something_else, 53) def test_unpack_userparams_default_overwrite(self): - default_arg_val = "haha" - actual_arg_val = "wawa" - arg_name = "arg1" + default_arg_val = 'haha' + actual_arg_val = 'wawa' + arg_name = 'arg1' configs = self.mock_test_cls_configs.copy() configs.user_params[arg_name] = actual_arg_val bc = base_test.BaseTestClass(configs) @@ -1980,8 +2005,8 @@ def test_unpack_userparams_default_overwrite(self): def test_unpack_userparams_default_None(self): bc = base_test.BaseTestClass(self.mock_test_cls_configs) - bc.unpack_userparams(arg1="haha") - self.assertEqual(bc.arg1, "haha") + bc.unpack_userparams(arg1='haha') + self.assertEqual(bc.arg1, 'haha') def test_pre_run_failure(self): """Test code path for `pre_run` failure. @@ -2015,13 +2040,14 @@ def test_foo(self): # TODO(angli): remove after the full deprecation of `setup_generated_tests`. def test_setup_generated_tests(self): - class MockBaseTest(base_test.BaseTestClass): def setup_generated_tests(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2070,13 +2096,14 @@ def test_foo(self): self.assertEqual(bt_cls.results.skipped, []) def test_generate_tests_run(self): - class MockBaseTest(base_test.BaseTestClass): def pre_run(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2094,14 +2121,15 @@ def logic(self, a, b): self.assertEqual(bt_cls.results.passed[1].test_name, 'test_3_4') def test_generate_tests_with_uid(self): - class MockBaseTest(base_test.BaseTestClass): def pre_run(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - uid_func=self.uid_logic, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + uid_func=self.uid_logic, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2118,14 +2146,15 @@ def logic(self, a, b): self.assertEqual(bt_cls.results.passed[1].uid, 'uid-3-4') def test_generate_tests_with_none_uid(self): - class MockBaseTest(base_test.BaseTestClass): def pre_run(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - uid_func=self.uid_logic, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + uid_func=self.uid_logic, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2144,13 +2173,14 @@ def logic(self, a, b): self.assertEqual(bt_cls.results.passed[1].uid, 'uid-3-4') def test_generate_tests_selected_run(self): - class MockBaseTest(base_test.BaseTestClass): def pre_run(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2165,13 +2195,14 @@ def logic(self, a, b): self.assertEqual(bt_cls.results.passed[0].test_name, 'test_3_4') def test_generate_tests_call_outside_of_pre_run(self): - class MockBaseTest(base_test.BaseTestClass): def test_ha(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'test_%s_%s' % (a, b) @@ -2183,23 +2214,26 @@ def logic(self, a, b): bt_cls.run() actual_record = bt_cls.results.error[0] utils.validate_test_result(bt_cls.results) - self.assertEqual(actual_record.test_name, "test_ha") + self.assertEqual(actual_record.test_name, 'test_ha') self.assertEqual( actual_record.details, "'generate_tests' cannot be called outside of the followin" - "g functions: ['pre_run', 'setup_generated_tests'].") - expected_summary = ("Error 1, Executed 1, Failed 0, Passed 0, " - "Requested 1, Skipped 0") + "g functions: ['pre_run', 'setup_generated_tests'].", + ) + expected_summary = ( + 'Error 1, Executed 1, Failed 0, Passed 0, Requested 1, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_generate_tests_dup_test_name(self): - class MockBaseTest(base_test.BaseTestClass): def pre_run(self): - self.generate_tests(test_logic=self.logic, - name_func=self.name_gen, - arg_sets=[(1, 2), (3, 4)]) + self.generate_tests( + test_logic=self.logic, + name_func=self.name_gen, + arg_sets=[(1, 2), (3, 4)], + ) def name_gen(self, a, b): return 'ha' @@ -2210,13 +2244,15 @@ def logic(self, a, b): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() actual_record = bt_cls.results.error[0] - self.assertEqual(actual_record.test_name, "pre_run") + self.assertEqual(actual_record.test_name, 'pre_run') self.assertEqual( actual_record.details, 'During test generation of "logic": Test name "ha" already exists' - ', cannot be duplicated!') - expected_summary = ("Error 1, Executed 0, Failed 0, Passed 0, " - "Requested 0, Skipped 0") + ', cannot be duplicated!', + ) + expected_summary = ( + 'Error 1, Executed 0, Failed 0, Passed 0, Requested 0, Skipped 0' + ) self.assertEqual(bt_cls.results.summary_str(), expected_summary) def test_write_user_data(self): @@ -2229,9 +2265,9 @@ def test_something(self): self.record_data(content) bt_cls = MockBaseTest(self.mock_test_cls_configs) - bt_cls.run(test_names=["test_something"]) + bt_cls.run(test_names=['test_something']) actual_record = bt_cls.results.passed[0] - self.assertEqual(actual_record.test_name, "test_something") + self.assertEqual(actual_record.test_name, 'test_something') hit = False with io.open(self.summary_file, 'r', encoding='utf-8') as f: for c in yaml.safe_load_all(f): @@ -2252,11 +2288,14 @@ def test_record_controller_info(self): """ mock_test_config = self.mock_test_cls_configs.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - mock_ctrlr_2_config_name = mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + mock_ctrlr_2_config_name = ( + mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + ) my_config = [{'serial': 'xxxx', 'magic': 'Magic'}] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs[mock_ctrlr_2_config_name] = copy.copy( - my_config) + my_config + ) class ControllerInfoTest(base_test.BaseTestClass): """Registers two different controller types and modifies controller @@ -2282,21 +2321,22 @@ def test_func(self): self.assertEqual(info1.controller_info, [{'MyMagic': {'magic': 'Magic'}}]) self.assertEqual(info2.test_class, 'ControllerInfoTest') self.assertEqual(info2.controller_name, 'AnotherMagicDevice') - self.assertEqual(info2.controller_info, [{ - 'MyOtherMagic': { - 'magic': 'Magic', - 'extra_magic': 'haha' - } - }]) + self.assertEqual( + info2.controller_info, + [{'MyOtherMagic': {'magic': 'Magic', 'extra_magic': 'haha'}}], + ) def test_record_controller_info_fail(self): mock_test_config = self.mock_test_cls_configs.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - mock_ctrlr_2_config_name = mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + mock_ctrlr_2_config_name = ( + mock_second_controller.MOBLY_CONTROLLER_CONFIG_NAME + ) my_config = [{'serial': 'xxxx', 'magic': 'Magic'}] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs[mock_ctrlr_2_config_name] = copy.copy( - my_config) + my_config + ) class ControllerInfoTest(base_test.BaseTestClass): """Registers two different controller types and modifies controller @@ -2320,25 +2360,24 @@ def test_func(self): self.assertEqual(len(bt_cls.results.controller_info), 1) self.assertEqual(info.test_class, 'ControllerInfoTest') self.assertEqual(info.controller_name, 'AnotherMagicDevice') - self.assertEqual(info.controller_info, [{ - 'MyOtherMagic': { - 'magic': 'Magic', - 'extra_magic': 'haha' - } - }]) + self.assertEqual( + info.controller_info, + [{'MyOtherMagic': {'magic': 'Magic', 'extra_magic': 'haha'}}], + ) record = bt_cls.results.error[0] print(record.to_dict()) self.assertEqual(record.test_name, 'clean_up') self.assertIsNotNone(record.begin_time) self.assertIsNotNone(record.end_time) - expected_msg = ('Failed to collect controller info from ' - 'mock_controller: Some failure') + expected_msg = ( + 'Failed to collect controller info from mock_controller: Some failure' + ) self.assertEqual(record.details, expected_msg) def test_repeat_invalid_count(self): - with self.assertRaisesRegex( - ValueError, 'The `count` for `repeat` must be larger than 1, got "1".'): + ValueError, 'The `count` for `repeat` must be larger than 1, got "1".' + ): class MockBaseTest(base_test.BaseTestClass): @@ -2347,11 +2386,13 @@ def test_something(self): pass def test_repeat_invalid_max_consec_error(self): - with self.assertRaisesRegex( ValueError, - re.escape('The `max_consecutive_error` (4) for `repeat` must be ' - 'smaller than `count` (3).')): + re.escape( + 'The `max_consecutive_error` (4) for `repeat` must be ' + 'smaller than `count` (3).' + ), + ): class MockBaseTest(base_test.BaseTestClass): @@ -2384,9 +2425,11 @@ def _run_test_logic(self, arg): pass def pre_run(self): - self.generate_tests(self._run_test_logic, - name_func=lambda arg: f'test_generated_{arg}', - arg_sets=[(1,)]) + self.generate_tests( + self._run_test_logic, + name_func=lambda arg: f'test_generated_{arg}', + arg_sets=[(1,)], + ) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() @@ -2418,7 +2461,8 @@ def test_something(self): @mock.patch('logging.error') def test_repeat_with_consec_error_at_the_beginning_aborts_repeat( - self, mock_logging_error): + self, mock_logging_error + ): repeat_count = 5 max_consec_error = 2 mock_action = mock.MagicMock() @@ -2430,16 +2474,21 @@ def test_repeat_with_consec_error_at_the_beginning_aborts_repeat( class MockBaseTest(base_test.BaseTestClass): - @base_test.repeat(count=repeat_count, - max_consecutive_error=max_consec_error) + @base_test.repeat( + count=repeat_count, max_consecutive_error=max_consec_error + ) def test_something(self): mock_action() bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() mock_logging_error.assert_called_with( - 'Repeated test case "%s" has consecutively failed %d iterations, aborting' - ' the remaining %d iterations.', 'test_something', 2, 3) + 'Repeated test case "%s" has consecutively failed %d iterations,' + ' aborting the remaining %d iterations.', + 'test_something', + 2, + 3, + ) self.assertEqual(max_consec_error, len(bt_cls.results.executed)) self.assertEqual(max_consec_error, len(bt_cls.results.error)) for i, record in enumerate(bt_cls.results.error): @@ -2447,7 +2496,8 @@ def test_something(self): @mock.patch('logging.error') def test_repeat_with_consec_error_in_the_middle_aborts_repeat( - self, mock_logging_error): + self, mock_logging_error + ): repeat_count = 5 max_consec_error = 2 mock_action = mock.MagicMock() @@ -2461,16 +2511,21 @@ def test_repeat_with_consec_error_in_the_middle_aborts_repeat( class MockBaseTest(base_test.BaseTestClass): - @base_test.repeat(count=repeat_count, - max_consecutive_error=max_consec_error) + @base_test.repeat( + count=repeat_count, max_consecutive_error=max_consec_error + ) def test_something(self): mock_action() bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() mock_logging_error.assert_called_with( - 'Repeated test case "%s" has consecutively failed %d iterations, aborting' - ' the remaining %d iterations.', 'test_something', 2, 1) + 'Repeated test case "%s" has consecutively failed %d iterations,' + ' aborting the remaining %d iterations.', + 'test_something', + 2, + 1, + ) self.assertEqual(4, len(bt_cls.results.executed)) self.assertEqual(2, len(bt_cls.results.error)) self.assertEqual(2, len(bt_cls.results.passed)) @@ -2491,8 +2546,9 @@ def test_repeat_with_consec_error_does_not_abort_repeat(self): class MockBaseTest(base_test.BaseTestClass): - @base_test.repeat(count=repeat_count, - max_consecutive_error=max_consec_error) + @base_test.repeat( + count=repeat_count, max_consecutive_error=max_consec_error + ) def test_something(self): mock_action() @@ -2502,10 +2558,10 @@ def test_something(self): self.assertEqual(3, len(bt_cls.results.error)) def test_retry_invalid_count(self): - with self.assertRaisesRegex( ValueError, - 'The `max_count` for `retry` must be larger than 1, got "1".'): + 'The `max_count` for `retry` must be larger than 1, got "1".', + ): class MockBaseTest(base_test.BaseTestClass): @@ -2525,8 +2581,9 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - self.assertTrue(bt_cls.results.is_all_pass, - 'This test run should be considered pass.') + self.assertTrue( + bt_cls.results.is_all_pass, 'This test run should be considered pass.' + ) self.assertEqual(1, len(bt_cls.results.executed)) self.assertEqual(1, len(bt_cls.results.passed)) pass_record = bt_cls.results.passed[0] @@ -2546,8 +2603,9 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - self.assertTrue(bt_cls.results.is_all_pass, - 'This test run should be considered pass.') + self.assertTrue( + bt_cls.results.is_all_pass, 'This test run should be considered pass.' + ) self.assertEqual(3, len(bt_cls.results.executed)) self.assertEqual(1, len(bt_cls.results.passed)) pass_record = bt_cls.results.passed[0] @@ -2562,8 +2620,8 @@ def test_something(self): def test_retry_generated_test_last_pass(self): max_count = 3 mock_action = mock.MagicMock( - side_effect=[Exception('Fail 1'), - Exception('Fail 2'), None]) + side_effect=[Exception('Fail 1'), Exception('Fail 2'), None] + ) class MockBaseTest(base_test.BaseTestClass): @@ -2572,14 +2630,17 @@ def _run_test_logic(self, arg): mock_action() def pre_run(self): - self.generate_tests(self._run_test_logic, - name_func=lambda arg: f'test_generated_{arg}', - arg_sets=[(1,)]) + self.generate_tests( + self._run_test_logic, + name_func=lambda arg: f'test_generated_{arg}', + arg_sets=[(1,)], + ) bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - self.assertTrue(bt_cls.results.is_all_pass, - 'This test run should be considered pass.') + self.assertTrue( + bt_cls.results.is_all_pass, 'This test run should be considered pass.' + ) self.assertEqual(3, len(bt_cls.results.executed)) self.assertEqual(1, len(bt_cls.results.passed)) pass_record = bt_cls.results.passed[0] @@ -2597,7 +2658,7 @@ def test_retry_all_fail(self): mock_action.side_effect = [ Exception('Fail 1'), Exception('Fail 2'), - Exception('Fail 3') + Exception('Fail 3'), ] class MockBaseTest(base_test.BaseTestClass): @@ -2608,8 +2669,9 @@ def test_something(self): bt_cls = MockBaseTest(self.mock_test_cls_configs) bt_cls.run() - self.assertFalse(bt_cls.results.is_all_pass, - 'This test run should be considered fail.') + self.assertFalse( + bt_cls.results.is_all_pass, 'This test run should be considered fail.' + ) self.assertEqual(3, len(bt_cls.results.executed)) self.assertEqual(3, len(bt_cls.results.error)) error_record_1, error_record_2, error_record_3 = bt_cls.results.error @@ -2620,7 +2682,6 @@ def test_something(self): self.assertIs(error_record_2, error_record_3.retry_parent) def test_uid(self): - class MockBaseTest(base_test.BaseTestClass): @records.uid('some-uid') @@ -2633,7 +2694,6 @@ def test_func(self): self.assertEqual(actual_record.uid, 'some-uid') def test_uid_not_specified(self): - class MockBaseTest(base_test.BaseTestClass): def test_func(self): @@ -2705,5 +2765,5 @@ class RecoverableError(Exception): logging_patch.debug.assert_called_with('[TestClass]#stage <<< END <<<') -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/config_parser_test.py b/tests/mobly/config_parser_test.py index 69018192..46548f0f 100644 --- a/tests/mobly/config_parser_test.py +++ b/tests/mobly/config_parser_test.py @@ -35,26 +35,26 @@ def tearDown(self): def test__load_config_file(self): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u'TestBeds:\n') - f.write(u' # A test bed where adb will find Android devices.\n') - f.write(u' - Name: SampleTestBed\n') - f.write(u' Controllers:\n') - f.write(u' AndroidDevice: \'*\'\n') + f.write('TestBeds:\n') + f.write(' # A test bed where adb will find Android devices.\n') + f.write(' - Name: SampleTestBed\n') + f.write(' Controllers:\n') + f.write(" AndroidDevice: '*'\n") config = config_parser._load_config_file(tmp_file_path) - self.assertEqual(config['TestBeds'][0]['Name'], u'SampleTestBed') + self.assertEqual(config['TestBeds'][0]['Name'], 'SampleTestBed') def test__load_config_file_with_unicode(self): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u'TestBeds:\n') - f.write(u' # A test bed where adb will find Android devices.\n') - f.write(u' - Name: \u901a\n') - f.write(u' Controllers:\n') - f.write(u' AndroidDevice: \'*\'\n') + f.write('TestBeds:\n') + f.write(' # A test bed where adb will find Android devices.\n') + f.write(' - Name: \u901a\n') + f.write(' Controllers:\n') + f.write(" AndroidDevice: '*'\n") config = config_parser._load_config_file(tmp_file_path) - self.assertEqual(config['TestBeds'][0]['Name'], u'\u901a') + self.assertEqual(config['TestBeds'][0]['Name'], '\u901a') def test_run_config_type(self): config = config_parser.TestRunConfig() @@ -66,13 +66,16 @@ def test_run_config_controller_configs_is_already_initialized(self): expected_value = 'SOME_VALUE' self.assertEqual( config.controller_configs.get('NON_EXISTENT_KEY', expected_value), - expected_value) + expected_value, + ) def test_run_config_user_params_is_already_initialized(self): config = config_parser.TestRunConfig() expected_value = 'SOME_VALUE' - self.assertEqual(config.user_params.get('NON_EXISTENT_KEY', expected_value), - expected_value) + self.assertEqual( + config.user_params.get('NON_EXISTENT_KEY', expected_value), + expected_value, + ) if __name__ == '__main__': diff --git a/tests/mobly/controller_manager_test.py b/tests/mobly/controller_manager_test.py index 53e4cfad..46aa2737 100755 --- a/tests/mobly/controller_manager_test.py +++ b/tests/mobly/controller_manager_test.py @@ -49,14 +49,16 @@ def test_verify_controller_module_missing_attr(self): def test_register_controller_no_config(self): c_manager = controller_manager.ControllerManager('SomeClass', {}) - with self.assertRaisesRegex(signals.ControllerError, - 'No corresponding config found for'): + with self.assertRaisesRegex( + signals.ControllerError, 'No corresponding config found for' + ): c_manager.register_controller(mock_controller) def test_register_controller_no_config_for_not_required(self): c_manager = controller_manager.ControllerManager('SomeClass', {}) self.assertIsNone( - c_manager.register_controller(mock_controller, required=False)) + c_manager.register_controller(mock_controller, required=False) + ) def test_register_controller_dup_register(self): """Verifies correctness of registration, internal tally of controllers @@ -65,8 +67,9 @@ def test_register_controller_dup_register(self): """ mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) registered_name = 'mock_controller' self.assertTrue(registered_name in c_manager._controller_objects) @@ -81,8 +84,9 @@ def test_register_controller_dup_register(self): def test_register_controller_return_value(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) magic_devices = c_manager.register_controller(mock_controller) self.assertEqual(magic_devices[0].magic, 'magic1') self.assertEqual(magic_devices[1].magic, 'magic2') @@ -90,8 +94,9 @@ def test_register_controller_return_value(self): def test_register_controller_change_return_value(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) magic_devices = c_manager.register_controller(mock_controller) magic1 = magic_devices.pop(0) self.assertIs(magic1, c_manager._controller_objects['mock_controller'][0]) @@ -100,8 +105,9 @@ def test_register_controller_change_return_value(self): def test_register_controller_less_than_min_number(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) expected_msg = 'Expected to get at least 3 controller objects, got 2.' with self.assertRaisesRegex(signals.ControllerError, expected_msg): c_manager.register_controller(mock_controller, min_number=3) @@ -110,19 +116,22 @@ def test_register_controller_less_than_min_number(self): def test_get_controller_info_record_not_serializable(self, _): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) record = c_manager.get_controller_info_records()[0] actual_controller_info = record.controller_info - self.assertEqual(actual_controller_info, - "[{'MyMagic': 'magic1'}, {'MyMagic': 'magic2'}]") + self.assertEqual( + actual_controller_info, "[{'MyMagic': 'magic1'}, {'MyMagic': 'magic2'}]" + ) def test_controller_record_exists_without_get_info(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) get_info = getattr(mock_controller, 'get_info') delattr(mock_controller, 'get_info') try: @@ -139,8 +148,9 @@ def test_get_controller_info_records_empty(self, mock_get_info_func): mock_get_info_func.return_value = None mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) record = c_manager.get_controller_info_records()[0] self.assertIsNone(record.controller_info) @@ -149,13 +159,15 @@ def test_get_controller_info_records_empty(self, mock_get_info_func): @mock.patch('mobly.expects._ExpectErrorRecorder.add_error') @mock.patch('tests.lib.mock_controller.get_info') - def test_get_controller_info_records_error(self, mock_get_info_func, - mock_add_error): + def test_get_controller_info_records_error( + self, mock_get_info_func, mock_add_error + ): mock_get_info_func.side_effect = Exception('Record info failed.') mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) self.assertFalse(c_manager.get_controller_info_records()) mock_add_error.assert_called_once() @@ -165,36 +177,37 @@ def test_get_controller_info_records_error(self, mock_get_info_func, def test_get_controller_info_records(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) record = c_manager.get_controller_info_records()[0] record_dict = record.to_dict() record_dict.pop('Timestamp') self.assertEqual( - record_dict, { - 'Controller Info': [{ - 'MyMagic': 'magic1' - }, { - 'MyMagic': 'magic2' - }], + record_dict, + { + 'Controller Info': [{'MyMagic': 'magic1'}, {'MyMagic': 'magic2'}], 'Controller Name': 'MagicDevice', - 'Test Class': 'SomeClass' - }) + 'Test Class': 'SomeClass', + }, + ) def test_get_controller_info_without_registration(self): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) self.assertFalse(c_manager.get_controller_info_records()) @mock.patch('tests.lib.mock_controller.destroy') def test_unregister_controller(self, mock_destroy_func): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) objects = c_manager.register_controller(mock_controller) c_manager.unregister_controllers() mock_destroy_func.assert_called_once_with(objects) @@ -206,8 +219,9 @@ def test_unregister_controller(self, mock_destroy_func): def test_unregister_controller_error(self, mock_destroy_func, mock_add_error): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.register_controller(mock_controller) mock_destroy_func.side_effect = Exception('Failed in destroy.') c_manager.unregister_controllers() @@ -221,13 +235,14 @@ def test_unregister_controller_error(self, mock_destroy_func, mock_add_error): def test_unregister_controller_without_registration(self, mock_destroy_func): mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME controller_configs = {mock_ctrlr_config_name: ['magic1', 'magic2']} - c_manager = controller_manager.ControllerManager('SomeClass', - controller_configs) + c_manager = controller_manager.ControllerManager( + 'SomeClass', controller_configs + ) c_manager.unregister_controllers() mock_destroy_func.assert_not_called() self.assertFalse(c_manager._controller_objects) self.assertFalse(c_manager._controller_modules) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/controllers/android_device_lib/adb_test.py b/tests/mobly/controllers/android_device_lib/adb_test.py index a0139599..4b26b92f 100755 --- a/tests/mobly/controllers/android_device_lib/adb_test.py +++ b/tests/mobly/controllers/android_device_lib/adb_test.py @@ -28,23 +28,30 @@ ('option2', 'value2'), ]) # Mock android instrumentation commands. -MOCK_BASIC_INSTRUMENTATION_COMMAND = ('am instrument -r -w com.my' - '.instrumentation.tests/com.android' - '.common.support.test.runner' - '.AndroidJUnitRunner') -MOCK_RUNNER_INSTRUMENTATION_COMMAND = ('am instrument -r -w com.my' - '.instrumentation.tests/com.my' - '.instrumentation.runner') -MOCK_OPTIONS_INSTRUMENTATION_COMMAND = ('am instrument -r -w -e option1 value1' - ' -e option2 value2 com.my' - '.instrumentation.tests/com.android' - '.common.support.test.runner' - '.AndroidJUnitRunner') +MOCK_BASIC_INSTRUMENTATION_COMMAND = ( + 'am instrument -r -w com.my' + '.instrumentation.tests/com.android' + '.common.support.test.runner' + '.AndroidJUnitRunner' +) +MOCK_RUNNER_INSTRUMENTATION_COMMAND = ( + 'am instrument -r -w com.my' + '.instrumentation.tests/com.my' + '.instrumentation.runner' +) +MOCK_OPTIONS_INSTRUMENTATION_COMMAND = ( + 'am instrument -r -w -e option1 value1' + ' -e option2 value2 com.my' + '.instrumentation.tests/com.android' + '.common.support.test.runner' + '.AndroidJUnitRunner' +) # Mock root command outputs. MOCK_ROOT_SUCCESS_OUTPUT = 'adbd is already running as root' -MOCK_ROOT_ERROR_OUTPUT = ( - 'adb: unable to connect for root: closed'.encode('utf-8')) +MOCK_ROOT_ERROR_OUTPUT = 'adb: unable to connect for root: closed'.encode( + 'utf-8' +) # Mock Shell Command MOCK_SHELL_COMMAND = 'ls' @@ -66,14 +73,18 @@ def _mock_execute_and_process_stdout_process(self, mock_popen): mock_popen.return_value.stdout.readline.side_effect = [''] mock_proc.communicate = mock.Mock( - return_value=('', MOCK_DEFAULT_STDERR.encode('utf-8'))) + return_value=('', MOCK_DEFAULT_STDERR.encode('utf-8')) + ) mock_proc.returncode = 0 return mock_popen @mock.patch('mobly.utils.run_command') def test_is_adb_available(self, mock_run_command): - mock_run_command.return_value = (0, '/usr/local/bin/adb\n'.encode('utf-8'), - ''.encode('utf-8')) + mock_run_command.return_value = ( + 0, + '/usr/local/bin/adb\n'.encode('utf-8'), + ''.encode('utf-8'), + ) self.assertTrue(adb.is_adb_available()) @mock.patch('mobly.utils.run_command') @@ -83,23 +94,29 @@ def test_is_adb_available_negative(self, mock_run_command): @mock.patch('mobly.utils.run_command') def test_exec_cmd_no_timeout_success(self, mock_run_command): - mock_run_command.return_value = (0, MOCK_DEFAULT_STDOUT.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) - out = adb.AdbProxy()._exec_cmd(['fake_cmd'], - shell=False, - timeout=None, - stderr=None) + mock_run_command.return_value = ( + 0, + MOCK_DEFAULT_STDOUT.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) + out = adb.AdbProxy()._exec_cmd( + ['fake_cmd'], shell=False, timeout=None, stderr=None + ) self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) mock_run_command.assert_called_with(['fake_cmd'], shell=False, timeout=None) @mock.patch('mobly.utils.run_command') def test_exec_cmd_error_with_serial(self, mock_run_command): # Return 1 for retcode for error. - mock_run_command.return_value = (1, MOCK_DEFAULT_STDOUT.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + mock_run_command.return_value = ( + 1, + MOCK_DEFAULT_STDOUT.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) mock_serial = 'ABCD1234' - with self.assertRaisesRegex(adb.AdbError, - 'Error executing adb cmd .*') as context: + with self.assertRaisesRegex( + adb.AdbError, 'Error executing adb cmd .*' + ) as context: adb.AdbProxy(mock_serial).fake_cmd() self.assertEqual(context.exception.serial, mock_serial) self.assertIn(mock_serial, context.exception.cmd) @@ -107,38 +124,45 @@ def test_exec_cmd_error_with_serial(self, mock_run_command): @mock.patch('mobly.utils.run_command') def test_exec_cmd_error_without_serial(self, mock_run_command): # Return 1 for retcode for error. - mock_run_command.return_value = (1, MOCK_DEFAULT_STDOUT.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) - with self.assertRaisesRegex(adb.AdbError, - 'Error executing adb cmd .*') as context: - adb.AdbProxy()._exec_cmd(['fake_cmd'], - shell=False, - timeout=None, - stderr=None) + mock_run_command.return_value = ( + 1, + MOCK_DEFAULT_STDOUT.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) + with self.assertRaisesRegex( + adb.AdbError, 'Error executing adb cmd .*' + ) as context: + adb.AdbProxy()._exec_cmd( + ['fake_cmd'], shell=False, timeout=None, stderr=None + ) self.assertFalse(context.exception.serial) mock_run_command.assert_called_with(['fake_cmd'], shell=False, timeout=None) @mock.patch('mobly.utils.run_command') def test_exec_cmd_with_timeout_success(self, mock_run_command): - mock_run_command.return_value = (0, MOCK_DEFAULT_STDOUT.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + mock_run_command.return_value = ( + 0, + MOCK_DEFAULT_STDOUT.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) - out = adb.AdbProxy()._exec_cmd(['fake_cmd'], - shell=False, - timeout=1, - stderr=None) + out = adb.AdbProxy()._exec_cmd( + ['fake_cmd'], shell=False, timeout=1, stderr=None + ) self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) mock_run_command.assert_called_with(['fake_cmd'], shell=False, timeout=1) @mock.patch('mobly.utils.run_command') def test_exec_cmd_timed_out(self, mock_run_command): - mock_run_command.side_effect = subprocess.TimeoutExpired(cmd='mock_command', - timeout=0.01) + mock_run_command.side_effect = subprocess.TimeoutExpired( + cmd='mock_command', timeout=0.01 + ) mock_serial = '1234Abcd' with self.assertRaisesRegex( - adb.AdbTimeoutError, 'Timed out executing command "adb -s ' - '1234Abcd fake-cmd" after 0.01s.') as context: + adb.AdbTimeoutError, + 'Timed out executing command "adb -s 1234Abcd fake-cmd" after 0.01s.', + ) as context: adb.AdbProxy(mock_serial).fake_cmd(timeout=0.01) self.assertEqual(context.exception.serial, mock_serial) @@ -146,21 +170,23 @@ def test_exec_cmd_timed_out(self, mock_run_command): @mock.patch('mobly.utils.run_command') def test_exec_cmd_timed_out_without_serial(self, mock_run_command): - mock_run_command.side_effect = subprocess.TimeoutExpired(cmd='mock_command', - timeout=0.01) + mock_run_command.side_effect = subprocess.TimeoutExpired( + cmd='mock_command', timeout=0.01 + ) with self.assertRaisesRegex( adb.AdbTimeoutError, - 'Timed out executing command "adb fake-cmd" after 0.01s.'): + 'Timed out executing command "adb fake-cmd" after 0.01s.', + ): adb.AdbProxy().fake_cmd(timeout=0.01) def test_exec_cmd_with_negative_timeout_value(self): - with self.assertRaisesRegex(ValueError, - 'Timeout is not a positive value: -1'): - adb.AdbProxy()._exec_cmd(['fake_cmd'], - shell=False, - timeout=-1, - stderr=None) + with self.assertRaisesRegex( + ValueError, 'Timeout is not a positive value: -1' + ): + adb.AdbProxy()._exec_cmd( + ['fake_cmd'], shell=False, timeout=-1, stderr=None + ) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') def test_execute_and_process_stdout_reads_stdout(self, mock_popen): @@ -168,9 +194,9 @@ def test_execute_and_process_stdout_reads_stdout(self, mock_popen): mock_popen.return_value.stdout.readline.side_effect = ['1', '2', ''] mock_handler = mock.MagicMock() - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock_handler) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock_handler + ) self.assertEqual(mock_handler.call_count, 2) mock_handler.assert_any_call('1') mock_handler.assert_any_call('2') @@ -182,50 +208,63 @@ def test_execute_and_process_stdout_reads_unexpected_stdout(self, mock_popen): self._mock_execute_and_process_stdout_process(mock_popen) mock_handler = mock.MagicMock() mock_popen.return_value.communicate = mock.Mock( - return_value=(unexpected_stdout, MOCK_DEFAULT_STDERR.encode('utf-8'))) + return_value=(unexpected_stdout, MOCK_DEFAULT_STDERR.encode('utf-8')) + ) - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock_handler) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock_handler + ) self.assertEqual(mock_handler.call_count, 1) mock_handler.assert_called_with(unexpected_stdout) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') @mock.patch('logging.debug') - def test_execute_and_process_stdout_logs_cmd(self, mock_debug_logger, - mock_popen): + def test_execute_and_process_stdout_logs_cmd( + self, mock_debug_logger, mock_popen + ): raw_expected_stdout = '' expected_stdout = '[elided, processed via handler]' expected_stderr = MOCK_DEFAULT_STDERR.encode('utf-8') self._mock_execute_and_process_stdout_process(mock_popen) mock_popen.return_value.communicate = mock.Mock( - return_value=(raw_expected_stdout, expected_stderr)) + return_value=(raw_expected_stdout, expected_stderr) + ) - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock.MagicMock()) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock.MagicMock() + ) mock_debug_logger.assert_called_with( - 'cmd: %s, stdout: %s, stderr: %s, ret: %s', 'fake_cmd', expected_stdout, - expected_stderr, 0) + 'cmd: %s, stdout: %s, stderr: %s, ret: %s', + 'fake_cmd', + expected_stdout, + expected_stderr, + 0, + ) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') @mock.patch('logging.debug') def test_execute_and_process_stdout_logs_cmd_with_unexpected_stdout( - self, mock_debug_logger, mock_popen): + self, mock_debug_logger, mock_popen + ): raw_expected_stdout = MOCK_DEFAULT_STDOUT.encode('utf-8') expected_stdout = '[unexpected stdout] %s' % raw_expected_stdout expected_stderr = MOCK_DEFAULT_STDERR.encode('utf-8') self._mock_execute_and_process_stdout_process(mock_popen) mock_popen.return_value.communicate = mock.Mock( - return_value=(raw_expected_stdout, expected_stderr)) + return_value=(raw_expected_stdout, expected_stderr) + ) - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock.MagicMock()) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock.MagicMock() + ) mock_debug_logger.assert_called_with( - 'cmd: %s, stdout: %s, stderr: %s, ret: %s', 'fake_cmd', expected_stdout, - expected_stderr, 0) + 'cmd: %s, stdout: %s, stderr: %s, ret: %s', + 'fake_cmd', + expected_stdout, + expected_stderr, + 0, + ) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') def test_execute_and_process_stdout_despite_cmd_exits(self, mock_popen): @@ -234,9 +273,9 @@ def test_execute_and_process_stdout_despite_cmd_exits(self, mock_popen): mock_popen.return_value.stdout.readline.side_effect = ['1', '2', '3', ''] mock_handler = mock.MagicMock() - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock_handler) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock_handler + ) self.assertEqual(mock_handler.call_count, 3) mock_handler.assert_any_call('1') @@ -249,9 +288,9 @@ def test_execute_and_process_stdout_when_cmd_eof(self, mock_popen): mock_popen.return_value.stdout.readline.side_effect = ['1', '2', '3', ''] mock_handler = mock.MagicMock() - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock_handler) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock_handler + ) self.assertEqual(mock_handler.call_count, 3) mock_handler.assert_any_call('1') @@ -262,9 +301,9 @@ def test_execute_and_process_stdout_when_cmd_eof(self, mock_popen): def test_execute_and_process_stdout_returns_stderr(self, mock_popen): self._mock_execute_and_process_stdout_process(mock_popen) - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock.MagicMock()) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock.MagicMock() + ) self.assertEqual(MOCK_DEFAULT_STDERR, err.decode('utf-8')) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') @@ -273,9 +312,9 @@ def test_execute_and_process_stdout_raises_adb_error(self, mock_popen): mock_popen.return_value.returncode = 1 with self.assertRaisesRegex(adb.AdbError, 'Error executing adb cmd .*'): - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock.MagicMock()) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock.MagicMock() + ) @mock.patch('mobly.controllers.android_device_lib.adb.subprocess.Popen') def test_execute_and_process_stdout_when_handler_crash(self, mock_popen): @@ -285,9 +324,9 @@ def test_execute_and_process_stdout_when_handler_crash(self, mock_popen): mock_handler.side_effect = ['', TypeError('fake crash'), '', ''] with self.assertRaisesRegex(TypeError, 'fake crash'): - err = adb.AdbProxy()._execute_and_process_stdout(['fake_cmd'], - shell=False, - handler=mock_handler) + err = adb.AdbProxy()._execute_and_process_stdout( + ['fake_cmd'], shell=False, handler=mock_handler + ) mock_popen.return_value.communicate.assert_called_once_with() @@ -297,180 +336,192 @@ def test_construct_adb_cmd(self): def test_construct_adb_cmd_with_one_command(self): adb_cmd = adb.AdbProxy()._construct_adb_cmd( - 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=False) + 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=False + ) self.assertEqual(adb_cmd, ['adb', 'shell ls /asdafsfd/asdf-asfd/asa']) def test_construct_adb_cmd_with_one_arg_command(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - 'ls /asdafsfd/asdf-asfd/asa', - shell=False) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', 'ls /asdafsfd/asdf-asfd/asa', shell=False + ) self.assertEqual(adb_cmd, ['adb', 'shell', 'ls /asdafsfd/asdf-asfd/asa']) def test_construct_adb_cmd_with_one_arg_command_list(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - ['ls /asdafsfd/asdf-asfd/asa'], - shell=False) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['ls /asdafsfd/asdf-asfd/asa'], shell=False + ) self.assertEqual(adb_cmd, ['adb', 'shell', 'ls /asdafsfd/asdf-asfd/asa']) def test_construct_adb_cmd_with_special_characters(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - ['a b', '"blah"', r'\/\/'], - shell=False) - self.assertEqual(adb_cmd, ['adb', 'shell', 'a b', '"blah"', r"\/\/"]) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['a b', '"blah"', r'\/\/'], shell=False + ) + self.assertEqual(adb_cmd, ['adb', 'shell', 'a b', '"blah"', r'\/\/']) def test_construct_adb_cmd_with_serial(self): - adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', - 'arg1', - shell=False) + adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd( + 'shell', 'arg1', shell=False + ) self.assertEqual(adb_cmd, ['adb', '-s', '12345', 'shell', 'arg1']) def test_construct_adb_cmd_with_list(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', ['arg1', 'arg2'], - shell=False) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['arg1', 'arg2'], shell=False + ) self.assertEqual(adb_cmd, ['adb', 'shell', 'arg1', 'arg2']) def test_construct_adb_cmd_with_serial_with_list(self): - adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', - ['arg1', 'arg2'], - shell=False) + adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd( + 'shell', ['arg1', 'arg2'], shell=False + ) self.assertEqual(adb_cmd, ['adb', '-s', '12345', 'shell', 'arg1', 'arg2']) def test_construct_adb_cmd_with_shell_true(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - 'arg1 arg2', - shell=True) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', 'arg1 arg2', shell=True + ) self.assertEqual(adb_cmd, '"adb" shell arg1 arg2') def test_construct_adb_cmd_with_shell_true_with_one_command(self): adb_cmd = adb.AdbProxy()._construct_adb_cmd( - 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=True) + 'shell ls /asdafsfd/asdf-asfd/asa', [], shell=True + ) self.assertEqual(adb_cmd, '"adb" shell ls /asdafsfd/asdf-asfd/asa ') def test_construct_adb_cmd_with_shell_true_with_one_arg_command(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - 'ls /asdafsfd/asdf-asfd/asa', - shell=True) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', 'ls /asdafsfd/asdf-asfd/asa', shell=True + ) self.assertEqual(adb_cmd, '"adb" shell ls /asdafsfd/asdf-asfd/asa') def test_construct_adb_cmd_with_shell_true_with_one_arg_command_list(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - ['ls /asdafsfd/asdf-asfd/asa'], - shell=True) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['ls /asdafsfd/asdf-asfd/asa'], shell=True + ) self.assertEqual(adb_cmd, '"adb" shell \'ls /asdafsfd/asdf-asfd/asa\'') def test_construct_adb_cmd_with_shell_true_with_auto_quotes(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', - ['a b', '"blah"', r'\/\/'], - shell=True) - self.assertEqual(adb_cmd, '"adb" shell \'a b\' \'"blah"\' \'\\/\\/\'') + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['a b', '"blah"', r'\/\/'], shell=True + ) + self.assertEqual(adb_cmd, "\"adb\" shell 'a b' '\"blah\"' '\\/\\/'") def test_construct_adb_cmd_with_shell_true_with_serial(self): - adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', - 'arg1 arg2', - shell=True) + adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd( + 'shell', 'arg1 arg2', shell=True + ) self.assertEqual(adb_cmd, '"adb" -s "12345" shell arg1 arg2') def test_construct_adb_cmd_with_shell_true_with_list(self): - adb_cmd = adb.AdbProxy()._construct_adb_cmd('shell', ['arg1', 'arg2'], - shell=True) + adb_cmd = adb.AdbProxy()._construct_adb_cmd( + 'shell', ['arg1', 'arg2'], shell=True + ) self.assertEqual(adb_cmd, '"adb" shell arg1 arg2') def test_construct_adb_cmd_with_shell_true_with_serial_with_list(self): - adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd('shell', - ['arg1', 'arg2'], - shell=True) + adb_cmd = adb.AdbProxy('12345')._construct_adb_cmd( + 'shell', ['arg1', 'arg2'], shell=True + ) self.assertEqual(adb_cmd, '"adb" -s "12345" shell arg1 arg2') def test_exec_adb_cmd(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT adb.AdbProxy().shell(['arg1', 'arg2']) - mock_exec_cmd.assert_called_once_with(['adb', 'shell', 'arg1', 'arg2'], - shell=False, - timeout=None, - stderr=None) + mock_exec_cmd.assert_called_once_with( + ['adb', 'shell', 'arg1', 'arg2'], + shell=False, + timeout=None, + stderr=None, + ) def test_exec_adb_cmd_with_shell_true(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT adb.AdbProxy().shell('arg1 arg2', shell=True) - mock_exec_cmd.assert_called_once_with('"adb" shell arg1 arg2', - shell=True, - timeout=None, - stderr=None) + mock_exec_cmd.assert_called_once_with( + '"adb" shell arg1 arg2', shell=True, timeout=None, stderr=None + ) def test_exec_adb_cmd_formats_command(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: - with mock.patch.object(adb.AdbProxy, - '_construct_adb_cmd') as mock_construct_adb_cmd: + with mock.patch.object( + adb.AdbProxy, '_construct_adb_cmd' + ) as mock_construct_adb_cmd: mock_adb_cmd = mock.MagicMock() mock_adb_args = mock.MagicMock() mock_construct_adb_cmd.return_value = mock_adb_cmd mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT adb.AdbProxy().shell(mock_adb_args) - mock_construct_adb_cmd.assert_called_once_with('shell', - mock_adb_args, - shell=False) - mock_exec_cmd.assert_called_once_with(mock_adb_cmd, - shell=False, - timeout=None, - stderr=None) + mock_construct_adb_cmd.assert_called_once_with( + 'shell', mock_adb_args, shell=False + ) + mock_exec_cmd.assert_called_once_with( + mock_adb_cmd, shell=False, timeout=None, stderr=None + ) def test_exec_adb_cmd_formats_command_with_shell_true(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: - with mock.patch.object(adb.AdbProxy, - '_construct_adb_cmd') as mock_construct_adb_cmd: + with mock.patch.object( + adb.AdbProxy, '_construct_adb_cmd' + ) as mock_construct_adb_cmd: mock_adb_cmd = mock.MagicMock() mock_adb_args = mock.MagicMock() mock_construct_adb_cmd.return_value = mock_adb_cmd adb.AdbProxy().shell(mock_adb_args, shell=True) - mock_construct_adb_cmd.assert_called_once_with('shell', - mock_adb_args, - shell=True) - mock_exec_cmd.assert_called_once_with(mock_adb_cmd, - shell=True, - timeout=None, - stderr=None) + mock_construct_adb_cmd.assert_called_once_with( + 'shell', mock_adb_args, shell=True + ) + mock_exec_cmd.assert_called_once_with( + mock_adb_cmd, shell=True, timeout=None, stderr=None + ) def test_execute_adb_and_process_stdout_formats_command(self): with mock.patch.object( - adb.AdbProxy, - '_execute_and_process_stdout') as mock_execute_and_process_stdout: - with mock.patch.object(adb.AdbProxy, - '_construct_adb_cmd') as mock_construct_adb_cmd: + adb.AdbProxy, '_execute_and_process_stdout' + ) as mock_execute_and_process_stdout: + with mock.patch.object( + adb.AdbProxy, '_construct_adb_cmd' + ) as mock_construct_adb_cmd: mock_adb_cmd = mock.MagicMock() mock_adb_args = mock.MagicMock() mock_handler = mock.MagicMock() mock_construct_adb_cmd.return_value = mock_adb_cmd - adb.AdbProxy()._execute_adb_and_process_stdout('shell', - mock_adb_args, - shell=False, - handler=mock_handler) - mock_construct_adb_cmd.assert_called_once_with('shell', - mock_adb_args, - shell=False) + adb.AdbProxy()._execute_adb_and_process_stdout( + 'shell', mock_adb_args, shell=False, handler=mock_handler + ) + mock_construct_adb_cmd.assert_called_once_with( + 'shell', mock_adb_args, shell=False + ) mock_execute_and_process_stdout.assert_called_once_with( - mock_adb_cmd, shell=False, handler=mock_handler) + mock_adb_cmd, shell=False, handler=mock_handler + ) @mock.patch('mobly.utils.run_command') def test_exec_adb_cmd_with_stderr_pipe(self, mock_run_command): - mock_run_command.return_value = (0, MOCK_DEFAULT_STDOUT.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + mock_run_command.return_value = ( + 0, + MOCK_DEFAULT_STDOUT.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) stderr_redirect = io.BytesIO() out = adb.AdbProxy().shell('arg1 arg2', shell=True, stderr=stderr_redirect) self.assertEqual(MOCK_DEFAULT_STDOUT, out.decode('utf-8')) - self.assertEqual(MOCK_DEFAULT_STDERR, - stderr_redirect.getvalue().decode('utf-8')) + self.assertEqual( + MOCK_DEFAULT_STDERR, stderr_redirect.getvalue().decode('utf-8') + ) @mock.patch('mobly.utils.run_command') def test_connect_success(self, mock_run_command): mock_address = 'localhost:1234' mock_run_command.return_value = ( - 0, f'connected to {mock_address}'.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + 0, + f'connected to {mock_address}'.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) out = adb.AdbProxy().connect(mock_address) self.assertEqual('connected to localhost:1234', out.decode('utf-8')) @@ -479,8 +530,10 @@ def test_connect_success(self, mock_run_command): def test_connect_already_connected(self, mock_run_command): mock_address = 'localhost:1234' mock_run_command.return_value = ( - 0, f'already connected to {mock_address}'.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + 0, + f'already connected to {mock_address}'.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) out = adb.AdbProxy().connect(mock_address) self.assertEqual('already connected to localhost:1234', out.decode('utf-8')) @@ -488,11 +541,15 @@ def test_connect_already_connected(self, mock_run_command): @mock.patch('mobly.utils.run_command') def test_connect_fail(self, mock_run_command): mock_address = 'localhost:1234' - mock_run_command.return_value = (0, 'Connection refused\n'.encode('utf-8'), - MOCK_DEFAULT_STDERR.encode('utf-8')) + mock_run_command.return_value = ( + 0, + 'Connection refused\n'.encode('utf-8'), + MOCK_DEFAULT_STDERR.encode('utf-8'), + ) with self.assertRaisesRegex( - adb.AdbError, 'Error executing adb cmd "connect localhost:1234".'): + adb.AdbError, 'Error executing adb cmd "connect localhost:1234".' + ): out = adb.AdbProxy().connect(mock_address) def test_getprop(self): @@ -503,18 +560,22 @@ def test_getprop(self): ['adb', 'shell', 'getprop', 'haha'], shell=False, stderr=None, - timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) + timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC, + ) def test_getprop_custom_timeout(self): timeout_s = adb.DEFAULT_GETPROP_TIMEOUT_SEC * 2 with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.return_value = b'blah' - self.assertEqual(adb.AdbProxy().getprop('haha', timeout=timeout_s), - 'blah') - mock_exec_cmd.assert_called_once_with(['adb', 'shell', 'getprop', 'haha'], - shell=False, - stderr=None, - timeout=timeout_s) + self.assertEqual( + adb.AdbProxy().getprop('haha', timeout=timeout_s), 'blah' + ) + mock_exec_cmd.assert_called_once_with( + ['adb', 'shell', 'getprop', 'haha'], + shell=False, + stderr=None, + timeout=timeout_s, + ) def test__parse_getprop_output_special_values(self): mock_adb_output = ( @@ -530,9 +591,10 @@ def test__parse_getprop_output_special_values(self): ) parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) expected_output = { - 'persist.sys.boot.reason.history': - ('reboot,adb,1558549857\nreboot,factory_reset,1558483886\n' - 'reboot,1558483823'), + 'persist.sys.boot.reason.history': ( + 'reboot,adb,1558549857\nreboot,factory_reset,1558483886\n' + 'reboot,1558483823' + ), 'selinux.abc': 'key: value', 'persist.something': 'haha\n', 'selinux.restorecon_recursive': '/data/misc_ce/10', @@ -542,26 +604,28 @@ def test__parse_getprop_output_special_values(self): self.assertEqual(parsed_props, expected_output) def test__parse_getprop_output_malformat_output(self): - mock_adb_output = ( - b'[selinux.restorecon_recursive][/data/misc_ce/10]\n' # Malformat + mock_adb_output = ( # Malformat + b'[selinux.restorecon_recursive][/data/misc_ce/10]\n' b'[persist.sys.boot.reason]: [reboot,adb,1558549857]\n' - b'[persist.something]: [haha]\n') + b'[persist.something]: [haha]\n' + ) parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) expected_output = { 'persist.sys.boot.reason': 'reboot,adb,1558549857', - 'persist.something': 'haha' + 'persist.something': 'haha', } self.assertEqual(parsed_props, expected_output) def test__parse_getprop_output_special_line_separator(self): - mock_adb_output = ( - b'[selinux.restorecon_recursive][/data/misc_ce/10]\r\n' # Malformat + mock_adb_output = ( # Malformat + b'[selinux.restorecon_recursive][/data/misc_ce/10]\r\n' b'[persist.sys.boot.reason]: [reboot,adb,1558549857]\r\n' - b'[persist.something]: [haha]\r\n') + b'[persist.something]: [haha]\r\n' + ) parsed_props = adb.AdbProxy()._parse_getprop_output(mock_adb_output) expected_output = { 'persist.sys.boot.reason': 'reboot,adb,1558549857', - 'persist.something': 'haha' + 'persist.something': 'haha', } self.assertEqual(parsed_props, expected_output) @@ -572,42 +636,51 @@ def test_getprops(self, mock_sleep): b'\n[sendbug.preferred.domain]: [google.com]\n' b'[sys.uidcpupower]: []\n' b'[sys.wifitracing.started]: [1]\n' - b'[telephony.lteOnCdmaDevice]: [1]\n\n') + b'[telephony.lteOnCdmaDevice]: [1]\n\n' + ) actual_output = adb.AdbProxy().getprops([ 'sys.wifitracing.started', # "numeric" value 'sys.uidcpupower', # empty value 'sendbug.preferred.domain', # string value - 'nonExistentProp' + 'nonExistentProp', ]) self.assertEqual( - actual_output, { + actual_output, + { 'sys.wifitracing.started': '1', 'sys.uidcpupower': '', - 'sendbug.preferred.domain': 'google.com' - }) + 'sendbug.preferred.domain': 'google.com', + }, + ) mock_exec_cmd.assert_called_once_with( ['adb', 'shell', 'getprop'], shell=False, stderr=None, - timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) + timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC, + ) mock_sleep.assert_not_called() @mock.patch('time.sleep', return_value=mock.MagicMock()) def test_getprops_when_empty_string_randomly_returned(self, mock_sleep): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.side_effect = [ - b'', (b'\n[ro.build.id]: [AB42]\n' - b'[ro.build.type]: [userdebug]\n\n') + b'', + b'\n[ro.build.id]: [AB42]\n[ro.build.type]: [userdebug]\n\n', ] actual_output = adb.AdbProxy().getprops(['ro.build.id']) - self.assertEqual(actual_output, { - 'ro.build.id': 'AB42', - }) + self.assertEqual( + actual_output, + { + 'ro.build.id': 'AB42', + }, + ) self.assertEqual(mock_exec_cmd.call_count, 2) - mock_exec_cmd.assert_called_with(['adb', 'shell', 'getprop'], - shell=False, - stderr=None, - timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) + mock_exec_cmd.assert_called_with( + ['adb', 'shell', 'getprop'], + shell=False, + stderr=None, + timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC, + ) self.assertEqual(mock_sleep.call_count, 1) mock_sleep.assert_called_with(1) @@ -618,10 +691,12 @@ def test_getprops_when_empty_string_always_returned(self, mock_sleep): actual_output = adb.AdbProxy().getprops(['ro.build.id']) self.assertEqual(actual_output, {}) self.assertEqual(mock_exec_cmd.call_count, 3) - mock_exec_cmd.assert_called_with(['adb', 'shell', 'getprop'], - shell=False, - stderr=None, - timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC) + mock_exec_cmd.assert_called_with( + ['adb', 'shell', 'getprop'], + shell=False, + stderr=None, + timeout=adb.DEFAULT_GETPROP_TIMEOUT_SEC, + ) self.assertEqual(mock_sleep.call_count, 2) mock_sleep.assert_called_with(1) @@ -639,7 +714,8 @@ def test_instrument_without_parameters(self): ['adb', 'shell', MOCK_BASIC_INSTRUMENTATION_COMMAND], shell=False, timeout=None, - stderr=None) + stderr=None, + ) self.assertEqual(output, mock_exec_cmd.return_value) def test_instrument_with_runner(self): @@ -647,13 +723,15 @@ def test_instrument_with_runner(self): with a runner specified. """ with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: - stdout = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, - runner=MOCK_INSTRUMENTATION_RUNNER) + stdout = adb.AdbProxy().instrument( + MOCK_INSTRUMENTATION_PACKAGE, runner=MOCK_INSTRUMENTATION_RUNNER + ) mock_exec_cmd.assert_called_once_with( ['adb', 'shell', MOCK_RUNNER_INSTRUMENTATION_COMMAND], shell=False, timeout=None, - stderr=None) + stderr=None, + ) self.assertEqual(stdout, mock_exec_cmd.return_value) def test_instrument_with_options(self): @@ -661,13 +739,15 @@ def test_instrument_with_options(self): with options. """ with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: - stdout = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, - options=MOCK_INSTRUMENTATION_OPTIONS) + stdout = adb.AdbProxy().instrument( + MOCK_INSTRUMENTATION_PACKAGE, options=MOCK_INSTRUMENTATION_OPTIONS + ) mock_exec_cmd.assert_called_once_with( ['adb', 'shell', MOCK_OPTIONS_INSTRUMENTATION_COMMAND], shell=False, timeout=None, - stderr=None) + stderr=None, + ) self.assertEqual(stdout, mock_exec_cmd.return_value) def test_instrument_with_handler(self): @@ -679,14 +759,16 @@ def mock_handler(raw_line): pass with mock.patch.object( - adb.AdbProxy, - '_execute_and_process_stdout') as mock_execute_and_process_stdout: - stderr = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, - handler=mock_handler) + adb.AdbProxy, '_execute_and_process_stdout' + ) as mock_execute_and_process_stdout: + stderr = adb.AdbProxy().instrument( + MOCK_INSTRUMENTATION_PACKAGE, handler=mock_handler + ) mock_execute_and_process_stdout.assert_called_once_with( ['adb', 'shell', MOCK_BASIC_INSTRUMENTATION_COMMAND], shell=False, - handler=mock_handler) + handler=mock_handler, + ) self.assertEqual(stderr, mock_execute_and_process_stdout.return_value) def test_instrument_with_handler_with_runner(self): @@ -698,15 +780,18 @@ def mock_handler(raw_line): pass with mock.patch.object( - adb.AdbProxy, - '_execute_and_process_stdout') as mock_execute_and_process_stdout: - stderr = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, - runner=MOCK_INSTRUMENTATION_RUNNER, - handler=mock_handler) + adb.AdbProxy, '_execute_and_process_stdout' + ) as mock_execute_and_process_stdout: + stderr = adb.AdbProxy().instrument( + MOCK_INSTRUMENTATION_PACKAGE, + runner=MOCK_INSTRUMENTATION_RUNNER, + handler=mock_handler, + ) mock_execute_and_process_stdout.assert_called_once_with( ['adb', 'shell', MOCK_RUNNER_INSTRUMENTATION_COMMAND], shell=False, - handler=mock_handler) + handler=mock_handler, + ) self.assertEqual(stderr, mock_execute_and_process_stdout.return_value) def test_instrument_with_handler_with_options(self): @@ -718,25 +803,27 @@ def mock_handler(raw_line): pass with mock.patch.object( - adb.AdbProxy, - '_execute_and_process_stdout') as mock_execute_and_process_stdout: - stderr = adb.AdbProxy().instrument(MOCK_INSTRUMENTATION_PACKAGE, - options=MOCK_INSTRUMENTATION_OPTIONS, - handler=mock_handler) + adb.AdbProxy, '_execute_and_process_stdout' + ) as mock_execute_and_process_stdout: + stderr = adb.AdbProxy().instrument( + MOCK_INSTRUMENTATION_PACKAGE, + options=MOCK_INSTRUMENTATION_OPTIONS, + handler=mock_handler, + ) mock_execute_and_process_stdout.assert_called_once_with( ['adb', 'shell', MOCK_OPTIONS_INSTRUMENTATION_COMMAND], shell=False, - handler=mock_handler) + handler=mock_handler, + ) self.assertEqual(stderr, mock_execute_and_process_stdout.return_value) @mock.patch.object(adb.AdbProxy, '_exec_cmd') def test_root_success(self, mock_exec_cmd): mock_exec_cmd.return_value = MOCK_ROOT_SUCCESS_OUTPUT output = adb.AdbProxy().root() - mock_exec_cmd.assert_called_once_with(['adb', 'root'], - shell=False, - timeout=None, - stderr=None) + mock_exec_cmd.assert_called_once_with( + ['adb', 'root'], shell=False, timeout=None, stderr=None + ) self.assertEqual(output, MOCK_ROOT_SUCCESS_OUTPUT) @mock.patch('time.sleep', return_value=mock.MagicMock()) @@ -744,13 +831,12 @@ def test_root_success(self, mock_exec_cmd): def test_root_success_with_retry(self, mock_exec_cmd, mock_sleep): mock_exec_cmd.side_effect = [ adb.AdbError('adb root', '', MOCK_ROOT_ERROR_OUTPUT, 1), - MOCK_ROOT_SUCCESS_OUTPUT + MOCK_ROOT_SUCCESS_OUTPUT, ] output = adb.AdbProxy().root() - mock_exec_cmd.assert_called_with(['adb', 'root'], - shell=False, - timeout=None, - stderr=None) + mock_exec_cmd.assert_called_with( + ['adb', 'root'], shell=False, timeout=None, stderr=None + ) self.assertEqual(output, MOCK_ROOT_SUCCESS_OUTPUT) self.assertEqual(mock_sleep.call_count, 1) mock_sleep.assert_called_with(10) @@ -758,17 +844,20 @@ def test_root_success_with_retry(self, mock_exec_cmd, mock_sleep): @mock.patch('time.sleep', return_value=mock.MagicMock()) @mock.patch.object(adb.AdbProxy, '_exec_cmd') def test_root_raises_adb_error_when_all_retries_failed( - self, mock_exec_cmd, mock_sleep): - mock_exec_cmd.side_effect = adb.AdbError('adb root', '', - MOCK_ROOT_ERROR_OUTPUT, 1) - expected_msg = ('Error executing adb cmd "adb root". ' - 'ret: 1, stdout: , stderr: %s' % MOCK_ROOT_ERROR_OUTPUT) + self, mock_exec_cmd, mock_sleep + ): + mock_exec_cmd.side_effect = adb.AdbError( + 'adb root', '', MOCK_ROOT_ERROR_OUTPUT, 1 + ) + expected_msg = ( + 'Error executing adb cmd "adb root". ret: 1, stdout: , stderr: %s' + % MOCK_ROOT_ERROR_OUTPUT + ) with self.assertRaisesRegex(adb.AdbError, expected_msg): adb.AdbProxy().root() - mock_exec_cmd.assert_called_with(['adb', 'root'], - shell=False, - timeout=None, - stderr=None) + mock_exec_cmd.assert_called_with( + ['adb', 'root'], shell=False, timeout=None, stderr=None + ) self.assertEqual(mock_sleep.call_count, adb.ADB_ROOT_RETRY_ATTEMPTS - 1) mock_sleep.assert_has_calls([mock.call(10), mock.call(20)]) @@ -780,7 +869,8 @@ def test_has_shell_command_called_correctly(self): ['adb', 'shell', 'command', '-v', MOCK_SHELL_COMMAND], shell=False, timeout=None, - stderr=None) + stderr=None, + ) def test_has_shell_command_with_existing_command(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: @@ -790,15 +880,17 @@ def test_has_shell_command_with_existing_command(self): def test_has_shell_command_with_missing_command_on_older_devices(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT - mock_exec_cmd.side_effect = adb.AdbError(MOCK_ADB_SHELL_COMMAND_CHECK, '', - '', 0) + mock_exec_cmd.side_effect = adb.AdbError( + MOCK_ADB_SHELL_COMMAND_CHECK, '', '', 0 + ) self.assertFalse(adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND)) def test_has_shell_command_with_missing_command_on_newer_devices(self): with mock.patch.object(adb.AdbProxy, '_exec_cmd') as mock_exec_cmd: mock_exec_cmd.return_value = MOCK_DEFAULT_COMMAND_OUTPUT - mock_exec_cmd.side_effect = adb.AdbError(MOCK_ADB_SHELL_COMMAND_CHECK, '', - '', 1) + mock_exec_cmd.side_effect = adb.AdbError( + MOCK_ADB_SHELL_COMMAND_CHECK, '', '', 1 + ) self.assertFalse(adb.AdbProxy().has_shell_command(MOCK_SHELL_COMMAND)) @mock.patch.object(adb.AdbProxy, 'getprop') @@ -811,25 +903,30 @@ def test_current_user_id_25_and_above(self, mock_exec_cmd, mock_getprop): ['adb', 'shell', 'am', 'get-current-user'], shell=False, stderr=None, - timeout=None) + timeout=None, + ) self.assertEqual(user_id, 123) @mock.patch.object(adb.AdbProxy, 'getprop') @mock.patch.object(adb.AdbProxy, '_exec_cmd') def test_current_user_id_between_21_and_24(self, mock_exec_cmd, mock_getprop): mock_getprop.return_value = b'23' - mock_exec_cmd.return_value = (b'Users:\n' - b'UserInfo{123:Owner:13} serialNo=0\n' - b'Created: \n' - b'Last logged in: +1h22m12s497ms ago\n' - b'UserInfo{456:Owner:14} serialNo=0\n' - b'Created: \n' - b'Last logged in: +1h01m12s497ms ago\n') + mock_exec_cmd.return_value = ( + b'Users:\n' + b'UserInfo{123:Owner:13} serialNo=0\n' + b'Created: \n' + b'Last logged in: +1h22m12s497ms ago\n' + b'UserInfo{456:Owner:14} serialNo=0\n' + b'Created: \n' + b'Last logged in: +1h01m12s497ms ago\n' + ) user_id = adb.AdbProxy().current_user_id - mock_exec_cmd.assert_called_once_with(['adb', 'shell', 'dumpsys', 'user'], - shell=False, - stderr=None, - timeout=None) + mock_exec_cmd.assert_called_once_with( + ['adb', 'shell', 'dumpsys', 'user'], + shell=False, + stderr=None, + timeout=None, + ) self.assertEqual(user_id, 123) diff --git a/tests/mobly/controllers/android_device_lib/callback_handler_test.py b/tests/mobly/controllers/android_device_lib/callback_handler_test.py index a30408f9..2f3398c5 100755 --- a/tests/mobly/controllers/android_device_lib/callback_handler_test.py +++ b/tests/mobly/controllers/android_device_lib/callback_handler_test.py @@ -18,7 +18,7 @@ from mobly.controllers.android_device_lib import callback_handler from mobly.controllers.android_device_lib import jsonrpc_client_base -MOCK_CALLBACK_ID = "1-0" +MOCK_CALLBACK_ID = '1-0' MOCK_RAW_EVENT = { 'callbackId': '2-1', 'name': 'AsyncTaskResult', @@ -26,26 +26,28 @@ 'data': { 'exampleData': "Here's a simple event.", 'successful': True, - 'secretNumber': 12 - } + 'secretNumber': 12, + }, } class CallbackHandlerTest(unittest.TestCase): - """Unit tests for mobly.controllers.android_device_lib.callback_handler. - """ + """Unit tests for mobly.controllers.android_device_lib.callback_handler.""" def test_timeout_value(self): - self.assertGreaterEqual(jsonrpc_client_base._SOCKET_READ_TIMEOUT, - callback_handler.MAX_TIMEOUT) + self.assertGreaterEqual( + jsonrpc_client_base._SOCKET_READ_TIMEOUT, callback_handler.MAX_TIMEOUT + ) def test_callback_id_property(self): mock_event_client = mock.Mock() - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) self.assertEqual(handler.callback_id, MOCK_CALLBACK_ID) with self.assertRaises(AttributeError): handler.callback_id = 'ha' @@ -53,11 +55,13 @@ def test_callback_id_property(self): def test_event_dict_to_snippet_event(self): mock_event_client = mock.Mock() mock_event_client.eventWaitAndGet = mock.Mock(return_value=MOCK_RAW_EVENT) - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) event = handler.waitAndGet('ha') self.assertEqual(event.name, MOCK_RAW_EVENT['name']) self.assertEqual(event.creation_time, MOCK_RAW_EVENT['time']) @@ -66,15 +70,20 @@ def test_event_dict_to_snippet_event(self): def test_wait_and_get_timeout(self): mock_event_client = mock.Mock() - java_timeout_msg = ('com.google.android.mobly.snippet.event.' - 'EventSnippet$EventSnippetException: timeout.') + java_timeout_msg = ( + 'com.google.android.mobly.snippet.event.' + 'EventSnippet$EventSnippetException: timeout.' + ) mock_event_client.eventWaitAndGet = mock.Mock( - side_effect=jsonrpc_client_base.ApiError(mock.Mock(), java_timeout_msg)) - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + side_effect=jsonrpc_client_base.ApiError(mock.Mock(), java_timeout_msg) + ) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) expected_msg = 'Timed out after waiting .*s for event "ha" .*' with self.assertRaisesRegex(callback_handler.TimeoutError, expected_msg): handler.waitAndGet('ha') @@ -82,11 +91,13 @@ def test_wait_and_get_timeout(self): def test_wait_for_event(self): mock_event_client = mock.Mock() mock_event_client.eventWaitAndGet = mock.Mock(return_value=MOCK_RAW_EVENT) - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) def some_condition(event): return event.data['successful'] @@ -96,14 +107,17 @@ def some_condition(event): def test_wait_for_event_negative(self): mock_event_client = mock.Mock() mock_event_client.eventWaitAndGet = mock.Mock(return_value=MOCK_RAW_EVENT) - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) expected_msg = ( 'Timed out after 0.01s waiting for an "AsyncTaskResult" event that' - ' satisfies the predicate "some_condition".') + ' satisfies the predicate "some_condition".' + ) def some_condition(event): return False @@ -112,25 +126,26 @@ def some_condition(event): handler.waitForEvent('AsyncTaskResult', some_condition, 0.01) def test_wait_for_event_max_timeout(self): - """waitForEvent should not raise the timeout exceed threshold error. - """ + """waitForEvent should not raise the timeout exceed threshold error.""" mock_event_client = mock.Mock() mock_event_client.eventWaitAndGet = mock.Mock(return_value=MOCK_RAW_EVENT) - handler = callback_handler.CallbackHandler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client, - ret_value=None, - method_name=None, - ad=mock.Mock()) + handler = callback_handler.CallbackHandler( + callback_id=MOCK_CALLBACK_ID, + event_client=mock_event_client, + ret_value=None, + method_name=None, + ad=mock.Mock(), + ) def some_condition(event): return event.data['successful'] big_timeout = callback_handler.MAX_TIMEOUT * 2 # This line should not raise. - event = handler.waitForEvent('AsyncTaskResult', - some_condition, - timeout=big_timeout) + event = handler.waitForEvent( + 'AsyncTaskResult', some_condition, timeout=big_timeout + ) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/controllers/android_device_lib/callback_handler_v2_test.py b/tests/mobly/controllers/android_device_lib/callback_handler_v2_test.py index b598cae7..a7b8e9f5 100644 --- a/tests/mobly/controllers/android_device_lib/callback_handler_v2_test.py +++ b/tests/mobly/controllers/android_device_lib/callback_handler_v2_test.py @@ -28,22 +28,24 @@ 'data': { 'exampleData': "Here's a simple event.", 'successful': True, - 'secretNumber': 12 - } + 'secretNumber': 12, + }, } class CallbackHandlerV2Test(unittest.TestCase): """Unit tests for callback_handler_v2.CallbackHandlerV2.""" - def _make_callback_handler(self, - callback_id=None, - event_client=None, - ret_value=None, - method_name=None, - device=None, - rpc_max_timeout_sec=600, - default_timeout_sec=120): + def _make_callback_handler( + self, + callback_id=None, + event_client=None, + ret_value=None, + method_name=None, + device=None, + rpc_max_timeout_sec=600, + default_timeout_sec=120, + ): return callback_handler_v2.CallbackHandlerV2( callback_id=callback_id, event_client=event_client, @@ -51,7 +53,8 @@ def _make_callback_handler(self, method_name=method_name, device=device, rpc_max_timeout_sec=rpc_max_timeout_sec, - default_timeout_sec=default_timeout_sec) + default_timeout_sec=default_timeout_sec, + ) def assert_event_correct(self, actual_event, expected_raw_event_dict): expected_event = callback_event.from_dict(expected_raw_event_dict) @@ -60,12 +63,14 @@ def assert_event_correct(self, actual_event, expected_raw_event_dict): def test_wait_and_get(self): mock_event_client = mock.Mock() mock_event_client.eventWaitAndGet = mock.Mock(return_value=MOCK_RAW_EVENT) - handler = self._make_callback_handler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client) + handler = self._make_callback_handler( + callback_id=MOCK_CALLBACK_ID, event_client=mock_event_client + ) event = handler.waitAndGet('ha') self.assert_event_correct(event, MOCK_RAW_EVENT) mock_event_client.eventWaitAndGet.assert_called_once_with( - MOCK_CALLBACK_ID, 'ha', mock.ANY) + MOCK_CALLBACK_ID, 'ha', mock.ANY + ) def test_wait_and_get_timeout_arg_transform(self): mock_event_client = mock.Mock() @@ -76,12 +81,14 @@ def test_wait_and_get_timeout_arg_transform(self): expected_rpc_timeout_ms = 10000 _ = handler.waitAndGet('ha', timeout=wait_and_get_timeout_sec) mock_event_client.eventWaitAndGet.assert_called_once_with( - mock.ANY, mock.ANY, expected_rpc_timeout_ms) + mock.ANY, mock.ANY, expected_rpc_timeout_ms + ) def test_wait_for_event(self): mock_event_client = mock.Mock() - handler = self._make_callback_handler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client) + handler = self._make_callback_handler( + callback_id=MOCK_CALLBACK_ID, event_client=mock_event_client + ) event_should_ignore = { 'callbackId': '2-1', @@ -89,10 +96,11 @@ def test_wait_for_event(self): 'time': 20460228696, 'data': { 'successful': False, - } + }, } mock_event_client.eventWaitAndGet.side_effect = [ - event_should_ignore, MOCK_RAW_EVENT + event_should_ignore, + MOCK_RAW_EVENT, ] def some_condition(event): @@ -107,11 +115,13 @@ def some_condition(event): def test_get_all(self): mock_event_client = mock.Mock() - handler = self._make_callback_handler(callback_id=MOCK_CALLBACK_ID, - event_client=mock_event_client) + handler = self._make_callback_handler( + callback_id=MOCK_CALLBACK_ID, event_client=mock_event_client + ) mock_event_client.eventGetAll = mock.Mock( - return_value=[MOCK_RAW_EVENT, MOCK_RAW_EVENT]) + return_value=[MOCK_RAW_EVENT, MOCK_RAW_EVENT] + ) all_events = handler.getAll('ha') self.assertEqual(len(all_events), 2) @@ -119,29 +129,36 @@ def test_get_all(self): self.assert_event_correct(event, MOCK_RAW_EVENT) mock_event_client.eventGetAll.assert_called_once_with( - MOCK_CALLBACK_ID, 'ha') + MOCK_CALLBACK_ID, 'ha' + ) def test_wait_and_get_timeout_message_pattern_matches(self): mock_event_client = mock.Mock() android_snippet_timeout_msg = ( 'com.google.android.mobly.snippet.event.EventSnippet$' - 'EventSnippetException: timeout.') + 'EventSnippetException: timeout.' + ) mock_event_client.eventWaitAndGet = mock.Mock( - side_effect=errors.ApiError(mock.Mock(), android_snippet_timeout_msg)) - handler = self._make_callback_handler(event_client=mock_event_client, - method_name='test_method') - - expected_msg = ('Timed out after waiting .*s for event "ha" triggered by ' - 'test_method .*') - with self.assertRaisesRegex(errors.CallbackHandlerTimeoutError, - expected_msg): + side_effect=errors.ApiError(mock.Mock(), android_snippet_timeout_msg) + ) + handler = self._make_callback_handler( + event_client=mock_event_client, method_name='test_method' + ) + + expected_msg = ( + 'Timed out after waiting .*s for event "ha" triggered by test_method .*' + ) + with self.assertRaisesRegex( + errors.CallbackHandlerTimeoutError, expected_msg + ): handler.waitAndGet('ha') def test_wait_and_get_reraise_if_pattern_not_match(self): mock_event_client = mock.Mock() snippet_timeout_msg = 'Snippet executed with error.' mock_event_client.eventWaitAndGet = mock.Mock( - side_effect=errors.ApiError(mock.Mock(), snippet_timeout_msg)) + side_effect=errors.ApiError(mock.Mock(), snippet_timeout_msg) + ) handler = self._make_callback_handler(event_client=mock_event_client) with self.assertRaisesRegex(errors.ApiError, snippet_timeout_msg): diff --git a/tests/mobly/controllers/android_device_lib/errors_test.py b/tests/mobly/controllers/android_device_lib/errors_test.py index 196aa03a..38a0ac15 100755 --- a/tests/mobly/controllers/android_device_lib/errors_test.py +++ b/tests/mobly/controllers/android_device_lib/errors_test.py @@ -31,19 +31,20 @@ def test_service_error(self): device = mock.MagicMock() device.__repr__ = lambda _: '[MockDevice]' exception = errors.ServiceError(device, 'Some error message.') - self.assertEqual(str(exception), - '[MockDevice]::Service Some error message.') + self.assertEqual( + str(exception), '[MockDevice]::Service Some error message.' + ) def test_subclass_service_error(self): - class Error(errors.ServiceError): SERVICE_TYPE = 'SomeType' device = mock.MagicMock() device.__repr__ = lambda _: '[MockDevice]' exception = Error(device, 'Some error message.') - self.assertEqual(str(exception), - '[MockDevice]::Service Some error message.') + self.assertEqual( + str(exception), '[MockDevice]::Service Some error message.' + ) if __name__ == '__main__': diff --git a/tests/mobly/controllers/android_device_lib/fastboot_test.py b/tests/mobly/controllers/android_device_lib/fastboot_test.py index 6e59dea2..86b697a9 100644 --- a/tests/mobly/controllers/android_device_lib/fastboot_test.py +++ b/tests/mobly/controllers/android_device_lib/fastboot_test.py @@ -24,19 +24,24 @@ class FastbootTest(unittest.TestCase): @mock.patch('mobly.controllers.android_device_lib.fastboot.Popen') @mock.patch('logging.debug') def test_fastboot_commands_and_results_are_logged_to_debug_log( - self, mock_debug_logger, mock_popen): + self, mock_debug_logger, mock_popen + ): expected_stdout = 'stdout' expected_stderr = b'stderr' mock_popen.return_value.communicate = mock.Mock( - return_value=(expected_stdout, expected_stderr)) + return_value=(expected_stdout, expected_stderr) + ) mock_popen.return_value.returncode = 123 fastboot.FastbootProxy().fake_command('extra', 'flags') mock_debug_logger.assert_called_with( 'cmd: %s, stdout: %s, stderr: %s, ret: %s', - '\'fastboot fake-command extra flags\'', expected_stdout, - expected_stderr, 123) + "'fastboot fake-command extra flags'", + expected_stdout, + expected_stderr, + 123, + ) if __name__ == '__main__': diff --git a/tests/mobly/controllers/android_device_lib/jsonrpc_client_base_test.py b/tests/mobly/controllers/android_device_lib/jsonrpc_client_base_test.py index 4cbeb35e..1861cc0f 100755 --- a/tests/mobly/controllers/android_device_lib/jsonrpc_client_base_test.py +++ b/tests/mobly/controllers/android_device_lib/jsonrpc_client_base_test.py @@ -28,8 +28,7 @@ def __init__(self): class JsonRpcClientBaseTest(jsonrpc_client_test_base.JsonRpcClientTestBase): - """Unit tests for mobly.controllers.android_device_lib.jsonrpc_client_base. - """ + """Unit tests for mobly.controllers.android_device_lib.jsonrpc_client_base.""" @mock.patch('socket.create_connection') def test_open_timeout_io_error(self, mock_create_connection): @@ -66,7 +65,8 @@ def test_handshake_error(self, mock_create_connection): client = FakeRpcClient() with self.assertRaisesRegex( jsonrpc_client_base.ProtocolError, - jsonrpc_client_base.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE): + jsonrpc_client_base.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE, + ): client.connect() def test_disconnect(self): @@ -124,8 +124,9 @@ def test_connect_handshake_unknown_status(self, mock_create_connection): Test that when the handshake is given an unknown status then the client will not be given a uid. """ - self.setup_mock_socket_file(mock_create_connection, - resp=self.MOCK_RESP_UNKNOWN_STATUS) + self.setup_mock_socket_file( + mock_create_connection, resp=self.MOCK_RESP_UNKNOWN_STATUS + ) client = FakeRpcClient() client.connect() self.assertEqual(client.uid, jsonrpc_client_base.UNKNOWN_UID) @@ -182,7 +183,8 @@ def test_rpc_id_mismatch(self, mock_create_connection): with self.assertRaisesRegex( jsonrpc_client_base.ProtocolError, - jsonrpc_client_base.ProtocolError.MISMATCHED_API_ID): + jsonrpc_client_base.ProtocolError.MISMATCHED_API_ID, + ): client.some_rpc(1, 2, 3) @mock.patch('socket.create_connection') @@ -201,7 +203,8 @@ def test_rpc_no_response(self, mock_create_connection): with self.assertRaisesRegex( jsonrpc_client_base.ProtocolError, - jsonrpc_client_base.ProtocolError.NO_RESPONSE_FROM_SERVER): + jsonrpc_client_base.ProtocolError.NO_RESPONSE_FROM_SERVER, + ): client.some_rpc(1, 2, 3) @mock.patch('socket.create_connection') @@ -232,7 +235,8 @@ def test_rpc_send_to_socket_without_callback(self, mock_create_connection): Logic is the same as test_rpc_send_to_socket. """ fake_file = self.setup_mock_socket_file( - mock_create_connection, resp=self.MOCK_RESP_WITHOUT_CALLBACK) + mock_create_connection, resp=self.MOCK_RESP_WITHOUT_CALLBACK + ) client = FakeRpcClient() client.connect() @@ -275,15 +279,17 @@ def test_rpc_verbose_logging_with_long_string(self, mock_create_connection): response = client._client_receive() self.assertEqual(response, testing_rpc_response) - client.log.debug.assert_called_with('Snippet received: %s', - testing_rpc_response) + client.log.debug.assert_called_with( + 'Snippet received: %s', testing_rpc_response + ) @mock.patch('socket.create_connection') def test_rpc_truncated_logging_short_response(self, mock_create_connection): """Test rpc response will full logged when length is short.""" fake_file = self.setup_mock_socket_file(mock_create_connection) testing_rpc_response = self.generate_rpc_response( - int(jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH / 2)) + int(jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH / 2) + ) fake_file.resp = testing_rpc_response client = FakeRpcClient() @@ -293,17 +299,19 @@ def test_rpc_truncated_logging_short_response(self, mock_create_connection): response = client._client_receive() self.assertEqual(response, testing_rpc_response) - client.log.debug.assert_called_with('Snippet received: %s', - testing_rpc_response) + client.log.debug.assert_called_with( + 'Snippet received: %s', testing_rpc_response + ) @mock.patch('socket.create_connection') - def test_rpc_truncated_logging_fit_size_response(self, - mock_create_connection): - """Test rpc response will full logged when length is equal to threshold. - """ + def test_rpc_truncated_logging_fit_size_response( + self, mock_create_connection + ): + """Test rpc response will full logged when length is equal to threshold.""" fake_file = self.setup_mock_socket_file(mock_create_connection) testing_rpc_response = self.generate_rpc_response( - jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH) + jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH + ) fake_file.resp = testing_rpc_response client = FakeRpcClient() @@ -313,8 +321,9 @@ def test_rpc_truncated_logging_fit_size_response(self, response = client._client_receive() self.assertEqual(response, testing_rpc_response) - client.log.debug.assert_called_with('Snippet received: %s', - testing_rpc_response) + client.log.debug.assert_called_with( + 'Snippet received: %s', testing_rpc_response + ) @mock.patch('socket.create_connection') def test_rpc_truncated_logging_long_response(self, mock_create_connection): @@ -334,8 +343,11 @@ def test_rpc_truncated_logging_long_response(self, mock_create_connection): # DEBUG level log should truncated by given length. client.log.debug.assert_called_with( 'Snippet received: %s... %d chars are truncated', - testing_rpc_response[:jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH], - resp_len - jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH) + testing_rpc_response[ + : jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH + ], + resp_len - jsonrpc_client_base._MAX_RPC_RESP_LOGGING_LENGTH, + ) def test_close_scoket_connection(self): client = FakeRpcClient() diff --git a/tests/mobly/controllers/android_device_lib/jsonrpc_shell_base_test.py b/tests/mobly/controllers/android_device_lib/jsonrpc_shell_base_test.py index 8ac7b787..2cdcd5cb 100755 --- a/tests/mobly/controllers/android_device_lib/jsonrpc_shell_base_test.py +++ b/tests/mobly/controllers/android_device_lib/jsonrpc_shell_base_test.py @@ -37,8 +37,9 @@ def test_load_device(self, mock_get_instances, mock_list_adb_devices): @mock.patch.object(android_device, 'list_adb_devices') @mock.patch.object(android_device, 'get_instances') @mock.patch.object(os, 'environ', new={}) - def test_load_device_when_one_device(self, mock_get_instances, - mock_list_adb_devices): + def test_load_device_when_one_device( + self, mock_get_instances, mock_list_adb_devices + ): mock_list_adb_devices.return_value = ['1234'] mock_device = mock.MagicMock(spec=android_device.AndroidDevice) mock_get_instances.return_value = [mock_device] @@ -49,8 +50,9 @@ def test_load_device_when_one_device(self, mock_get_instances, @mock.patch.object(android_device, 'list_adb_devices') @mock.patch.object(android_device, 'get_instances') @mock.patch.object(os, 'environ', new={'ANDROID_SERIAL': '1234'}) - def test_load_device_when_android_serial(self, mock_get_instances, - mock_list_adb_devices): + def test_load_device_when_android_serial( + self, mock_get_instances, mock_list_adb_devices + ): mock_list_adb_devices.return_value = ['1234', '4321'] mock_device = mock.MagicMock(spec=android_device.AndroidDevice) mock_get_instances.return_value = [mock_device] @@ -62,8 +64,9 @@ def test_load_device_when_android_serial(self, mock_get_instances, def test_load_device_when_no_devices(self, mock_list_adb_devices): mock_list_adb_devices.return_value = [] json_shell = jsonrpc_shell_base.JsonRpcShellBase() - with self.assertRaisesRegex(jsonrpc_shell_base.Error, - 'No adb device found!'): + with self.assertRaisesRegex( + jsonrpc_shell_base.Error, 'No adb device found!' + ): json_shell.load_device() @mock.patch.object(android_device, 'list_adb_devices') @@ -71,8 +74,9 @@ def test_load_device_when_no_devices(self, mock_list_adb_devices): def test_load_device_when_unspecified_device(self, mock_list_adb_devices): mock_list_adb_devices.return_value = ['1234', '4321'] json_shell = jsonrpc_shell_base.JsonRpcShellBase() - with self.assertRaisesRegex(jsonrpc_shell_base.Error, - 'Expected one phone.*'): + with self.assertRaisesRegex( + jsonrpc_shell_base.Error, 'Expected one phone.*' + ): json_shell.load_device() @mock.patch.object(android_device, 'list_adb_devices') @@ -80,8 +84,9 @@ def test_load_device_when_unspecified_device(self, mock_list_adb_devices): def test_load_device_when_device_not_found(self, mock_list_adb_devices): mock_list_adb_devices.return_value = ['4321'] json_shell = jsonrpc_shell_base.JsonRpcShellBase() - with self.assertRaisesRegex(jsonrpc_shell_base.Error, - 'Device "1234" is not found by adb.'): + with self.assertRaisesRegex( + jsonrpc_shell_base.Error, 'Device "1234" is not found by adb.' + ): json_shell.load_device(serial='1234') diff --git a/tests/mobly/controllers/android_device_lib/service_manager_test.py b/tests/mobly/controllers/android_device_lib/service_manager_test.py index 1eae045f..471c83f5 100755 --- a/tests/mobly/controllers/android_device_lib/service_manager_test.py +++ b/tests/mobly/controllers/android_device_lib/service_manager_test.py @@ -62,7 +62,7 @@ def setUp(self): def assert_recorded_one_error(self, message): self.assertEqual(expects.recorder.error_count, 1) - for _, error in (expects.DEFAULT_TEST_RESULT_RECORD.extra_errors.items()): + for _, error in expects.DEFAULT_TEST_RESULT_RECORD.extra_errors.items(): self.assertIn(message, error.details) def test_service_manager_instantiation(self): @@ -102,13 +102,13 @@ def test_register_not_a_class(self): manager.register('mock_service', base_service) def test_register_wrong_subclass_type(self): - class MyClass: pass manager = service_manager.ServiceManager(mock.MagicMock()) - with self.assertRaisesRegex(service_manager.Error, - '.* is not a subclass of BaseService!'): + with self.assertRaisesRegex( + service_manager.Error, '.* is not a subclass of BaseService!' + ): manager.register('mock_service', MyClass) def test_register_dup_alias(self): @@ -139,7 +139,8 @@ def test_for_each_modify_during_iteration(self): service1.ha = mock.MagicMock() service2.ha = mock.MagicMock() manager.for_each( - lambda service: manager._service_objects.pop(service.alias)) + lambda service: manager._service_objects.pop(service.alias) + ) self.assertFalse(manager._service_objects) def test_for_each_one_fail(self): @@ -169,14 +170,16 @@ def test_create_output_excerpts_all(self): service3.create_output_excerpts = mock.MagicMock() service1.create_output_excerpts.return_value = ['path/to/1.txt'] service2.create_output_excerpts.return_value = [ - 'path/to/2-1.txt', 'path/to/2-2.txt' + 'path/to/2-1.txt', + 'path/to/2-2.txt', ] service3.create_output_excerpts.return_value = [] mock_test_info = mock.MagicMock(output_path='path/to') result = manager.create_output_excerpts_all(mock_test_info) self.assertEqual(result['mock_service1'], ['path/to/1.txt']) - self.assertEqual(result['mock_service2'], - ['path/to/2-1.txt', 'path/to/2-2.txt']) + self.assertEqual( + result['mock_service2'], ['path/to/2-1.txt', 'path/to/2-2.txt'] + ) self.assertEqual(result['mock_service3'], []) def test_unregister(self): @@ -201,7 +204,8 @@ def test_unregister_non_existent(self): manager = service_manager.ServiceManager(mock.MagicMock()) with self.assertRaisesRegex( service_manager.Error, - '.* No service is registered with alias "mock_service"'): + '.* No service is registered with alias "mock_service"', + ): manager.unregister('mock_service') def test_unregister_handle_error_from_stop(self): @@ -211,7 +215,8 @@ def test_unregister_handle_error_from_stop(self): service.stop_func.side_effect = Exception('Something failed in stop.') manager.unregister('mock_service') self.assert_recorded_one_error( - 'Failed to stop service instance "mock_service".') + 'Failed to stop service instance "mock_service".' + ) def test_unregister_all(self): manager = service_manager.ServiceManager(mock.MagicMock()) @@ -238,7 +243,8 @@ def test_unregister_all_with_some_failed(self): self.assertTrue(service1.is_alive) self.assertFalse(service2.is_alive) self.assert_recorded_one_error( - 'Failed to stop service instance "mock_service1".') + 'Failed to stop service instance "mock_service1".' + ) def test_start_all(self): manager = service_manager.ServiceManager(mock.MagicMock()) @@ -256,7 +262,8 @@ def test_start_all(self): self.assertEqual(service2.start_func.call_count, 1) self.assertEqual( mock_call_tracker.mock_calls, - [mock.call.start1(None), mock.call.start2(None)]) + [mock.call.start1(None), mock.call.start2(None)], + ) def test_start_all_with_already_started_services(self): manager = service_manager.ServiceManager(mock.MagicMock()) @@ -295,8 +302,9 @@ def test_stop_all(self): manager.stop_all() self.assertFalse(service1.is_alive) self.assertFalse(service2.is_alive) - self.assertEqual(mock_call_tracker.mock_calls, - [mock.call.stop2(), mock.call.stop1()]) + self.assertEqual( + mock_call_tracker.mock_calls, [mock.call.stop2(), mock.call.stop1()] + ) self.assertEqual(service1.start_func.call_count, 1) self.assertEqual(service2.start_func.call_count, 1) self.assertEqual(service1.stop_func.call_count, 1) @@ -359,8 +367,8 @@ def test_pause_all(self): mock_call_tracker.pause2 = service2.pause_func manager.pause_all() self.assertEqual( - mock_call_tracker.mock_calls, - [mock.call.pause2(), mock.call.pause1()]) + mock_call_tracker.mock_calls, [mock.call.pause2(), mock.call.pause1()] + ) self.assertEqual(service1.pause_func.call_count, 1) self.assertEqual(service2.pause_func.call_count, 1) self.assertEqual(service1.resume_func.call_count, 0) @@ -392,8 +400,8 @@ def test_resume_all(self): manager.pause_all() manager.resume_all() self.assertEqual( - mock_call_tracker.mock_calls, - [mock.call.resume1(), mock.call.resume2()]) + mock_call_tracker.mock_calls, [mock.call.resume1(), mock.call.resume2()] + ) self.assertEqual(service1.pause_func.call_count, 1) self.assertEqual(service2.pause_func.call_count, 1) self.assertEqual(service1.resume_func.call_count, 1) @@ -434,8 +442,10 @@ def test_start_services(self): def test_start_services_non_existent(self): manager = service_manager.ServiceManager(mock.MagicMock()) - msg = ('.* No service is registered under the name "mock_service", ' - 'cannot start.') + msg = ( + '.* No service is registered under the name "mock_service", ' + 'cannot start.' + ) with self.assertRaisesRegex(service_manager.Error, msg): manager.start_services(['mock_service']) @@ -452,8 +462,10 @@ def test_resume_services(self): def test_resume_services_non_existent(self): manager = service_manager.ServiceManager(mock.MagicMock()) - msg = ('.* No service is registered under the name "mock_service", ' - 'cannot resume.') + msg = ( + '.* No service is registered under the name "mock_service", ' + 'cannot resume.' + ) with self.assertRaisesRegex(service_manager.Error, msg): manager.resume_services(['mock_service']) diff --git a/tests/mobly/controllers/android_device_lib/services/logcat_test.py b/tests/mobly/controllers/android_device_lib/services/logcat_test.py index df15d760..66a20f85 100755 --- a/tests/mobly/controllers/android_device_lib/services/logcat_test.py +++ b/tests/mobly/controllers/android_device_lib/services/logcat_test.py @@ -29,24 +29,25 @@ # The expected result of the cat adb operation. MOCK_ADB_LOGCAT_CAT_RESULT = [ '02-29 14:02:21.456 4454 Something\n', - '02-29 14:02:21.789 4454 Something again\n' + '02-29 14:02:21.789 4454 Something again\n', ] # A mocked piece of adb logcat output. -MOCK_ADB_LOGCAT = (u'02-29 14:02:19.123 4454 Nothing\n' - u'%s' - u'02-29 14:02:22.123 4454 Something again and again\n' - ) % u''.join(MOCK_ADB_LOGCAT_CAT_RESULT) +MOCK_ADB_LOGCAT = ( + '02-29 14:02:19.123 4454 Nothing\n' + '%s' + '02-29 14:02:22.123 4454 Something again and again\n' +) % ''.join(MOCK_ADB_LOGCAT_CAT_RESULT) # The expected result of the cat adb operation. MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT = [ '02-29 14:02:21.456 4454 Something \u901a\n', - '02-29 14:02:21.789 4454 Something again\n' + '02-29 14:02:21.789 4454 Something again\n', ] # A mocked piece of adb logcat output. MOCK_ADB_UNICODE_LOGCAT = ( - u'02-29 14:02:19.123 4454 Nothing\n' - u'%s' - u'02-29 14:02:22.123 4454 Something again and again\n' -) % u''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT) + '02-29 14:02:19.123 4454 Nothing\n' + '%s' + '02-29 14:02:22.123 4454 Something again and again\n' +) % ''.join(MOCK_ADB_UNICODE_LOGCAT_CAT_RESULT) # Mock start and end time of the adb cat. MOCK_ADB_LOGCAT_BEGIN_TIME = '02-29 14:02:20.123' @@ -54,11 +55,17 @@ # Mock AdbError for missing logpersist scripts MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR = adb.AdbError( - 'logpersist.stop --clear', b'', - '/system/bin/sh: logpersist.stop: not found', 0) + 'logpersist.stop --clear', + b'', + '/system/bin/sh: logpersist.stop: not found', + 0, +) MOCK_LOGPERSIST_START_MISSING_ADB_ERROR = adb.AdbError( - 'logpersist.start --clear', b'', - b'/system/bin/sh: logpersist.stop: not found', 0) + 'logpersist.start --clear', + b'', + b'/system/bin/sh: logpersist.stop: not found', + 0, +) class LogcatTest(unittest.TestCase): @@ -72,8 +79,7 @@ def setUp(self): self.tmp_dir = tempfile.mkdtemp() def tearDown(self): - """Removes the temp dir. - """ + """Removes the temp dir.""" shutil.rmtree(self.tmp_dir) def AssertFileContains(self, content, file_path): @@ -86,18 +92,29 @@ def AssertFileDoesNotContain(self, content, file_path): output = f.read() self.assertNotIn(content, output) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch('mobly.logger.get_log_file_timestamp') - def test_start_and_stop(self, get_timestamp_mock, open_logcat_mock, - stop_proc_mock, start_proc_mock, create_dir_mock, - FastbootProxy, MockAdbProxy): + def test_start_and_stop( + self, + get_timestamp_mock, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. @@ -109,17 +126,18 @@ def test_start_and_stop(self, get_timestamp_mock, open_logcat_mock, logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) - expected_log_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, - 'logcat,%s,fakemodel,123.txt' % ad.serial) + expected_log_path = os.path.join( + logging.log_path, + 'AndroidDevice%s' % ad.serial, + 'logcat,%s,fakemodel,123.txt' % ad.serial, + ) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = ' "adb" -s %s logcat -v threadtime -T 1 >> %s' - start_proc_mock.assert_called_with(adb_cmd % - (ad.serial, '"%s" ' % expected_log_path), - shell=True) + start_proc_mock.assert_called_with( + adb_cmd % (ad.serial, '"%s" ' % expected_log_path), shell=True + ) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) - expected_msg = ('Logcat thread is already running, cannot start another' - ' one.') + expected_msg = 'Logcat thread is already running, cannot start another one.' # Expect error if start is called back to back. with self.assertRaisesRegex(logcat.Error, expected_msg): logcat_service.start() @@ -129,15 +147,21 @@ def test_start_and_stop(self, get_timestamp_mock, open_logcat_mock, self.assertIsNone(logcat_service._adb_logcat_process) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device.list_fastboot_devices', - return_value='1') - def test_start_in_fastboot_mode(self, _, start_proc_mock, FastbootProxy, - MockAdbProxy): + @mock.patch( + 'mobly.controllers.android_device.list_fastboot_devices', return_value='1' + ) + def test_start_in_fastboot_mode( + self, _, start_proc_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) @@ -146,17 +170,27 @@ def test_start_in_fastboot_mode(self, _, start_proc_mock, FastbootProxy, self.assertFalse(logcat_service._adb_logcat_process) start_proc_mock.assert_not_called() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') - def test_update_config(self, open_logcat_mock, stop_proc_mock, - start_proc_mock, create_dir_mock, FastbootProxy, - MockAdbProxy): + def test_update_config( + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) @@ -164,56 +198,82 @@ def test_update_config(self, open_logcat_mock, stop_proc_mock, logcat_service.stop() new_log_params = '-a -b -c' new_file_path = 'some/path/log.txt' - new_config = logcat.Config(logcat_params=new_log_params, - output_file_path=new_file_path) + new_config = logcat.Config( + logcat_params=new_log_params, output_file_path=new_file_path + ) logcat_service.update_config(new_config) logcat_service.start() self.assertTrue(logcat_service._adb_logcat_process) create_dir_mock.assert_has_calls([mock.call('some/path')]) - expected_adb_cmd = (' "adb" -s 1 logcat -v threadtime -T 1 -a -b -c >> ' - '"some/path/log.txt" ') + expected_adb_cmd = ( + ' "adb" -s 1 logcat -v threadtime -T 1 -a -b -c >> "some/path/log.txt" ' + ) start_proc_mock.assert_called_with(expected_adb_cmd, shell=True) self.assertEqual(logcat_service.adb_logcat_file_path, 'some/path/log.txt') logcat_service.stop() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') - def test_update_config_while_running(self, open_logcat_mock, stop_proc_mock, - start_proc_mock, create_dir_mock, - FastbootProxy, MockAdbProxy): + def test_update_config_while_running( + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service.start() - new_config = logcat.Config(logcat_params='-blah', - output_file_path='some/path/file.txt') + new_config = logcat.Config( + logcat_params='-blah', output_file_path='some/path/file.txt' + ) with self.assertRaisesRegex( logcat.Error, - 'Logcat thread is already running, cannot start another one'): + 'Logcat thread is already running, cannot start another one', + ): logcat_service.update_config(new_config) self.assertTrue(logcat_service.is_alive) logcat_service.stop() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', - return_value=mock_android_device.MockAdbProxy('1')) - def test_pause_and_resume(self, clear_adb_mock, open_logcat_mock, - stop_proc_mock, start_proc_mock, create_dir_mock, - FastbootProxy, MockAdbProxy): + return_value=mock_android_device.MockAdbProxy('1'), + ) + def test_pause_and_resume( + self, + clear_adb_mock, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad, logcat.Config(clear_log=True)) @@ -230,44 +290,58 @@ def test_pause_and_resume(self, clear_adb_mock, open_logcat_mock, clear_adb_mock.assert_not_called() logcat_service.stop() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch( 'mobly.controllers.android_device_lib.services.logcat.Logcat.clear_adb_log', - return_value=mock_android_device.MockAdbProxy('1')) - def test_logcat_service_create_output_excerpts(self, clear_adb_mock, - stop_proc_mock, - start_proc_mock, FastbootProxy, - MockAdbProxy): + return_value=mock_android_device.MockAdbProxy('1'), + ) + def test_logcat_service_create_output_excerpts( + self, + clear_adb_mock, + stop_proc_mock, + start_proc_mock, + FastbootProxy, + MockAdbProxy, + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) logcat_service = logcat.Logcat(ad) logcat_service._start() - def _write_logcat_file_and_assert_excerpts_exists(logcat_file_content, - test_begin_time, - test_name): + def _write_logcat_file_and_assert_excerpts_exists( + logcat_file_content, test_begin_time, test_name + ): with open(logcat_service.adb_logcat_file_path, 'a') as f: f.write(logcat_file_content) test_output_dir = os.path.join(self.tmp_dir, test_name) mock_record = records.TestResultRecord(test_name) mock_record.begin_time = test_begin_time mock_record.signature = f'{test_name}-{test_begin_time}' - test_run_info = runtime_test_info.RuntimeTestInfo(test_name, - test_output_dir, - mock_record) + test_run_info = runtime_test_info.RuntimeTestInfo( + test_name, test_output_dir, mock_record + ) actual_path = logcat_service.create_output_excerpts(test_run_info)[0] expected_path = os.path.join( - test_output_dir, '{test_name}-{test_begin_time}'.format( - test_name=test_name, test_begin_time=test_begin_time), - 'logcat,{mock_serial},fakemodel,{test_name}-{test_begin_time}.txt'. - format(mock_serial=mock_serial, - test_name=test_name, - test_begin_time=test_begin_time)) + test_output_dir, + '{test_name}-{test_begin_time}'.format( + test_name=test_name, test_begin_time=test_begin_time + ), + 'logcat,{mock_serial},fakemodel,{test_name}-{test_begin_time}.txt' + .format( + mock_serial=mock_serial, + test_name=test_name, + test_begin_time=test_begin_time, + ), + ) self.assertEqual(actual_path, expected_path) self.assertTrue(os.path.exists(expected_path)) return expected_path @@ -306,19 +380,29 @@ def _write_logcat_file_and_assert_excerpts_exists(logcat_file_content, ) self.assertEqual(os.stat(expected_path3).st_size, 0) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') @mock.patch('mobly.logger.get_log_file_timestamp') - def test_take_logcat_with_extra_params(self, get_timestamp_mock, - open_logcat_mock, stop_proc_mock, - start_proc_mock, create_dir_mock, - FastbootProxy, MockAdbProxy): + def test_take_logcat_with_extra_params( + self, + get_timestamp_mock, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): """Verifies the steps of collecting adb logcat on an AndroidDevice object, including various function calls and the expected behaviors of the calls. @@ -332,21 +416,27 @@ def test_take_logcat_with_extra_params(self, get_timestamp_mock, logcat_service.start() # Verify start did the correct operations. self.assertTrue(logcat_service._adb_logcat_process) - expected_log_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, - 'logcat,%s,fakemodel,123.txt' % ad.serial) + expected_log_path = os.path.join( + logging.log_path, + 'AndroidDevice%s' % ad.serial, + 'logcat,%s,fakemodel,123.txt' % ad.serial, + ) create_dir_mock.assert_called_with(os.path.dirname(expected_log_path)) adb_cmd = ' "adb" -s %s logcat -v threadtime -T 1 -b radio >> %s' - start_proc_mock.assert_called_with(adb_cmd % - (ad.serial, '"%s" ' % expected_log_path), - shell=True) + start_proc_mock.assert_called_with( + adb_cmd % (ad.serial, '"%s" ' % expected_log_path), shell=True + ) self.assertEqual(logcat_service.adb_logcat_file_path, expected_log_path) logcat_service.stop() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. @@ -357,10 +447,14 @@ def test_instantiation(self, MockFastboot, MockAdbProxy): self.assertIsNone(logcat_service._adb_logcat_process) self.assertIsNone(logcat_service.adb_logcat_file_path) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock.MagicMock()) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock.MagicMock(), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test__enable_logpersist_with_logpersist(self, MockFastboot, MockAdbProxy): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value @@ -381,12 +475,17 @@ def test__enable_logpersist_with_logpersist(self, MockFastboot, MockAdbProxy): mock.call('logpersist.start'), ]) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock.MagicMock()) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) - def test__enable_logpersist_with_user_build_device(self, MockFastboot, - MockAdbProxy): + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock.MagicMock(), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + def test__enable_logpersist_with_user_build_device( + self, MockFastboot, MockAdbProxy + ): mock_serial = '1' mock_adb_proxy = MockAdbProxy.return_value mock_adb_proxy.getprops.return_value = { @@ -403,13 +502,17 @@ def test__enable_logpersist_with_user_build_device(self, MockFastboot, logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock.MagicMock()) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock.MagicMock(), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test__enable_logpersist_with_missing_all_logpersist( - self, MockFastboot, MockAdbProxy): - + self, MockFastboot, MockAdbProxy + ): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR @@ -435,13 +538,17 @@ def adb_shell_helper(command): logcat_service._enable_logpersist() mock_adb_proxy.shell.assert_not_called() - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock.MagicMock()) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock.MagicMock(), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test__enable_logpersist_with_missing_logpersist_stop( - self, MockFastboot, MockAdbProxy): - + self, MockFastboot, MockAdbProxy + ): def adb_shell_helper(command): if command == 'logpersist.stop --clear': raise MOCK_LOGPERSIST_STOP_MISSING_ADB_ERROR @@ -467,13 +574,17 @@ def adb_shell_helper(command): mock.call('logpersist.stop --clear'), ]) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock.MagicMock()) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock.MagicMock(), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test__enable_logpersist_with_missing_logpersist_start( - self, MockFastboot, MockAdbProxy): - + self, MockFastboot, MockAdbProxy + ): def adb_shell_helper(command): if command == 'logpersist.start': raise MOCK_LOGPERSIST_START_MISSING_ADB_ERROR @@ -498,14 +609,17 @@ def adb_shell_helper(command): mock_adb_proxy.shell.assert_not_called() @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy') - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_clear_adb_log(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) ad.adb.logcat = mock.MagicMock() ad.adb.logcat.side_effect = adb.AdbError( - cmd='cmd', stdout=b'', stderr=b'failed to clear "main" log', ret_code=1) + cmd='cmd', stdout=b'', stderr=b'failed to clear "main" log', ret_code=1 + ) logcat_service = logcat.Logcat(ad) logcat_service.clear_adb_log() diff --git a/tests/mobly/controllers/android_device_lib/services/snippet_management_service_test.py b/tests/mobly/controllers/android_device_lib/services/snippet_management_service_test.py index 969092b2..b6431d54 100755 --- a/tests/mobly/controllers/android_device_lib/services/snippet_management_service_test.py +++ b/tests/mobly/controllers/android_device_lib/services/snippet_management_service_test.py @@ -19,7 +19,9 @@ from mobly.controllers.android_device_lib.services import snippet_management_service MOCK_PACKAGE = 'com.mock.package' -SNIPPET_CLIENT_V2_CLASS_PATH = 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' +SNIPPET_CLIENT_V2_CLASS_PATH = ( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' +) class SnippetManagementServiceTest(unittest.TestCase): @@ -27,7 +29,8 @@ class SnippetManagementServiceTest(unittest.TestCase): def test_empty_manager_start_stop(self): manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.start() # When no client is registered, manager is never alive. self.assertFalse(manager.is_alive) @@ -38,21 +41,24 @@ def test_empty_manager_start_stop(self): def test_get_snippet_client(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) self.assertEqual(manager.get_snippet_client('foo'), mock_client) @mock.patch(SNIPPET_CLIENT_V2_CLASS_PATH) def test_get_snippet_client_fail(self, _): manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) self.assertIsNone(manager.get_snippet_client('foo')) @mock.patch(SNIPPET_CLIENT_V2_CLASS_PATH) def test_stop_with_live_client(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) mock_client.initialize.assert_called_once_with() manager.stop() @@ -67,30 +73,35 @@ def test_stop_with_live_client(self, mock_class): def test_add_snippet_client_without_config(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) - mock_class.assert_called_once_with(package=mock.ANY, - ad=mock.ANY, - config=None) + mock_class.assert_called_once_with( + package=mock.ANY, ad=mock.ANY, config=None + ) @mock.patch(SNIPPET_CLIENT_V2_CLASS_PATH) def test_add_snippet_client_with_config(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) snippet_config = snippet_client_v2.Config() manager.add_snippet_client('foo', MOCK_PACKAGE, snippet_config) - mock_class.assert_called_once_with(package=mock.ANY, - ad=mock.ANY, - config=snippet_config) + mock_class.assert_called_once_with( + package=mock.ANY, ad=mock.ANY, config=snippet_config + ) @mock.patch(SNIPPET_CLIENT_V2_CLASS_PATH) def test_add_snippet_client_dup_name(self, _): manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) - msg = ('.* Name "foo" is already registered with package ".*", it ' - 'cannot be used again.') + msg = ( + '.* Name "foo" is already registered with package ".*", it ' + 'cannot be used again.' + ) with self.assertRaisesRegex(snippet_management_service.Error, msg): manager.add_snippet_client('foo', MOCK_PACKAGE + 'ha') @@ -99,10 +110,13 @@ def test_add_snippet_client_dup_package(self, mock_class): mock_client = mock_class.return_value mock_client.package = MOCK_PACKAGE manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) - msg = ('Snippet package "com.mock.package" has already been loaded ' - 'under name "foo".') + msg = ( + 'Snippet package "com.mock.package" has already been loaded ' + 'under name "foo".' + ) with self.assertRaisesRegex(snippet_management_service.Error, msg): manager.add_snippet_client('bar', MOCK_PACKAGE) @@ -111,7 +125,8 @@ def test_remove_snippet_client(self, mock_class): mock_client = mock.MagicMock() mock_class.return_value = mock_client manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) manager.remove_snippet_client('foo') msg = 'No snippet client is registered with name "foo".' @@ -123,17 +138,20 @@ def test_remove_snippet_client(self, mock_class): mock_client = mock.MagicMock() mock_class.return_value = mock_client manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) with self.assertRaisesRegex( snippet_management_service.Error, - 'No snippet client is registered with name "foo".'): + 'No snippet client is registered with name "foo".', + ): manager.remove_snippet_client('foo') @mock.patch(SNIPPET_CLIENT_V2_CLASS_PATH) def test_start_with_live_service(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) mock_client.initialize.reset_mock() mock_client.is_alive = True @@ -148,7 +166,8 @@ def test_start_with_live_service(self, mock_class): def test_pause(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) manager.pause() mock_client.close_connection.assert_called_once_with() @@ -157,7 +176,8 @@ def test_pause(self, mock_class): def test_resume_positive_case(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) mock_client.is_alive = False manager.resume() @@ -167,7 +187,8 @@ def test_resume_positive_case(self, mock_class): def test_resume_negative_case(self, mock_class): mock_client = mock_class.return_value manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) mock_client.is_alive = True manager.resume() @@ -178,7 +199,8 @@ def test_attribute_access(self, mock_class): mock_client = mock.MagicMock() mock_class.return_value = mock_client manager = snippet_management_service.SnippetManagementService( - mock.MagicMock()) + mock.MagicMock() + ) manager.add_snippet_client('foo', MOCK_PACKAGE) manager.foo.ha('param') mock_client.ha.assert_called_once_with('param') diff --git a/tests/mobly/controllers/android_device_lib/sl4a_client_test.py b/tests/mobly/controllers/android_device_lib/sl4a_client_test.py index 08560d41..bf11b07b 100755 --- a/tests/mobly/controllers/android_device_lib/sl4a_client_test.py +++ b/tests/mobly/controllers/android_device_lib/sl4a_client_test.py @@ -22,43 +22,60 @@ class Sl4aClientTest(jsonrpc_client_test_base.JsonRpcClientTestBase): - """Unit tests for mobly.controllers.android_device_lib.sl4a_client. - """ + """Unit tests for mobly.controllers.android_device_lib.sl4a_client.""" @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_start_app_and_connect(self, mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_start_app_and_connect( + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[b'\n']) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, resp_lines=[b'\n'] + ) client = self._make_client() client.start_app_and_connect() self.assertEqual(8080, client.device_port) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_app_not_installed(self, mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_app_not_installed( + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[b'\n']) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, resp_lines=[b'\n'] + ) client = self._make_client(adb_proxy=mock_android_device.MockAdbProxy()) - with self.assertRaisesRegex(jsonrpc_client_base.AppStartError, - '.* SL4A is not installed on .*'): + with self.assertRaisesRegex( + jsonrpc_client_base.AppStartError, '.* SL4A is not installed on .*' + ): client.start_app_and_connect() def _make_client(self, adb_proxy=None): adb_proxy = adb_proxy or mock_android_device.MockAdbProxy( - installed_packages=['com.googlecode.android_scripting']) + installed_packages=['com.googlecode.android_scripting'] + ) ad = mock.Mock() ad.adb = adb_proxy ad.build_info = { @@ -67,11 +84,12 @@ def _make_client(self, adb_proxy=None): } return sl4a_client.Sl4aClient(ad=ad) - def _setup_mock_instrumentation_cmd(self, mock_start_standing_subprocess, - resp_lines): + def _setup_mock_instrumentation_cmd( + self, mock_start_standing_subprocess, resp_lines + ): mock_proc = mock_start_standing_subprocess() mock_proc.stdout.readline.side_effect = resp_lines -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/controllers/android_device_lib/snippet_client_test.py b/tests/mobly/controllers/android_device_lib/snippet_client_test.py index 1a9fe989..5f31c476 100755 --- a/tests/mobly/controllers/android_device_lib/snippet_client_test.py +++ b/tests/mobly/controllers/android_device_lib/snippet_client_test.py @@ -23,13 +23,14 @@ MOCK_PACKAGE_NAME = 'some.package.name' MOCK_MISSING_PACKAGE_NAME = 'not.installed' -JSONRPC_BASE_CLASS = 'mobly.controllers.android_device_lib.jsonrpc_client_base.JsonRpcClientBase' +JSONRPC_BASE_CLASS = ( + 'mobly.controllers.android_device_lib.jsonrpc_client_base.JsonRpcClientBase' +) MOCK_USER_ID = 0 class SnippetClientTest(jsonrpc_client_test_base.JsonRpcClientTestBase): - """Unit tests for mobly.controllers.android_device_lib.snippet_client. - """ + """Unit tests for mobly.controllers.android_device_lib.snippet_client.""" def test_check_app_installed_normal(self): sc = self._make_client() @@ -38,29 +39,40 @@ def test_check_app_installed_normal(self): def test_check_app_installed_fail_app_not_installed(self): sc = self._make_client(mock_android_device.MockAdbProxy()) expected_msg = '.* %s is not installed.' % MOCK_PACKAGE_NAME - with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, - expected_msg): + with self.assertRaisesRegex( + snippet_client.AppStartPreCheckError, expected_msg + ): sc._check_app_installed() def test_check_app_installed_fail_not_instrumented(self): sc = self._make_client( - mock_android_device.MockAdbProxy( - installed_packages=[MOCK_PACKAGE_NAME])) - expected_msg = ('.* %s is installed, but it is not instrumented.' % - MOCK_PACKAGE_NAME) - with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, - expected_msg): + mock_android_device.MockAdbProxy(installed_packages=[MOCK_PACKAGE_NAME]) + ) + expected_msg = ( + '.* %s is installed, but it is not instrumented.' % MOCK_PACKAGE_NAME + ) + with self.assertRaisesRegex( + snippet_client.AppStartPreCheckError, expected_msg + ): sc._check_app_installed() def test_check_app_installed_fail_target_not_installed(self): sc = self._make_client( - mock_android_device.MockAdbProxy(instrumented_packages=[( - MOCK_PACKAGE_NAME, snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, - MOCK_MISSING_PACKAGE_NAME)])) - expected_msg = ('.* Instrumentation target %s is not installed.' % - MOCK_MISSING_PACKAGE_NAME) - with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, - expected_msg): + mock_android_device.MockAdbProxy( + instrumented_packages=[( + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + MOCK_MISSING_PACKAGE_NAME, + )] + ) + ) + expected_msg = ( + '.* Instrumentation target %s is not installed.' + % MOCK_MISSING_PACKAGE_NAME + ) + with self.assertRaisesRegex( + snippet_client.AppStartPreCheckError, expected_msg + ): sc._check_app_installed() @mock.patch('socket.create_connection') @@ -91,10 +103,13 @@ def test_snippet_start_event_client(self, mock_create_connection): callback.getAll('eventName') @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_snippet_restore_event_client(self, mock_get_port, - mock_create_connection): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_snippet_restore_event_client( + self, mock_get_port, mock_create_connection + ): mock_get_port.return_value = 789 fake_file = self.setup_mock_socket_file(mock_create_connection) client = self._make_client() @@ -130,24 +145,37 @@ def test_snippet_restore_event_client(self, mock_get_port, mock_create_connection.side_effect = IOError('socket timed out') with self.assertRaisesRegex( jsonrpc_client_base.AppRestoreConnectionError, - ('Failed to restore app connection for %s at host port %s, ' - 'device port %s') % (MOCK_PACKAGE_NAME, 789, 456)): + ( + 'Failed to restore app connection for %s at host port %s, ' + 'device port %s' + ) + % (MOCK_PACKAGE_NAME, 789, 456), + ): client.restore_app_connection() @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_snippet_start_app_and_connect(self, mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_snippet_start_app_and_connect( + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[ - b'SNIPPET START, PROTOCOL 1 0\n', - b'SNIPPET SERVING, PORT 123\n', - ]) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, + resp_lines=[ + b'SNIPPET START, PROTOCOL 1 0\n', + b'SNIPPET SERVING, PORT 123\n', + ], + ) client = self._make_client() client.start_app_and_connect() self.assertEqual(123, client.device_port) @@ -155,8 +183,9 @@ def test_snippet_start_app_and_connect(self, mock_get_port, @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_snippet_stop_app(self, mock_stop_standing_subprocess, - mock_create_connection): + def test_snippet_stop_app( + self, mock_stop_standing_subprocess, mock_create_connection + ): adb_proxy = mock.MagicMock() adb_proxy.shell.return_value = b'OK (0 tests)' client = self._make_client(adb_proxy) @@ -179,14 +208,15 @@ def test_snippet_stop_app_raises(self): @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_snippet_stop_app_stops_event_client(self, - mock_stop_standing_subprocess, - mock_create_connection): + def test_snippet_stop_app_stops_event_client( + self, mock_stop_standing_subprocess, mock_create_connection + ): adb_proxy = mock.MagicMock() adb_proxy.shell.return_value = b'OK (0 tests)' client = self._make_client(adb_proxy) - event_client = snippet_client.SnippetClient(package=MOCK_PACKAGE_NAME, - ad=client._ad) + event_client = snippet_client.SnippetClient( + package=MOCK_PACKAGE_NAME, ad=client._ad + ) client._event_client = event_client event_client_conn = mock.Mock() event_client._conn = event_client_conn @@ -200,12 +230,14 @@ def test_snippet_stop_app_stops_event_client(self, @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') def test_snippet_stop_app_stops_event_client_without_connection( - self, mock_stop_standing_subprocess, mock_create_connection): + self, mock_stop_standing_subprocess, mock_create_connection + ): adb_proxy = mock.MagicMock() adb_proxy.shell.return_value = b'OK (0 tests)' client = self._make_client(adb_proxy) - event_client = snippet_client.SnippetClient(package=MOCK_PACKAGE_NAME, - ad=client._ad) + event_client = snippet_client.SnippetClient( + package=MOCK_PACKAGE_NAME, ad=client._ad + ) client._event_client = event_client event_client._conn = None @@ -216,9 +248,9 @@ def test_snippet_stop_app_stops_event_client_without_connection( @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_snippet_stop_app_without_event_client(self, - mock_stop_standing_subprocess, - mock_create_connection): + def test_snippet_stop_app_without_event_client( + self, mock_stop_standing_subprocess, mock_create_connection + ): adb_proxy = mock.MagicMock() adb_proxy.shell.return_value = b'OK (0 tests)' client = self._make_client(adb_proxy) @@ -232,8 +264,8 @@ def test_snippet_stop_app_without_event_client(self, @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(snippet_client.SnippetClient, 'connect') def test_event_client_does_not_stop_port_forwarding( - self, mock_stop_standing_subprocess, mock_create_connection, - mock_connect): + self, mock_stop_standing_subprocess, mock_create_connection, mock_connect + ): adb_proxy = mock.MagicMock() adb_proxy.shell.return_value = b'OK (0 tests)' client = self._make_client(adb_proxy) @@ -254,55 +286,78 @@ def test_event_client_does_not_stop_port_forwarding( event_client._adb.forward.assert_not_called() @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient.' - 'disable_hidden_api_blacklist') + 'disable_hidden_api_blacklist' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient.' - 'stop_app') - def test_start_app_and_connect_precheck_fail(self, mock_stop, mock_precheck, - mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + 'stop_app' + ) + def test_start_app_and_connect_precheck_fail( + self, + mock_stop, + mock_precheck, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[ - b'SNIPPET START, PROTOCOL 1 0\n', - b'SNIPPET SERVING, PORT 123\n', - ]) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, + resp_lines=[ + b'SNIPPET START, PROTOCOL 1 0\n', + b'SNIPPET SERVING, PORT 123\n', + ], + ) client = self._make_client() mock_precheck.side_effect = snippet_client.AppStartPreCheckError( - client.ad, 'ha') + client.ad, 'ha' + ) with self.assertRaisesRegex(snippet_client.AppStartPreCheckError, 'ha'): client.start_app_and_connect() mock_stop.assert_not_called() self.assertFalse(client.is_alive) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient._start_app_and_connect' ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient.stop_app' ) - def test_start_app_and_connect_generic_error(self, mock_stop, mock_start, - mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + def test_start_app_and_connect_generic_error( + self, + mock_stop, + mock_start, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[ - b'SNIPPET START, PROTOCOL 1 0\n', - b'SNIPPET SERVING, PORT 123\n', - ]) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, + resp_lines=[ + b'SNIPPET START, PROTOCOL 1 0\n', + b'SNIPPET SERVING, PORT 123\n', + ], + ) client = self._make_client() mock_start.side_effect = Exception('ha') with self.assertRaisesRegex(Exception, 'ha'): @@ -311,10 +366,14 @@ def test_start_app_and_connect_generic_error(self, mock_stop, mock_start, self.assertFalse(client.is_alive) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client.SnippetClient._start_app_and_connect' ) @@ -322,14 +381,21 @@ def test_start_app_and_connect_generic_error(self, mock_stop, mock_start, 'mobly.controllers.android_device_lib.snippet_client.SnippetClient.stop_app' ) def test_start_app_and_connect_fail_stop_also_fail( - self, mock_stop, mock_start, mock_get_port, - mock_start_standing_subprocess, mock_create_connection): + self, + mock_stop, + mock_start, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) - self._setup_mock_instrumentation_cmd(mock_start_standing_subprocess, - resp_lines=[ - b'SNIPPET START, PROTOCOL 1 0\n', - b'SNIPPET SERVING, PORT 123\n', - ]) + self._setup_mock_instrumentation_cmd( + mock_start_standing_subprocess, + resp_lines=[ + b'SNIPPET START, PROTOCOL 1 0\n', + b'SNIPPET SERVING, PORT 123\n', + ], + ) client = self._make_client() mock_start.side_effect = Exception('Some error') mock_stop.side_effect = Exception('Another error') @@ -338,19 +404,34 @@ def test_start_app_and_connect_fail_stop_also_fail( mock_stop.assert_called_once_with() self.assertFalse(client.is_alive) - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._do_start_app') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._check_app_installed') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._read_protocol_line') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient.connect') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_snippet_start_on_sdk_21(self, mock_get_port, mock_connect, - mock_read_protocol_line, - mock_check_app_installed, mock_do_start_app): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._do_start_app' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._check_app_installed' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._read_protocol_line' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient.connect' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_snippet_start_on_sdk_21( + self, + mock_get_port, + mock_connect, + mock_read_protocol_line, + mock_check_app_installed, + mock_do_start_app, + ): """Check that `--user` is not added to start command on SDK < 24.""" def _mocked_shell(arg): @@ -375,24 +456,40 @@ def _mocked_shell(arg): client._adb.shell = mock.Mock(return_value=b'setsid') client.start_app_and_connect() cmd_setsid = '%s am instrument -w -e action start %s/%s' % ( - snippet_client._SETSID_COMMAND, MOCK_PACKAGE_NAME, - snippet_client._INSTRUMENTATION_RUNNER_PACKAGE) + snippet_client._SETSID_COMMAND, + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + ) mock_do_start_app.assert_has_calls([mock.call(cmd_setsid)]) - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._do_start_app') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._check_app_installed') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient._read_protocol_line') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'SnippetClient.connect') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._do_start_app' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._check_app_installed' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient._read_protocol_line' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'SnippetClient.connect' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) def test_snippet_start_app_and_connect_persistent_session( - self, mock_get_port, mock_connect, mock_read_protocol_line, - mock_check_app_installed, mock_do_start_app): - + self, + mock_get_port, + mock_connect, + mock_read_protocol_line, + mock_check_app_installed, + mock_do_start_app, + ): def _mocked_shell(arg): if 'setsid' in arg: raise adb.AdbError('cmd', 'stdout', 'stderr', 'ret_code') @@ -416,8 +513,11 @@ def _mocked_shell(arg): client._adb.current_user_id = MOCK_USER_ID client.start_app_and_connect() cmd_setsid = '%s am instrument --user %s -w -e action start %s/%s' % ( - snippet_client._SETSID_COMMAND, MOCK_USER_ID, MOCK_PACKAGE_NAME, - snippet_client._INSTRUMENTATION_RUNNER_PACKAGE) + snippet_client._SETSID_COMMAND, + MOCK_USER_ID, + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + ) mock_do_start_app.assert_has_calls([mock.call(cmd_setsid)]) # Test 'setsid' does not exist, but 'nohup' exsits @@ -425,67 +525,97 @@ def _mocked_shell(arg): client._adb.shell = _mocked_shell client.start_app_and_connect() cmd_nohup = '%s am instrument --user %s -w -e action start %s/%s' % ( - snippet_client._NOHUP_COMMAND, MOCK_USER_ID, MOCK_PACKAGE_NAME, - snippet_client._INSTRUMENTATION_RUNNER_PACKAGE) + snippet_client._NOHUP_COMMAND, + MOCK_USER_ID, + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + ) mock_do_start_app.assert_has_calls( - [mock.call(cmd_setsid), mock.call(cmd_nohup)]) + [mock.call(cmd_setsid), mock.call(cmd_nohup)] + ) # Test both 'setsid' and 'nohup' do not exist client._adb.shell = mock.Mock( - side_effect=adb.AdbError('cmd', 'stdout', 'stderr', 'ret_code')) + side_effect=adb.AdbError('cmd', 'stdout', 'stderr', 'ret_code') + ) client = self._make_client() client.start_app_and_connect() cmd_not_persist = ' am instrument --user %s -w -e action start %s/%s' % ( - MOCK_USER_ID, MOCK_PACKAGE_NAME, - snippet_client._INSTRUMENTATION_RUNNER_PACKAGE) + MOCK_USER_ID, + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + ) mock_do_start_app.assert_has_calls([ mock.call(cmd_setsid), mock.call(cmd_nohup), - mock.call(cmd_not_persist) + mock.call(cmd_not_persist), ]) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') - def test_snippet_start_app_crash(self, mock_get_port, - mock_start_standing_subprocess, - mock_create_connection): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) + def test_snippet_start_app_crash( + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): mock_get_port.return_value = 456 self.setup_mock_socket_file(mock_create_connection) self._setup_mock_instrumentation_cmd( mock_start_standing_subprocess, - resp_lines=[b'INSTRUMENTATION_RESULT: shortMsg=Process crashed.\n']) + resp_lines=[b'INSTRUMENTATION_RESULT: shortMsg=Process crashed.\n'], + ) client = self._make_client() with self.assertRaisesRegex( snippet_client.ProtocolVersionError, - 'INSTRUMENTATION_RESULT: shortMsg=Process crashed.'): + 'INSTRUMENTATION_RESULT: shortMsg=Process crashed.', + ): client.start_app_and_connect() - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) def test_snippet_start_app_and_connect_unknown_protocol( - self, mock_get_port, mock_start_standing_subprocess): + self, mock_get_port, mock_start_standing_subprocess + ): mock_get_port.return_value = 789 self._setup_mock_instrumentation_cmd( mock_start_standing_subprocess, - resp_lines=[b'SNIPPET START, PROTOCOL 99 0\n']) + resp_lines=[b'SNIPPET START, PROTOCOL 99 0\n'], + ) client = self._make_client() - with self.assertRaisesRegex(snippet_client.ProtocolVersionError, - 'SNIPPET START, PROTOCOL 99 0'): + with self.assertRaisesRegex( + snippet_client.ProtocolVersionError, 'SNIPPET START, PROTOCOL 99 0' + ): client.start_app_and_connect() @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) def test_snippet_start_app_and_connect_header_junk( - self, mock_get_port, mock_start_standing_subprocess, - mock_create_connection): + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): self.setup_mock_socket_file(mock_create_connection) self._setup_mock_instrumentation_cmd( mock_start_standing_subprocess, @@ -495,19 +625,27 @@ def test_snippet_start_app_and_connect_header_junk( b'SNIPPET START, PROTOCOL 1 0\n', b'Maybe in the middle too\n', b'SNIPPET SERVING, PORT 123\n', - ]) + ], + ) client = self._make_client() client.start_app_and_connect() self.assertEqual(123, client.device_port) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client.' - 'utils.get_available_host_port') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client.' + 'utils.get_available_host_port' + ) def test_snippet_start_app_and_connect_no_valid_line( - self, mock_get_port, mock_start_standing_subprocess, - mock_create_connection): + self, + mock_get_port, + mock_start_standing_subprocess, + mock_create_connection, + ): mock_get_port.return_value = 456 self.setup_mock_socket_file(mock_create_connection) self._setup_mock_instrumentation_cmd( @@ -516,10 +654,13 @@ def test_snippet_start_app_and_connect_no_valid_line( b'This is some header junk\n', b'Some phones print arbitrary output\n', b'', # readline uses '' to mark EOF - ]) + ], + ) client = self._make_client() - with self.assertRaisesRegex(jsonrpc_client_base.AppStartError, - 'Unexpected EOF waiting for app to start'): + with self.assertRaisesRegex( + jsonrpc_client_base.AppStartError, + 'Unexpected EOF waiting for app to start', + ): client.start_app_and_connect() @mock.patch('builtins.print') @@ -546,9 +687,12 @@ def test_help_rpc_when_not_printing(self, mock_print): def _make_client(self, adb_proxy=None): adb_proxy = adb_proxy or mock_android_device.MockAdbProxy( - instrumented_packages=[(MOCK_PACKAGE_NAME, - snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, - MOCK_PACKAGE_NAME)]) + instrumented_packages=[( + MOCK_PACKAGE_NAME, + snippet_client._INSTRUMENTATION_RUNNER_PACKAGE, + MOCK_PACKAGE_NAME, + )] + ) ad = mock.Mock() ad.adb = adb_proxy ad.adb.current_user_id = MOCK_USER_ID @@ -558,11 +702,12 @@ def _make_client(self, adb_proxy=None): } return snippet_client.SnippetClient(package=MOCK_PACKAGE_NAME, ad=ad) - def _setup_mock_instrumentation_cmd(self, mock_start_standing_subprocess, - resp_lines): + def _setup_mock_instrumentation_cmd( + self, mock_start_standing_subprocess, resp_lines + ): mock_proc = mock_start_standing_subprocess() mock_proc.stdout.readline.side_effect = resp_lines -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/controllers/android_device_lib/snippet_client_v2_test.py b/tests/mobly/controllers/android_device_lib/snippet_client_v2_test.py index c18bcbda..61d81b61 100644 --- a/tests/mobly/controllers/android_device_lib/snippet_client_v2_test.py +++ b/tests/mobly/controllers/android_device_lib/snippet_client_v2_test.py @@ -24,7 +24,9 @@ from tests.lib import mock_android_device MOCK_PACKAGE_NAME = 'some.package.name' -MOCK_SERVER_PATH = f'{MOCK_PACKAGE_NAME}/{snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE}' +MOCK_SERVER_PATH = ( + f'{MOCK_PACKAGE_NAME}/{snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE}' +) MOCK_USER_ID = 0 MOCK_DEVICE_PORT = 1234 @@ -93,90 +95,107 @@ class SnippetClientV2Test(unittest.TestCase): """Unit tests for SnippetClientV2.""" def _make_client(self, adb_proxy=None, mock_properties=None, config=None): - adb_proxy = adb_proxy or _MockAdbProxy(instrumented_packages=[ - (MOCK_PACKAGE_NAME, snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE, - MOCK_PACKAGE_NAME) - ], - mock_properties=mock_properties) + adb_proxy = adb_proxy or _MockAdbProxy( + instrumented_packages=[( + MOCK_PACKAGE_NAME, + snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE, + MOCK_PACKAGE_NAME, + )], + mock_properties=mock_properties, + ) self.adb = adb_proxy device = mock.Mock() device.adb = adb_proxy device.adb.current_user_id = MOCK_USER_ID device.build_info = { - 'build_version_codename': - adb_proxy.getprop('ro.build.version.codename'), - 'build_version_sdk': - adb_proxy.getprop('ro.build.version.sdk'), + 'build_version_codename': adb_proxy.getprop( + 'ro.build.version.codename' + ), + 'build_version_sdk': adb_proxy.getprop('ro.build.version.sdk'), } self.device = device - self.client = snippet_client_v2.SnippetClientV2(MOCK_PACKAGE_NAME, device, - config) + self.client = snippet_client_v2.SnippetClientV2( + MOCK_PACKAGE_NAME, device, config + ) def _make_client_with_extra_adb_properties(self, extra_properties): mock_properties = mock_android_device.DEFAULT_MOCK_PROPERTIES.copy() mock_properties.update(extra_properties) self._make_client(mock_properties=mock_properties) - def _mock_server_process_starting_response(self, - mock_start_subprocess, - resp_lines=None): + def _mock_server_process_starting_response( + self, mock_start_subprocess, resp_lines=None + ): resp_lines = resp_lines or [ - b'SNIPPET START, PROTOCOL 1 0', b'SNIPPET SERVING, PORT 1234' + b'SNIPPET START, PROTOCOL 1 0', + b'SNIPPET SERVING, PORT 1234', ] mock_proc = mock_start_subprocess.return_value mock_proc.stdout.readline.side_effect = resp_lines - def _make_client_and_mock_socket_conn(self, - mock_socket_create_conn, - socket_resp=None, - device_port=MOCK_DEVICE_PORT, - adb_proxy=None, - mock_properties=None, - set_counter=True): + def _make_client_and_mock_socket_conn( + self, + mock_socket_create_conn, + socket_resp=None, + device_port=MOCK_DEVICE_PORT, + adb_proxy=None, + mock_properties=None, + set_counter=True, + ): """Makes the snippet client and mocks the socket connection.""" self._make_client(adb_proxy, mock_properties) if socket_resp is None: socket_resp = [b'{"status": true, "uid": 1}'] - self.mock_socket_file = _setup_mock_socket_file(mock_socket_create_conn, - socket_resp) + self.mock_socket_file = _setup_mock_socket_file( + mock_socket_create_conn, socket_resp + ) self.client.device_port = device_port self.socket_conn = mock_socket_create_conn.return_value if set_counter: self.client._counter = self.client._id_counter() - def _assert_client_resources_released(self, mock_start_subprocess, - mock_stop_standing_subprocess, - mock_get_port): + def _assert_client_resources_released( + self, mock_start_subprocess, mock_stop_standing_subprocess, mock_get_port + ): """Asserts the resources had been released before the client stopped.""" self.assertIs(self.client._proc, None) self.adb.mock_shell_func.assert_any_call( f'am instrument --user {MOCK_USER_ID} -w -e action stop ' - f'{MOCK_SERVER_PATH}') + f'{MOCK_SERVER_PATH}' + ) mock_stop_standing_subprocess.assert_called_once_with( - mock_start_subprocess.return_value) + mock_start_subprocess.return_value + ) self.assertFalse(self.client.is_alive) self.assertIs(self.client._conn, None) self.socket_conn.close.assert_called() self.assertIs(self.client.host_port, None) self.adb.mock_forward_func.assert_any_call( - ['--remove', f'tcp:{mock_get_port.return_value}']) + ['--remove', f'tcp:{mock_get_port.return_value}'] + ) self.assertIsNone(self.client._event_client) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - def test_the_whole_lifecycle_with_a_sync_rpc(self, mock_start_subprocess, - mock_stop_standing_subprocess, - mock_socket_create_conn, - mock_get_port): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + def test_the_whole_lifecycle_with_a_sync_rpc( + self, + mock_start_subprocess, + mock_stop_standing_subprocess, + mock_socket_create_conn, + mock_get_port, + ): """Tests the whole lifecycle of the client with sending a sync RPC.""" socket_resp = [ b'{"status": true, "uid": 1}', @@ -184,41 +203,51 @@ def test_the_whole_lifecycle_with_a_sync_rpc(self, mock_start_subprocess, ] expected_socket_writes = [ mock.call(b'{"cmd": "initiate", "uid": -1}\n'), - mock.call(b'{"id": 0, "method": "some_sync_rpc", ' - b'"params": [1, 2, "hello"]}\n'), + mock.call( + b'{"id": 0, "method": "some_sync_rpc", "params": [1, 2, "hello"]}\n' + ), ] - self._make_client_and_mock_socket_conn(mock_socket_create_conn, - socket_resp, - set_counter=False) + self._make_client_and_mock_socket_conn( + mock_socket_create_conn, socket_resp, set_counter=False + ) self._mock_server_process_starting_response(mock_start_subprocess) self.client.initialize() rpc_result = self.client.some_sync_rpc(1, 2, 'hello') self.client.stop() - self._assert_client_resources_released(mock_start_subprocess, - mock_stop_standing_subprocess, - mock_get_port) + self._assert_client_resources_released( + mock_start_subprocess, mock_stop_standing_subprocess, mock_get_port + ) - self.assertListEqual(self.mock_socket_file.write.call_args_list, - expected_socket_writes) + self.assertListEqual( + self.mock_socket_file.write.call_args_list, expected_socket_writes + ) self.assertEqual(rpc_result, 123) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.callback_handler_v2.' - 'CallbackHandlerV2') - def test_the_whole_lifecycle_with_an_async_rpc(self, mock_callback_class, - mock_start_subprocess, - mock_stop_standing_subprocess, - mock_socket_create_conn, - mock_get_port): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.callback_handler_v2.' + 'CallbackHandlerV2' + ) + def test_the_whole_lifecycle_with_an_async_rpc( + self, + mock_callback_class, + mock_start_subprocess, + mock_stop_standing_subprocess, + mock_socket_create_conn, + mock_get_port, + ): """Tests the whole lifecycle of the client with sending an async RPC.""" mock_socket_resp = [ b'{"status": true, "uid": 1}', @@ -227,13 +256,15 @@ def test_the_whole_lifecycle_with_an_async_rpc(self, mock_callback_class, ] expected_socket_writes = [ mock.call(b'{"cmd": "initiate", "uid": -1}\n'), - mock.call(b'{"id": 0, "method": "some_async_rpc", ' - b'"params": [1, 2, "async"]}\n'), + mock.call( + b'{"id": 0, "method": "some_async_rpc", ' + b'"params": [1, 2, "async"]}\n' + ), mock.call(b'{"cmd": "continue", "uid": 1}\n'), ] - self._make_client_and_mock_socket_conn(mock_socket_create_conn, - mock_socket_resp, - set_counter=False) + self._make_client_and_mock_socket_conn( + mock_socket_create_conn, mock_socket_resp, set_counter=False + ) self._mock_server_process_starting_response(mock_start_subprocess) self.client.initialize() @@ -241,12 +272,13 @@ def test_the_whole_lifecycle_with_an_async_rpc(self, mock_callback_class, event_client = self.client._event_client self.client.stop() - self._assert_client_resources_released(mock_start_subprocess, - mock_stop_standing_subprocess, - mock_get_port) + self._assert_client_resources_released( + mock_start_subprocess, mock_stop_standing_subprocess, mock_get_port + ) - self.assertListEqual(self.mock_socket_file.write.call_args_list, - expected_socket_writes) + self.assertListEqual( + self.mock_socket_file.write.call_args_list, expected_socket_writes + ) mock_callback_class.assert_called_with( callback_id='1-0', event_client=event_client, @@ -254,7 +286,8 @@ def test_the_whole_lifecycle_with_an_async_rpc(self, mock_callback_class, method_name='some_async_rpc', device=self.device, rpc_max_timeout_sec=snippet_client_v2._SOCKET_READ_TIMEOUT, - default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC) + default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC, + ) self.assertIs(rpc_result, mock_callback_class.return_value) self.assertIsNone(event_client.host_port, None) self.assertIsNone(event_client.device_port, None) @@ -262,18 +295,26 @@ def test_the_whole_lifecycle_with_an_async_rpc(self, mock_callback_class, @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') @mock.patch('mobly.utils.stop_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.callback_handler_v2.' - 'CallbackHandlerV2') - def test_the_whole_lifecycle_with_multiple_rpcs(self, mock_callback_class, - mock_start_subprocess, - mock_stop_standing_subprocess, - mock_socket_create_conn, - mock_get_port): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.callback_handler_v2.' + 'CallbackHandlerV2' + ) + def test_the_whole_lifecycle_with_multiple_rpcs( + self, + mock_callback_class, + mock_start_subprocess, + mock_stop_standing_subprocess, + mock_socket_create_conn, + mock_get_port, + ): """Tests the whole lifecycle of the client with sending multiple RPCs.""" # Prepare the test mock_socket_resp = [ @@ -285,9 +326,9 @@ def test_the_whole_lifecycle_with_multiple_rpcs(self, mock_callback_class, b'{"id": 2, "result": 789, "error": null, "callback": null}', b'{"id": 3, "result": 321, "error": null, "callback": "2-0"}', ] - self._make_client_and_mock_socket_conn(mock_socket_create_conn, - mock_socket_resp, - set_counter=False) + self._make_client_and_mock_socket_conn( + mock_socket_create_conn, mock_socket_resp, set_counter=False + ) self._mock_server_process_starting_response(mock_start_subprocess) rpc_results_expected = [ @@ -299,7 +340,8 @@ def test_the_whole_lifecycle_with_multiple_rpcs(self, mock_callback_class, # Extract the two mock objects to use as return values of callback handler # class mock_callback_class.side_effect = [ - rpc_results_expected[1], rpc_results_expected[3] + rpc_results_expected[1], + rpc_results_expected[3], ] # Run tests @@ -314,14 +356,17 @@ def test_the_whole_lifecycle_with_multiple_rpcs(self, mock_callback_class, # Assertions mock_callback_class_calls_expected = [ - mock.call(callback_id='1-0', - event_client=event_client, - ret_value=456, - method_name='some_async_rpc', - device=self.device, - rpc_max_timeout_sec=snippet_client_v2._SOCKET_READ_TIMEOUT, - default_timeout_sec=( - snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC)), + mock.call( + callback_id='1-0', + event_client=event_client, + ret_value=456, + method_name='some_async_rpc', + device=self.device, + rpc_max_timeout_sec=snippet_client_v2._SOCKET_READ_TIMEOUT, + default_timeout_sec=( + snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC + ), + ), mock.call( callback_id='2-0', event_client=event_client, @@ -329,13 +374,14 @@ def test_the_whole_lifecycle_with_multiple_rpcs(self, mock_callback_class, method_name='some_async_rpc', device=self.device, rpc_max_timeout_sec=snippet_client_v2._SOCKET_READ_TIMEOUT, - default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC) + default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC, + ), ] self.assertListEqual(rpc_results, rpc_results_expected) mock_callback_class.assert_has_calls(mock_callback_class_calls_expected) - self._assert_client_resources_released(mock_start_subprocess, - mock_stop_standing_subprocess, - mock_get_port) + self._assert_client_resources_released( + mock_start_subprocess, mock_stop_standing_subprocess, mock_get_port + ) self.assertIsNone(event_client.host_port, None) self.assertIsNone(event_client.device_port, None) @@ -355,18 +401,23 @@ def test_check_app_installed_fail_not_instrumented(self): """Tests that app checker fails without instrumenting app.""" self._make_client(_MockAdbProxy(installed_packages=[MOCK_PACKAGE_NAME])) expected_msg = ( - f'.* {MOCK_PACKAGE_NAME} is installed, but it is not instrumented.') + f'.* {MOCK_PACKAGE_NAME} is installed, but it is not instrumented.' + ) with self.assertRaisesRegex(errors.ServerStartPreCheckError, expected_msg): self.client._validate_snippet_app_on_device() def test_check_app_installed_fail_instrumentation_not_installed(self): """Tests that app checker fails without installing instrumentation.""" self._make_client( - _MockAdbProxy(instrumented_packages=[( - MOCK_PACKAGE_NAME, - snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE, - 'not.installed')])) - expected_msg = ('.* Instrumentation target not.installed is not installed.') + _MockAdbProxy( + instrumented_packages=[( + MOCK_PACKAGE_NAME, + snippet_client_v2._INSTRUMENTATION_RUNNER_PACKAGE, + 'not.installed', + )] + ) + ) + expected_msg = '.* Instrumentation target not.installed is not installed.' with self.assertRaisesRegex(errors.ServerStartPreCheckError, expected_msg): self.client._validate_snippet_app_on_device() @@ -379,7 +430,8 @@ def test_disable_hidden_api_normally(self): self.device.is_rootable = True self.client._disable_hidden_api_blocklist() self.adb.mock_shell_func.assert_called_with( - 'settings put global hidden_api_blacklist_exemptions "*"') + 'settings put global hidden_api_blacklist_exemptions "*"' + ) def test_disable_hidden_api_low_sdk(self): """Tests it doesn't disable hidden api with low SDK.""" @@ -401,8 +453,10 @@ def test_disable_hidden_api_non_rootable(self): self.client._disable_hidden_api_blocklist() self.adb.mock_shell_func.assert_not_called() - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch.object(_MockAdbProxy, 'shell', return_value=b'setsid') def test_start_server_with_user_id(self, mock_adb, mock_start_subprocess): """Tests that `--user` is added to starting command with SDK >= 24.""" @@ -411,20 +465,28 @@ def test_start_server_with_user_id(self, mock_adb, mock_start_subprocess): self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f'setsid am instrument --user {MOCK_USER_ID} -w -e action start ' - f'{MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + f'setsid am instrument --user {MOCK_USER_ID} -w -e action start ' + f'{MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) self.assertEqual(self.client.device_port, 1234) mock_adb.assert_called_with(['which', 'setsid']) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch.object(_MockAdbProxy, 'shell', return_value=b'setsid') - def test_start_server_with_config_specific_user_id(self, _, - mock_start_subprocess): + def test_start_server_with_config_specific_user_id( + self, _, mock_start_subprocess + ): """Tests that the correct `--user` argument is passed.""" self._make_client(config=snippet_client_v2.Config(user_id=42)) self._mock_server_process_starting_response(mock_start_subprocess) @@ -432,15 +494,22 @@ def test_start_server_with_config_specific_user_id(self, _, self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f'setsid am instrument --user 42 -w -e action start ' - f'{MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + 'setsid am instrument --user 42 -w -e action start ' + f'{MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch.object(_MockAdbProxy, 'shell', return_value=b'setsid') def test_start_server_without_user_id(self, mock_adb, mock_start_subprocess): """Tests that `--user` is not added to starting command on SDK < 24.""" @@ -449,41 +518,55 @@ def test_start_server_without_user_id(self, mock_adb, mock_start_subprocess): self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - f'setsid am instrument -w -e action start {MOCK_SERVER_PATH}' + 'adb', + 'shell', + f'setsid am instrument -w -e action start {MOCK_SERVER_PATH}', ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) mock_adb.assert_called_with(['which', 'setsid']) self.assertEqual(self.client.device_port, 1234) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch.object(_MockAdbProxy, - 'shell', - side_effect=adb.AdbError('cmd', 'stdout', 'stderr', - 'ret_code')) - def test_start_server_without_persisting_commands(self, mock_adb, - mock_start_subprocess): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch.object( + _MockAdbProxy, + 'shell', + side_effect=adb.AdbError('cmd', 'stdout', 'stderr', 'ret_code'), + ) + def test_start_server_without_persisting_commands( + self, mock_adb, mock_start_subprocess + ): """Checks the starting server command without persisting commands.""" self._make_client() self._mock_server_process_starting_response(mock_start_subprocess) self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f' am instrument --user {MOCK_USER_ID} -w -e action start ' - f'{MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + f' am instrument --user {MOCK_USER_ID} -w -e action start ' + f'{MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) mock_adb.assert_has_calls( - [mock.call(['which', 'setsid']), - mock.call(['which', 'nohup'])]) + [mock.call(['which', 'setsid']), mock.call(['which', 'nohup'])] + ) self.assertEqual(self.client.device_port, 1234) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_with_nohup(self, mock_start_subprocess): """Checks the starting server command with nohup.""" self._make_client() @@ -498,16 +581,23 @@ def _mocked_shell(arg): self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f'nohup am instrument --user {MOCK_USER_ID} -w -e action start ' - f'{MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + f'nohup am instrument --user {MOCK_USER_ID} -w -e action start ' + f'{MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) self.assertEqual(self.client.device_port, 1234) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_with_setsid(self, mock_start_subprocess): """Checks the starting server command with setsid.""" self._make_client() @@ -521,22 +611,28 @@ def _mocked_shell(arg): self.client._adb.shell = _mocked_shell self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f'setsid am instrument --user {MOCK_USER_ID} -w -e action start ' - f'{MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + f'setsid am instrument --user {MOCK_USER_ID} -w -e action start ' + f'{MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) self.assertEqual(self.client.device_port, 1234) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_with_instrument_options(self, mock_start_subprocess): """Checks the starting server command with instrument options.""" - config = snippet_client_v2.Config(am_instrument_options={ - 'key_1': 'val_1', - 'key_2': 'val_2' - },) + config = snippet_client_v2.Config( + am_instrument_options={'key_1': 'val_1', 'key_2': 'val_2'}, + ) instrument_options_str = '-e key_1 val_1 -e key_2 val_2' self._make_client(config=config) self._mock_server_process_starting_response(mock_start_subprocess) @@ -544,57 +640,79 @@ def test_start_server_with_instrument_options(self, mock_start_subprocess): self.client.start_server() start_cmd_list = [ - 'adb', 'shell', - (f' am instrument --user {MOCK_USER_ID} -w -e action start ' - f'{instrument_options_str} {MOCK_SERVER_PATH}') + 'adb', + 'shell', + ( + f' am instrument --user {MOCK_USER_ID} -w -e action start ' + f'{instrument_options_str} {MOCK_SERVER_PATH}' + ), ] - self.assertListEqual(mock_start_subprocess.call_args_list, - [mock.call(start_cmd_list, shell=False)]) + self.assertListEqual( + mock_start_subprocess.call_args_list, + [mock.call(start_cmd_list, shell=False)], + ) self.assertEqual(self.client.device_port, 1234) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_server_crash(self, mock_start_standing_subprocess): """Tests that starting server process crashes.""" self._make_client() self._mock_server_process_starting_response( mock_start_standing_subprocess, - resp_lines=[b'INSTRUMENTATION_RESULT: shortMsg=Process crashed.\n']) + resp_lines=[b'INSTRUMENTATION_RESULT: shortMsg=Process crashed.\n'], + ) with self.assertRaisesRegex( errors.ServerStartProtocolError, - 'INSTRUMENTATION_RESULT: shortMsg=Process crashed.'): + 'INSTRUMENTATION_RESULT: shortMsg=Process crashed.', + ): self.client.start_server() - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_unknown_protocol_version( - self, mock_start_standing_subprocess): + self, mock_start_standing_subprocess + ): """Tests that starting server process reports unknown protocol version.""" self._make_client() self._mock_server_process_starting_response( mock_start_standing_subprocess, - resp_lines=[b'SNIPPET START, PROTOCOL 99 0\n']) - with self.assertRaisesRegex(errors.ServerStartProtocolError, - 'SNIPPET START, PROTOCOL 99 0'): + resp_lines=[b'SNIPPET START, PROTOCOL 99 0\n'], + ) + with self.assertRaisesRegex( + errors.ServerStartProtocolError, 'SNIPPET START, PROTOCOL 99 0' + ): self.client.start_server() - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - def test_start_server_invalid_device_port(self, - mock_start_standing_subprocess): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + def test_start_server_invalid_device_port( + self, mock_start_standing_subprocess + ): """Tests that starting server process reports invalid device port.""" self._make_client() self._mock_server_process_starting_response( mock_start_standing_subprocess, resp_lines=[ - b'SNIPPET START, PROTOCOL 1 0\n', b'SNIPPET SERVING, PORT ABC\n' - ]) - with self.assertRaisesRegex(errors.ServerStartProtocolError, - 'SNIPPET SERVING, PORT ABC'): + b'SNIPPET START, PROTOCOL 1 0\n', + b'SNIPPET SERVING, PORT ABC\n', + ], + ) + with self.assertRaisesRegex( + errors.ServerStartProtocolError, 'SNIPPET SERVING, PORT ABC' + ): self.client.start_server() - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_with_junk(self, mock_start_standing_subprocess): """Tests that starting server process reports known protocol with junk.""" self._make_client() @@ -606,12 +724,15 @@ def test_start_server_with_junk(self, mock_start_standing_subprocess): b'SNIPPET START, PROTOCOL 1 0\n', b'Maybe in the middle too\n', b'SNIPPET SERVING, PORT 123\n', - ]) + ], + ) self.client.start_server() self.assertEqual(123, self.client.device_port) - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_start_server_no_valid_line(self, mock_start_standing_subprocess): """Tests that starting server process reports unknown protocol message.""" self._make_client() @@ -621,10 +742,12 @@ def test_start_server_no_valid_line(self, mock_start_standing_subprocess): b'This is some header junk\n', b'Some phones print arbitrary output\n', b'', # readline uses '' to mark EOF - ]) + ], + ) with self.assertRaisesRegex( errors.ServerStartError, - 'Unexpected EOF when waiting for server to start.'): + 'Unexpected EOF when waiting for server to start.', + ): self.client.start_server() @mock.patch('mobly.utils.stop_standing_subprocess') @@ -642,19 +765,22 @@ def test_stop_normally(self, mock_stop_standing_subprocess): self.assertIs(self.client._proc, None) self.adb.mock_shell_func.assert_called_once_with( f'am instrument --user {MOCK_USER_ID} -w -e action stop ' - f'{MOCK_SERVER_PATH}') + f'{MOCK_SERVER_PATH}' + ) mock_stop_standing_subprocess.assert_called_once_with(mock_proc) self.assertFalse(self.client.is_alive) self.assertIs(self.client._conn, None) mock_conn.close.assert_called_once_with() self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) self.assertIsNone(self.client._event_client) @mock.patch('mobly.utils.stop_standing_subprocess') - def test_stop_when_server_is_already_cleaned(self, - mock_stop_standing_subprocess): + def test_stop_when_server_is_already_cleaned( + self, mock_stop_standing_subprocess + ): """Tests that stop server process when subprocess is already cleaned.""" self._make_client() self.client._proc = None @@ -668,17 +794,20 @@ def test_stop_when_server_is_already_cleaned(self, mock_stop_standing_subprocess.assert_not_called() self.adb.assert_called_once_with( f'am instrument --user {MOCK_USER_ID} -w -e action stop ' - f'{MOCK_SERVER_PATH}') + f'{MOCK_SERVER_PATH}' + ) self.assertFalse(self.client.is_alive) self.assertIs(self.client._conn, None) mock_conn.close.assert_called_once_with() self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) @mock.patch('mobly.utils.stop_standing_subprocess') - def test_stop_when_conn_is_already_cleaned(self, - mock_stop_standing_subprocess): + def test_stop_when_conn_is_already_cleaned( + self, mock_stop_standing_subprocess + ): """Tests that stop server process when the connection is already closed.""" self._make_client() mock_proc = mock.Mock() @@ -692,17 +821,20 @@ def test_stop_when_conn_is_already_cleaned(self, mock_stop_standing_subprocess.assert_called_once_with(mock_proc) self.adb.assert_called_once_with( f'am instrument --user {MOCK_USER_ID} -w -e action stop ' - f'{MOCK_SERVER_PATH}') + f'{MOCK_SERVER_PATH}' + ) self.assertFalse(self.client.is_alive) self.assertIs(self.client._conn, None) self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(_MockAdbProxy, 'shell', return_value=b'Closed with error.') - def test_stop_with_device_side_error(self, mock_adb_shell, - mock_stop_standing_subprocess): + def test_stop_with_device_side_error( + self, mock_adb_shell, mock_stop_standing_subprocess + ): """Tests all resources will be cleaned when server stop throws an error.""" self._make_client() mock_proc = mock.Mock() @@ -710,21 +842,24 @@ def test_stop_with_device_side_error(self, mock_adb_shell, mock_conn = mock.Mock() self.client._conn = mock_conn self.client.host_port = 12345 - with self.assertRaisesRegex(android_device_lib_errors.DeviceError, - 'Closed with error'): + with self.assertRaisesRegex( + android_device_lib_errors.DeviceError, 'Closed with error' + ): self.client.stop() self.assertIs(self.client._proc, None) mock_stop_standing_subprocess.assert_called_once_with(mock_proc) mock_adb_shell.assert_called_once_with( f'am instrument --user {MOCK_USER_ID} -w -e action stop ' - f'{MOCK_SERVER_PATH}') + f'{MOCK_SERVER_PATH}' + ) self.assertFalse(self.client.is_alive) self.assertIs(self.client._conn, None) mock_conn.close.assert_called_once_with() self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) @mock.patch('mobly.utils.stop_standing_subprocess') def test_stop_with_conn_close_error(self, mock_stop_standing_subprocess): @@ -743,16 +878,22 @@ def test_stop_with_conn_close_error(self, mock_stop_standing_subprocess): self.client.stop() self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) @mock.patch('mobly.utils.stop_standing_subprocess') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'create_socket_connection') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'send_handshake_request') - def test_stop_with_event_client(self, mock_send_handshake_func, - mock_create_socket_conn_func, - mock_stop_standing_subprocess): + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'create_socket_connection' + ) + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'send_handshake_request' + ) + def test_stop_with_event_client( + self, + mock_send_handshake_func, + mock_create_socket_conn_func, + mock_stop_standing_subprocess, + ): """Tests that stopping with an event client works normally.""" del mock_send_handshake_func del mock_create_socket_conn_func @@ -779,16 +920,22 @@ def test_stop_with_event_client(self, mock_send_handshake_func, self.assertIsNone(self.client._event_client) self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) @mock.patch('mobly.utils.stop_standing_subprocess') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'create_socket_connection') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'send_handshake_request') + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'create_socket_connection' + ) + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'send_handshake_request' + ) def test_stop_with_event_client_stops_port_forwarding_once( - self, mock_send_handshake_func, mock_create_socket_conn_func, - mock_stop_standing_subprocess): + self, + mock_send_handshake_func, + mock_create_socket_conn_func, + mock_stop_standing_subprocess, + ): """Tests that client with an event client stops port forwarding once.""" del mock_send_handshake_func del mock_create_socket_conn_func @@ -805,7 +952,8 @@ def test_stop_with_event_client_stops_port_forwarding_once( self.assertIsNone(self.client._event_client) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:12345']) + ['--remove', 'tcp:12345'] + ) def test_close_connection_normally(self): """Tests that closing connection works normally.""" @@ -820,7 +968,8 @@ def test_close_connection_normally(self): self.assertIs(self.client.host_port, None) mock_conn.close.assert_called_once_with() self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:123']) + ['--remove', 'tcp:123'] + ) def test_close_connection_when_host_port_has_been_released(self): """Tests that close connection when the host port has been released.""" @@ -847,17 +996,22 @@ def test_close_connection_when_conn_have_been_closed(self): self.assertIs(self.client._conn, None) self.assertIs(self.client.host_port, None) self.device.adb.mock_forward_func.assert_called_once_with( - ['--remove', 'tcp:123']) + ['--remove', 'tcp:123'] + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - def test_send_sync_rpc_normally(self, mock_start_subprocess, - mock_socket_create_conn, mock_get_port): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + def test_send_sync_rpc_normally( + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests that sending a sync RPC works normally.""" del mock_get_port socket_resp = [ @@ -872,16 +1026,21 @@ def test_send_sync_rpc_normally(self, mock_start_subprocess, self.assertEqual(rpc_result, 123) self.mock_socket_file.write.assert_called_with( - b'{"id": 0, "method": "some_rpc", "params": [1, 2, "hello"]}\n') + b'{"id": 0, "method": "some_rpc", "params": [1, 2, "hello"]}\n' + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.callback_handler_v2.' - 'CallbackHandlerV2') - def test_async_rpc_start_event_client(self, mock_callback_class, - mock_start_subprocess, - mock_socket_create_conn): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.callback_handler_v2.' + 'CallbackHandlerV2' + ) + def test_async_rpc_start_event_client( + self, mock_callback_class, mock_start_subprocess, mock_socket_create_conn + ): """Tests that sending an async RPC starts the event client.""" socket_resp = [ b'{"status": true, "uid": 1}', @@ -891,15 +1050,19 @@ def test_async_rpc_start_event_client(self, mock_callback_class, ] socket_write_expected = [ mock.call(b'{"cmd": "initiate", "uid": -1}\n'), - mock.call(b'{"id": 0, "method": "some_async_rpc", ' - b'"params": [1, 2, "hello"]}\n'), + mock.call( + b'{"id": 0, "method": "some_async_rpc", ' + b'"params": [1, 2, "hello"]}\n' + ), mock.call(b'{"cmd": "continue", "uid": 1}\n'), - mock.call(b'{"id": 1, "method": "eventGetAll", ' - b'"params": ["1-0", "eventName"]}\n'), + mock.call( + b'{"id": 1, "method": "eventGetAll", ' + b'"params": ["1-0", "eventName"]}\n' + ), ] - self._make_client_and_mock_socket_conn(mock_socket_create_conn, - socket_resp, - set_counter=True) + self._make_client_and_mock_socket_conn( + mock_socket_create_conn, socket_resp, set_counter=True + ) self._mock_server_process_starting_response(mock_start_subprocess) self.client.host_port = 12345 @@ -913,7 +1076,8 @@ def test_async_rpc_start_event_client(self, mock_callback_class, method_name='some_async_rpc', device=self.device, rpc_max_timeout_sec=snippet_client_v2._SOCKET_READ_TIMEOUT, - default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC) + default_timeout_sec=snippet_client_v2._CALLBACK_DEFAULT_TIMEOUT_SEC, + ) self.assertIs(rpc_result, mock_callback_class.return_value) # Ensure the event client is alive @@ -937,19 +1101,23 @@ def test_async_rpc_start_event_client(self, mock_callback_class, ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.get_available_host_port') - def test_initialize_client_normally(self, mock_get_port, - mock_start_subprocess, - mock_socket_create_conn): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.get_available_host_port' + ) + def test_initialize_client_normally( + self, mock_get_port, mock_start_subprocess, mock_socket_create_conn + ): """Tests that initializing the client works normally.""" mock_get_port.return_value = 12345 socket_resp = [b'{"status": true, "uid": 1}'] - self._make_client_and_mock_socket_conn(mock_socket_create_conn, - socket_resp, - set_counter=True) + self._make_client_and_mock_socket_conn( + mock_socket_create_conn, socket_resp, set_counter=True + ) self._mock_server_process_starting_response(mock_start_subprocess) self.client.initialize() @@ -960,12 +1128,17 @@ def test_initialize_client_normally(self, mock_get_port, self.assertEqual(next(self.client._counter), 0) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.get_available_host_port') - def test_restore_event_client(self, mock_get_port, mock_start_subprocess, - mock_socket_create_conn): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.get_available_host_port' + ) + def test_restore_event_client( + self, mock_get_port, mock_start_subprocess, mock_socket_create_conn + ): """Tests restoring the event client.""" mock_get_port.return_value = 12345 socket_resp = [ @@ -1036,25 +1209,35 @@ def test_restore_event_client(self, mock_get_port, mock_start_subprocess, mock_socket_create_conn.side_effect = IOError('socket timed out') with self.assertRaisesRegex( errors.ServerRestoreConnectionError, - (f'Failed to restore server connection for {MOCK_PACKAGE_NAME} at ' - f'host port 56789, device port {MOCK_DEVICE_PORT}')): + ( + f'Failed to restore server connection for {MOCK_PACKAGE_NAME} at ' + f'host port 56789, device port {MOCK_DEVICE_PORT}' + ), + ): self.client.restore_server_connection() - self.assertListEqual(self.mock_socket_file.write.call_args_list, - socket_write_expected) + self.assertListEqual( + self.mock_socket_file.write.call_args_list, socket_write_expected + ) @mock.patch.object(snippet_client_v2.SnippetClientV2, '_make_connection') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'send_handshake_request') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'create_socket_connection') + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'send_handshake_request' + ) + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'create_socket_connection' + ) def test_restore_server_connection_with_event_client( - self, mock_create_socket_conn_func, mock_send_handshake_func, - mock_make_connection): + self, + mock_create_socket_conn_func, + mock_send_handshake_func, + mock_make_connection, + ): """Tests restoring server connection when the event client is not None.""" self._make_client() - event_client = snippet_client_v2.SnippetClientV2('mock-package', - mock.Mock()) + event_client = snippet_client_v2.SnippetClientV2( + 'mock-package', mock.Mock() + ) self.client._event_client = event_client self.client.device_port = 54321 self.client.uid = 5 @@ -1067,7 +1250,8 @@ def test_restore_server_connection_with_event_client( self.assertEqual(next(event_client._counter), 0) mock_create_socket_conn_func.assert_called_once_with() mock_send_handshake_func.assert_called_once_with( - -1, snippet_client_v2.ConnectionHandshakeCommand.INIT) + -1, snippet_client_v2.ConnectionHandshakeCommand.INIT + ) @mock.patch('builtins.print') def test_help_rpc_when_printing_by_default(self, mock_print): @@ -1094,14 +1278,18 @@ def test_help_rpc_when_not_printing(self, mock_print): mock_print.assert_not_called() @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) - def test_make_connection_normally(self, mock_get_port, mock_start_subprocess, - mock_socket_create_conn): + return_value=12345, + ) + def test_make_connection_normally( + self, mock_get_port, mock_start_subprocess, mock_socket_create_conn + ): """Tests that making a connection works normally.""" del mock_get_port socket_resp = [b'{"status": true, "uid": 1}'] @@ -1112,22 +1300,28 @@ def test_make_connection_normally(self, mock_get_port, mock_start_subprocess, self.assertEqual(self.client.uid, 1) self.assertEqual(self.client.device_port, MOCK_DEVICE_PORT) self.adb.mock_forward_func.assert_called_once_with( - ['tcp:12345', f'tcp:{MOCK_DEVICE_PORT}']) + ['tcp:12345', f'tcp:{MOCK_DEVICE_PORT}'] + ) mock_socket_create_conn.assert_called_once_with( - ('localhost', 12345), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT) + ('localhost', 12345), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT + ) self.socket_conn.settimeout.assert_called_once_with( - snippet_client_v2._SOCKET_READ_TIMEOUT) + snippet_client_v2._SOCKET_READ_TIMEOUT + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) - def test_make_connection_with_preset_host_port(self, mock_get_port, - mock_start_subprocess, - mock_socket_create_conn): + return_value=12345, + ) + def test_make_connection_with_preset_host_port( + self, mock_get_port, mock_start_subprocess, mock_socket_create_conn + ): """Tests that make a connection with the preset host port.""" del mock_get_port socket_resp = [b'{"status": true, "uid": 1}'] @@ -1140,21 +1334,28 @@ def test_make_connection_with_preset_host_port(self, mock_get_port, self.assertEqual(self.client.device_port, MOCK_DEVICE_PORT) # Test that the host port for forwarding is 23456 instead of 12345 self.adb.mock_forward_func.assert_called_once_with( - ['tcp:23456', f'tcp:{MOCK_DEVICE_PORT}']) + ['tcp:23456', f'tcp:{MOCK_DEVICE_PORT}'] + ) mock_socket_create_conn.assert_called_once_with( - ('localhost', 23456), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT) + ('localhost', 23456), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT + ) self.socket_conn.settimeout.assert_called_once_with( - snippet_client_v2._SOCKET_READ_TIMEOUT) + snippet_client_v2._SOCKET_READ_TIMEOUT + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) - def test_make_connection_with_ip(self, mock_get_port, mock_start_subprocess, - mock_socket_create_conn): + return_value=12345, + ) + def test_make_connection_with_ip( + self, mock_get_port, mock_start_subprocess, mock_socket_create_conn + ): """Tests that make a connection with 127.0.0.1 instead of localhost.""" del mock_get_port socket_resp = [b'{"status": true, "uid": 1}'] @@ -1177,19 +1378,24 @@ def _mock_create_conn_side_effect(address, *args, **kwargs): self.assertEqual(self.client.uid, 1) self.assertEqual(self.client.device_port, MOCK_DEVICE_PORT) self.adb.mock_forward_func.assert_called_once_with( - ['tcp:12345', f'tcp:{MOCK_DEVICE_PORT}']) + ['tcp:12345', f'tcp:{MOCK_DEVICE_PORT}'] + ) mock_socket_create_conn.assert_any_call( - ('127.0.0.1', 12345), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT) + ('127.0.0.1', 12345), snippet_client_v2._SOCKET_CONNECTION_TIMEOUT + ) self.socket_conn.settimeout.assert_called_once_with( - snippet_client_v2._SOCKET_READ_TIMEOUT) + snippet_client_v2._SOCKET_READ_TIMEOUT + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - def test_make_connection_io_error(self, mock_socket_create_conn, - mock_get_port): + def test_make_connection_io_error( + self, mock_socket_create_conn, mock_get_port + ): """Tests IOError occurred trying to create a socket connection.""" del mock_get_port mock_socket_create_conn.side_effect = IOError() @@ -1201,10 +1407,12 @@ def test_make_connection_io_error(self, mock_socket_create_conn, @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - def test_make_connection_timeout(self, mock_socket_create_conn, - mock_get_port): + def test_make_connection_timeout( + self, mock_socket_create_conn, mock_get_port + ): """Tests timeout occurred trying to create a socket connection.""" del mock_get_port mock_socket_create_conn.side_effect = socket.timeout @@ -1216,12 +1424,16 @@ def test_make_connection_timeout(self, mock_socket_create_conn, @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_make_connection_receives_none_handshake_response( - self, mock_start_subprocess, mock_socket_create_conn, mock_get_port): + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests make_connection receives None as the handshake response.""" del mock_get_port socket_resp = [None] @@ -1229,18 +1441,23 @@ def test_make_connection_receives_none_handshake_response( self._mock_server_process_starting_response(mock_start_subprocess) with self.assertRaisesRegex( - errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE): + errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE + ): self.client.make_connection() @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_make_connection_receives_empty_handshake_response( - self, mock_start_subprocess, mock_socket_create_conn, mock_get_port): + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests make_connection receives an empty handshake response.""" del mock_get_port socket_resp = [b''] @@ -1248,18 +1465,23 @@ def test_make_connection_receives_empty_handshake_response( self._mock_server_process_starting_response(mock_start_subprocess) with self.assertRaisesRegex( - errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE): + errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_HANDSHAKE + ): self.client.make_connection() @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_make_connection_receives_invalid_handshake_response( - self, mock_start_subprocess, mock_socket_create_conn, mock_get_port): + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests make_connection receives an invalid handshake response.""" del mock_get_port socket_resp = [b'{"status": false, "uid": 1}'] @@ -1272,14 +1494,16 @@ def test_make_connection_receives_invalid_handshake_response( @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') - def test_make_connection_send_handshake_request_error(self, - mock_start_subprocess, - mock_socket_create_conn, - mock_get_port): + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) + def test_make_connection_send_handshake_request_error( + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests that an error occurred trying to send a handshake request.""" del mock_get_port self._make_client_and_mock_socket_conn(mock_socket_create_conn) @@ -1292,18 +1516,23 @@ def test_make_connection_send_handshake_request_error(self, @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_make_connection_receive_handshake_response_error( - self, mock_start_subprocess, mock_socket_create_conn, mock_get_port): + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests that an error occurred trying to receive a handshake response.""" del mock_get_port self._make_client_and_mock_socket_conn(mock_socket_create_conn) self._mock_server_process_starting_response(mock_start_subprocess) self.mock_socket_file.readline.side_effect = socket.error( - 'Socket read error') + 'Socket read error' + ) with self.assertRaisesRegex(errors.Error, 'Socket read error'): self.client.make_connection() @@ -1311,12 +1540,16 @@ def test_make_connection_receive_handshake_response_error( @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.' 'utils.get_available_host_port', - return_value=12345) + return_value=12345, + ) @mock.patch('socket.create_connection') - @mock.patch('mobly.controllers.android_device_lib.snippet_client_v2.' - 'utils.start_standing_subprocess') + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.' + 'utils.start_standing_subprocess' + ) def test_make_connection_decode_handshake_response_bytes_error( - self, mock_start_subprocess, mock_socket_create_conn, mock_get_port): + self, mock_start_subprocess, mock_socket_create_conn, mock_get_port + ): """Tests that an error occurred trying to decode a handshake response.""" del mock_get_port self._make_client_and_mock_socket_conn(mock_socket_create_conn) @@ -1328,11 +1561,15 @@ def test_make_connection_decode_handshake_response_bytes_error( with self.assertRaises(UnicodeError): self.client.make_connection() - self.client.log.error.assert_has_calls([ - mock.call( - 'Failed to decode socket response bytes using encoding utf8: %s', - socket_response) - ]) + self.client.log.error.assert_has_calls( + [ + mock.call( + 'Failed to decode socket response bytes using encoding' + ' utf8: %s', + socket_response, + ) + ] + ) def test_rpc_sending_and_receiving(self): """Test RPC sending and receiving. @@ -1341,14 +1578,16 @@ def test_rpc_sending_and_receiving(self): """ self._make_client() rpc_request = '{"id": 0, "method": "some_rpc", "params": []}' - rpc_response_expected = ('{"id": 0, "result": 123, "error": null, ' - '"callback": null}') + rpc_response_expected = ( + '{"id": 0, "result": 123, "error": null, "callback": null}' + ) socket_write_expected = [ mock.call(b'{"id": 0, "method": "some_rpc", "params": []}\n') ] - socket_response = (b'{"id": 0, "result": 123, "error": null, ' - b'"callback": null}') + socket_response = ( + b'{"id": 0, "result": 123, "error": null, "callback": null}' + ) mock_socket_file = mock.Mock() mock_socket_file.readline.return_value = socket_response @@ -1357,8 +1596,9 @@ def test_rpc_sending_and_receiving(self): rpc_response = self.client.send_rpc_request(rpc_request) self.assertEqual(rpc_response, rpc_response_expected) - self.assertEqual(mock_socket_file.write.call_args_list, - socket_write_expected) + self.assertEqual( + mock_socket_file.write.call_args_list, socket_write_expected + ) def test_rpc_send_socket_write_error(self): """Tests that an error occurred trying to write the socket file.""" @@ -1387,26 +1627,33 @@ def test_rpc_send_decode_socket_response_bytes_error(self): self.client._client = mock.Mock() socket_response = bytes( '{"id": 0, "result": 123, "error": null, "callback": null}', - encoding='cp037') + encoding='cp037', + ) self.client._client.readline.return_value = socket_response rpc_request = '{"id": 0, "method": "some_rpc", "params": []}' with self.assertRaises(UnicodeError): self.client.send_rpc_request(rpc_request) - self.client.log.error.assert_has_calls([ - mock.call( - 'Failed to decode socket response bytes using encoding utf8: %s', - socket_response) - ]) - - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'send_handshake_request') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'create_socket_connection') - def test_make_conn_with_forwarded_port_init(self, - mock_create_socket_conn_func, - mock_send_handshake_func): + self.client.log.error.assert_has_calls( + [ + mock.call( + 'Failed to decode socket response bytes using encoding' + ' utf8: %s', + socket_response, + ) + ] + ) + + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'send_handshake_request' + ) + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'create_socket_connection' + ) + def test_make_conn_with_forwarded_port_init( + self, mock_create_socket_conn_func, mock_send_handshake_func + ): """Tests make_connection_with_forwarded_port initiates a new session.""" self._make_client() self.client._counter = None @@ -1417,27 +1664,32 @@ def test_make_conn_with_forwarded_port_init(self, self.assertEqual(next(self.client._counter), 0) mock_create_socket_conn_func.assert_called_once_with() mock_send_handshake_func.assert_called_once_with( - -1, snippet_client_v2.ConnectionHandshakeCommand.INIT) - - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'send_handshake_request') - @mock.patch.object(snippet_client_v2.SnippetClientV2, - 'create_socket_connection') - def test_make_conn_with_forwarded_port_continue(self, - mock_create_socket_conn_func, - mock_send_handshake_func): + -1, snippet_client_v2.ConnectionHandshakeCommand.INIT + ) + + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'send_handshake_request' + ) + @mock.patch.object( + snippet_client_v2.SnippetClientV2, 'create_socket_connection' + ) + def test_make_conn_with_forwarded_port_continue( + self, mock_create_socket_conn_func, mock_send_handshake_func + ): """Tests make_connection_with_forwarded_port continues current session.""" self._make_client() self.client._counter = None self.client.make_connection_with_forwarded_port( - 12345, 54321, 3, snippet_client_v2.ConnectionHandshakeCommand.CONTINUE) + 12345, 54321, 3, snippet_client_v2.ConnectionHandshakeCommand.CONTINUE + ) self.assertEqual(self.client.host_port, 12345) self.assertEqual(self.client.device_port, 54321) self.assertEqual(next(self.client._counter), 0) mock_create_socket_conn_func.assert_called_once_with() mock_send_handshake_func.assert_called_once_with( - 3, snippet_client_v2.ConnectionHandshakeCommand.CONTINUE) + 3, snippet_client_v2.ConnectionHandshakeCommand.CONTINUE + ) if __name__ == '__main__': diff --git a/tests/mobly/controllers/android_device_lib/snippet_event_test.py b/tests/mobly/controllers/android_device_lib/snippet_event_test.py index e59461c9..367a1399 100755 --- a/tests/mobly/controllers/android_device_lib/snippet_event_test.py +++ b/tests/mobly/controllers/android_device_lib/snippet_event_test.py @@ -25,14 +25,15 @@ class SnippetEventTest(unittest.TestCase): def test_basic(self): - """Verifies that an event object can be created and logged properly. - """ - event = snippet_event.SnippetEvent(MOCK_CALLBACK_ID, MOCK_EVENT_NAME, - MOCK_CREATION_TIME, MOCK_DATA) + """Verifies that an event object can be created and logged properly.""" + event = snippet_event.SnippetEvent( + MOCK_CALLBACK_ID, MOCK_EVENT_NAME, MOCK_CREATION_TIME, MOCK_DATA + ) self.assertEqual( repr(event), - "SnippetEvent(callback_id: myCallbackId, name: onXyzEvent, " - "creation_time: 12345678, data: {'foo': 'bar'})") + 'SnippetEvent(callback_id: myCallbackId, name: onXyzEvent, ' + "creation_time: 12345678, data: {'foo': 'bar'})", + ) if __name__ == '__main__': diff --git a/tests/mobly/controllers/android_device_test.py b/tests/mobly/controllers/android_device_test.py index a4354407..fc939dbb 100755 --- a/tests/mobly/controllers/android_device_test.py +++ b/tests/mobly/controllers/android_device_test.py @@ -50,68 +50,88 @@ def setUp(self): self.tmp_dir = tempfile.mkdtemp() def tearDown(self): - """Removes the temp dir. - """ + """Removes the temp dir.""" shutil.rmtree(self.tmp_dir) # Tests for android_device module functions. # These tests use mock AndroidDevice instances. - @mock.patch.object(android_device, - 'get_all_instances', - new=mock_android_device.get_all_instances) - @mock.patch.object(android_device, - 'list_adb_devices', - new=mock_android_device.list_adb_devices) - @mock.patch.object(android_device, - 'list_adb_devices_by_usb_id', - new=mock_android_device.list_adb_devices) + @mock.patch.object( + android_device, + 'get_all_instances', + new=mock_android_device.get_all_instances, + ) + @mock.patch.object( + android_device, + 'list_adb_devices', + new=mock_android_device.list_adb_devices, + ) + @mock.patch.object( + android_device, + 'list_adb_devices_by_usb_id', + new=mock_android_device.list_adb_devices, + ) def test_create_with_pickup_all(self): pick_all_token = android_device.ANDROID_DEVICE_PICK_ALL_TOKEN actual_ads = android_device.create(pick_all_token) - for actual, expected in zip(actual_ads, - mock_android_device.get_mock_ads(5)): + for actual, expected in zip( + actual_ads, mock_android_device.get_mock_ads(5) + ): self.assertEqual(actual.serial, expected.serial) - @mock.patch.object(android_device, - 'get_instances', - new=mock_android_device.get_instances) - @mock.patch.object(android_device, - 'list_adb_devices', - new=mock_android_device.list_adb_devices) - @mock.patch.object(android_device, - 'list_adb_devices_by_usb_id', - new=mock_android_device.list_adb_devices) + @mock.patch.object( + android_device, 'get_instances', new=mock_android_device.get_instances + ) + @mock.patch.object( + android_device, + 'list_adb_devices', + new=mock_android_device.list_adb_devices, + ) + @mock.patch.object( + android_device, + 'list_adb_devices_by_usb_id', + new=mock_android_device.list_adb_devices, + ) def test_create_with_string_list(self): - string_list = [u'1', '2'] + string_list = ['1', '2'] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) - @mock.patch.object(android_device, - 'get_instances_with_configs', - new=mock_android_device.get_instances_with_configs) - @mock.patch.object(android_device, - 'list_adb_devices', - new=mock_android_device.list_adb_devices) - @mock.patch.object(android_device, - 'list_adb_devices_by_usb_id', - new=mock_android_device.list_adb_devices) + @mock.patch.object( + android_device, + 'get_instances_with_configs', + new=mock_android_device.get_instances_with_configs, + ) + @mock.patch.object( + android_device, + 'list_adb_devices', + new=mock_android_device.list_adb_devices, + ) + @mock.patch.object( + android_device, + 'list_adb_devices_by_usb_id', + new=mock_android_device.list_adb_devices, + ) def test_create_with_dict_list(self): string_list = [{'serial': '1'}, {'serial': '2'}] actual_ads = android_device.create(string_list) for actual_ad, expected_serial in zip(actual_ads, ['1', '2']): self.assertEqual(actual_ad.serial, expected_serial) - @mock.patch.object(android_device, - 'get_instances_with_configs', - new=mock_android_device.get_instances_with_configs) - @mock.patch.object(android_device, - 'list_adb_devices', - new=mock_android_device.list_adb_devices) - @mock.patch.object(android_device, - 'list_adb_devices_by_usb_id', - return_value=['usb:1']) + @mock.patch.object( + android_device, + 'get_instances_with_configs', + new=mock_android_device.get_instances_with_configs, + ) + @mock.patch.object( + android_device, + 'list_adb_devices', + new=mock_android_device.list_adb_devices, + ) + @mock.patch.object( + android_device, 'list_adb_devices_by_usb_id', return_value=['usb:1'] + ) def test_create_with_usb_id(self, mock_list_adb_devices_by_usb_id): string_list = [{'serial': '1'}, {'serial': '2'}, {'serial': 'usb:1'}] actual_ads = android_device.create(string_list) @@ -137,8 +157,9 @@ def test_create_with_no_valid_config(self): @mock.patch('mobly.controllers.android_device.list_adb_devices') @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id') @mock.patch('mobly.controllers.android_device.AndroidDevice') - def test_get_instances(self, mock_ad_class, mock_list_adb_usb, mock_list_adb, - mock_list_fastboot): + def test_get_instances( + self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot + ): mock_list_fastboot.return_value = ['0'] mock_list_adb.return_value = ['1'] mock_list_adb_usb.return_value = [] @@ -150,14 +171,15 @@ def test_get_instances(self, mock_ad_class, mock_list_adb_usb, mock_list_adb, @mock.patch('mobly.controllers.android_device.list_adb_devices') @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id') @mock.patch('mobly.controllers.android_device.AndroidDevice') - def test_get_instances_do_not_exist(self, mock_ad_class, mock_list_adb_usb, - mock_list_adb, mock_list_fastboot): + def test_get_instances_do_not_exist( + self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot + ): mock_list_fastboot.return_value = [] mock_list_adb.return_value = [] mock_list_adb_usb.return_value = [] with self.assertRaisesRegex( errors.Error, - 'Android device serial "1" is specified in config but is not reachable' + 'Android device serial "1" is specified in config but is not reachable', ): android_device.get_instances(['1']) @@ -165,8 +187,9 @@ def test_get_instances_do_not_exist(self, mock_ad_class, mock_list_adb_usb, @mock.patch('mobly.controllers.android_device.list_adb_devices') @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id') @mock.patch('mobly.controllers.android_device.AndroidDevice') - def test_get_instances_with_configs(self, mock_ad_class, mock_list_adb_usb, - mock_list_adb, mock_list_fastboot): + def test_get_instances_with_configs( + self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot + ): mock_list_fastboot.return_value = ['1'] mock_list_adb.return_value = ['2'] mock_list_adb_usb.return_value = [] @@ -179,24 +202,24 @@ def test_get_instances_with_configs_invalid_config(self): config = {'something': 'random'} with self.assertRaisesRegex( errors.Error, - f'Required value "serial" is missing in AndroidDevice config {config}'): + f'Required value "serial" is missing in AndroidDevice config {config}', + ): android_device.get_instances_with_configs([config]) @mock.patch('mobly.controllers.android_device.list_fastboot_devices') @mock.patch('mobly.controllers.android_device.list_adb_devices') @mock.patch('mobly.controllers.android_device.list_adb_devices_by_usb_id') @mock.patch('mobly.controllers.android_device.AndroidDevice') - def test_get_instances_with_configsdo_not_exist(self, mock_ad_class, - mock_list_adb_usb, - mock_list_adb, - mock_list_fastboot): + def test_get_instances_with_configsdo_not_exist( + self, mock_ad_class, mock_list_adb_usb, mock_list_adb, mock_list_fastboot + ): mock_list_fastboot.return_value = [] mock_list_adb.return_value = [] mock_list_adb_usb.return_value = [] config = {'serial': '1'} with self.assertRaisesRegex( errors.Error, - 'Android device serial "1" is specified in config but is not reachable' + 'Android device serial "1" is specified in config but is not reachable', ): android_device.get_instances_with_configs([config]) @@ -213,8 +236,10 @@ def test_get_devices_success_with_extra_field(self): def test_get_devices_no_match(self): ads = mock_android_device.get_mock_ads(5) - expected_msg = ('Could not find a target device that matches condition' - ": {'label': 'selected'}.") + expected_msg = ( + 'Could not find a target device that matches condition' + ": {'label': 'selected'}." + ) with self.assertRaisesRegex(android_device.Error, expected_msg): selected_ads = android_device.get_devices(ads, label='selected') @@ -229,16 +254,17 @@ def test_get_device_success_with_serial_and_extra_field(self): expected_serial = '1' expected_h_port = 5555 ads[1].h_port = expected_h_port - ad = android_device.get_device(ads, - serial=expected_serial, - h_port=expected_h_port) + ad = android_device.get_device( + ads, serial=expected_serial, h_port=expected_h_port + ) self.assertEqual(ad.serial, expected_serial) self.assertEqual(ad.h_port, expected_h_port) def test_get_device_no_match(self): ads = mock_android_device.get_mock_ads(5) - expected_msg = ('Could not find a target device that matches condition' - ": {'serial': 5}.") + expected_msg = ( + "Could not find a target device that matches condition: {'serial': 5}." + ) with self.assertRaisesRegex(android_device.Error, expected_msg): ad = android_device.get_device(ads, serial=len(ads)) @@ -261,7 +287,8 @@ def test_start_services_on_ads(self): ad.skip_logcat = False ad.is_required = True ads[1].services.logcat.start = mock.MagicMock( - side_effect=android_device.Error(msg)) + side_effect=android_device.Error(msg) + ) with self.assertRaisesRegex(android_device.Error, msg): android_device._start_services_on_ads(ads) ads[0].services.stop_all.assert_called_once_with() @@ -273,35 +300,36 @@ def test_start_services_on_ads_skip_logcat(self): ads[0].services.logcat.start = mock.MagicMock() ads[1].services.logcat.start = mock.MagicMock() ads[2].services.logcat.start = mock.MagicMock( - side_effect=Exception('Should not have called this.')) + side_effect=Exception('Should not have called this.') + ) ads[2].skip_logcat = True android_device._start_services_on_ads(ads) def test_take_bug_reports(self): ads = mock_android_device.get_mock_ads(3) android_device.take_bug_reports(ads, 'test_something', 'sometime') - ads[0].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='sometime', - destination=None) - ads[1].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='sometime', - destination=None) - ads[2].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='sometime', - destination=None) + ads[0].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='sometime', destination=None + ) + ads[1].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='sometime', destination=None + ) + ads[2].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='sometime', destination=None + ) def test_take_bug_reports_with_int_begin_time(self): ads = mock_android_device.get_mock_ads(3) android_device.take_bug_reports(ads, 'test_something', 123) - ads[0].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='123', - destination=None) - ads[1].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='123', - destination=None) - ads[2].take_bug_report.assert_called_once_with(test_name='test_something', - begin_time='123', - destination=None) + ads[0].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='123', destination=None + ) + ads[1].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='123', destination=None + ) + ads[2].take_bug_report.assert_called_once_with( + test_name='test_something', begin_time='123', destination=None + ) @mock.patch('mobly.logger.get_log_file_timestamp') def test_take_bug_reports_with_none_values(self, get_log_file_timestamp_mock): @@ -309,24 +337,28 @@ def test_take_bug_reports_with_none_values(self, get_log_file_timestamp_mock): get_log_file_timestamp_mock.return_value = mock_timestamp ads = mock_android_device.get_mock_ads(3) android_device.take_bug_reports(ads) - ads[0].take_bug_report.assert_called_once_with(test_name=None, - begin_time=mock_timestamp, - destination=None) - ads[1].take_bug_report.assert_called_once_with(test_name=None, - begin_time=mock_timestamp, - destination=None) - ads[2].take_bug_report.assert_called_once_with(test_name=None, - begin_time=mock_timestamp, - destination=None) + ads[0].take_bug_report.assert_called_once_with( + test_name=None, begin_time=mock_timestamp, destination=None + ) + ads[1].take_bug_report.assert_called_once_with( + test_name=None, begin_time=mock_timestamp, destination=None + ) + ads[2].take_bug_report.assert_called_once_with( + test_name=None, begin_time=mock_timestamp, destination=None + ) # Tests for android_device.AndroidDevice class. # These tests mock out any interaction with the OS and real android device # in AndroidDeivce. - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. @@ -335,19 +367,25 @@ def test_AndroidDevice_instantiation(self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.serial, '1') self.assertEqual(ad.model, 'fakemodel') - expected_lp = os.path.join(logging.log_path, - 'AndroidDevice%s' % mock_serial) + expected_lp = os.path.join( + logging.log_path, 'AndroidDevice%s' % mock_serial + ) self.assertEqual(ad.log_path, expected_lp) self.assertIsNotNone(ad.services.logcat) self.assertIsNotNone(ad.services.snippets) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') - def test_AndroidDevice_load_config(self, create_dir_mock, FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_load_config( + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' config = {'space': 'the final frontier', 'number': 1, 'debug_tag': 'my_tag'} ad = android_device.AndroidDevice(serial=mock_serial) @@ -356,24 +394,34 @@ def test_AndroidDevice_load_config(self, create_dir_mock, FastbootProxy, self.assertEqual(ad.number, 1) self.assertEqual(ad.debug_tag, 'my_tag') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') - def test_AndroidDevice_load_config_dup(self, create_dir_mock, FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_load_config_dup( + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' config = {'serial': 'new_serial'} ad = android_device.AndroidDevice(serial=mock_serial) - with self.assertRaisesRegex(android_device.DeviceError, - 'Attribute serial already exists with'): + with self.assertRaisesRegex( + android_device.DeviceError, 'Attribute serial already exists with' + ): ad.load_config(config) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. @@ -382,8 +430,10 @@ def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): build_info = ad.build_info self.assertEqual(build_info['build_id'], 'AB42') self.assertEqual(build_info['build_type'], 'userdebug') - self.assertEqual(build_info['build_fingerprint'], - 'FakeModel:Dessert/AB42/1234567:userdebug/dev-keys') + self.assertEqual( + build_info['build_fingerprint'], + 'FakeModel:Dessert/AB42/1234567:userdebug/dev-keys', + ) self.assertEqual(build_info['build_version_codename'], 'Z') self.assertEqual(build_info['build_version_incremental'], '1234567') self.assertEqual(build_info['build_version_sdk'], '28') @@ -394,17 +444,23 @@ def test_AndroidDevice_build_info(self, MockFastboot, MockAdbProxy): self.assertEqual(build_info['hardware'], 'marlin') self.assertEqual(len(build_info), len(android_device.CACHED_SYSTEM_PROPS)) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - '1', - mock_properties={ - 'ro.build.id': 'AB42', - 'ro.build.type': 'userdebug', - })) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + '1', + mock_properties={ + 'ro.build.id': 'AB42', + 'ro.build.type': 'userdebug', + }, + ), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_build_info_with_minimal_properties( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') build_info = ad.build_info self.assertEqual(build_info['build_id'], 'AB42') @@ -419,10 +475,14 @@ def test_AndroidDevice_build_info_with_minimal_properties( self.assertEqual(build_info['debuggable'], '') self.assertEqual(build_info['hardware'], '') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_build_info_cached(self, MockFastboot, MockAdbProxy): """Verifies the AndroidDevice object's basic attributes are correctly set after instantiation. @@ -433,40 +493,56 @@ def test_AndroidDevice_build_info_cached(self, MockFastboot, MockAdbProxy): _ = ad.build_info self.assertEqual(ad.adb.getprops_call_count, 1) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - '1', - mock_properties={ - 'ro.build.id': 'AB42', - 'ro.build.type': 'userdebug', - 'ro.debuggable': '1', - })) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + '1', + mock_properties={ + 'ro.build.id': 'AB42', + 'ro.build.type': 'userdebug', + 'ro.debuggable': '1', + }, + ), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_is_rootable_when_userdebug_device( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') self.assertTrue(ad.is_rootable) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - '1', - mock_properties={ - 'ro.build.id': 'AB42', - 'ro.build.type': 'user', - 'ro.debuggable': '0', - })) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) - def test_AndroidDevice_is_rootable_when_user_device(self, MockFastboot, - MockAdbProxy): + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + '1', + mock_properties={ + 'ro.build.id': 'AB42', + 'ro.build.type': 'user', + 'ro.debuggable': '0', + }, + ), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + def test_AndroidDevice_is_rootable_when_user_device( + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') self.assertFalse(ad.is_rootable) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial=1) device_info = ad.device_info @@ -480,237 +556,328 @@ def test_AndroidDevice_device_info(self, MockFastboot, MockAdbProxy): self.assertEqual(device_info['user_added_info']['sim_type'], 'Fi') self.assertEqual(device_info['user_added_info']['build_id'], 'CD42') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_serial_is_valid(self, MockFastboot, MockAdbProxy): - """Verifies that the serial is a primitive string type and serializable. - """ + """Verifies that the serial is a primitive string type and serializable.""" ad = android_device.AndroidDevice(serial=1) self.assertTrue(isinstance(ad.serial, str)) yaml.safe_dump(ad.serial) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_is_emulator_when_realish_device( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') self.assertFalse(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('localhost:123')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('localhost:123'), + ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('localhost:123')) + return_value=mock_android_device.MockFastbootProxy('localhost:123'), + ) def test_AndroidDevice_is_emulator_when_local_networked_device( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): # Although these devices are usually emulators, there might be a reason # to do this with a real device. ad = android_device.AndroidDevice(serial='localhost:123') self.assertFalse(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('example.com:123')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('example:123')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('example.com:123'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('example:123'), + ) def test_AndroidDevice_is_emulator_when_remote_networked_device( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='example.com:123') self.assertFalse(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - 'localhost:5554', - mock_properties={ - 'ro.hardware': 'ranchu', - 'ro.build.id': 'AB42', - 'ro.build.type': 'userdebug', - })) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + 'localhost:5554', + mock_properties={ + 'ro.hardware': 'ranchu', + 'ro.build.id': 'AB42', + 'ro.build.type': 'userdebug', + }, + ), + ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('localhost:5554')) - def test_AndroidDevice_is_emulator_when_ranchu_device(self, MockFastboot, - MockAdbProxy): + return_value=mock_android_device.MockFastbootProxy('localhost:5554'), + ) + def test_AndroidDevice_is_emulator_when_ranchu_device( + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='localhost:5554') self.assertTrue(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - '1', - mock_properties={ - 'ro.build.id': 'AB42', - 'ro.build.type': 'userdebug', - 'ro.hardware': 'goldfish', - })) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + '1', + mock_properties={ + 'ro.build.id': 'AB42', + 'ro.build.type': 'userdebug', + 'ro.hardware': 'goldfish', + }, + ), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_is_emulator_when_goldfish_device( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') self.assertTrue(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - 'example.com:123', - mock_properties={ - 'ro.build.id': 'AB42', - 'ro.build.type': 'userdebug', - 'ro.build.characteristics': 'emulator', - })) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy( + 'example.com:123', + mock_properties={ + 'ro.build.id': 'AB42', + 'ro.build.type': 'userdebug', + 'ro.build.characteristics': 'emulator', + }, + ), + ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('example.com:123')) + return_value=mock_android_device.MockFastbootProxy('example.com:123'), + ) def test_AndroidDevice_is_emulator_when_emulator_characteristic( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='example.com:123') self.assertTrue(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('emulator-5554')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('emulator-5554'), + ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('emulator-5554')) + return_value=mock_android_device.MockFastbootProxy('emulator-5554'), + ) def test_AndroidDevice_is_emulator_when_emulator_serial( - self, MockFastboot, MockAdbProxy): + self, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='emulator-5554') self.assertTrue(ad.is_emulator) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) - @mock.patch('mobly.controllers.android_device.list_fastboot_devices', - return_value='1') + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device.list_fastboot_devices', return_value='1' + ) def test_AndroidDevice_is_fastboot(self, _, MockFastboot, MockAdbProxy): ad = android_device.AndroidDevice(serial='1') self.assertTrue(ad.is_bootloader) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') - def test_AndroidDevice_generate_filename_default(self, - get_log_file_timestamp_mock, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_generate_filename_default( + self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy + ): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' filename = ad.generate_filename('MagicLog') self.assertEqual(filename, 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') @mock.patch('mobly.logger.sanitize_filename') def test_AndroidDevice_generate_filename_assert_sanitation( - self, sanitize_filename_mock, get_log_file_timestamp_mock, MockFastboot, - MockAdbProxy): + self, + sanitize_filename_mock, + get_log_file_timestamp_mock, + MockFastboot, + MockAdbProxy, + ): mock_serial = 1 sanitize_filename_mock.return_value = '1' ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' filename = ad.generate_filename('MagicLog') sanitize_filename_mock.assert_called_with( - 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450') + 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450' + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') - def test_AndroidDevice_generate_filename_with_ext(self, - get_log_file_timestamp_mock, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_generate_filename_with_ext( + self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy + ): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' filename = ad.generate_filename('MagicLog', extension_name='log') - self.assertEqual(filename, - 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450.log') + self.assertEqual( + filename, 'MagicLog,1,fakemodel,07-22-2019_17-53-34-450.log' + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_generate_filename_with_debug_tag( - self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy): + self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy + ): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' ad.debug_tag = 'RoleX' filename = ad.generate_filename('MagicLog') - self.assertEqual(filename, - 'MagicLog,RoleX,1,fakemodel,07-22-2019_17-53-34-450') + self.assertEqual( + filename, 'MagicLog,RoleX,1,fakemodel,07-22-2019_17-53-34-450' + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_generate_filename_with_runtime_info( - self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy): + self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy + ): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' - mock_record = mock.MagicMock(test_name='test_xyz', - begin_time='1234567', - signature='test_xyz-1234567') - mock_test_info = runtime_test_info.RuntimeTestInfo(mock_record.test_name, - '/tmp/blah/', - mock_record) + mock_record = mock.MagicMock( + test_name='test_xyz', begin_time='1234567', signature='test_xyz-1234567' + ) + mock_test_info = runtime_test_info.RuntimeTestInfo( + mock_record.test_name, '/tmp/blah/', mock_record + ) filename = ad.generate_filename('MagicLog', time_identifier=mock_test_info) self.assertEqual(filename, 'MagicLog,1,fakemodel,test_xyz-1234567') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_generate_filename_with_custom_timestamp( - self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy): + self, get_log_file_timestamp_mock, MockFastboot, MockAdbProxy + ): mock_serial = 1 ad = android_device.AndroidDevice(serial=mock_serial) get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' - filename = ad.generate_filename('MagicLog', - time_identifier='my_special_time') + filename = ad.generate_filename( + 'MagicLog', time_identifier='my_special_time' + ) self.assertEqual(filename, 'MagicLog,1,fakemodel,my_special_time') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') - def test_AndroidDevice_take_bug_report(self, create_dir_mock, FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_take_bug_report( + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): """Verifies AndroidDevice.take_bug_report calls the correct adb command and writes the bugreport file to the correct path. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) - output_path = ad.take_bug_report(test_name='test_something', - begin_time='sometime') - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + output_path = ad.take_bug_report( + test_name='test_something', begin_time='sometime' + ) + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, - os.path.join(expected_path, - 'bugreport,test_something,1,fakemodel,sometime.zip')) + os.path.join( + expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1', fail_br=True)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1', fail_br=True), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') - def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock, - FastbootProxy, MockAdbProxy): + def test_AndroidDevice_take_bug_report_fail( + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): """Verifies AndroidDevice.take_bug_report writes out the correct message when taking bugreport fails. """ @@ -720,170 +887,247 @@ def test_AndroidDevice_take_bug_report_fail(self, create_dir_mock, with self.assertRaisesRegex(android_device.Error, expected_msg): ad.take_bug_report(test_name='test_something', begin_time='sometime') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_take_bug_report_without_args( - self, get_log_file_timestamp_mock, create_dir_mock, FastbootProxy, - MockAdbProxy): + self, + get_log_file_timestamp_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report() - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) self.assertEqual( output_path, - os.path.join(expected_path, - 'bugreport,1,fakemodel,07-22-2019_17-53-34-450.zip')) + os.path.join( + expected_path, 'bugreport,1,fakemodel,07-22-2019_17-53-34-450.zip' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_take_bug_report_with_only_test_name( - self, get_log_file_timestamp_mock, create_dir_mock, FastbootProxy, - MockAdbProxy): + self, + get_log_file_timestamp_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(test_name='test_something') - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, os.path.join( expected_path, - 'bugreport,test_something,1,fakemodel,07-22-2019_17-53-34-450.zip')) + 'bugreport,test_something,1,fakemodel,07-22-2019_17-53-34-450.zip', + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_only_begin_time( - self, create_dir_mock, FastbootProxy, MockAdbProxy): + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(begin_time='sometime') - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, - os.path.join(expected_path, 'bugreport,1,fakemodel,sometime.zip')) + os.path.join(expected_path, 'bugreport,1,fakemodel,sometime.zip'), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_int_begin_time( - self, create_dir_mock, FastbootProxy, MockAdbProxy): + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report(begin_time=123) - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( - output_path, os.path.join(expected_path, - 'bugreport,1,fakemodel,123.zip')) + output_path, + os.path.join(expected_path, 'bugreport,1,fakemodel,123.zip'), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_positional_args( - self, create_dir_mock, FastbootProxy, MockAdbProxy): + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) output_path = ad.take_bug_report('test_something', 'sometime') - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, - os.path.join(expected_path, - 'bugreport,test_something,1,fakemodel,sometime.zip')) + os.path.join( + expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') def test_AndroidDevice_take_bug_report_with_destination( - self, create_dir_mock, FastbootProxy, MockAdbProxy): + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) dest = tempfile.gettempdir() - output_path = ad.take_bug_report(test_name="test_something", - begin_time="sometime", - destination=dest) + output_path = ad.take_bug_report( + test_name='test_something', begin_time='sometime', destination=dest + ) expected_path = os.path.join(dest) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, - os.path.join(expected_path, - 'bugreport,test_something,1,fakemodel,sometime.zip')) - - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy( - '1', fail_br_before_N=True)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + os.path.join( + expected_path, 'bugreport,test_something,1,fakemodel,sometime.zip' + ), + ) + + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1', fail_br_before_N=True), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') - def test_AndroidDevice_take_bug_report_fallback(self, create_dir_mock, - FastbootProxy, MockAdbProxy): + def test_AndroidDevice_take_bug_report_fallback( + self, create_dir_mock, FastbootProxy, MockAdbProxy + ): """Verifies AndroidDevice.take_bug_report falls back to traditional bugreport on builds that do not have bugreportz. """ mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) - output_path = ad.take_bug_report(test_name='test_something', - begin_time='sometime') - expected_path = os.path.join(logging.log_path, - 'AndroidDevice%s' % ad.serial, 'BugReports') + output_path = ad.take_bug_report( + test_name='test_something', begin_time='sometime' + ) + expected_path = os.path.join( + logging.log_path, 'AndroidDevice%s' % ad.serial, 'BugReports' + ) create_dir_mock.assert_called_with(expected_path) self.assertEqual( output_path, - os.path.join(expected_path, - 'bugreport,test_something,1,fakemodel,sometime.txt')) + os.path.join( + expected_path, 'bugreport,test_something,1,fakemodel,sometime.txt' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.logger.get_log_file_timestamp') - def test_AndroidDevice_take_screenshot(self, get_log_file_timestamp_mock, - create_dir_mock, FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_take_screenshot( + self, + get_log_file_timestamp_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) full_pic_path = ad.take_screenshot(self.tmp_dir) self.assertEqual( full_pic_path, - os.path.join(self.tmp_dir, - 'screenshot,1,fakemodel,07-22-2019_17-53-34-450.png')) + os.path.join( + self.tmp_dir, 'screenshot,1,fakemodel,07-22-2019_17-53-34-450.png' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.logger.get_log_file_timestamp') def test_AndroidDevice_take_screenshot_with_prefix( - self, get_log_file_timestamp_mock, create_dir_mock, FastbootProxy, - MockAdbProxy): + self, + get_log_file_timestamp_mock, + create_dir_mock, + FastbootProxy, + MockAdbProxy, + ): get_log_file_timestamp_mock.return_value = '07-22-2019_17-53-34-450' mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) @@ -892,17 +1136,24 @@ def test_AndroidDevice_take_screenshot_with_prefix( self.assertEqual( full_pic_path, - os.path.join(self.tmp_dir, - 'page_a,1,fakemodel,07-22-2019_17-53-34-450.png')) + os.path.join( + self.tmp_dir, 'page_a,1,fakemodel,07-22-2019_17-53-34-450.png' + ), + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_AndroidDevice_change_log_path(self, stop_proc_mock, start_proc_mock, - FastbootProxy, MockAdbProxy): + def test_AndroidDevice_change_log_path( + self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') old_path = ad.log_path new_log_path = tempfile.mkdtemp() @@ -910,16 +1161,19 @@ def test_AndroidDevice_change_log_path(self, stop_proc_mock, start_proc_mock, self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_AndroidDevice_change_log_path_no_log_exists(self, stop_proc_mock, - start_proc_mock, - FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_change_log_path_no_log_exists( + self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') old_path = ad.log_path new_log_path = tempfile.mkdtemp() @@ -927,30 +1181,44 @@ def test_AndroidDevice_change_log_path_no_log_exists(self, stop_proc_mock, self.assertTrue(os.path.exists(new_log_path)) self.assertFalse(os.path.exists(old_path)) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('127.0.0.1:5557')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('127.0.0.1:5557'), + ) @mock.patch( 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('127.0.0.1:5557')) + return_value=mock_android_device.MockFastbootProxy('127.0.0.1:5557'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_with_reserved_character_in_serial_log_path( - self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy): + self, stop_proc_mock, start_proc_mock, FastbootProxy, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='127.0.0.1:5557') base_log_path = os.path.basename(ad.log_path) self.assertEqual(base_log_path, 'AndroidDevice127.0.0.1-5557') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_AndroidDevice_change_log_path_with_service( - self, open_logcat_mock, stop_proc_mock, start_proc_mock, creat_dir_mock, - FastbootProxy, MockAdbProxy): + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + creat_dir_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') ad.services.logcat.start() new_log_path = tempfile.mkdtemp() @@ -958,35 +1226,53 @@ def test_AndroidDevice_change_log_path_with_service( with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') def test_AndroidDevice_change_log_path_with_existing_file( - self, stop_proc_mock, start_proc_mock, creat_dir_mock, FastbootProxy, - MockAdbProxy): + self, + stop_proc_mock, + start_proc_mock, + creat_dir_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') new_log_path = tempfile.mkdtemp() new_file_path = os.path.join(new_log_path, 'file.txt') with io.open(new_file_path, 'w', encoding='utf-8') as f: - f.write(u'hahah.') + f.write('hahah.') expected_msg = '.* Logs already exist .*' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.log_path = new_log_path - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') - def test_AndroidDevice_update_serial(self, stop_proc_mock, start_proc_mock, - creat_dir_mock, FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_update_serial( + self, + stop_proc_mock, + start_proc_mock, + creat_dir_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') ad.update_serial('2') self.assertEqual(ad.serial, '2') @@ -994,114 +1280,160 @@ def test_AndroidDevice_update_serial(self, stop_proc_mock, start_proc_mock, self.assertEqual(ad.adb.serial, ad.serial) self.assertEqual(ad.fastboot.serial, ad.serial) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.create_dir') @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_AndroidDevice_update_serial_with_service_running( - self, open_logcat_mock, stop_proc_mock, start_proc_mock, creat_dir_mock, - FastbootProxy, MockAdbProxy): + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + creat_dir_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') ad.services.logcat.start() - expected_msg = '.* Cannot change device serial number when there is service running.' + expected_msg = ( + '.* Cannot change device serial number when there is service running.' + ) with self.assertRaisesRegex(android_device.Error, expected_msg): ad.update_serial('2') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_load_snippet(self, MockGetPort, MockSnippetClient, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_load_snippet( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_getattr(self, MockGetPort, MockSnippetClient, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_getattr( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) value = {'value': 42} actual_value = getattr(ad, 'some_attr', value) self.assertEqual(actual_value, value) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2', - return_value=MockSnippetClient) + return_value=MockSnippetClient, + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_load_snippet_dup_package(self, MockGetPort, - MockSnippetClient, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_load_snippet_dup_package( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) - expected_msg = ('Snippet package "%s" has already been loaded under ' - 'name "snippet".') % MOCK_SNIPPET_PACKAGE_NAME + expected_msg = ( + 'Snippet package "%s" has already been loaded under name "snippet".' + ) % MOCK_SNIPPET_PACKAGE_NAME with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet2', MOCK_SNIPPET_PACKAGE_NAME) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch( 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2', - return_value=MockSnippetClient) + return_value=MockSnippetClient, + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_load_snippet_dup_snippet_name(self, MockGetPort, - MockSnippetClient, - MockFastboot, - MockAdbProxy): + def test_AndroidDevice_load_snippet_dup_snippet_name( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) - expected_msg = ('.* Attribute "snippet" already exists, please use a ' - 'different name.') + expected_msg = ( + '.* Attribute "snippet" already exists, please use a different name.' + ) with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME + 'haha') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_dup_attribute_name( - self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') - expected_msg = ('Attribute "%s" already exists, please use a different' - ' name') % 'adb' + expected_msg = ( + 'Attribute "%s" already exists, please use a different name' + ) % 'adb' with self.assertRaisesRegex(android_device.Error, expected_msg): ad.load_snippet('adb', MOCK_SNIPPET_PACKAGE_NAME) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_load_snippet_start_app_fails(self, MockGetPort, - MockSnippetClient, - MockFastboot, - MockAdbProxy): + def test_AndroidDevice_load_snippet_start_app_fails( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): """Verifies that the correct exception is raised if start app failed. It's possible that the `stop` call as part of the start app failure @@ -1117,95 +1449,133 @@ def test_AndroidDevice_load_snippet_start_app_fails(self, MockGetPort, except Exception as e: assertIs(e, expected_e) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') def test_AndroidDevice_load_snippet_with_snippet_config( - self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy): + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') snippet_config = snippet_client_v2.Config() ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME, snippet_config) self.assertTrue(hasattr(ad, 'snippet')) - MockSnippetClient.assert_called_once_with(package=mock.ANY, - ad=mock.ANY, - config=snippet_config) + MockSnippetClient.assert_called_once_with( + package=mock.ANY, ad=mock.ANY, config=snippet_config + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') - def test_AndroidDevice_unload_snippet(self, MockGetPort, MockSnippetClient, - MockFastboot, MockAdbProxy): + def test_AndroidDevice_unload_snippet( + self, MockGetPort, MockSnippetClient, MockFastboot, MockAdbProxy + ): ad = android_device.AndroidDevice(serial='1') ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.unload_snippet('snippet') self.assertFalse(hasattr(ad, 'snippet')) with self.assertRaisesRegex( android_device.SnippetError, - ' No snippet registered with name "snippet"'): + ' No snippet registered with name "snippet"', + ): ad.unload_snippet('snippet') # Loading the same snippet again should succeed ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) self.assertTrue(hasattr(ad, 'snippet')) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) @mock.patch( - 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2') + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.snippet_client_v2.SnippetClientV2' + ) @mock.patch('mobly.utils.get_available_host_port') @mock.patch.object(logcat.Logcat, '_open_logcat_file') - def test_AndroidDevice_snippet_cleanup(self, open_logcat_mock, MockGetPort, - MockSnippetClient, MockFastboot, - MockAdbProxy): + def test_AndroidDevice_snippet_cleanup( + self, + open_logcat_mock, + MockGetPort, + MockSnippetClient, + MockFastboot, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') ad.services.start_all() ad.load_snippet('snippet', MOCK_SNIPPET_PACKAGE_NAME) ad.unload_snippet('snippet') self.assertFalse(hasattr(ad, 'snippet')) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) def test_AndroidDevice_debug_tag(self, MockFastboot, MockAdbProxy): mock_serial = '1' ad = android_device.AndroidDevice(serial=mock_serial) self.assertEqual(ad.debug_tag, '1') - with self.assertRaisesRegex(android_device.DeviceError, - r' Something'): + with self.assertRaisesRegex( + android_device.DeviceError, r' Something' + ): raise android_device.DeviceError(ad, 'Something') # Verify that debug tag's setter updates the debug prefix correctly. ad.debug_tag = 'Mememe' - with self.assertRaisesRegex(android_device.DeviceError, - r' Something'): + with self.assertRaisesRegex( + android_device.DeviceError, r' Something' + ): raise android_device.DeviceError(ad, 'Something') # Verify that repr is changed correctly. - with self.assertRaisesRegex(Exception, - r'(, \'Something\')'): + with self.assertRaisesRegex( + Exception, r'(, \'Something\')' + ): raise Exception(ad, 'Something') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') - def test_AndroidDevice_handle_usb_disconnect(self, open_logcat_mock, - stop_proc_mock, start_proc_mock, - FastbootProxy, MockAdbProxy): - + def test_AndroidDevice_handle_usb_disconnect( + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + FastbootProxy, + MockAdbProxy, + ): class MockService(base_service.BaseService): def __init__(self, device, configs=None): @@ -1241,17 +1611,25 @@ def resume(self): self.assertTrue(ad.services.is_any_alive) self.assertTrue(ad.services.mock_service.resume_called) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') - def test_AndroidDevice_handle_reboot(self, open_logcat_mock, stop_proc_mock, - start_proc_mock, FastbootProxy, - MockAdbProxy): - + def test_AndroidDevice_handle_reboot( + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + FastbootProxy, + MockAdbProxy, + ): class MockService(base_service.BaseService): def __init__(self, device, configs=None): @@ -1287,16 +1665,25 @@ def resume(self): self.assertTrue(ad.services.is_any_alive) self.assertFalse(ad.services.mock_service.resume_called) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_AndroidDevice_handle_reboot_changes_build_info( - self, open_logcat_mock, stop_proc_mock, start_proc_mock, FastbootProxy, - MockAdbProxy): + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') with ad.handle_reboot(): ad.adb.mock_properties['ro.build.type'] = 'user' @@ -1306,16 +1693,25 @@ def test_AndroidDevice_handle_reboot_changes_build_info( self.assertFalse(ad.is_rootable) self.assertEqual(ad.adb.getprops_call_count, 2) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch('mobly.utils.start_standing_subprocess', return_value='process') @mock.patch('mobly.utils.stop_standing_subprocess') @mock.patch.object(logcat.Logcat, '_open_logcat_file') def test_AndroidDevice_handle_reboot_changes_build_info_with_caching( - self, open_logcat_mock, stop_proc_mock, start_proc_mock, FastbootProxy, - MockAdbProxy): + self, + open_logcat_mock, + stop_proc_mock, + start_proc_mock, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') # Call getprops 1. rootable_states = [ad.is_rootable] with ad.handle_reboot(): @@ -1328,25 +1724,37 @@ def test_AndroidDevice_handle_reboot_changes_build_info_with_caching( self.assertEqual(ad.adb.getprops_call_count, 4) self.assertEqual(rootable_states, [True, True, False, False, False]) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch( 'mobly.controllers.android_device.AndroidDevice.is_boot_completed', side_effect=[ - False, False, - adb.AdbTimeoutError(['adb', 'shell', 'getprop sys.boot_completed'], - timeout=5, - serial=1), True - ]) + False, + False, + adb.AdbTimeoutError( + ['adb', 'shell', 'getprop sys.boot_completed'], + timeout=5, + serial=1, + ), + True, + ], + ) @mock.patch('time.sleep', return_value=None) @mock.patch('time.time', side_effect=[0, 5, 10, 15, 20, 25, 30]) - def test_AndroidDevice_wait_for_completion_completed(self, MockTime, - MockSleep, - MockIsBootCompleted, - FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_wait_for_completion_completed( + self, + MockTime, + MockSleep, + MockIsBootCompleted, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') raised = False try: @@ -1355,27 +1763,43 @@ def test_AndroidDevice_wait_for_completion_completed(self, MockTime, raised = True self.assertFalse( raised, - 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.') + 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.', + ) - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy('1')) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy('1')) + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy('1'), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy('1'), + ) @mock.patch( 'mobly.controllers.android_device.AndroidDevice.is_boot_completed', side_effect=[ - False, False, - adb.AdbTimeoutError(['adb', 'shell', 'getprop sys.boot_completed'], - timeout=5, - serial=1), False, False, False, False - ]) + False, + False, + adb.AdbTimeoutError( + ['adb', 'shell', 'getprop sys.boot_completed'], + timeout=5, + serial=1, + ), + False, + False, + False, + False, + ], + ) @mock.patch('time.sleep', return_value=None) @mock.patch('time.perf_counter', side_effect=[0, 5, 10, 15, 20, 25, 30]) - def test_AndroidDevice_wait_for_completion_never_boot(self, MockTime, - MockSleep, - MockIsBootCompleted, - FastbootProxy, - MockAdbProxy): + def test_AndroidDevice_wait_for_completion_never_boot( + self, + MockTime, + MockSleep, + MockIsBootCompleted, + FastbootProxy, + MockAdbProxy, + ): ad = android_device.AndroidDevice(serial='1') raised = False try: @@ -1385,7 +1809,8 @@ def test_AndroidDevice_wait_for_completion_never_boot(self, MockTime, raised = True self.assertFalse( raised, - 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.') + 'adb.AdbError or adb.AdbTimeoutError exception raised but not handled.', + ) def test_AndroidDevice_parse_device_list_when_decode_error(self): gbk_str = b'\xc4\xe3\xba\xc3' diff --git a/tests/mobly/logger_test.py b/tests/mobly/logger_test.py index e0ac14d2..d975ac79 100755 --- a/tests/mobly/logger_test.py +++ b/tests/mobly/logger_test.py @@ -33,18 +33,19 @@ def tearDown(self): shutil.rmtree(self.log_dir) def test_epoch_to_log_line_timestamp(self): - actual_stamp = logger.epoch_to_log_line_timestamp(1469134262116, - time_zone=pytz.utc) - self.assertEqual("07-21 20:51:02.116", actual_stamp) + actual_stamp = logger.epoch_to_log_line_timestamp( + 1469134262116, time_zone=pytz.utc + ) + self.assertEqual('07-21 20:51:02.116', actual_stamp) def test_is_valid_logline_timestamp(self): - self.assertTrue(logger.is_valid_logline_timestamp("06-21 17:44:42.336")) + self.assertTrue(logger.is_valid_logline_timestamp('06-21 17:44:42.336')) def test_is_valid_logline_timestamp_when_wrong_length(self): - self.assertFalse(logger.is_valid_logline_timestamp(" 06-21 17:44:42.336")) + self.assertFalse(logger.is_valid_logline_timestamp(' 06-21 17:44:42.336')) def test_is_valid_logline_timestamp_when_invalid_content(self): - self.assertFalse(logger.is_valid_logline_timestamp("------------------")) + self.assertFalse(logger.is_valid_logline_timestamp('------------------')) @mock.patch('mobly.utils.create_alias') def test_create_latest_log_alias(self, mock_create_alias): @@ -53,24 +54,28 @@ def test_create_latest_log_alias(self, mock_create_alias): @mock.patch('mobly.logger._setup_test_logger') @mock.patch('mobly.logger.create_latest_log_alias') - def test_setup_test_logger_creates_log_alias(self, - mock_create_latest_log_alias, - mock__setup_test_logger): + def test_setup_test_logger_creates_log_alias( + self, mock_create_latest_log_alias, mock__setup_test_logger + ): logger.setup_test_logger(self.log_dir) - mock__setup_test_logger.assert_called_once_with(self.log_dir, logging.INFO, - None) - mock_create_latest_log_alias.assert_called_once_with(self.log_dir, - alias='latest') + mock__setup_test_logger.assert_called_once_with( + self.log_dir, logging.INFO, None + ) + mock_create_latest_log_alias.assert_called_once_with( + self.log_dir, alias='latest' + ) @mock.patch('mobly.logger._setup_test_logger') @mock.patch('mobly.logger.create_latest_log_alias') def test_setup_test_logger_creates_log_alias_with_custom_value( - self, mock_create_latest_log_alias, mock__setup_test_logger): + self, mock_create_latest_log_alias, mock__setup_test_logger + ): mock_alias = mock.MagicMock() logger.setup_test_logger(self.log_dir, alias=mock_alias) - mock_create_latest_log_alias.assert_called_once_with(self.log_dir, - alias=mock_alias) + mock_create_latest_log_alias.assert_called_once_with( + self.log_dir, alias=mock_alias + ) def test_sanitize_filename_when_valid(self): fake_filename = 'logcat.txt' @@ -114,8 +119,9 @@ def test_sanitize_filename_when_extension_over_max_characters(self): def test__sanitize_windows_filename_when_path_characters(self): fake_filename = '/\\' expected_filename = '__' - self.assertEqual(logger._sanitize_windows_filename(fake_filename), - expected_filename) + self.assertEqual( + logger._sanitize_windows_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_specical_characters(self): fake_filename = '<>:"|?*\x00' @@ -129,8 +135,9 @@ def test_sanitize_filename_when_con(self): ('con.txt', 'mobly_con.txt'), ('connections.log', 'connections.log'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_prn(self): for fake_filename, expected_filename in [ @@ -139,8 +146,9 @@ def test_sanitize_filename_when_prn(self): ('prn.txt', 'mobly_prn.txt'), ('prnters.log', 'prnters.log'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_aux(self): for fake_filename, expected_filename in [ @@ -149,8 +157,9 @@ def test_sanitize_filename_when_aux(self): ('aux.txt', 'mobly_aux.txt'), ('auxiliaries.log', 'auxiliaries.log'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_nul(self): for fake_filename, expected_filename in [ @@ -159,8 +168,9 @@ def test_sanitize_filename_when_nul(self): ('nul.txt', 'mobly_nul.txt'), ('nullptrs.log', 'nullptrs.log'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_com(self): for fake_filename, expected_filename in [ @@ -178,8 +188,9 @@ def test_sanitize_filename_when_com(self): ('com0.log', 'mobly_com0.log'), ('com0files.log', 'com0files.log'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_lpt(self): for fake_filename, expected_filename in [ @@ -197,8 +208,9 @@ def test_sanitize_filename_when_lpt(self): ('lpt3.txt', 'mobly_lpt3.txt'), ('lpt3_file.txt', 'lpt3_file.txt'), ]: - self.assertEqual(logger.sanitize_filename(fake_filename), - expected_filename) + self.assertEqual( + logger.sanitize_filename(fake_filename), expected_filename + ) def test_sanitize_filename_when_ends_with_space(self): fake_filename = 'logcat.txt ' @@ -217,8 +229,9 @@ def test_prefix_logger_adapter_prefix_log_lines(self): adapted_logger = logger.PrefixLoggerAdapter(mock.Mock(), extra) kwargs = mock.Mock() - processed_log, processed_kwargs = adapted_logger.process('mock log line', - kwargs=kwargs) + processed_log, processed_kwargs = adapted_logger.process( + 'mock log line', kwargs=kwargs + ) self.assertEqual(processed_log, '[MOCK_PREFIX] mock log line') self.assertIs(processed_kwargs, kwargs) @@ -231,12 +244,13 @@ def test_prefix_logger_adapter_modify_prefix(self): adapted_logger.set_log_prefix('[NEW]') kwargs = mock.Mock() - processed_log, processed_kwargs = adapted_logger.process('mock log line', - kwargs=kwargs) + processed_log, processed_kwargs = adapted_logger.process( + 'mock log line', kwargs=kwargs + ) self.assertEqual(processed_log, '[NEW] mock log line') self.assertIs(processed_kwargs, kwargs) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/output_test.py b/tests/mobly/output_test.py index 4b2d94a2..bbffa897 100755 --- a/tests/mobly/output_test.py +++ b/tests/mobly/output_test.py @@ -47,7 +47,7 @@ def setUp(self): self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, - 'extra_param': 'haha' + 'extra_param': 'haha', } self.base_mock_test_config.log_path = self.tmp_dir self.log_dir = self.base_mock_test_config.log_path @@ -59,13 +59,10 @@ def tearDown(self): def create_mock_test_config(self, base_mock_test_config): mock_test_config = base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - my_config = [{ - 'serial': 'xxxx', - 'magic': 'Magic1' - }, { - 'serial': 'xxxx', - 'magic': 'Magic2' - }] + my_config = [ + {'serial': 'xxxx', 'magic': 'Magic1'}, + {'serial': 'xxxx', 'magic': 'Magic2'}, + ] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config return mock_test_config @@ -76,8 +73,9 @@ def get_output_logs(self, output_dir): return (summary_file_path, debug_log_path, info_log_path) def assert_output_logs_exist(self, output_dir): - (summary_file_path, debug_log_path, - info_log_path) = self.get_output_logs(output_dir) + (summary_file_path, debug_log_path, info_log_path) = self.get_output_logs( + output_dir + ) self.assertTrue(os.path.isfile(summary_file_path)) self.assertTrue(os.path.isfile(debug_log_path)) self.assertTrue(os.path.isfile(info_log_path)) @@ -96,8 +94,10 @@ def test_yields_logging_path(self): with tr.mobly_logger() as log_path: self.assertEqual(log_path, logging.log_path) - @unittest.skipIf(platform.system() == 'Windows', - 'Symlinks are usually specific to Unix operating systems') + @unittest.skipIf( + platform.system() == 'Windows', + 'Symlinks are usually specific to Unix operating systems', + ) def test_symlink(self): """Verifies the symlink is created and links properly.""" mock_test_config = self.create_mock_test_config(self.base_mock_test_config) @@ -107,12 +107,14 @@ def test_symlink(self): symlink = os.path.join(self.log_dir, self.testbed_name, 'latest') self.assertEqual(os.readlink(symlink), logging.log_path) - @unittest.skipIf(platform.system() != 'Windows', - 'Shortcuts are specific to Windows operating systems') + @unittest.skipIf( + platform.system() != 'Windows', + 'Shortcuts are specific to Windows operating systems', + ) def test_shortcut(self): """Verifies the shortcut is created and links properly.""" shortcut_path = os.path.join(self.log_dir, self.testbed_name, 'latest.lnk') - shell = client.Dispatch("WScript.Shell") + shell = client.Dispatch('WScript.Shell') shortcut = shell.CreateShortCut(shortcut_path) self.assertFalse(shortcut.Targetpath) mock_test_config = self.create_mock_test_config(self.base_mock_test_config) @@ -122,9 +124,11 @@ def test_shortcut(self): shortcut = shell.CreateShortCut(shortcut_path) # Normalize paths for case and truncation normalized_shortcut_path = os.path.normcase( - win32file.GetLongPathName(shortcut.Targetpath)) + win32file.GetLongPathName(shortcut.Targetpath) + ) normalized_logger_path = os.path.normcase( - win32file.GetLongPathName(logging.log_path)) + win32file.GetLongPathName(logging.log_path) + ) self.assertEqual(normalized_shortcut_path, normalized_logger_path) @mock.patch('mobly.utils.create_alias') @@ -134,8 +138,9 @@ def test_mobly_logger_with_default_latest_log_alias(self, mock_create_alias): with tr.mobly_logger(): pass expected_alias_dir = os.path.join(self.log_dir, self.testbed_name, 'latest') - mock_create_alias.assert_called_once_with(logging.log_path, - expected_alias_dir) + mock_create_alias.assert_called_once_with( + logging.log_path, expected_alias_dir + ) @mock.patch('mobly.utils.create_alias') def test_mobly_logger_with_custom_latest_log_alias(self, mock_create_alias): @@ -143,14 +148,17 @@ def test_mobly_logger_with_custom_latest_log_alias(self, mock_create_alias): tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(alias='history'): pass - expected_alias_dir = os.path.join(self.log_dir, self.testbed_name, - 'history') - mock_create_alias.assert_called_once_with(logging.log_path, - expected_alias_dir) + expected_alias_dir = os.path.join( + self.log_dir, self.testbed_name, 'history' + ) + mock_create_alias.assert_called_once_with( + logging.log_path, expected_alias_dir + ) @mock.patch('mobly.utils.create_alias') def test_mobly_logger_skips_latest_log_alias_when_none( - self, mock_create_alias): + self, mock_create_alias + ): mock_test_config = self.create_mock_test_config(self.base_mock_test_config) tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(alias=None): @@ -159,7 +167,8 @@ def test_mobly_logger_skips_latest_log_alias_when_none( @mock.patch('mobly.utils.create_alias') def test_mobly_logger_skips_latest_log_alias_when_empty( - self, mock_create_alias): + self, mock_create_alias + ): mock_test_config = self.create_mock_test_config(self.base_mock_test_config) tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(alias=''): @@ -182,15 +191,17 @@ def test_logging_before_run(self): tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() output_dir = logging.root_output_path - (summary_file_path, debug_log_path, - info_log_path) = self.assert_output_logs_exist(output_dir) + (summary_file_path, debug_log_path, info_log_path) = ( + self.assert_output_logs_exist(output_dir) + ) self.assert_log_contents(debug_log_path, whitelist=[debug_uuid, info_uuid]) - self.assert_log_contents(info_log_path, - whitelist=[info_uuid], - blacklist=[debug_uuid]) + self.assert_log_contents( + info_log_path, whitelist=[info_uuid], blacklist=[debug_uuid] + ) - @mock.patch('mobly.logger.get_log_file_timestamp', - side_effect=str(time.time())) + @mock.patch( + 'mobly.logger.get_log_file_timestamp', side_effect=str(time.time()) + ) def test_run_twice_for_two_sets_of_logs(self, mock_timestamp): """Verifies the expected output files from a test run. @@ -210,8 +221,9 @@ def test_run_twice_for_two_sets_of_logs(self, mock_timestamp): self.assert_output_logs_exist(output_dir1) self.assert_output_logs_exist(output_dir2) - @mock.patch('mobly.logger.get_log_file_timestamp', - side_effect=str(time.time())) + @mock.patch( + 'mobly.logger.get_log_file_timestamp', side_effect=str(time.time()) + ) def test_teardown_erases_logs(self, mock_timestamp): """Verifies the expected output files from a test run. @@ -237,17 +249,23 @@ def test_teardown_erases_logs(self, mock_timestamp): self.assertNotEqual(output_dir1, output_dir2) - (summary_file_path1, debug_log_path1, - info_log_path1) = self.get_output_logs(output_dir1) - (summary_file_path2, debug_log_path2, - info_log_path2) = self.get_output_logs(output_dir2) - - self.assert_log_contents(debug_log_path1, - whitelist=[debug_uuid1, info_uuid1], - blacklist=[info_uuid2, debug_uuid2]) - self.assert_log_contents(debug_log_path2, - whitelist=[debug_uuid2, info_uuid2], - blacklist=[info_uuid1, debug_uuid1]) + (summary_file_path1, debug_log_path1, info_log_path1) = ( + self.get_output_logs(output_dir1) + ) + (summary_file_path2, debug_log_path2, info_log_path2) = ( + self.get_output_logs(output_dir2) + ) + + self.assert_log_contents( + debug_log_path1, + whitelist=[debug_uuid1, info_uuid1], + blacklist=[info_uuid2, debug_uuid2], + ) + self.assert_log_contents( + debug_log_path2, + whitelist=[debug_uuid2, info_uuid2], + blacklist=[info_uuid1, debug_uuid1], + ) def test_basic_output(self): """Verifies the expected output files from a test run. @@ -260,22 +278,24 @@ def test_basic_output(self): with tr.mobly_logger(): tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() - expected_class_path = os.path.join(logging.root_output_path, - 'IntegrationTest') + expected_class_path = os.path.join( + logging.root_output_path, 'IntegrationTest' + ) self.assertEqual(expected_class_path, logging.log_path) os.path.exists(logging.log_path) output_dir = logging.root_output_path - (summary_file_path, debug_log_path, - info_log_path) = self.assert_output_logs_exist(output_dir) + (summary_file_path, debug_log_path, info_log_path) = ( + self.assert_output_logs_exist(output_dir) + ) summary_entries = [] with io.open(summary_file_path, 'r', encoding='utf-8') as f: for entry in yaml.safe_load_all(f): self.assertTrue(entry['Type']) summary_entries.append(entry) self.assert_log_contents(debug_log_path, whitelist=['DEBUG', 'INFO']) - self.assert_log_contents(info_log_path, - whitelist=['INFO'], - blacklist=['DEBUG']) + self.assert_log_contents( + info_log_path, whitelist=['INFO'], blacklist=['DEBUG'] + ) def test_teardown_class_output(self): """Verifies the summary file includes the failure record for @@ -284,8 +304,9 @@ def test_teardown_class_output(self): mock_test_config = self.base_mock_test_config.copy() tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(): - tr.add_test_class(mock_test_config, - teardown_class_failure_test.TearDownClassFailureTest) + tr.add_test_class( + mock_test_config, teardown_class_failure_test.TearDownClassFailureTest + ) tr.run() output_dir = logging.root_output_path summary_file_path = os.path.join(output_dir, records.OUTPUT_FILE_SUMMARY) @@ -294,14 +315,18 @@ def test_teardown_class_output(self): raw_content = f.read() f.seek(0) for entry in yaml.safe_load_all(f): - if (entry['Type'] == 'Record' and - entry[records.TestResultEnums.RECORD_NAME] == 'teardown_class'): + if ( + entry['Type'] == 'Record' + and entry[records.TestResultEnums.RECORD_NAME] == 'teardown_class' + ): found = True break self.assertTrue( - found, 'No record for teardown_class found in the output file:\n %s' % - raw_content) + found, + 'No record for teardown_class found in the output file:\n %s' + % raw_content, + ) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/records_test.py b/tests/mobly/records_test.py index ec6254de..bcee67a1 100755 --- a/tests/mobly/records_test.py +++ b/tests/mobly/records_test.py @@ -50,8 +50,7 @@ def __str__(self): class RecordsTest(unittest.TestCase): - """This test class tests the implementation of classes in mobly.records. - """ + """This test class tests the implementation of classes in mobly.records.""" def setUp(self): self.tn = 'test_name' @@ -63,13 +62,15 @@ def setUp(self): def tearDown(self): shutil.rmtree(self.tmp_path) - def verify_record(self, - record, - result, - details, - extras, - termination_signal_type=None, - stacktrace=None): + def verify_record( + self, + record, + result, + details, + extras, + termination_signal_type=None, + stacktrace=None, + ): record.update_record() # Verify each field. self.assertEqual(record.test_name, self.tn) @@ -86,13 +87,15 @@ def verify_record(self, d[records.TestResultEnums.RECORD_NAME] = self.tn d[records.TestResultEnums.RECORD_RESULT] = result d[records.TestResultEnums.RECORD_DETAILS] = details - d[records.TestResultEnums. - RECORD_TERMINATION_SIGNAL_TYPE] = termination_signal_type + d[records.TestResultEnums.RECORD_TERMINATION_SIGNAL_TYPE] = ( + termination_signal_type + ) d[records.TestResultEnums.RECORD_EXTRAS] = extras d[records.TestResultEnums.RECORD_BEGIN_TIME] = record.begin_time d[records.TestResultEnums.RECORD_END_TIME] = record.end_time - d[records.TestResultEnums. - RECORD_SIGNATURE] = f'{self.tn}-{record.begin_time}' + d[records.TestResultEnums.RECORD_SIGNATURE] = ( + f'{self.tn}-{record.begin_time}' + ) d[records.TestResultEnums.RECORD_UID] = None d[records.TestResultEnums.RECORD_RETRY_PARENT] = None d[records.TestResultEnums.RECORD_CLASS] = None @@ -114,42 +117,50 @@ def test_result_record_implicit_pass(self): record = records.TestResultRecord(self.tn) record.test_begin() record.test_pass() - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_PASS, - details=None, - extras=None) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_PASS, + details=None, + extras=None, + ) def test_result_record_explicit_pass_with_float_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestPass(self.details, self.float_extra) record.test_pass(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_PASS, - details=self.details, - termination_signal_type='TestPass', - extras=self.float_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_PASS, + details=self.details, + termination_signal_type='TestPass', + extras=self.float_extra, + ) def test_result_record_explicit_pass_with_json_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestPass(self.details, self.json_extra) record.test_pass(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_PASS, - details=self.details, - termination_signal_type='TestPass', - extras=self.json_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_PASS, + details=self.details, + termination_signal_type='TestPass', + extras=self.json_extra, + ) def test_result_record_fail_none(self): """Verifies that `test_fail` can be called without an error object.""" record = records.TestResultRecord(self.tn) record.test_begin() record.test_fail() - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details=None, - extras=None) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details=None, + extras=None, + ) def test_result_record_fail_stacktrace(self): record = records.TestResultRecord(self.tn) @@ -161,91 +172,109 @@ def test_result_record_fail_stacktrace(self): # Verify stacktrace separately if we expect a non-None value. # Because stacktrace includes file names and line numbers, we can't do # a simple equality check. - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details='Something failed.', - termination_signal_type='Exception', - extras=None, - stacktrace='in test_result_record_fail_stacktrace\n ' - 'raise Exception(\'Something failed.\')\nException: ' - 'Something failed.\n') + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details='Something failed.', + termination_signal_type='Exception', + extras=None, + stacktrace=( + 'in test_result_record_fail_stacktrace\n ' + "raise Exception('Something failed.')\nException: " + 'Something failed.\n' + ), + ) def test_result_record_fail_with_float_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestFailure(self.details, self.float_extra) record.test_fail(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details=self.details, - termination_signal_type='TestFailure', - extras=self.float_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details=self.details, + termination_signal_type='TestFailure', + extras=self.float_extra, + ) def test_result_record_fail_with_unicode_test_signal(self): record = records.TestResultRecord(self.tn) record.test_begin() - details = u'\u2022' + details = '\u2022' s = signals.TestFailure(details, self.float_extra) record.test_fail(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details=details, - termination_signal_type='TestFailure', - extras=self.float_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details=details, + termination_signal_type='TestFailure', + extras=self.float_extra, + ) def test_result_record_fail_with_unicode_exception(self): record = records.TestResultRecord(self.tn) record.test_begin() - details = u'\u2022' + details = '\u2022' s = Exception(details) record.test_fail(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details=details, - termination_signal_type='Exception', - extras=None) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details=details, + termination_signal_type='Exception', + extras=None, + ) def test_result_record_fail_with_json_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestFailure(self.details, self.json_extra) record.test_fail(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_FAIL, - details=self.details, - termination_signal_type='TestFailure', - extras=self.json_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_FAIL, + details=self.details, + termination_signal_type='TestFailure', + extras=self.json_extra, + ) def test_result_record_skip_none(self): record = records.TestResultRecord(self.tn) record.test_begin() record.test_skip() - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_SKIP, - details=None, - extras=None) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_SKIP, + details=None, + extras=None, + ) def test_result_record_skip_with_float_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestSkip(self.details, self.float_extra) record.test_skip(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_SKIP, - details=self.details, - termination_signal_type='TestSkip', - extras=self.float_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_SKIP, + details=self.details, + termination_signal_type='TestSkip', + extras=self.float_extra, + ) def test_result_record_skip_with_json_extra(self): record = records.TestResultRecord(self.tn) record.test_begin() s = signals.TestSkip(self.details, self.json_extra) record.test_skip(s) - self.verify_record(record=record, - result=records.TestResultEnums.TEST_RESULT_SKIP, - details=self.details, - termination_signal_type='TestSkip', - extras=self.json_extra) + self.verify_record( + record=record, + result=records.TestResultEnums.TEST_RESULT_SKIP, + details=self.details, + termination_signal_type='TestSkip', + extras=self.json_extra, + ) def test_result_add_operator_success(self): record1 = records.TestResultRecord(self.tn) @@ -254,8 +283,9 @@ def test_result_add_operator_success(self): record1.test_pass(s) tr1 = records.TestResult() tr1.add_record(record1) - controller_info = records.ControllerInfoRecord('SomeClass', 'MockDevice', - ['magicA', 'magicB']) + controller_info = records.ControllerInfoRecord( + 'SomeClass', 'MockDevice', ['magicA', 'magicB'] + ) tr1.add_controller_info_record(controller_info) record2 = records.TestResultRecord(self.tn) record2.test_begin() @@ -263,8 +293,9 @@ def test_result_add_operator_success(self): record2.test_pass(s) tr2 = records.TestResult() tr2.add_record(record2) - controller_info = records.ControllerInfoRecord('SomeClass', 'MockDevice', - ['magicC']) + controller_info = records.ControllerInfoRecord( + 'SomeClass', 'MockDevice', ['magicC'] + ) tr2.add_controller_info_record(controller_info) tr2 += tr1 self.assertTrue(tr2.passed, [tr1, tr2]) @@ -378,16 +409,19 @@ def test_summary_write_dump(self): writer.dump(record1.to_dict(), records.TestSummaryEntryType.RECORD) with io.open(dump_path, 'r', encoding='utf-8') as f: content = yaml.safe_load(f) - self.assertEqual(content['Type'], - records.TestSummaryEntryType.RECORD.value) - self.assertEqual(content[records.TestResultEnums.RECORD_DETAILS], - self.details) - self.assertEqual(content[records.TestResultEnums.RECORD_EXTRAS], - self.float_extra) + self.assertEqual( + content['Type'], records.TestSummaryEntryType.RECORD.value + ) + self.assertEqual( + content[records.TestResultEnums.RECORD_DETAILS], self.details + ) + self.assertEqual( + content[records.TestResultEnums.RECORD_EXTRAS], self.float_extra + ) def test_summary_write_dump_with_unicode(self): - unicode_details = u'\u901a' # utf-8 -> b'\xe9\x80\x9a' - unicode_extras = u'\u8fc7' # utf-8 -> b'\xe8\xbf\x87' + unicode_details = '\u901a' # utf-8 -> b'\xe9\x80\x9a' + unicode_extras = '\u8fc7' # utf-8 -> b'\xe8\xbf\x87' s = signals.TestFailure(unicode_details, unicode_extras) record1 = records.TestResultRecord(self.tn) record1.test_begin() @@ -397,12 +431,15 @@ def test_summary_write_dump_with_unicode(self): writer.dump(record1.to_dict(), records.TestSummaryEntryType.RECORD) with io.open(dump_path, 'r', encoding='utf-8') as f: content = yaml.safe_load(f) - self.assertEqual(content['Type'], - records.TestSummaryEntryType.RECORD.value) - self.assertEqual(content[records.TestResultEnums.RECORD_DETAILS], - unicode_details) - self.assertEqual(content[records.TestResultEnums.RECORD_EXTRAS], - unicode_extras) + self.assertEqual( + content['Type'], records.TestSummaryEntryType.RECORD.value + ) + self.assertEqual( + content[records.TestResultEnums.RECORD_DETAILS], unicode_details + ) + self.assertEqual( + content[records.TestResultEnums.RECORD_EXTRAS], unicode_extras + ) @mock.patch('mobly.utils.get_current_epoch_time') def test_signature(self, mock_time_src): @@ -424,8 +461,9 @@ def test_summary_user_data(self): for c in yaml.safe_load_all(f): contents.append(c) for content in contents: - self.assertEqual(content['Type'], - records.TestSummaryEntryType.USER_DATA.value) + self.assertEqual( + content['Type'], records.TestSummaryEntryType.USER_DATA.value + ) self.assertEqual(contents[0]['a'], user_data1['a']) self.assertEqual(contents[1]['b'], user_data2['b']) @@ -456,16 +494,17 @@ def test_recursive_exception_record_deepcopy(self): def test_add_controller_info_record(self): tr = records.TestResult() self.assertFalse(tr.controller_info) - controller_info = records.ControllerInfoRecord('SomeClass', 'MockDevice', - ['magicA', 'magicB']) + controller_info = records.ControllerInfoRecord( + 'SomeClass', 'MockDevice', ['magicA', 'magicB'] + ) tr.add_controller_info_record(controller_info) self.assertTrue(tr.controller_info[0]) self.assertEqual(tr.controller_info[0].controller_name, 'MockDevice') - self.assertEqual(tr.controller_info[0].controller_info, - ['magicA', 'magicB']) + self.assertEqual( + tr.controller_info[0].controller_info, ['magicA', 'magicB'] + ) def test_uid(self): - @records.uid('some-uuid') def test_uid_helper(): """Dummy test used by `test_uid` for testing the uid decorator.""" diff --git a/tests/mobly/snippet/callback_event_test.py b/tests/mobly/snippet/callback_event_test.py index 2593cc3c..afd122dd 100755 --- a/tests/mobly/snippet/callback_event_test.py +++ b/tests/mobly/snippet/callback_event_test.py @@ -28,12 +28,14 @@ class CallbackEventTest(unittest.TestCase): def test_basic(self): """Verifies that an event object can be created and logged properly.""" - event = callback_event.CallbackEvent(MOCK_CALLBACK_ID, MOCK_EVENT_NAME, - MOCK_CREATION_TIME, MOCK_DATA) + event = callback_event.CallbackEvent( + MOCK_CALLBACK_ID, MOCK_EVENT_NAME, MOCK_CREATION_TIME, MOCK_DATA + ) self.assertEqual( repr(event), - "CallbackEvent(callback_id: myCallbackId, name: onXyzEvent, " - "creation_time: 12345678, data: {'foo': 'bar'})") + 'CallbackEvent(callback_id: myCallbackId, name: onXyzEvent, ' + "creation_time: 12345678, data: {'foo': 'bar'})", + ) if __name__ == '__main__': diff --git a/tests/mobly/snippet/callback_handler_base_test.py b/tests/mobly/snippet/callback_handler_base_test.py index 0891fd5b..32199b29 100644 --- a/tests/mobly/snippet/callback_handler_base_test.py +++ b/tests/mobly/snippet/callback_handler_base_test.py @@ -28,25 +28,34 @@ 'data': { 'exampleData': "Here's a simple event.", 'successful': True, - 'secretNumber': 12 - } + 'secretNumber': 12, + }, } class FakeCallbackHandler(callback_handler_base.CallbackHandlerBase): """Fake client class for unit tests.""" - def __init__(self, - callback_id=None, - event_client=None, - ret_value=None, - method_name=None, - device=None, - rpc_max_timeout_sec=120, - default_timeout_sec=120): + def __init__( + self, + callback_id=None, + event_client=None, + ret_value=None, + method_name=None, + device=None, + rpc_max_timeout_sec=120, + default_timeout_sec=120, + ): """Initializes a fake callback handler object used for unit tests.""" - super().__init__(callback_id, event_client, ret_value, method_name, device, - rpc_max_timeout_sec, default_timeout_sec) + super().__init__( + callback_id, + event_client, + ret_value, + method_name, + device, + rpc_max_timeout_sec, + default_timeout_sec, + ) self.mock_rpc_func = mock.Mock() def callEventWaitAndGetRpc(self, *args, **kwargs): @@ -66,15 +75,18 @@ def assert_event_correct(self, actual_event, expected_raw_event_dict): self.assertEqual(str(actual_event), str(expected_event)) def test_default_timeout_too_large(self): - err_msg = ('The max timeout of a single RPC must be no smaller than ' - 'the default timeout of the callback handler. ' - 'Got rpc_max_timeout_sec=10, default_timeout_sec=20.') + err_msg = ( + 'The max timeout of a single RPC must be no smaller than ' + 'the default timeout of the callback handler. ' + 'Got rpc_max_timeout_sec=10, default_timeout_sec=20.' + ) with self.assertRaisesRegex(ValueError, err_msg): _ = FakeCallbackHandler(rpc_max_timeout_sec=10, default_timeout_sec=20) def test_timeout_property(self): - handler = FakeCallbackHandler(rpc_max_timeout_sec=20, - default_timeout_sec=10) + handler = FakeCallbackHandler( + rpc_max_timeout_sec=20, default_timeout_sec=10 + ) self.assertEqual(handler.rpc_max_timeout_sec, 20) self.assertEqual(handler.default_timeout_sec, 10) with self.assertRaises(AttributeError): @@ -92,39 +104,48 @@ def test_callback_id_property(self): def test_event_dict_to_snippet_event(self): handler = FakeCallbackHandler(callback_id=MOCK_CALLBACK_ID) handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) event = handler.waitAndGet('ha', timeout=10) self.assert_event_correct(event, MOCK_RAW_EVENT) handler.mock_rpc_func.callEventWaitAndGetRpc.assert_called_once_with( - MOCK_CALLBACK_ID, 'ha', 10) + MOCK_CALLBACK_ID, 'ha', 10 + ) def test_wait_and_get_timeout_default(self): handler = FakeCallbackHandler(rpc_max_timeout_sec=20, default_timeout_sec=5) handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) _ = handler.waitAndGet('ha') handler.mock_rpc_func.callEventWaitAndGetRpc.assert_called_once_with( - mock.ANY, mock.ANY, 5) + mock.ANY, mock.ANY, 5 + ) def test_wait_and_get_timeout_ecxeed_threshold(self): rpc_max_timeout_sec = 5 big_timeout_sec = 10 - handler = FakeCallbackHandler(rpc_max_timeout_sec=rpc_max_timeout_sec, - default_timeout_sec=rpc_max_timeout_sec) + handler = FakeCallbackHandler( + rpc_max_timeout_sec=rpc_max_timeout_sec, + default_timeout_sec=rpc_max_timeout_sec, + ) handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) expected_msg = ( f'Specified timeout {big_timeout_sec} is longer than max timeout ' - f'{rpc_max_timeout_sec}.') + f'{rpc_max_timeout_sec}.' + ) with self.assertRaisesRegex(errors.CallbackHandlerBaseError, expected_msg): handler.waitAndGet('ha', big_timeout_sec) def test_wait_for_event(self): handler = FakeCallbackHandler() handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) def some_condition(event): return event.data['successful'] @@ -135,48 +156,56 @@ def some_condition(event): def test_wait_for_event_negative(self): handler = FakeCallbackHandler() handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) expected_msg = ( 'Timed out after 0.01s waiting for an "AsyncTaskResult" event that' - ' satisfies the predicate "some_condition".') + ' satisfies the predicate "some_condition".' + ) def some_condition(_): return False - with self.assertRaisesRegex(errors.CallbackHandlerTimeoutError, - expected_msg): + with self.assertRaisesRegex( + errors.CallbackHandlerTimeoutError, expected_msg + ): handler.waitForEvent('AsyncTaskResult', some_condition, 0.01) def test_wait_for_event_max_timeout(self): """waitForEvent should not raise the timeout exceed threshold error.""" rpc_max_timeout_sec = 5 big_timeout_sec = 10 - handler = FakeCallbackHandler(rpc_max_timeout_sec=rpc_max_timeout_sec, - default_timeout_sec=rpc_max_timeout_sec) + handler = FakeCallbackHandler( + rpc_max_timeout_sec=rpc_max_timeout_sec, + default_timeout_sec=rpc_max_timeout_sec, + ) handler.mock_rpc_func.callEventWaitAndGetRpc = mock.Mock( - return_value=MOCK_RAW_EVENT) + return_value=MOCK_RAW_EVENT + ) def some_condition(event): return event.data['successful'] # This line should not raise. - event = handler.waitForEvent('AsyncTaskResult', - some_condition, - timeout=big_timeout_sec) + event = handler.waitForEvent( + 'AsyncTaskResult', some_condition, timeout=big_timeout_sec + ) self.assert_event_correct(event, MOCK_RAW_EVENT) def test_get_all(self): handler = FakeCallbackHandler(callback_id=MOCK_CALLBACK_ID) handler.mock_rpc_func.callEventGetAllRpc = mock.Mock( - return_value=[MOCK_RAW_EVENT, MOCK_RAW_EVENT]) + return_value=[MOCK_RAW_EVENT, MOCK_RAW_EVENT] + ) all_events = handler.getAll('ha') for event in all_events: self.assert_event_correct(event, MOCK_RAW_EVENT) handler.mock_rpc_func.callEventGetAllRpc.assert_called_once_with( - MOCK_CALLBACK_ID, 'ha') + MOCK_CALLBACK_ID, 'ha' + ) if __name__ == '__main__': diff --git a/tests/mobly/snippet/client_base_test.py b/tests/mobly/snippet/client_base_test.py index d9d99bdb..57a3ed80 100755 --- a/tests/mobly/snippet/client_base_test.py +++ b/tests/mobly/snippet/client_base_test.py @@ -25,7 +25,8 @@ def _generate_fix_length_rpc_response( response_length, - template='{"id": 0, "result": "%s", "error": null, "callback": null}'): + template='{"id": 0, "result": "%s", "error": null, "callback": null}', +): """Generates an RPC response string with specified length. This function generates a random string and formats the template with the @@ -46,9 +47,11 @@ def _generate_fix_length_rpc_response( # '%s' in the template, of which the length is 2. result_length = response_length - (len(template) - 2) if result_length < 0: - raise ValueError(f'The response_length should be no smaller than ' - f'template_length + 2. Got response_length ' - f'{response_length}, template_length {len(template)}.') + raise ValueError( + 'The response_length should be no smaller than ' + 'template_length + 2. Got response_length ' + f'{response_length}, template_length {len(template)}.' + ) chars = string.ascii_letters + string.digits return template % ''.join(random.choice(chars) for _ in range(result_length)) @@ -102,8 +105,9 @@ def setUp(self): @mock.patch.object(FakeClient, 'before_starting_server') @mock.patch.object(FakeClient, 'start_server') @mock.patch.object(FakeClient, '_make_connection') - def test_init_server_stage_order(self, mock_make_conn_func, mock_start_func, - mock_before_func): + def test_init_server_stage_order( + self, mock_make_conn_func, mock_start_func, mock_before_func + ): """Test that initialization runs its stages in expected order.""" order_manager = mock.Mock() order_manager.attach_mock(mock_before_func, 'mock_before_func') @@ -121,8 +125,9 @@ def test_init_server_stage_order(self, mock_make_conn_func, mock_start_func, @mock.patch.object(FakeClient, 'stop') @mock.patch.object(FakeClient, 'before_starting_server') - def test_init_server_before_starting_server_fail(self, mock_before_func, - mock_stop_func): + def test_init_server_before_starting_server_fail( + self, mock_before_func, mock_stop_func + ): """Test before_starting_server stage of initialization fails.""" mock_before_func.side_effect = Exception('ha') @@ -142,8 +147,9 @@ def test_init_server_start_server_fail(self, mock_start_func, mock_stop_func): @mock.patch.object(FakeClient, 'stop') @mock.patch.object(FakeClient, '_make_connection') - def test_init_server_make_connection_fail(self, mock_make_conn_func, - mock_stop_func): + def test_init_server_make_connection_fail( + self, mock_make_conn_func, mock_stop_func + ): """Test _make_connection stage of initialization fails.""" mock_make_conn_func.side_effect = Exception('ha') @@ -156,9 +162,14 @@ def test_init_server_make_connection_fail(self, mock_make_conn_func, @mock.patch.object(FakeClient, 'send_rpc_request') @mock.patch.object(FakeClient, '_decode_response_string_and_validate_format') @mock.patch.object(FakeClient, '_handle_rpc_response') - def test_rpc_stage_dependencies(self, mock_handle_resp, mock_decode_resp_str, - mock_send_request, mock_gen_request, - mock_precheck): + def test_rpc_stage_dependencies( + self, + mock_handle_resp, + mock_decode_resp_str, + mock_send_request, + mock_gen_request, + mock_precheck, + ): """Test the internal dependencies when sending an RPC. When sending an RPC, it calls multiple functions in specific order, and @@ -175,16 +186,19 @@ def test_rpc_stage_dependencies(self, mock_handle_resp, mock_decode_resp_str, """ self.client.initialize() - expected_response_str = ('{"id": 0, "result": 123, "error": null, ' - '"callback": null}') + expected_response_str = ( + '{"id": 0, "result": 123, "error": null, "callback": null}' + ) expected_response_dict = { 'id': 0, 'result': 123, 'error': None, 'callback': None, } - expected_request = ('{"id": 10, "method": "some_rpc", "params": [1, 2],' - '"kwargs": {"test_key": 3}') + expected_request = ( + '{"id": 10, "method": "some_rpc", "params": [1, 2],' + '"kwargs": {"test_key": 3}' + ) expected_result = 123 mock_gen_request.return_value = expected_request @@ -205,9 +219,14 @@ def test_rpc_stage_dependencies(self, mock_handle_resp, mock_decode_resp_str, @mock.patch.object(FakeClient, 'send_rpc_request') @mock.patch.object(FakeClient, '_decode_response_string_and_validate_format') @mock.patch.object(FakeClient, '_handle_rpc_response') - def test_rpc_precheck_fail(self, mock_handle_resp, mock_decode_resp_str, - mock_send_request, mock_gen_request, - mock_precheck): + def test_rpc_precheck_fail( + self, + mock_handle_resp, + mock_decode_resp_str, + mock_send_request, + mock_gen_request, + mock_precheck, + ): """Test when RPC precheck fails it will skip sending the RPC.""" self.client.initialize() mock_precheck.side_effect = Exception('server_died') @@ -227,8 +246,10 @@ def test_gen_request(self): with all required fields. """ request = self.client._gen_rpc_request(0, 'test_rpc', 1, 2, test_key=3) - expected_result = ('{"id": 0, "kwargs": {"test_key": 3}, ' - '"method": "test_rpc", "params": [1, 2]}') + expected_result = ( + '{"id": 0, "kwargs": {"test_key": 3}, ' + '"method": "test_rpc", "params": [1, 2]}' + ) self.assertEqual(request, expected_result) def test_gen_request_without_kwargs(self): @@ -243,43 +264,52 @@ def test_gen_request_without_kwargs(self): def test_rpc_no_response(self): """Test parsing an empty RPC response.""" - with self.assertRaisesRegex(errors.ProtocolError, - errors.ProtocolError.NO_RESPONSE_FROM_SERVER): + with self.assertRaisesRegex( + errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_SERVER + ): self.client._decode_response_string_and_validate_format(0, '') - with self.assertRaisesRegex(errors.ProtocolError, - errors.ProtocolError.NO_RESPONSE_FROM_SERVER): + with self.assertRaisesRegex( + errors.ProtocolError, errors.ProtocolError.NO_RESPONSE_FROM_SERVER + ): self.client._decode_response_string_and_validate_format(0, None) def test_rpc_response_missing_fields(self): """Test parsing an RPC response that misses some required fields.""" mock_resp_without_id = '{"result": 123, "error": null, "callback": null}' with self.assertRaisesRegex( - errors.ProtocolError, - errors.ProtocolError.RESPONSE_MISSING_FIELD % 'id'): + errors.ProtocolError, errors.ProtocolError.RESPONSE_MISSING_FIELD % 'id' + ): self.client._decode_response_string_and_validate_format( - 10, mock_resp_without_id) + 10, mock_resp_without_id + ) mock_resp_without_result = '{"id": 10, "error": null, "callback": null}' with self.assertRaisesRegex( errors.ProtocolError, - errors.ProtocolError.RESPONSE_MISSING_FIELD % 'result'): + errors.ProtocolError.RESPONSE_MISSING_FIELD % 'result', + ): self.client._decode_response_string_and_validate_format( - 10, mock_resp_without_result) + 10, mock_resp_without_result + ) mock_resp_without_error = '{"id": 10, "result": 123, "callback": null}' with self.assertRaisesRegex( errors.ProtocolError, - errors.ProtocolError.RESPONSE_MISSING_FIELD % 'error'): + errors.ProtocolError.RESPONSE_MISSING_FIELD % 'error', + ): self.client._decode_response_string_and_validate_format( - 10, mock_resp_without_error) + 10, mock_resp_without_error + ) mock_resp_without_callback = '{"id": 10, "result": 123, "error": null}' with self.assertRaisesRegex( errors.ProtocolError, - errors.ProtocolError.RESPONSE_MISSING_FIELD % 'callback'): + errors.ProtocolError.RESPONSE_MISSING_FIELD % 'callback', + ): self.client._decode_response_string_and_validate_format( - 10, mock_resp_without_callback) + 10, mock_resp_without_callback + ) def test_rpc_response_error(self): """Test parsing an RPC response with a non-empty error field.""" @@ -299,15 +329,17 @@ def test_rpc_response_callback(self): 'id': 10, 'result': 123, 'error': None, - 'callback': '1-0' + 'callback': '1-0', } - with mock.patch.object(self.client, - 'handle_callback') as mock_handle_callback: + with mock.patch.object( + self.client, 'handle_callback' + ) as mock_handle_callback: expected_callback = mock.Mock() mock_handle_callback.return_value = expected_callback - rpc_result = self.client._handle_rpc_response('some_rpc', - mock_resp_with_callback) + rpc_result = self.client._handle_rpc_response( + 'some_rpc', mock_resp_with_callback + ) mock_handle_callback.assert_called_with('1-0', 123, 'some_rpc') # Ensure the RPC function returns what handle_callback returned self.assertIs(expected_callback, rpc_result) @@ -317,10 +349,11 @@ def test_rpc_response_callback(self): 'id': 10, 'result': 123, 'error': None, - 'callback': None + 'callback': None, } - with mock.patch.object(self.client, - 'handle_callback') as mock_handle_callback: + with mock.patch.object( + self.client, 'handle_callback' + ) as mock_handle_callback: self.client._handle_rpc_response('some_rpc', mock_resp_without_callback) mock_handle_callback.assert_not_called() @@ -330,8 +363,9 @@ def test_rpc_response_id_mismatch(self): wrong_id = 20 resp = f'{{"id": {right_id}, "result": 1, "error": null, "callback": null}}' - with self.assertRaisesRegex(errors.ProtocolError, - errors.ProtocolError.MISMATCHED_API_ID): + with self.assertRaisesRegex( + errors.ProtocolError, errors.ProtocolError.MISMATCHED_API_ID + ): self.client._decode_response_string_and_validate_format(wrong_id, resp) @mock.patch.object(FakeClient, 'send_rpc_request') @@ -343,7 +377,8 @@ def test_rpc_verbose_logging_with_long_string(self, mock_send_request): self.client.initialize() resp = _generate_fix_length_rpc_response( - client_base._MAX_RPC_RESP_LOGGING_LENGTH * 2) + client_base._MAX_RPC_RESP_LOGGING_LENGTH * 2 + ) mock_send_request.return_value = resp self.client.some_rpc(1, 2) mock_log.debug.assert_called_with('Snippet received: %s', resp) @@ -357,7 +392,8 @@ def test_rpc_truncated_logging_short_response(self, mock_send_request): self.client.initialize() resp = _generate_fix_length_rpc_response( - int(client_base._MAX_RPC_RESP_LOGGING_LENGTH // 2)) + int(client_base._MAX_RPC_RESP_LOGGING_LENGTH // 2) + ) mock_send_request.return_value = resp self.client.some_rpc(1, 2) mock_log.debug.assert_called_with('Snippet received: %s', resp) @@ -371,7 +407,8 @@ def test_rpc_truncated_logging_fit_size_response(self, mock_send_request): self.client.initialize() resp = _generate_fix_length_rpc_response( - client_base._MAX_RPC_RESP_LOGGING_LENGTH) + client_base._MAX_RPC_RESP_LOGGING_LENGTH + ) mock_send_request.return_value = resp self.client.some_rpc(1, 2) mock_log.debug.assert_called_with('Snippet received: %s', resp) @@ -390,8 +427,9 @@ def test_rpc_truncated_logging_long_response(self, mock_send_request): self.client.some_rpc(1, 2) mock_log.debug.assert_called_with( 'Snippet received: %s... %d chars are truncated', - resp[:client_base._MAX_RPC_RESP_LOGGING_LENGTH], - len(resp) - max_len) + resp[: client_base._MAX_RPC_RESP_LOGGING_LENGTH], + len(resp) - max_len, + ) @mock.patch.object(FakeClient, 'send_rpc_request') def test_rpc_call_increment_counter(self, mock_send_request): diff --git a/tests/mobly/suite_runner_test.py b/tests/mobly/suite_runner_test.py index 93b01161..b1023e7f 100755 --- a/tests/mobly/suite_runner_test.py +++ b/tests/mobly/suite_runner_test.py @@ -40,53 +40,67 @@ def tearDown(self): shutil.rmtree(self.tmp_dir) def test_select_no_args(self): - identifiers = suite_runner.compute_selected_tests(test_classes=[ - integration_test.IntegrationTest, integration2_test.Integration2Test - ], - selected_tests=None) + identifiers = suite_runner.compute_selected_tests( + test_classes=[ + integration_test.IntegrationTest, + integration2_test.Integration2Test, + ], + selected_tests=None, + ) self.assertEqual( { integration_test.IntegrationTest: None, integration2_test.Integration2Test: None, - }, identifiers) + }, + identifiers, + ) def test_select_by_class(self): identifiers = suite_runner.compute_selected_tests( test_classes=[ - integration_test.IntegrationTest, integration2_test.Integration2Test + integration_test.IntegrationTest, + integration2_test.Integration2Test, ], - selected_tests=['IntegrationTest']) + selected_tests=['IntegrationTest'], + ) self.assertEqual({integration_test.IntegrationTest: None}, identifiers) def test_select_by_method(self): identifiers = suite_runner.compute_selected_tests( test_classes=[ - integration_test.IntegrationTest, integration2_test.Integration2Test + integration_test.IntegrationTest, + integration2_test.Integration2Test, ], - selected_tests=['IntegrationTest.test_a', 'IntegrationTest.test_b']) - self.assertEqual({integration_test.IntegrationTest: ['test_a', 'test_b']}, - identifiers) + selected_tests=['IntegrationTest.test_a', 'IntegrationTest.test_b'], + ) + self.assertEqual( + {integration_test.IntegrationTest: ['test_a', 'test_b']}, identifiers + ) def test_select_all_clobbers_method(self): identifiers = suite_runner.compute_selected_tests( test_classes=[ - integration_test.IntegrationTest, integration2_test.Integration2Test + integration_test.IntegrationTest, + integration2_test.Integration2Test, ], - selected_tests=['IntegrationTest.test_a', 'IntegrationTest']) + selected_tests=['IntegrationTest.test_a', 'IntegrationTest'], + ) self.assertEqual({integration_test.IntegrationTest: None}, identifiers) identifiers = suite_runner.compute_selected_tests( test_classes=[ - integration_test.IntegrationTest, integration2_test.Integration2Test + integration_test.IntegrationTest, + integration2_test.Integration2Test, ], - selected_tests=['IntegrationTest', 'IntegrationTest.test_a']) + selected_tests=['IntegrationTest', 'IntegrationTest.test_a'], + ) self.assertEqual({integration_test.IntegrationTest: None}, identifiers) @mock.patch('sys.exit') def test_run_suite(self, mock_exit): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u""" + f.write(""" TestBeds: # A test bed where adb will find Android devices. - Name: SampleTestBed @@ -96,23 +110,25 @@ def test_run_suite(self, mock_exit): icecream: 42 extra_param: 'haha' """) - suite_runner.run_suite([integration_test.IntegrationTest], - argv=['-c', tmp_file_path]) + suite_runner.run_suite( + [integration_test.IntegrationTest], argv=['-c', tmp_file_path] + ) mock_exit.assert_not_called() @mock.patch('sys.exit') def test_run_suite_with_failures(self, mock_exit): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u""" + f.write(""" TestBeds: # A test bed where adb will find Android devices. - Name: SampleTestBed Controllers: MagicDevice: '*' """) - suite_runner.run_suite([integration_test.IntegrationTest], - argv=['-c', tmp_file_path]) + suite_runner.run_suite( + [integration_test.IntegrationTest], argv=['-c', tmp_file_path] + ) mock_exit.assert_called_once_with(1) @mock.patch('sys.exit') @@ -135,7 +151,7 @@ def teardown_suite(self): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u""" + f.write(""" TestBeds: # A test bed where adb will find Android devices. - Name: SampleTestBed @@ -170,5 +186,5 @@ def test_print_test_names_with_exception(self): mock_cls_instance._clean_up.assert_called_once() -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/test_runner_test.py b/tests/mobly/test_runner_test.py index b8a1ff99..bd9a8fd3 100755 --- a/tests/mobly/test_runner_test.py +++ b/tests/mobly/test_runner_test.py @@ -47,7 +47,7 @@ def setUp(self): self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, - 'extra_param': 'haha' + 'extra_param': 'haha', } self.base_mock_test_config.log_path = self.tmp_dir self.log_dir = self.base_mock_test_config.log_path @@ -57,11 +57,13 @@ def tearDown(self): shutil.rmtree(self.tmp_dir) def _assertControllerInfoEqual(self, info, expected_info_dict): - self.assertEqual(expected_info_dict['Controller Name'], - info.controller_name) + self.assertEqual( + expected_info_dict['Controller Name'], info.controller_name + ) self.assertEqual(expected_info_dict['Test Class'], info.test_class) - self.assertEqual(expected_info_dict['Controller Info'], - info.controller_info) + self.assertEqual( + expected_info_dict['Controller Info'], info.controller_info + ) def test_run_twice(self): """Verifies that: @@ -71,20 +73,18 @@ def test_run_twice(self): """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - my_config = [{ - 'serial': 'xxxx', - 'magic': 'Magic1' - }, { - 'serial': 'xxxx', - 'magic': 'Magic2' - }] + my_config = [ + {'serial': 'xxxx', 'magic': 'Magic1'}, + {'serial': 'xxxx', 'magic': 'Magic2'}, + ] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(): tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() self.assertTrue( - mock_test_config.controller_configs[mock_ctrlr_config_name][0]) + mock_test_config.controller_configs[mock_ctrlr_config_name][0] + ) with tr.mobly_logger(): tr.run() results = tr.results.summary_dict() @@ -92,24 +92,22 @@ def test_run_twice(self): self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) expected_info_dict = { - 'Controller Info': [{ - 'MyMagic': { - 'magic': 'Magic1' - } - }, { - 'MyMagic': { - 'magic': 'Magic2' - } - }], + 'Controller Info': [ + {'MyMagic': {'magic': 'Magic1'}}, + {'MyMagic': {'magic': 'Magic2'}}, + ], 'Controller Name': 'MagicDevice', 'Test Class': 'IntegrationTest', } - self._assertControllerInfoEqual(tr.results.controller_info[0], - expected_info_dict) - self._assertControllerInfoEqual(tr.results.controller_info[1], - expected_info_dict) - self.assertNotEqual(tr.results.controller_info[0], - tr.results.controller_info[1]) + self._assertControllerInfoEqual( + tr.results.controller_info[0], expected_info_dict + ) + self._assertControllerInfoEqual( + tr.results.controller_info[1], expected_info_dict + ) + self.assertNotEqual( + tr.results.controller_info[0], tr.results.controller_info[1] + ) def test_summary_file_entries(self): """Verifies the output summary's file format. @@ -119,40 +117,46 @@ def test_summary_file_entries(self): """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - my_config = [{ - 'serial': 'xxxx', - 'magic': 'Magic1' - }, { - 'serial': 'xxxx', - 'magic': 'Magic2' - }] + my_config = [ + {'serial': 'xxxx', 'magic': 'Magic1'}, + {'serial': 'xxxx', 'magic': 'Magic2'}, + ] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(): tr.add_test_class(mock_test_config, integration_test.IntegrationTest) tr.run() - summary_path = os.path.join(logging.root_output_path, - records.OUTPUT_FILE_SUMMARY) + summary_path = os.path.join( + logging.root_output_path, records.OUTPUT_FILE_SUMMARY + ) with io.open(summary_path, 'r', encoding='utf-8') as f: summary_entries = list(yaml.safe_load_all(f)) self.assertEqual(len(summary_entries), 4) # Verify the first entry is the list of test names. - self.assertEqual(summary_entries[0]['Type'], - records.TestSummaryEntryType.TEST_NAME_LIST.value) - self.assertEqual(summary_entries[1]['Type'], - records.TestSummaryEntryType.RECORD.value) - self.assertEqual(summary_entries[2]['Type'], - records.TestSummaryEntryType.CONTROLLER_INFO.value) - self.assertEqual(summary_entries[3]['Type'], - records.TestSummaryEntryType.SUMMARY.value) + self.assertEqual( + summary_entries[0]['Type'], + records.TestSummaryEntryType.TEST_NAME_LIST.value, + ) + self.assertEqual( + summary_entries[1]['Type'], records.TestSummaryEntryType.RECORD.value + ) + self.assertEqual( + summary_entries[2]['Type'], + records.TestSummaryEntryType.CONTROLLER_INFO.value, + ) + self.assertEqual( + summary_entries[3]['Type'], records.TestSummaryEntryType.SUMMARY.value + ) def test_run(self): tr = test_runner.TestRunner(self.log_dir, self.testbed_name) self.base_mock_test_config.controller_configs[ - mock_controller.MOBLY_CONTROLLER_CONFIG_NAME] = '*' + mock_controller.MOBLY_CONTROLLER_CONFIG_NAME + ] = '*' with tr.mobly_logger(): - tr.add_test_class(self.base_mock_test_config, - integration_test.IntegrationTest) + tr.add_test_class( + self.base_mock_test_config, integration_test.IntegrationTest + ) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 1) @@ -165,9 +169,11 @@ def test_run(self): def test_run_without_mobly_logger_context(self): tr = test_runner.TestRunner(self.log_dir, self.testbed_name) self.base_mock_test_config.controller_configs[ - mock_controller.MOBLY_CONTROLLER_CONFIG_NAME] = '*' - tr.add_test_class(self.base_mock_test_config, - integration_test.IntegrationTest) + mock_controller.MOBLY_CONTROLLER_CONFIG_NAME + ] = '*' + tr.add_test_class( + self.base_mock_test_config, integration_test.IntegrationTest + ) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 1) @@ -177,16 +183,24 @@ def test_run_without_mobly_logger_context(self): record = tr.results.executed[0] self.assertEqual(record.test_class, 'IntegrationTest') - @mock.patch('mobly.controllers.android_device_lib.adb.AdbProxy', - return_value=mock_android_device.MockAdbProxy(1)) - @mock.patch('mobly.controllers.android_device_lib.fastboot.FastbootProxy', - return_value=mock_android_device.MockFastbootProxy(1)) - @mock.patch('mobly.controllers.android_device.list_adb_devices', - return_value=['1']) - @mock.patch('mobly.controllers.android_device.get_all_instances', - return_value=mock_android_device.get_mock_ads(1)) - def test_run_two_test_classes(self, mock_get_all, mock_list_adb, - mock_fastboot, mock_adb): + @mock.patch( + 'mobly.controllers.android_device_lib.adb.AdbProxy', + return_value=mock_android_device.MockAdbProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device_lib.fastboot.FastbootProxy', + return_value=mock_android_device.MockFastbootProxy(1), + ) + @mock.patch( + 'mobly.controllers.android_device.list_adb_devices', return_value=['1'] + ) + @mock.patch( + 'mobly.controllers.android_device.get_all_instances', + return_value=mock_android_device.get_mock_ads(1), + ) + def test_run_two_test_classes( + self, mock_get_all, mock_list_adb, mock_fastboot, mock_adb + ): """Verifies that running more than one test class in one test run works properly. @@ -195,13 +209,10 @@ def test_run_two_test_classes(self, mock_get_all, mock_list_adb, """ mock_test_config = self.base_mock_test_config.copy() mock_ctrlr_config_name = mock_controller.MOBLY_CONTROLLER_CONFIG_NAME - my_config = [{ - 'serial': 'xxxx', - 'magic': 'Magic1' - }, { - 'serial': 'xxxx', - 'magic': 'Magic2' - }] + my_config = [ + {'serial': 'xxxx', 'magic': 'Magic1'}, + {'serial': 'xxxx', 'magic': 'Magic2'}, + ] mock_test_config.controller_configs[mock_ctrlr_config_name] = my_config mock_test_config.controller_configs['AndroidDevice'] = [{'serial': '1'}] tr = test_runner.TestRunner(self.log_dir, self.testbed_name) @@ -226,20 +237,18 @@ def test_run_two_test_classes_different_configs_and_aliases(self): """ config1 = self.base_mock_test_config.copy() config1.controller_configs[mock_controller.MOBLY_CONTROLLER_CONFIG_NAME] = [ - { - 'serial': 'xxxx' - } + {'serial': 'xxxx'} ] config2 = config1.copy() config2.user_params['icecream'] = 10 tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with tr.mobly_logger(): - tr.add_test_class(config1, - integration_test.IntegrationTest, - name_suffix='FirstConfig') - tr.add_test_class(config2, - integration_test.IntegrationTest, - name_suffix='SecondConfig') + tr.add_test_class( + config1, integration_test.IntegrationTest, name_suffix='FirstConfig' + ) + tr.add_test_class( + config2, integration_test.IntegrationTest, name_suffix='SecondConfig' + ) tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) @@ -278,8 +287,9 @@ def test_run_when_terminated(self): logging.getLogger().handlers[0].setLevel(logging.WARNING) tr.run() - self.assertIn('Test received a SIGTERM. Aborting all tests.', - log_output.output[0]) + self.assertIn( + 'Test received a SIGTERM. Aborting all tests.', log_output.output[0] + ) self.assertIn('Abort all subsequent test classes', log_output.output[1]) self.assertIn('Test received a SIGTERM.', log_output.output[1]) @@ -288,42 +298,52 @@ def test_add_test_class_mismatched_log_path(self): with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s log folder is "/different/log/dir", but a test ' - r'config with a different log folder \("%s"\) was added.' % - re.escape(self.log_dir)): - tr.add_test_class(self.base_mock_test_config, - integration_test.IntegrationTest) + r'config with a different log folder \("%s"\) was added.' + % re.escape(self.log_dir), + ): + tr.add_test_class( + self.base_mock_test_config, integration_test.IntegrationTest + ) def test_add_test_class_mismatched_testbed_name(self): tr = test_runner.TestRunner(self.log_dir, 'different_test_bed') with self.assertRaisesRegex( test_runner.Error, 'TestRunner\'s test bed is "different_test_bed", but a test ' - r'config with a different test bed \("%s"\) was added.' % - self.testbed_name): - tr.add_test_class(self.base_mock_test_config, - integration_test.IntegrationTest) + r'config with a different test bed \("%s"\) was added.' + % self.testbed_name, + ): + tr.add_test_class( + self.base_mock_test_config, integration_test.IntegrationTest + ) def test_run_no_tests(self): tr = test_runner.TestRunner(self.log_dir, self.testbed_name) with self.assertRaisesRegex(test_runner.Error, 'No tests to execute.'): tr.run() - @mock.patch('mobly.test_runner._find_test_class', - return_value=type('SampleTest', (), {})) - @mock.patch('mobly.test_runner.config_parser.load_test_config_file', - return_value=[config_parser.TestRunConfig()]) + @mock.patch( + 'mobly.test_runner._find_test_class', + return_value=type('SampleTest', (), {}), + ) + @mock.patch( + 'mobly.test_runner.config_parser.load_test_config_file', + return_value=[config_parser.TestRunConfig()], + ) @mock.patch('mobly.test_runner.TestRunner', return_value=mock.MagicMock()) def test_main_parse_args(self, mock_test_runner, mock_config, mock_find_test): test_runner.main(['-c', 'some/path/foo.yaml', '-b', 'hello']) mock_config.assert_called_with('some/path/foo.yaml', None) - @mock.patch('mobly.test_runner._find_test_class', - return_value=integration_test.IntegrationTest) + @mock.patch( + 'mobly.test_runner._find_test_class', + return_value=integration_test.IntegrationTest, + ) @mock.patch('sys.exit') def test_main(self, mock_exit, mock_find_test): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u""" + f.write(""" TestBeds: # A test bed where adb will find Android devices. - Name: SampleTestBed @@ -336,13 +356,15 @@ def test_main(self, mock_exit, mock_find_test): test_runner.main(['-c', tmp_file_path]) mock_exit.assert_not_called() - @mock.patch('mobly.test_runner._find_test_class', - return_value=integration_test.IntegrationTest) + @mock.patch( + 'mobly.test_runner._find_test_class', + return_value=integration_test.IntegrationTest, + ) @mock.patch('sys.exit') def test_main_with_failures(self, mock_exit, mock_find_test): tmp_file_path = os.path.join(self.tmp_dir, 'config.yml') with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u""" + f.write(""" TestBeds: # A test bed where adb will find Android devices. - Name: SampleTestBed @@ -384,5 +406,5 @@ def test_print_test_names_with_exception(self): mock_cls_instance._clean_up.assert_called_once() -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/test_suite_test.py b/tests/mobly/test_suite_test.py index d3537f83..4eadfdb7 100755 --- a/tests/mobly/test_suite_test.py +++ b/tests/mobly/test_suite_test.py @@ -36,16 +36,17 @@ def setUp(self): self.mock_test_cls_configs = config_parser.TestRunConfig() self.summary_file = os.path.join(self.tmp_dir, 'summary.yaml') self.mock_test_cls_configs.summary_writer = records.TestSummaryWriter( - self.summary_file) + self.summary_file + ) self.mock_test_cls_configs.log_path = self.tmp_dir - self.mock_test_cls_configs.user_params = {"some_param": "hahaha"} + self.mock_test_cls_configs.user_params = {'some_param': 'hahaha'} self.mock_test_cls_configs.reporter = mock.MagicMock() self.base_mock_test_config = config_parser.TestRunConfig() self.base_mock_test_config.testbed_name = 'SampleTestBed' self.base_mock_test_config.controller_configs = {} self.base_mock_test_config.user_params = { 'icecream': 42, - 'extra_param': 'haha' + 'extra_param': 'haha', } self.base_mock_test_config.log_path = self.tmp_dir @@ -74,5 +75,5 @@ def setup_class(cls2): self.assertIsNot(self.controller1, self.controller2) -if __name__ == "__main__": +if __name__ == '__main__': unittest.main() diff --git a/tests/mobly/utils_test.py b/tests/mobly/utils_test.py index 7e957182..fff38034 100755 --- a/tests/mobly/utils_test.py +++ b/tests/mobly/utils_test.py @@ -45,11 +45,14 @@ def _is_process_running(pid): """Whether the process with given PID is running.""" if os.name == 'nt': - return str(pid) in subprocess.check_output([ - 'tasklist', - '/fi', - f'PID eq {pid}', - ]).decode() + return ( + str(pid) + in subprocess.check_output([ + 'tasklist', + '/fi', + f'PID eq {pid}', + ]).decode() + ) try: # os.kill throws OSError if the process with PID pid is not running. @@ -102,19 +105,24 @@ def sleep_cmd(self, wait_secs): else: return ['sleep', str(wait_secs)] - @unittest.skipIf(os.name == "nt", - 'collect_process_tree only available on Unix like system.') + @unittest.skipIf( + os.name == 'nt', + 'collect_process_tree only available on Unix like system.', + ) @mock.patch('subprocess.check_output') def test_collect_process_tree_without_child(self, mock_check_output): - mock_check_output.side_effect = (subprocess.CalledProcessError( - -1, 'fake_cmd')) + mock_check_output.side_effect = subprocess.CalledProcessError( + -1, 'fake_cmd' + ) pid_list = utils._collect_process_tree(123) self.assertListEqual(pid_list, []) - @unittest.skipIf(os.name == "nt", - 'collect_process_tree only available on Unix like system.') + @unittest.skipIf( + os.name == 'nt', + 'collect_process_tree only available on Unix like system.', + ) @mock.patch('subprocess.check_output') def test_collect_process_tree_returns_list(self, mock_check_output): # Creates subprocess 777 with descendants looks like: @@ -151,8 +159,9 @@ def test_collect_process_tree_returns_list(self, mock_check_output): @mock.patch.object(os, 'kill') @mock.patch.object(utils, '_collect_process_tree') - def test_kill_process_tree_on_unix_succeeds(self, mock_collect_process_tree, - mock_os_kill): + def test_kill_process_tree_on_unix_succeeds( + self, mock_collect_process_tree, mock_os_kill + ): mock_collect_process_tree.return_value = [799, 888, 890] mock_proc = mock.MagicMock() mock_proc.pid = 123 @@ -170,7 +179,8 @@ def test_kill_process_tree_on_unix_succeeds(self, mock_collect_process_tree, @mock.patch.object(os, 'kill') @mock.patch.object(utils, '_collect_process_tree') def test_kill_process_tree_on_unix_kill_children_failed_throws_error( - self, mock_collect_process_tree, mock_os_kill): + self, mock_collect_process_tree, mock_os_kill + ): mock_collect_process_tree.return_value = [799, 888, 890] mock_os_kill.side_effect = [None, OSError(), None] mock_proc = mock.MagicMock() @@ -184,7 +194,8 @@ def test_kill_process_tree_on_unix_kill_children_failed_throws_error( @mock.patch.object(utils, '_collect_process_tree') def test_kill_process_tree_on_unix_kill_proc_failed_throws_error( - self, mock_collect_process_tree): + self, mock_collect_process_tree + ): mock_collect_process_tree.return_value = [] mock_proc = mock.MagicMock() mock_proc.pid = 123 @@ -262,13 +273,15 @@ def test_run_command_with_custom_params(self, mock_popen, mock_timer): mock_proc.communicate.return_value = ('fake_out', 'fake_err') mock_proc.returncode = 127 - out = utils.run_command(mock_command, - stdout=mock_stdout, - stderr=mock_stderr, - shell=mock_shell, - timeout=mock_timeout, - env=mock_env, - universal_newlines=mock_universal_newlines) + out = utils.run_command( + mock_command, + stdout=mock_stdout, + stderr=mock_stderr, + shell=mock_shell, + timeout=mock_timeout, + env=mock_env, + universal_newlines=mock_universal_newlines, + ) self.assertEqual(out, (127, 'fake_out', 'fake_err')) mock_popen.assert_called_with( @@ -283,8 +296,9 @@ def test_run_command_with_custom_params(self, mock_popen, mock_timer): mock_timer.assert_called_with(1234, mock.ANY) def test_run_command_with_universal_newlines_false(self): - _, out, _ = utils.run_command(self.sleep_cmd(0.01), - universal_newlines=False) + _, out, _ = utils.run_command( + self.sleep_cmd(0.01), universal_newlines=False + ) self.assertIsInstance(out, bytes) @@ -352,19 +366,29 @@ def test_stop_standing_subproc_and_descendants(self): # │ └─ Y (grandchild) # ├─ C (child) # └─ D (child) - process_tree_args = ('subprocess_a', [ - ('child_b', [ - ('grand_child_x', [ - ('great_grand_child_1', []), - ('great_grand_child_2', []), - ]), - ('grand_child_y', []), - ]), - ('child_c', []), - ('child_d', []), - ]) - subprocess_a = multiprocessing.Process(target=_fork_children_processes, - args=process_tree_args) + process_tree_args = ( + 'subprocess_a', + [ + ( + 'child_b', + [ + ( + 'grand_child_x', + [ + ('great_grand_child_1', []), + ('great_grand_child_2', []), + ], + ), + ('grand_child_y', []), + ], + ), + ('child_c', []), + ('child_d', []), + ], + ) + subprocess_a = multiprocessing.Process( + target=_fork_children_processes, args=process_tree_args + ) subprocess_a.start() mock_subprocess_a_popen = mock.MagicMock() mock_subprocess_a_popen.pid = subprocess_a.pid @@ -376,16 +400,17 @@ def test_stop_standing_subproc_and_descendants(self): subprocess_a.join(timeout=1) mock_subprocess_a_popen.wait.assert_called_once() - @unittest.skipIf(sys.version_info >= (3, 4) and sys.version_info < (3, 5), - 'Python 3.4 does not support `None` max_workers.') + @unittest.skipIf( + sys.version_info >= (3, 4) and sys.version_info < (3, 5), + 'Python 3.4 does not support `None` max_workers.', + ) def test_concurrent_exec_when_none_workers(self): - def adder(a, b): return a + b - with mock.patch.object(futures, - 'ThreadPoolExecutor', - wraps=futures.ThreadPoolExecutor) as thread_pool_spy: + with mock.patch.object( + futures, 'ThreadPoolExecutor', wraps=futures.ThreadPoolExecutor + ) as thread_pool_spy: results = utils.concurrent_exec(adder, [(1, 1), (2, 2)], max_workers=None) thread_pool_spy.assert_called_once_with(max_workers=None) @@ -395,13 +420,12 @@ def adder(a, b): self.assertIn(4, results) def test_concurrent_exec_when_default_max_workers(self): - def adder(a, b): return a + b - with mock.patch.object(futures, - 'ThreadPoolExecutor', - wraps=futures.ThreadPoolExecutor) as thread_pool_spy: + with mock.patch.object( + futures, 'ThreadPoolExecutor', wraps=futures.ThreadPoolExecutor + ) as thread_pool_spy: results = utils.concurrent_exec(adder, [(1, 1), (2, 2)]) thread_pool_spy.assert_called_once_with(max_workers=30) @@ -411,13 +435,12 @@ def adder(a, b): self.assertIn(4, results) def test_concurrent_exec_when_custom_max_workers(self): - def adder(a, b): return a + b - with mock.patch.object(futures, - 'ThreadPoolExecutor', - wraps=futures.ThreadPoolExecutor) as thread_pool_spy: + with mock.patch.object( + futures, 'ThreadPoolExecutor', wraps=futures.ThreadPoolExecutor + ) as thread_pool_spy: results = utils.concurrent_exec(adder, [(1, 1), (2, 2)], max_workers=1) thread_pool_spy.assert_called_once_with(max_workers=1) @@ -427,18 +450,20 @@ def adder(a, b): def test_concurrent_exec_makes_all_calls(self): mock_function = mock.MagicMock() - _ = utils.concurrent_exec(mock_function, [ - (1, 1), - (2, 2), - (3, 3), - ]) + _ = utils.concurrent_exec( + mock_function, + [ + (1, 1), + (2, 2), + (3, 3), + ], + ) self.assertEqual(mock_function.call_count, 3) mock_function.assert_has_calls( - [mock.call(1, 1), mock.call(2, 2), - mock.call(3, 3)], any_order=True) + [mock.call(1, 1), mock.call(2, 2), mock.call(3, 3)], any_order=True + ) def test_concurrent_exec_generates_results(self): - def adder(a, b): return a + b @@ -451,42 +476,54 @@ def test_concurrent_exec_when_exception_makes_all_calls(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) - utils.concurrent_exec(fake_int, [ - (1,), - ('123',), - ('not_int',), - (5435,), - ]) + utils.concurrent_exec( + fake_int, + [ + (1,), + ('123',), + ('not_int',), + (5435,), + ], + ) self.assertEqual(mock_call_recorder.call_count, 4) - mock_call_recorder.assert_has_calls([ - mock.call(1), - mock.call('123'), - mock.call('not_int'), - mock.call(5435), - ], - any_order=True) + mock_call_recorder.assert_has_calls( + [ + mock.call(1), + mock.call('123'), + mock.call('not_int'), + mock.call(5435), + ], + any_order=True, + ) def test_concurrent_exec_when_exception_generates_results(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) - results = utils.concurrent_exec(fake_int, [ - (1,), - ('123',), - ('not_int',), - (5435,), - ]) + results = utils.concurrent_exec( + fake_int, + [ + (1,), + ('123',), + ('not_int',), + (5435,), + ], + ) self.assertEqual(len(results), 4) self.assertIn(1, results) @@ -500,42 +537,54 @@ def test_concurrent_exec_when_multiple_exceptions_makes_all_calls(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) - utils.concurrent_exec(fake_int, [ - (1,), - ('not_int1',), - ('not_int2',), - (5435,), - ]) + utils.concurrent_exec( + fake_int, + [ + (1,), + ('not_int1',), + ('not_int2',), + (5435,), + ], + ) self.assertEqual(mock_call_recorder.call_count, 4) - mock_call_recorder.assert_has_calls([ - mock.call(1), - mock.call('not_int1'), - mock.call('not_int2'), - mock.call(5435), - ], - any_order=True) + mock_call_recorder.assert_has_calls( + [ + mock.call(1), + mock.call('not_int1'), + mock.call('not_int2'), + mock.call(5435), + ], + any_order=True, + ) def test_concurrent_exec_when_multiple_exceptions_generates_results(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) - results = utils.concurrent_exec(fake_int, [ - (1,), - ('not_int1',), - ('not_int2',), - (5435,), - ]) + results = utils.concurrent_exec( + fake_int, + [ + (1,), + ('not_int1',), + ('not_int2',), + (5435,), + ], + ) self.assertEqual(len(results), 4) self.assertIn(1, results) @@ -547,12 +596,12 @@ def fake_int(a,): self.assertNotEqual(exceptions[0], exceptions[1]) def test_concurrent_exec_when_raising_exception_generates_results(self): - def adder(a, b): return a + b - results = utils.concurrent_exec(adder, [(1, 1), (2, 2)], - raise_on_exception=True) + results = utils.concurrent_exec( + adder, [(1, 1), (2, 2)], raise_on_exception=True + ) self.assertEqual(len(results), 2) self.assertIn(2, results) self.assertIn(4, results) @@ -561,58 +610,74 @@ def test_concurrent_exec_when_raising_exception_makes_all_calls(self): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) with self.assertRaisesRegex(RuntimeError, '.*not_int.*'): - _ = utils.concurrent_exec(fake_int, [ - (1,), - ('123',), - ('not_int',), - (5435,), - ], - raise_on_exception=True) + _ = utils.concurrent_exec( + fake_int, + [ + (1,), + ('123',), + ('not_int',), + (5435,), + ], + raise_on_exception=True, + ) self.assertEqual(mock_call_recorder.call_count, 4) - mock_call_recorder.assert_has_calls([ - mock.call(1), - mock.call('123'), - mock.call('not_int'), - mock.call(5435), - ], - any_order=True) + mock_call_recorder.assert_has_calls( + [ + mock.call(1), + mock.call('123'), + mock.call('not_int'), + mock.call(5435), + ], + any_order=True, + ) def test_concurrent_exec_when_raising_multiple_exceptions_makes_all_calls( - self): + self, + ): mock_call_recorder = mock.MagicMock() lock_call_count = threading.Lock() - def fake_int(a,): + def fake_int( + a, + ): with lock_call_count: mock_call_recorder(a) return int(a) with self.assertRaisesRegex( RuntimeError, - r'(?m).*(not_int1(.|\s)+not_int2|not_int2(.|\s)+not_int1).*'): - _ = utils.concurrent_exec(fake_int, [ - (1,), - ('not_int1',), - ('not_int2',), - (5435,), - ], - raise_on_exception=True) + r'(?m).*(not_int1(.|\s)+not_int2|not_int2(.|\s)+not_int1).*', + ): + _ = utils.concurrent_exec( + fake_int, + [ + (1,), + ('not_int1',), + ('not_int2',), + (5435,), + ], + raise_on_exception=True, + ) self.assertEqual(mock_call_recorder.call_count, 4) - mock_call_recorder.assert_has_calls([ - mock.call(1), - mock.call('not_int1'), - mock.call('not_int2'), - mock.call(5435), - ], - any_order=True) + mock_call_recorder.assert_has_calls( + [ + mock.call(1), + mock.call('not_int1'), + mock.call('not_int2'), + mock.call(5435), + ], + any_order=True, + ) def test_create_dir(self): new_path = os.path.join(self.tmp_dir, 'haha') @@ -634,14 +699,17 @@ def test_get_available_port_positive(self, *_): @mock.patch(f'{ADB_MODULE_PACKAGE_NAME}.is_adb_available', return_value=False) @mock.patch('portpicker.pick_unused_port', return_value=MOCK_AVAILABLE_PORT) @mock.patch(f'{ADB_MODULE_PACKAGE_NAME}.list_occupied_adb_ports') - def test_get_available_port_positive_no_adb(self, - mock_list_occupied_adb_ports, *_): + def test_get_available_port_positive_no_adb( + self, mock_list_occupied_adb_ports, *_ + ): self.assertEqual(utils.get_available_host_port(), MOCK_AVAILABLE_PORT) mock_list_occupied_adb_ports.assert_not_called() @mock.patch(f'{ADB_MODULE_PACKAGE_NAME}.is_adb_available', return_value=True) - @mock.patch(f'{ADB_MODULE_PACKAGE_NAME}.list_occupied_adb_ports', - return_value=[MOCK_AVAILABLE_PORT]) + @mock.patch( + f'{ADB_MODULE_PACKAGE_NAME}.list_occupied_adb_ports', + return_value=[MOCK_AVAILABLE_PORT], + ) @mock.patch('portpicker.pick_unused_port', return_value=MOCK_AVAILABLE_PORT) def test_get_available_port_negative(self, *_): with self.assertRaisesRegex(utils.Error, 'Failed to find.* retries'): @@ -672,36 +740,38 @@ def test_get_available_port_returns_free_port(self, _): def test_load_file_to_base64_str_reads_bytes_file_as_base64_string(self): tmp_file_path = os.path.join(self.tmp_dir, 'b64.bin') - expected_base64_encoding = u'SGVsbG93IHdvcmxkIQ==' + expected_base64_encoding = 'SGVsbG93IHdvcmxkIQ==' with io.open(tmp_file_path, 'wb') as f: f.write(b'Hellow world!') - self.assertEqual(utils.load_file_to_base64_str(tmp_file_path), - expected_base64_encoding) + self.assertEqual( + utils.load_file_to_base64_str(tmp_file_path), expected_base64_encoding + ) def test_load_file_to_base64_str_reads_text_file_as_base64_string(self): tmp_file_path = os.path.join(self.tmp_dir, 'b64.bin') - expected_base64_encoding = u'SGVsbG93IHdvcmxkIQ==' + expected_base64_encoding = 'SGVsbG93IHdvcmxkIQ==' with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u'Hellow world!') - self.assertEqual(utils.load_file_to_base64_str(tmp_file_path), - expected_base64_encoding) + f.write('Hellow world!') + self.assertEqual( + utils.load_file_to_base64_str(tmp_file_path), expected_base64_encoding + ) def test_load_file_to_base64_str_reads_unicode_file_as_base64_string(self): tmp_file_path = os.path.join(self.tmp_dir, 'b64.bin') - expected_base64_encoding = u'6YCa' + expected_base64_encoding = '6YCa' with io.open(tmp_file_path, 'w', encoding='utf-8') as f: - f.write(u'\u901a') - self.assertEqual(utils.load_file_to_base64_str(tmp_file_path), - expected_base64_encoding) + f.write('\u901a') + self.assertEqual( + utils.load_file_to_base64_str(tmp_file_path), expected_base64_encoding + ) def test_cli_cmd_to_string(self): cmd = ['"adb"', 'a b', 'c//'] - self.assertEqual(utils.cli_cmd_to_string(cmd), '\'"adb"\' \'a b\' c//') + self.assertEqual(utils.cli_cmd_to_string(cmd), "'\"adb\"' 'a b' c//") cmd = 'adb -s meme do something ab_cd' self.assertEqual(utils.cli_cmd_to_string(cmd), cmd) def test_get_settable_properties(self): - class SomeClass: regular_attr = 'regular_attr' _foo = 'foo' @@ -726,26 +796,31 @@ def func(self): self.assertEqual(actual, ['settable_prop']) def test_find_subclasses_in_module_when_one_subclass(self): - subclasses = utils.find_subclasses_in_module([base_test.BaseTestClass], - integration_test) + subclasses = utils.find_subclasses_in_module( + [base_test.BaseTestClass], integration_test + ) self.assertEqual(len(subclasses), 1) self.assertEqual(subclasses[0], integration_test.IntegrationTest) def test_find_subclasses_in_module_when_indirect_subclass(self): - subclasses = utils.find_subclasses_in_module([base_test.BaseTestClass], - mock_instrumentation_test) + subclasses = utils.find_subclasses_in_module( + [base_test.BaseTestClass], mock_instrumentation_test + ) self.assertEqual(len(subclasses), 1) - self.assertEqual(subclasses[0], - mock_instrumentation_test.MockInstrumentationTest) + self.assertEqual( + subclasses[0], mock_instrumentation_test.MockInstrumentationTest + ) def test_find_subclasses_in_module_when_no_subclasses(self): - subclasses = utils.find_subclasses_in_module([base_test.BaseTestClass], - mock_controller) + subclasses = utils.find_subclasses_in_module( + [base_test.BaseTestClass], mock_controller + ) self.assertEqual(len(subclasses), 0) def test_find_subclasses_in_module_when_multiple_subclasses(self): - subclasses = utils.find_subclasses_in_module([base_test.BaseTestClass], - multiple_subclasses_module) + subclasses = utils.find_subclasses_in_module( + [base_test.BaseTestClass], multiple_subclasses_module + ) self.assertEqual(len(subclasses), 2) self.assertIn(multiple_subclasses_module.Subclass1Test, subclasses) self.assertIn(multiple_subclasses_module.Subclass2Test, subclasses) @@ -753,7 +828,8 @@ def test_find_subclasses_in_module_when_multiple_subclasses(self): def test_find_subclasses_in_module_when_multiple_base_classes(self): subclasses = utils.find_subclasses_in_module( [base_test.BaseTestClass, test_runner.TestRunner], - multiple_subclasses_module) + multiple_subclasses_module, + ) self.assertEqual(len(subclasses), 4) self.assertIn(multiple_subclasses_module.Subclass1Test, subclasses) self.assertIn(multiple_subclasses_module.Subclass2Test, subclasses) @@ -762,37 +838,45 @@ def test_find_subclasses_in_module_when_multiple_base_classes(self): def test_find_subclasses_in_module_when_only_some_base_classes_present(self): subclasses = utils.find_subclasses_in_module( - [signals.TestSignal, test_runner.TestRunner], - multiple_subclasses_module) + [signals.TestSignal, test_runner.TestRunner], multiple_subclasses_module + ) self.assertEqual(len(subclasses), 2) self.assertIn(multiple_subclasses_module.Subclass1Runner, subclasses) self.assertIn(multiple_subclasses_module.Subclass2Runner, subclasses) def test_find_subclass_in_module_when_one_subclass(self): - subclass = utils.find_subclass_in_module(base_test.BaseTestClass, - integration_test) + subclass = utils.find_subclass_in_module( + base_test.BaseTestClass, integration_test + ) self.assertEqual(subclass, integration_test.IntegrationTest) def test_find_subclass_in_module_when_indirect_subclass(self): - subclass = utils.find_subclass_in_module(base_test.BaseTestClass, - mock_instrumentation_test) - self.assertEqual(subclass, - mock_instrumentation_test.MockInstrumentationTest) + subclass = utils.find_subclass_in_module( + base_test.BaseTestClass, mock_instrumentation_test + ) + self.assertEqual( + subclass, mock_instrumentation_test.MockInstrumentationTest + ) def test_find_subclass_in_module_when_no_subclasses(self): with self.assertRaisesRegex( - ValueError, '.*Expected 1 subclass of BaseTestClass per module, found' - r' \[\].*'): - _ = utils.find_subclass_in_module(base_test.BaseTestClass, - mock_controller) + ValueError, + '.*Expected 1 subclass of BaseTestClass per module, found' r' \[\].*', + ): + _ = utils.find_subclass_in_module( + base_test.BaseTestClass, mock_controller + ) def test_find_subclass_in_module_when_multiple_subclasses(self): with self.assertRaisesRegex( - ValueError, '.*Expected 1 subclass of BaseTestClass per module, found' + ValueError, + '.*Expected 1 subclass of BaseTestClass per module, found' r' \[(\'Subclass1Test\', \'Subclass2Test\'' - r'|\'Subclass2Test\', \'Subclass1Test\')\].*'): - _ = utils.find_subclass_in_module(base_test.BaseTestClass, - multiple_subclasses_module) + r'|\'Subclass2Test\', \'Subclass1Test\')\].*', + ): + _ = utils.find_subclass_in_module( + base_test.BaseTestClass, multiple_subclasses_module + ) if __name__ == '__main__': diff --git a/tools/sl4a_shell.py b/tools/sl4a_shell.py index e8365da0..6ad656ef 100755 --- a/tools/sl4a_shell.py +++ b/tools/sl4a_shell.py @@ -51,9 +51,11 @@ def _start_services(self, console_env): def _get_banner(self, serial): lines = [ - 'Connected to %s.' % serial, 'Call methods against:', - ' ad (android_device.AndroidDevice)', ' sl4a or s (SL4A)', - ' ed (EventDispatcher)' + 'Connected to %s.' % serial, + 'Call methods against:', + ' ad (android_device.AndroidDevice)', + ' sl4a or s (SL4A)', + ' ed (EventDispatcher)', ] return '\n'.join(lines) @@ -63,7 +65,8 @@ def _get_banner(self, serial): parser.add_argument( '-s', '--serial', - help='Device serial to connect to (if more than one device is connected)') + help='Device serial to connect to (if more than one device is connected)', + ) args = parser.parse_args() logging.basicConfig(level=logging.INFO) Sl4aShell().main(args.serial) diff --git a/tools/snippet_shell.py b/tools/snippet_shell.py index 74e23c16..1d5fad44 100755 --- a/tools/snippet_shell.py +++ b/tools/snippet_shell.py @@ -46,27 +46,35 @@ def _start_services(self, console_env): def _get_banner(self, serial): lines = [ - 'Connected to %s.' % serial, 'Call methods against:', - ' ad (android_device.AndroidDevice)', ' snippet or s (Snippet)' + 'Connected to %s.' % serial, + 'Call methods against:', + ' ad (android_device.AndroidDevice)', + ' snippet or s (Snippet)', ] return '\n'.join(lines) if __name__ == '__main__': parser = argparse.ArgumentParser( - description='Interactive client for Mobly code snippets.') + description='Interactive client for Mobly code snippets.' + ) parser.add_argument( '-s', '--serial', - help='Device serial to connect to (if more than one device is connected)') - parser.add_argument('package', - metavar='PACKAGE_NAME', - type=str, - nargs='?', - help='The package name of the snippet to use.') - parser.add_argument('--mbs', - help='Whether to connect to Mobly Bundled Snippets', - action='store_true') + help='Device serial to connect to (if more than one device is connected)', + ) + parser.add_argument( + 'package', + metavar='PACKAGE_NAME', + type=str, + nargs='?', + help='The package name of the snippet to use.', + ) + parser.add_argument( + '--mbs', + help='Whether to connect to Mobly Bundled Snippets', + action='store_true', + ) args = parser.parse_args() if args.package and args.mbs: print('Cannot specify both --package and --mbs', file=sys.stderr)