1# Copyright 2016 Google Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15# This module has common mock objects and functions used in unit tests for 16# mobly.controllers.android_device module. 17 18import logging 19import os 20from unittest import mock 21 22DEFAULT_MOCK_PROPERTIES = { 23 'ro.build.id': 'AB42', 24 'ro.build.type': 'userdebug', 25 'ro.build.fingerprint': 'FakeModel:Dessert/AB42/1234567:userdebug/dev-keys', 26 'ro.build.product': 'FakeModel', 27 'ro.build.version.codename': 'Z', 28 'ro.build.version.incremental': '1234567', 29 'ro.build.version.sdk': '28', 30 'ro.product.name': 'FakeModel', 31 'ro.debuggable': '1', 32 'sys.boot_completed': "1", 33 'ro.build.characteristics': 'emulator,phone', 34 'ro.hardware': 'marlin', 35} 36 37 38class Error(Exception): 39 pass 40 41 42def get_mock_ads(num): 43 """Generates a list of mock AndroidDevice objects. 44 45 The serial number of each device will be integer 0 through num - 1. 46 47 Args: 48 num: An integer that is the number of mock AndroidDevice objects to 49 create. 50 """ 51 ads = [] 52 for i in range(num): 53 ad = mock.MagicMock(name="AndroidDevice", serial=str(i), h_port=None) 54 ad.skip_logcat = False 55 ads.append(ad) 56 return ads 57 58 59def get_all_instances(): 60 return get_mock_ads(5) 61 62 63def get_instances(serials): 64 ads = [] 65 for serial in serials: 66 ad = mock.MagicMock(name="AndroidDevice", serial=serial, h_port=None) 67 ads.append(ad) 68 return ads 69 70 71def get_instances_with_configs(dicts): 72 return get_instances([d['serial'] for d in dicts]) 73 74 75def list_adb_devices(): 76 return [ad.serial for ad in get_mock_ads(5)] 77 78 79class MockAdbProxy: 80 """Mock class that swaps out calls to adb with mock calls.""" 81 82 def __init__(self, 83 serial='', 84 fail_br=False, 85 fail_br_before_N=False, 86 mock_properties=None, 87 installed_packages=None, 88 instrumented_packages=None): 89 self.serial = serial 90 self.fail_br = fail_br 91 self.fail_br_before_N = fail_br_before_N 92 self.getprops_call_count = 0 93 if mock_properties is None: 94 self.mock_properties = DEFAULT_MOCK_PROPERTIES.copy() 95 else: 96 self.mock_properties = mock_properties 97 if installed_packages is None: 98 installed_packages = [] 99 self.installed_packages = installed_packages 100 if instrumented_packages is None: 101 instrumented_packages = [] 102 self.installed_packages = installed_packages 103 self.instrumented_packages = instrumented_packages 104 105 def shell(self, params, timeout=None): 106 if params == "id -u": 107 return b"root" 108 elif params == "bugreportz": 109 if self.fail_br: 110 return b"OMG I died!\n" 111 return b'OK:/path/bugreport.zip\n' 112 elif params == "bugreportz -v": 113 if self.fail_br_before_N: 114 return b"/system/bin/sh: bugreportz: not found" 115 return b'1.1' 116 elif 'pm list package' in params: 117 packages = self.installed_packages + [ 118 package for package, _, _ in self.instrumented_packages 119 ] 120 return bytes('\n'.join(['package:%s' % package for package in packages]), 121 'utf-8') 122 elif 'pm list instrumentation' in params: 123 return bytes( 124 '\n'.join([ 125 'instrumentation:%s/%s (target=%s)' % (package, runner, target) 126 for package, runner, target in self.instrumented_packages 127 ]), 'utf-8') 128 elif 'which' in params: 129 return b'' 130 131 def getprop(self, params): 132 if params in self.mock_properties: 133 return self.mock_properties[params] 134 135 def getprops(self, params): 136 self.getprops_call_count = self.getprops_call_count + 1 137 return self.mock_properties 138 139 def bugreport(self, args, shell=False, timeout=None): 140 expected = os.path.join( 141 logging.log_path, 'AndroidDevice%s' % self.serial, 'BugReports', 142 'bugreport,test_something,%s,fakemodel,sometime' % self.serial) 143 if expected not in args: 144 raise Error('"Expected "%s", got "%s"' % (expected, args)) 145 146 def __getattr__(self, name): 147 """All calls to the none-existent functions in adb proxy would 148 simply return the adb command string. 149 """ 150 151 def adb_call(*args, **kwargs): 152 arg_str = ' '.join(str(elem) for elem in args) 153 return arg_str 154 155 return adb_call 156 157 158class MockFastbootProxy: 159 """Mock class that swaps out calls to adb with mock calls.""" 160 161 def __init__(self, serial): 162 self.serial = serial 163 164 def devices(self): 165 return b"xxxx device\nyyyy device" 166 167 def __getattr__(self, name): 168 169 def fastboot_call(*args): 170 arg_str = ' '.join(str(elem) for elem in args) 171 return arg_str 172 173 return fastboot_call 174