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__( 83 self, 84 serial='', 85 fail_br=False, 86 fail_br_before_N=False, 87 mock_properties=None, 88 installed_packages=None, 89 instrumented_packages=None, 90 ): 91 self.serial = serial 92 self.fail_br = fail_br 93 self.fail_br_before_N = fail_br_before_N 94 self.getprops_call_count = 0 95 if mock_properties is None: 96 self.mock_properties = DEFAULT_MOCK_PROPERTIES.copy() 97 else: 98 self.mock_properties = mock_properties 99 if installed_packages is None: 100 installed_packages = [] 101 self.installed_packages = installed_packages 102 if instrumented_packages is None: 103 instrumented_packages = [] 104 self.installed_packages = installed_packages 105 self.instrumented_packages = instrumented_packages 106 107 def shell(self, params, timeout=None): 108 if params == 'id -u': 109 return b'root' 110 elif params == 'bugreportz': 111 if self.fail_br: 112 return b'OMG I died!\n' 113 return b'OK:/path/bugreport.zip\n' 114 elif params == 'bugreportz -v': 115 if self.fail_br_before_N: 116 return b'/system/bin/sh: bugreportz: not found' 117 return b'1.1' 118 elif 'pm list package' in params: 119 packages = self.installed_packages + [ 120 package for package, _, _ in self.instrumented_packages 121 ] 122 return bytes( 123 '\n'.join(['package:%s' % package for package in packages]), 'utf-8' 124 ) 125 elif 'pm list instrumentation' in params: 126 return bytes( 127 '\n'.join([ 128 'instrumentation:%s/%s (target=%s)' % (package, runner, target) 129 for package, runner, target in self.instrumented_packages 130 ]), 131 'utf-8', 132 ) 133 elif 'which' in params: 134 return b'' 135 136 def getprop(self, params): 137 if params in self.mock_properties: 138 return self.mock_properties[params] 139 140 def getprops(self, params): 141 self.getprops_call_count = self.getprops_call_count + 1 142 return self.mock_properties 143 144 def bugreport(self, args, shell=False, timeout=None): 145 expected = os.path.join( 146 logging.log_path, 147 'AndroidDevice%s' % self.serial, 148 'BugReports', 149 'bugreport,test_something,%s,fakemodel,sometime' % self.serial, 150 ) 151 if expected not in args: 152 raise Error('"Expected "%s", got "%s"' % (expected, args)) 153 154 def __getattr__(self, name): 155 """All calls to the none-existent functions in adb proxy would 156 simply return the adb command string. 157 """ 158 159 def adb_call(*args, **kwargs): 160 arg_str = ' '.join(str(elem) for elem in args) 161 return arg_str 162 163 return adb_call 164 165 166class MockFastbootProxy: 167 """Mock class that swaps out calls to adb with mock calls.""" 168 169 def __init__(self, serial): 170 self.serial = serial 171 172 def devices(self): 173 return b'xxxx device\nyyyy device' 174 175 def __getattr__(self, name): 176 def fastboot_call(*args): 177 arg_str = ' '.join(str(elem) for elem in args) 178 return arg_str 179 180 return fastboot_call 181