blob: aa38f8139aec01ee9e7ce08f7f9e3bdb5e6ad270 [file] [log] [blame]
Xinan Lin3ba18a02019-08-13 15:44:55 -07001# Copyright 2019 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Module for buildbucket unittests."""
6
7import mock
8import os
9import unittest
10
11import build_lib
12import buildbucket
13import task_executor
14
15from chromite.api.gen.test_platform import request_pb2
16from google.appengine.ext import testbed
17from google.protobuf import json_format
18
19
20ADDR = u'http://localhost:1'
21
22
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -070023def _get_default_suite_params():
Prathmesh Prabhu2382a182019-09-07 21:18:10 -070024 return _get_suite_params(
25 board='fake_board',
26 model='fake_model',
27 suite='fake_suite',
28 pool='DUT_POOL_SUITES',
29 cros_build='fake_cros_build',
30 )
31
32def _get_suite_params(board, model, suite, pool, cros_build):
Xinan Lin3ba18a02019-08-13 15:44:55 -070033 return {
Prathmesh Prabhu2382a182019-09-07 21:18:10 -070034 'suite': suite,
35 'board': board,
36 'model': model,
37 build_lib.BuildVersionKey.CROS_VERSION: cros_build,
Xinan Lin3ba18a02019-08-13 15:44:55 -070038 build_lib.BuildVersionKey.FW_RW_VERSION: 'fake_firmware_rw_build',
39 build_lib.BuildVersionKey.FW_RO_VERSION: 'fake_firmware_ro_build',
40 build_lib.BuildVersionKey.ANDROID_BUILD_VERSION: 'fake_android_build',
41 build_lib.BuildVersionKey.TESTBED_BUILD_VERSION: 'fake_testbed_build',
42 'num': 1,
Prathmesh Prabhu2382a182019-09-07 21:18:10 -070043 'pool': pool,
Xinan Lin3ba18a02019-08-13 15:44:55 -070044 'priority': 10,
Xinan Lin6e097382019-08-27 18:43:35 -070045 'timeout': 12,
46 'timeout_mins': 4320,
47 'max_runtime_mins': 4320,
Xinan Lin3ba18a02019-08-13 15:44:55 -070048 'no_wait_for_results': True,
49 'test_source_build': 'fake_test_source_build',
50 'job_retry': False,
51 'no_delay': False,
52 'force': False,
53 'run_prod_code': True,
54 'is_skylab': False,
55 }
56
57
58class FakeTestPlatformClient(object):
59
60 def __init__(self, test):
61 self._test = test
62 self.called_with_requests = []
63
64 def ScheduleBuild(self, req, credentials=None):
65 self.called_with_requests.append(req)
66 # No test_platform_response proto. Simply return '200, ok'.
67 return '200 ok'
68
69
70class TestPlatformClientTestCase(unittest.TestCase):
71
72 def setUp(self):
73 super(TestPlatformClientTestCase, self).setUp()
74 self.fake_client = FakeTestPlatformClient(self)
75 patcher = mock.patch('buildbucket._get_client',
76 return_value=self._get_client(ADDR))
77 patcher.start()
78 self.client = buildbucket.TestPlatformClient(ADDR,
79 'foo-proj',
80 'foo-bucket',
81 'foo-builder')
82 self.addCleanup(patcher.stop)
83 self.testbed = testbed.Testbed()
84 self.testbed.activate()
85 self.addCleanup(self.testbed.deactivate)
86 self.testbed.init_taskqueue_stub(
87 root_path=os.path.join(os.path.dirname(__file__)))
88 self.taskqueue_stub = self.testbed.get_stub(
89 testbed.TASKQUEUE_SERVICE_NAME)
90
Xinan Lin3ba18a02019-08-13 15:44:55 -070091 def testFormTestPlatformRequestSuccessfully(self):
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -070092 tp = _get_default_suite_params()
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -070093 self.client.run(**self._marshal_to_tq_params(tp))
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -070094 self._assert_bb_client_called()
Prathmesh Prabhu6348ea82019-08-30 14:15:21 -070095 req = self._extract_request_from_bb_client()
Xinan Lin3ba18a02019-08-13 15:44:55 -070096 self.assertEqual(req.params.scheduling.managed_pool,
97 request_pb2.Request.Params.Scheduling.MANAGED_POOL_SUITES)
Xinan Lin6e097382019-08-27 18:43:35 -070098 self.assertEqual(req.params.time.maximum_duration.seconds, 165600)
Xinan Lin3ba18a02019-08-13 15:44:55 -070099 self.assertEqual(req.params.metadata.test_metadata_url,
Xinan Lin6e097382019-08-27 18:43:35 -0700100 'gs://chromeos-image-archive/' + tp['test_source_build'])
Xinan Lin3ba18a02019-08-13 15:44:55 -0700101 self.assertEqual(req.test_plan.suite[0].name, tp['suite'])
102
Alex Zamorzaevc1935602019-08-28 14:37:35 -0700103 def testNonStandardPoolName(self):
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -0700104 tp = _get_default_suite_params()
Alex Zamorzaevc1935602019-08-28 14:37:35 -0700105 tp['pool'] = 'cts'
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -0700106 self.client.run(**self._marshal_to_tq_params(tp))
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700107 self._assert_bb_client_called()
Prathmesh Prabhu6348ea82019-08-30 14:15:21 -0700108 req = self._extract_request_from_bb_client()
Alex Zamorzaevc1935602019-08-28 14:37:35 -0700109 self.assertEqual(req.params.scheduling.managed_pool,
110 request_pb2.Request.Params.Scheduling.MANAGED_POOL_CTS)
111
Xinan Lin3ba18a02019-08-13 15:44:55 -0700112 def testShouldGoUnmanagedPool(self):
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -0700113 tp = _get_default_suite_params()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700114 tp['pool'] = 'wifi'
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -0700115 self.client.run(**self._marshal_to_tq_params(tp))
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700116 self._assert_bb_client_called()
Prathmesh Prabhu6348ea82019-08-30 14:15:21 -0700117 req = self._extract_request_from_bb_client()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700118 self.assertEqual(req.params.scheduling.unmanaged_pool, tp['pool'])
119
120 def testShouldSchedulewithQuotaAccount(self):
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -0700121 tp = _get_default_suite_params()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700122 tp['override_qs_account'] = 'dummy@foo.com'
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -0700123 self.client.run(**self._marshal_to_tq_params(tp))
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700124 self._assert_bb_client_called()
Prathmesh Prabhu6348ea82019-08-30 14:15:21 -0700125 req = self._extract_request_from_bb_client()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700126 self.assertEqual(req.params.scheduling.quota_account,
127 tp['override_qs_account'])
128
Prathmesh Prabhu88409f62019-08-30 14:32:28 -0700129 def testShouldSetPriority(self):
130 tp = _get_default_suite_params()
131 tp['priority'] = '30'
132 self.client.run(**self._marshal_to_tq_params(tp))
133 self._assert_bb_client_called()
134 req = self._extract_request_from_bb_client()
135 self.assertEqual(req.params.scheduling.priority, 30)
136
Xinan Lin3ba18a02019-08-13 15:44:55 -0700137 def testNoFinalBuild(self):
Prathmesh Prabhu91ef1622019-08-30 14:07:42 -0700138 tp = _get_default_suite_params()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700139 tp[build_lib.BuildVersionKey.CROS_VERSION] = None
140 tp[build_lib.BuildVersionKey.ANDROID_BUILD_VERSION] = None
141 tp[build_lib.BuildVersionKey.TESTBED_BUILD_VERSION] = None
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -0700142 params = self._marshal_to_tq_params(tp)
Xinan Lin3ba18a02019-08-13 15:44:55 -0700143 self.assertRaises(buildbucket.BuildbucketRunError,
144 self.client.run, **params)
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700145 self._assert_bb_client_not_called()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700146
Xinan Linfb63d572019-09-24 15:49:04 -0700147 def testRequestNoneStringTags(self):
148 tp = _get_suite_params(
149 board='some_board',
150 model='None',
151 pool='DUT_POOL_SUITES',
152 suite='some_suite',
153 cros_build='some_build',
154 )
155 self.client.run(**self._marshal_to_tq_params(tp))
156 self._assert_bb_client_called()
157 want = {
158 'label-board:some_board',
159 'label-pool:DUT_POOL_SUITES',
160 'suite:some_suite',
161 'build:some_build',
162 }
163 req = self._extract_request_from_bb_client()
164 req_tags = set([t for t in req.params.decorations.tags])
165 self.assertEqual(want, req_tags)
166 bb_tags = set([t for t in self._extract_tags_from_bb_client()])
167 self.assertEqual(want, bb_tags)
168
169 def testRequestNoneTags(self):
170 tp = _get_suite_params(
171 board='some_board',
172 model=None,
173 pool='DUT_POOL_SUITES',
174 suite='some_suite',
175 cros_build='some_build',
176 )
177 self.client.run(**self._marshal_to_tq_params(tp))
178 self._assert_bb_client_called()
179 want = {
180 'label-board:some_board',
181 'label-pool:DUT_POOL_SUITES',
182 'suite:some_suite',
183 'build:some_build',
184 }
185 req = self._extract_request_from_bb_client()
186 req_tags = set([t for t in req.params.decorations.tags])
187 self.assertEqual(want, req_tags)
188 bb_tags = set([t for t in self._extract_tags_from_bb_client()])
189 self.assertEqual(want, bb_tags)
190
Prathmesh Prabhu2382a182019-09-07 21:18:10 -0700191 def testRequestTags(self):
192 tp = _get_suite_params(
193 board='some_board',
194 model='some_model',
195 pool='DUT_POOL_SUITES',
196 suite='some_suite',
197 cros_build='some_build',
198 )
199 self.client.run(**self._marshal_to_tq_params(tp))
200 self._assert_bb_client_called()
201 want = {
202 'label-board:some_board',
203 'label-model:some_model',
204 'label-pool:DUT_POOL_SUITES',
205 'suite:some_suite',
206 'build:some_build',
207 }
208 req = self._extract_request_from_bb_client()
209 req_tags = set([t for t in req.params.decorations.tags])
210 self.assertEqual(want, req_tags)
211 bb_tags = set([t for t in self._extract_tags_from_bb_client()])
212 self.assertEqual(want, bb_tags)
213
Prathmesh Prabhu6f8d2f92019-08-30 14:05:35 -0700214 def _marshal_to_tq_params(self, suite_params):
215 """Marshal given suite parameters to a format returned from taskqueue.
216
217 buildbucket.TestPlatformClient.run() expects arguments pulled from a
218 taskqueue. This helper function marshals suite parameters into the format
219 they would be in when pulled from a taskqueue.
220 """
221 task_executor.push(task_executor.SUITES_QUEUE, **suite_params)
222 tasks = self.taskqueue_stub.get_filtered_tasks()
223 return tasks[0].extract_params()
Xinan Lin3ba18a02019-08-13 15:44:55 -0700224
Prathmesh Prabhu73801e12019-08-30 14:09:31 -0700225 def _get_client(self, addr):
226 self.assertEqual(ADDR, addr)
227 return self.fake_client
228
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700229 def _assert_bb_client_called(self):
230 self.assertEqual(len(self.fake_client.called_with_requests), 1)
231
232 def _assert_bb_client_not_called(self):
233 self.assertEqual(len(self.fake_client.called_with_requests), 0)
234
Prathmesh Prabhu6348ea82019-08-30 14:15:21 -0700235 def _extract_request_from_bb_client(self):
236 return _struct_pb2_to_request_pb2(
237 self.fake_client.called_with_requests[0].properties['request'])
238
Prathmesh Prabhu2382a182019-09-07 21:18:10 -0700239 def _extract_tags_from_bb_client(self):
240 return ['%s:%s' % (t.key, t.value)
241 for t in self.fake_client.called_with_requests[0].tags]
242
Prathmesh Prabhu9a8060a2019-08-30 14:13:23 -0700243
Xinan Lin3ba18a02019-08-13 15:44:55 -0700244def _struct_pb2_to_request_pb2(struct_pb2):
245 """Transform google struct proto to test_platform_request.
246
247 Args:
248 struct_pb2: A struct_pb2 instance.
249
250 Returns:
251 A request_pb2 instance.
252 """
253 json = json_format.MessageToJson(struct_pb2)
254 return json_format.Parse(json, request_pb2.Request())