conftest.py (8104B)
1 import sys 2 from io import StringIO 3 from random import randint, seed 4 from unittest.mock import patch 5 6 import mozdevice 7 import pytest 8 9 # set up required module-level variables/objects 10 seed(1488590) 11 12 13 def random_tcp_port(): 14 """Returns a pseudo-random integer generated from a seed. 15 16 :returns: int: pseudo-randomly generated integer 17 """ 18 return randint(8000, 12000) 19 20 21 @pytest.fixture(autouse=True) 22 def mock_command_output(monkeypatch): 23 """Monkeypatches the ADBDevice.command_output() method call. 24 25 Instead of calling the concrete method implemented in adb.py::ADBDevice, 26 this method simply returns a string representation of the command that was 27 received. 28 29 As an exception, if the command begins with "forward tcp:0 ", this method 30 returns a mock port number. 31 32 :param object monkeypatch: pytest provided fixture for mocking. 33 """ 34 35 def command_output_wrapper(object, cmd, timeout): 36 """Actual monkeypatch implementation of the command_output method call. 37 38 :param object object: placeholder object representing ADBDevice 39 :param str cmd: command to be executed 40 :param timeout: unused parameter to represent timeout threshold 41 :returns: string - string representation of command to be executed 42 int - mock port number (only used when cmd begins with "forward tcp:0 ") 43 """ 44 45 if cmd[0] == "forward" and cmd[1] == "tcp:0": 46 return 7777 47 48 print(str(cmd)) 49 return str(cmd) 50 51 monkeypatch.setattr(mozdevice.ADBDevice, "command_output", command_output_wrapper) 52 53 54 @pytest.fixture(autouse=True) 55 def mock_shell_output(monkeypatch): 56 """Monkeypatches the ADBDevice.shell_output() method call. 57 58 Instead of returning the output of an adb call, this method will 59 return appropriate string output. Content of the string output is 60 in line with the calling method's expectations. 61 62 :param object monkeypatch: pytest provided fixture for mocking. 63 """ 64 65 def shell_output_wrapper( 66 object, cmd, env=None, cwd=None, timeout=None, enable_run_as=False, attempts=3 67 ): 68 """Actual monkeypatch implementation of the shell_output method call. 69 70 :param object object: placeholder object representing ADBDevice 71 :param str cmd: command to be executed 72 :param env: contains the environment variable 73 :type env: dict or None 74 :param cwd: The directory from which to execute. 75 :type cwd: str or None 76 :param timeout: unused parameter tp represent timeout threshold 77 :param enable_run_as: bool determining if run_as <app> is to be used 78 :returns: string - string representation of a simulated call to adb 79 """ 80 if "pm list package error" in cmd: 81 return "Error: Could not access the Package Manager" 82 elif "pm list package none" in cmd: 83 return "" 84 elif "pm list package" in cmd: 85 apps = ["org.mozilla.fennec", "org.mozilla.geckoview_example"] 86 return ("package:{}\n" * len(apps)).format(*apps) 87 else: 88 print(str(cmd)) 89 return str(cmd) 90 91 monkeypatch.setattr(mozdevice.ADBDevice, "shell_output", shell_output_wrapper) 92 93 94 @pytest.fixture(autouse=True) 95 def mock_is_path_internal_storage(monkeypatch): 96 """Monkeypatches the ADBDevice.is_path_internal_storage() method call. 97 98 Instead of returning the outcome of whether the path provided is 99 internal storage or external, this will always return True. 100 101 :param object monkeypatch: pytest provided fixture for mocking. 102 """ 103 104 def is_path_internal_storage_wrapper(object, path, timeout=None): 105 """Actual monkeypatch implementation of the is_path_internal_storage() call. 106 107 :param str path: The path to test. 108 :param timeout: The maximum time in 109 seconds for any spawned adb process to complete before 110 throwing an ADBTimeoutError. This timeout is per adb call. The 111 total time spent may exceed this value. If it is not 112 specified, the value set in the ADBDevice constructor is used. 113 :returns: boolean 114 115 :raises: * ADBTimeoutError 116 * ADBError 117 """ 118 if "internal_storage" in path: 119 return True 120 return False 121 122 monkeypatch.setattr( 123 mozdevice.ADBDevice, 124 "is_path_internal_storage", 125 is_path_internal_storage_wrapper, 126 ) 127 128 129 @pytest.fixture(autouse=True) 130 def mock_enable_run_as_for_path(monkeypatch): 131 """Monkeypatches the ADBDevice.enable_run_as_for_path(path) method. 132 133 Always return True 134 135 :param object monkeypatch: pytest provided fixture for mocking. 136 """ 137 138 def enable_run_as_for_path_wrapper(object, path): 139 """Actual monkeypatch implementation of the enable_run_as_for_path() call. 140 141 :param str path: The path to test. 142 :returns: boolean 143 """ 144 return True 145 146 monkeypatch.setattr( 147 mozdevice.ADBDevice, "enable_run_as_for_path", enable_run_as_for_path_wrapper 148 ) 149 150 151 @pytest.fixture(autouse=True) 152 def mock_shell_bool(monkeypatch): 153 """Monkeypatches the ADBDevice.shell_bool() method call. 154 155 Instead of returning the output of an adb call, this method will 156 return appropriate string output. Content of the string output is 157 in line with the calling method's expectations. 158 159 :param object monkeypatch: pytest provided fixture for mocking. 160 """ 161 162 def shell_bool_wrapper( 163 object, cmd, env=None, cwd=None, timeout=None, enable_run_as=False 164 ): 165 """Actual monkeypatch implementation of the shell_bool method call. 166 167 :param object object: placeholder object representing ADBDevice 168 :param str cmd: command to be executed 169 :param env: contains the environment variable 170 :type env: dict or None 171 :param cwd: The directory from which to execute. 172 :type cwd: str or None 173 :param timeout: unused parameter tp represent timeout threshold 174 :param enable_run_as: bool determining if run_as <app> is to be used 175 :returns: string - string representation of a simulated call to adb 176 """ 177 print(cmd) 178 return str(cmd) 179 180 monkeypatch.setattr(mozdevice.ADBDevice, "shell_bool", shell_bool_wrapper) 181 182 183 @pytest.fixture(autouse=True) 184 def mock_adb_object(): 185 """Patches the __init__ method call when instantiating ADBDevice. 186 187 ADBDevice normally requires instantiated objects in order to execute 188 its commands. 189 190 With a pytest-mock patch, we are able to mock the initialization of 191 the ADBDevice object. By yielding the instantiated mock object, 192 unit tests can be run that call methods that require an instantiated 193 object. 194 195 :yields: ADBDevice - mock instance of ADBDevice object 196 """ 197 with patch.object(mozdevice.ADBDevice, "__init__", lambda self: None): 198 yield mozdevice.ADBDevice() 199 200 201 @pytest.fixture 202 def redirect_stdout_and_assert(): 203 """Redirects the stdout pipe temporarily to a StringIO stream. 204 205 This is useful to assert on methods that do not return 206 a value, such as most ADBDevice methods. 207 208 The original stdout pipe is preserved throughout the process. 209 210 :returns: _wrapper method 211 """ 212 213 def _wrapper(func, **kwargs): 214 """Implements the stdout sleight-of-hand. 215 216 After preserving the original sys.stdout, it is switched 217 to use cStringIO.StringIO. 218 219 Method with no return value is called, and the stdout 220 pipe is switched back to the original sys.stdout. 221 222 The expected outcome is received as part of the kwargs. 223 This is asserted against a sanitized output from the method 224 under test. 225 226 :param object func: method under test 227 :param dict kwargs: dictionary of function parameters 228 """ 229 original_stdout = sys.stdout 230 sys.stdout = testing_stdout = StringIO() 231 expected_text = kwargs.pop("text") 232 func(**kwargs) 233 sys.stdout = original_stdout 234 assert expected_text in testing_stdout.getvalue().rstrip() 235 236 return _wrapper