1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2017 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 # 17 18 import unittest 19 from host_controller.build import build_provider_pab 20 21 try: 22 from unittest import mock 23 except ImportError: 24 import mock 25 26 from requests.models import Response 27 28 29 class BuildProviderPABTest(unittest.TestCase): 30 """Tests for Partner Android Build client.""" 31 32 def setUp(self): 33 self.client = build_provider_pab.BuildProviderPAB() 34 self.client.XSRF_STORE = None 35 36 @mock.patch("build_provider_pab.flow_from_clientsecrets") 37 @mock.patch("build_provider_pab.run_flow") 38 @mock.patch("build_provider_pab.Storage") 39 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 40 def testAuthenticationNew(self, mock_creds, mock_storage, mock_rf, 41 mock_ffc): 42 mock_creds.invalid = True 43 self.client.Authenticate() 44 mock_ffc.assert_called_once() 45 mock_storage.assert_called_once() 46 mock_rf.assert_called_once() 47 48 @mock.patch("build_provider_pab.flow_from_clientsecrets") 49 @mock.patch("build_provider_pab.run_flow") 50 @mock.patch("build_provider_pab.Storage") 51 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 52 def testAuthenticationStale(self, mock_creds, mock_storage, mock_rf, 53 mock_ffc): 54 mock_creds.invalid = False 55 mock_creds.access_token_expired = True 56 self.client.Authenticate() 57 mock_ffc.assert_called_once() 58 mock_storage.assert_called_once() 59 mock_rf.assert_not_called() 60 mock_creds.refresh.assert_called_once() 61 62 @mock.patch("build_provider_pab.flow_from_clientsecrets") 63 @mock.patch("build_provider_pab.run_flow") 64 @mock.patch("build_provider_pab.Storage") 65 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 66 def testAuthenticationFresh(self, mock_creds, mock_storage, mock_rf, 67 mock_ffc): 68 mock_creds.invalid = False 69 mock_creds.access_token_expired = False 70 self.client.Authenticate() 71 mock_ffc.assert_called_once() 72 mock_storage.assert_called_once() 73 mock_rf.assert_not_called() 74 mock_creds.refresh.assert_not_called() 75 76 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 77 @mock.patch('build_provider_pab.requests') 78 @mock.patch('build_provider_pab.open') 79 def testDownloadArtifact(self, mock_open, mock_requests, mock_creds): 80 artifact_url = ( 81 "https://partnerdash.google.com/build/gmsdownload/" 82 "f_companion/label/clockwork.companion_20170906_211311_RC00/" 83 "ClockworkCompanionGoogleWithGmsRelease_signed.apk?a=100621237") 84 self.client.DownloadArtifact( 85 artifact_url, 'ClockworkCompanionGoogleWithGmsRelease_signed.apk') 86 mock_creds.apply.assert_called_with({}) 87 mock_requests.get.assert_called_with( 88 artifact_url, headers={}, stream=True) 89 mock_open.assert_called_with( 90 'ClockworkCompanionGoogleWithGmsRelease_signed.apk', 'wb') 91 92 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 93 @mock.patch('build_provider_pab.requests') 94 def testGetArtifactURL(self, mock_requests, mock_creds): 95 self.client._xsrf = 'disable' 96 response = Response() 97 response.status_code = 200 98 response._content = b'{ "result" : {"1": "this_url"}}' 99 mock_requests.post.return_value = response 100 url = self.client.GetArtifactURL( 101 100621237, 102 "4331445", 103 "darwin_mac", 104 "android-ndk-43345-darwin-x86_64.tar.bz2", 105 "aosp-master-ndk", 106 0, 107 method='POST') 108 109 mock_requests.post.assert_called_with( 110 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc', 111 data=mock.ANY, 112 headers={ 113 'Content-Type': 'application/json', 114 'x-alkali-account': 100621237 115 }) 116 self.assertEqual(url, "this_url") 117 118 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 119 @mock.patch('build_provider_pab.requests') 120 def testGetArtifactURLBackendError(self, mock_requests, mock_creds): 121 self.client._xsrf = 'disable' 122 response = Response() 123 response.status_code = 200 124 response._content = b'not JSON' 125 mock_requests.post.return_value = response 126 with self.assertRaises(ValueError) as cm: 127 self.client.GetArtifactURL( 128 100621237, 129 "4331445", 130 "darwin_mac", 131 "android-ndk-43345-darwin-x86_64.tar.bz2", 132 "aosp-master-ndk", 133 0, 134 method='POST') 135 expected = "Backend error -- check your account ID" 136 self.assertEqual(str(cm.exception), expected) 137 138 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 139 @mock.patch('build_provider_pab.requests') 140 def testGetArtifactURLMissingResultError(self, mock_requests, mock_creds): 141 self.client._xsrf = 'disable' 142 response = Response() 143 response.status_code = 200 144 response._content = b'{"result": {}}' 145 mock_requests.post.return_value = response 146 with self.assertRaises(ValueError) as cm: 147 self.client.GetArtifactURL( 148 100621237, 149 "4331445", 150 "darwin_mac", 151 "android-ndk-43345-darwin-x86_64.tar.bz2", 152 "aosp-master-ndk", 153 0, 154 method='POST') 155 expected = "Resource not found" 156 self.assertIn(expected, str(cm.exception)) 157 158 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 159 @mock.patch('build_provider_pab.requests') 160 def testGetArtifactURLInvalidXSRFError(self, mock_requests, mock_creds): 161 self.client._xsrf = 'disable' 162 response = Response() 163 response.status_code = 200 164 response._content = b'{"error": {"code": -32000, "message":"Invalid"}}' 165 mock_requests.post.return_value = response 166 with self.assertRaises(ValueError) as cm: 167 self.client.GetArtifactURL( 168 100621237, 169 "4331445", 170 "darwin_mac", 171 "android-ndk-43345-darwin-x86_64.tar.bz2", 172 "aosp-master-ndk", 173 0, 174 method='POST') 175 self.assertIn('Bad XSRF token', str(cm.exception)) 176 177 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 178 @mock.patch('build_provider_pab.requests') 179 def testGetArtifactURLExpiredXSRFError(self, mock_requests, mock_creds): 180 self.client._xsrf = 'disable' 181 response = Response() 182 response.status_code = 200 183 response._content = b'{"error": {"code": -32001, "message":"Expired"}}' 184 mock_requests.post.return_value = response 185 with self.assertRaises(ValueError) as cm: 186 self.client.GetArtifactURL( 187 100621237, 188 "4331445", 189 "darwin_mac", 190 "android-ndk-43345-darwin-x86_64.tar.bz2", 191 "aosp-master-ndk", 192 0, 193 method='POST') 194 self.assertIn('Expired XSRF token', str(cm.exception)) 195 196 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 197 @mock.patch('build_provider_pab.requests') 198 def testGetArtifactURLUnknownError(self, mock_requests, mock_creds): 199 self.client._xsrf = 'disable' 200 response = Response() 201 response.status_code = 200 202 response._content = b'{"some_other_json": "foo"}' 203 mock_requests.post.return_value = response 204 with self.assertRaises(ValueError) as cm: 205 self.client.GetArtifactURL( 206 100621237, 207 "4331445", 208 "darwin_mac", 209 "android-ndk-43345-darwin-x86_64.tar.bz2", 210 "aosp-master-ndk", 211 0, 212 method='POST') 213 self.assertIn('Unknown response from server', str(cm.exception)) 214 215 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 216 @mock.patch('build_provider_pab.requests') 217 def testGetBuildListSuccess(self, mock_requests, mock_creds): 218 self.client._xsrf = 'disable' 219 response = Response() 220 response.status_code = 200 221 response._content = b'{"result": {"1": "foo"}}' 222 mock_requests.post.return_value = response 223 result = self.client.GetBuildList( 224 100621237, 225 "git_oc-treble-dev", 226 "aosp_arm64_ab-userdebug", 227 method='POST') 228 self.assertEqual(result, "foo") 229 mock_requests.post.assert_called_with( 230 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc', 231 data=mock.ANY, 232 headers={ 233 'Content-Type': 'application/json', 234 'x-alkali-account': 100621237 235 }) 236 237 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 238 @mock.patch('build_provider_pab.requests') 239 def testGetBuildListError(self, mock_requests, mock_creds): 240 self.client._xsrf = 'disable' 241 response = Response() 242 response.status_code = 200 243 response._content = b'{"result": {"3": "foo"}}' 244 mock_requests.post.return_value = response 245 with self.assertRaises(ValueError) as cm: 246 self.client.GetBuildList( 247 100621237, 248 "git_oc-treble-dev", 249 "aosp_arm64_ab-userdebug", 250 method='POST') 251 self.assertIn('Build list not found', str(cm.exception)) 252 253 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 254 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 255 def testGetLatestBuildIdSuccess(self, mock_gbl, mock_creds): 256 self.client._xsrf = 'disable' 257 mock_gbl.return_value = [{'7': 5, '1': 'bad'}, {'7': 7, '1': 'good'}] 258 result = self.client.GetLatestBuildId( 259 100621237, 260 "git_oc-treble-dev", 261 "aosp_arm64_ab-userdebug", 262 method='POST') 263 self.assertEqual(result, 'good') 264 265 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 266 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 267 def testGetLatestBuildIdEmpty(self, mock_gbl, mock_creds): 268 self.client._xsrf = 'disable' 269 mock_gbl.return_value = [] 270 with self.assertRaises(ValueError) as cm: 271 result = self.client.GetLatestBuildId( 272 100621237, 273 "git_oc-treble-dev", 274 "aosp_arm64_ab-userdebug", 275 method='POST') 276 self.assertIn("No builds found for", str(cm.exception)) 277 278 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 279 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 280 def testGetLatestBuildIdAllBad(self, mock_gbl, mock_creds): 281 self.client._xsrf = 'disable' 282 mock_gbl.return_value = [{'7': 0}, {'7': 0}] 283 with self.assertRaises(ValueError) as cm: 284 result = self.client.GetLatestBuildId( 285 100621237, 286 "git_oc-treble-dev", 287 "aosp_arm64_ab-userdebug", 288 method='POST') 289 self.assertEqual( 290 "No complete builds found: 2 failed or incomplete builds found", 291 str(cm.exception)) 292 293 294 if __name__ == "__main__": 295 unittest.main() 296