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 18import unittest 19from host_controller.build import build_provider_pab 20 21try: 22 from unittest import mock 23except ImportError: 24 import mock 25 26from requests.models import Response 27 28 29class 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 def tearDown(self): 37 del self.client 38 39 @mock.patch("build_provider_pab.flow_from_clientsecrets") 40 @mock.patch("build_provider_pab.run_flow") 41 @mock.patch("build_provider_pab.Storage.get") 42 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 43 def testAuthenticationNew(self, mock_creds, mock_storage_get, mock_rf, 44 mock_ffc): 45 mock_creds.invalid = True 46 build_provider_pab.flow_from_clientsecrets = mock_ffc 47 build_provider_pab.run_flow = mock_rf 48 self.client.Authenticate() 49 mock_ffc.assert_called_once() 50 mock_storage_get.assert_called_once() 51 mock_rf.assert_called_once() 52 53 @mock.patch("build_provider_pab.flow_from_clientsecrets") 54 @mock.patch("build_provider_pab.run_flow") 55 @mock.patch("build_provider_pab.Storage.get") 56 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 57 def testAuthenticationStale(self, mock_creds, mock_storage_get, mock_rf, 58 mock_ffc): 59 mock_creds.invalid = False 60 mock_creds.access_token_expired = True 61 build_provider_pab.flow_from_clientsecrets = mock_ffc 62 build_provider_pab.run_flow = mock_rf 63 mock_storage_get.return_value = mock_creds 64 self.client.Authenticate() 65 mock_ffc.assert_called_once() 66 mock_storage_get.assert_called_once() 67 mock_rf.assert_not_called() 68 mock_creds.refresh.assert_called_once() 69 70 @mock.patch("build_provider_pab.flow_from_clientsecrets") 71 @mock.patch("build_provider_pab.run_flow") 72 @mock.patch("build_provider_pab.Storage.get") 73 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 74 def testAuthenticationFresh(self, mock_creds, mock_storage_get, mock_rf, 75 mock_ffc): 76 mock_creds.invalid = False 77 mock_creds.access_token_expired = False 78 build_provider_pab.flow_from_clientsecrets = mock_ffc 79 build_provider_pab.run_flow = mock_rf 80 mock_storage_get.return_value = mock_creds 81 self.client.Authenticate() 82 mock_ffc.assert_called_once() 83 mock_storage_get.assert_called_once() 84 mock_rf.assert_not_called() 85 mock_creds.refresh.assert_not_called() 86 87 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 88 @mock.patch('requests.get') 89 @mock.patch('__builtin__.open') 90 def testDownloadArtifact(self, mock_open, mock_get, mock_creds): 91 self.client._credentials = mock_creds 92 artifact_url = ( 93 "https://partnerdash.google.com/build/gmsdownload/" 94 "f_companion/label/clockwork.companion_20170906_211311_RC00/" 95 "ClockworkCompanionGoogleWithGmsRelease_signed.apk?a=100621237") 96 self.client.DownloadArtifact( 97 artifact_url, 'ClockworkCompanionGoogleWithGmsRelease_signed.apk') 98 self.client._credentials.apply.assert_called_with({}) 99 mock_get.assert_called_with( 100 artifact_url, headers={}, stream=True) 101 mock_open.assert_called_with( 102 'ClockworkCompanionGoogleWithGmsRelease_signed.apk', 'wb') 103 104 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 105 @mock.patch('requests.post') 106 def testGetArtifactURL(self, mock_post, mock_creds): 107 self.client._xsrf = 'disable' 108 response = Response() 109 response.status_code = 200 110 response._content = b'{ "result" : {"1": "this_url"}}' 111 mock_post.return_value = response 112 self.client._credentials = mock_creds 113 url = self.client.GetArtifactURL( 114 100621237, 115 "4331445", 116 "darwin_mac", 117 "android-ndk-43345-darwin-x86_64.tar.bz2", 118 "aosp-master-ndk", 119 0, 120 method='POST') 121 mock_post.assert_called_with( 122 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc', 123 data=mock.ANY, 124 headers={ 125 'Content-Type': 'application/json', 126 'x-alkali-account': 100621237, 127 }) 128 self.assertEqual(url, "this_url") 129 130 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 131 @mock.patch('requests.post') 132 def testGetArtifactURLBackendError(self, mock_post, mock_creds): 133 self.client._xsrf = 'disable' 134 response = Response() 135 response.status_code = 200 136 response._content = b'not JSON' 137 mock_post.return_value = response 138 self.client._credentials = mock_creds 139 with self.assertRaises(ValueError) as cm: 140 self.client.GetArtifactURL( 141 100621237, 142 "4331445", 143 "darwin_mac", 144 "android-ndk-43345-darwin-x86_64.tar.bz2", 145 "aosp-master-ndk", 146 0, 147 method='POST') 148 expected = "Backend error -- check your account ID" 149 self.assertEqual(str(cm.exception), expected) 150 151 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 152 @mock.patch('requests.post') 153 def testGetArtifactURLMissingResultError(self, mock_post, mock_creds): 154 self.client._xsrf = 'disable' 155 response = Response() 156 response.status_code = 200 157 response._content = b'{"result": {}}' 158 mock_post.return_value = response 159 self.client._credentials = mock_creds 160 with self.assertRaises(ValueError) as cm: 161 self.client.GetArtifactURL( 162 100621237, 163 "4331445", 164 "darwin_mac", 165 "android-ndk-43345-darwin-x86_64.tar.bz2", 166 "aosp-master-ndk", 167 0, 168 method='POST') 169 expected = "Resource not found" 170 self.assertIn(expected, str(cm.exception)) 171 172 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 173 @mock.patch('requests.post') 174 def testGetArtifactURLInvalidXSRFError(self, mock_post, mock_creds): 175 self.client._xsrf = 'disable' 176 response = Response() 177 response.status_code = 200 178 response._content = b'{"error": {"code": -32000, "message":"Invalid"}}' 179 mock_post.return_value = response 180 self.client._credentials = mock_creds 181 with self.assertRaises(ValueError) as cm: 182 self.client.GetArtifactURL( 183 100621237, 184 "4331445", 185 "darwin_mac", 186 "android-ndk-43345-darwin-x86_64.tar.bz2", 187 "aosp-master-ndk", 188 0, 189 method='POST') 190 self.assertIn('Bad XSRF token', str(cm.exception)) 191 192 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 193 @mock.patch('requests.post') 194 def testGetArtifactURLExpiredXSRFError(self, mock_post, mock_creds): 195 self.client._xsrf = 'disable' 196 response = Response() 197 response.status_code = 200 198 response._content = b'{"error": {"code": -32001, "message":"Expired"}}' 199 mock_post.return_value = response 200 self.client._credentials = mock_creds 201 with self.assertRaises(ValueError) as cm: 202 self.client.GetArtifactURL( 203 100621237, 204 "4331445", 205 "darwin_mac", 206 "android-ndk-43345-darwin-x86_64.tar.bz2", 207 "aosp-master-ndk", 208 0, 209 method='POST') 210 self.assertIn('Expired XSRF token', str(cm.exception)) 211 212 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 213 @mock.patch('requests.post') 214 def testGetArtifactURLUnknownError(self, mock_post, mock_creds): 215 self.client._xsrf = 'disable' 216 response = Response() 217 response.status_code = 200 218 response._content = b'{"some_other_json": "foo"}' 219 mock_post.return_value = response 220 self.client._credentials = mock_creds 221 with self.assertRaises(ValueError) as cm: 222 self.client.GetArtifactURL( 223 100621237, 224 "4331445", 225 "darwin_mac", 226 "android-ndk-43345-darwin-x86_64.tar.bz2", 227 "aosp-master-ndk", 228 0, 229 method='POST') 230 self.assertIn('Unknown response from server', str(cm.exception)) 231 232 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 233 @mock.patch('requests.post') 234 def testGetBuildListSuccess(self, mock_post, mock_creds): 235 self.client._xsrf = 'disable' 236 response = Response() 237 response.status_code = 200 238 response._content = b'{"result": {"1": "foo"}}' 239 mock_post.return_value = response 240 self.client._credentials = mock_creds 241 result = self.client.GetBuildList( 242 100621237, 243 "git_oc-treble-dev", 244 "aosp_arm64_ab-userdebug", 245 method='POST') 246 self.assertEqual(result, "foo") 247 mock_post.assert_called_with( 248 'https://partner.android.com/build/u/0/_gwt/_rpc/buildsvc', 249 data=mock.ANY, 250 headers={ 251 'Content-Type': 'application/json', 252 'x-alkali-account': 100621237, 253 }) 254 255 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 256 @mock.patch('requests.post') 257 def testGetBuildListError(self, mock_post, mock_creds): 258 self.client._xsrf = 'disable' 259 response = Response() 260 response.status_code = 200 261 response._content = b'{"result": {"3": "foo"}}' 262 mock_post.return_value = response 263 self.client._credentials = mock_creds 264 with self.assertRaises(ValueError) as cm: 265 self.client.GetBuildList( 266 100621237, 267 "git_oc-treble-dev", 268 "aosp_arm64_ab-userdebug", 269 method='POST') 270 self.assertIn('Build list not found', str(cm.exception)) 271 272 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 273 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 274 def testGetLatestBuildIdSuccess(self, mock_gbl, mock_creds): 275 self.client._xsrf = 'disable' 276 mock_gbl.return_value = [{'7': 5, '1': 'bad'}, {'7': 7, '1': 'good'}] 277 self.client.GetBuildList = mock_gbl 278 result = self.client.GetLatestBuildId( 279 100621237, 280 "git_oc-treble-dev", 281 "aosp_arm64_ab-userdebug", 282 method='POST') 283 self.assertEqual(result, 'good') 284 285 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 286 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 287 def testGetLatestBuildIdEmpty(self, mock_gbl, mock_creds): 288 self.client._xsrf = 'disable' 289 mock_gbl.return_value = [] 290 self.client.GetBuildList = mock_gbl 291 with self.assertRaises(ValueError) as cm: 292 result = self.client.GetLatestBuildId( 293 100621237, 294 "git_oc-treble-dev", 295 "aosp_arm64_ab-userdebug", 296 method='POST') 297 self.assertIn("No builds found for", str(cm.exception)) 298 299 @mock.patch('build_provider_pab.BuildProviderPAB._credentials') 300 @mock.patch('build_provider_pab.BuildProviderPAB.GetBuildList') 301 def testGetLatestBuildIdAllBad(self, mock_gbl, mock_creds): 302 self.client._xsrf = 'disable' 303 mock_gbl.return_value = [{'7': 0}, {'7': 0}] 304 self.client.GetBuildList = mock_gbl 305 with self.assertRaises(ValueError) as cm: 306 result = self.client.GetLatestBuildId( 307 100621237, 308 "git_oc-treble-dev", 309 "aosp_arm64_ab-userdebug", 310 method='POST') 311 self.assertEqual( 312 "No complete builds found: 2 failed or incomplete builds found", 313 str(cm.exception)) 314 315 316if __name__ == "__main__": 317 unittest.main() 318