def test_set_build_status_metric(self): ndb.put_multi([ model.Build( bucket='chromium', status=model.BuildStatus.SCHEDULED, create_time=datetime.datetime(2015, 1, 1), ), model.Build( bucket='chromium', status=model.BuildStatus.SCHEDULED, create_time=datetime.datetime(2015, 1, 1), ), model.Build( bucket='v8', status=model.BuildStatus.SCHEDULED, create_time=datetime.datetime(2015, 1, 1), ), model.Build( bucket='chromium', status=model.BuildStatus.STARTED, create_time=datetime.datetime(2015, 1, 1), start_time=datetime.datetime(2015, 1, 1), ), ]) metrics.set_build_status_metric( metrics.CURRENTLY_PENDING, 'chromium', model.BuildStatus.SCHEDULED).get_result() self.assertEqual( 2, metrics.CURRENTLY_PENDING.get( {'bucket': 'chromium'}, target_fields=metrics.GLOBAL_TARGET_FIELDS))
def test_post_with_different_task_id(self): build = model.Build( id=1, bucket='chromium', parameters={'builder_name': 'release'}, status=model.BuildStatus.SCHEDULED, swarming_hostname='chromium-swarm.appspot.com', swarming_task_id='deadbeef', ) build.put() self.handler.request = mock.Mock( json={ 'message': { 'data': b64json({ 'task_id': 'deadbeefffffffffff', 'userdata': json.dumps( { 'build_id': 1L, 'created_ts': 1448841600000000, 'swarming_hostname': 'chromium-swarm.appspot.com', }) }) } })
def test_create_task_async_override_cfg(self): build = model.Build( id=1, bucket='bucket', create_time=utils.utcnow(), created_by=auth.Identity('user', '*****@*****.**'), parameters={ 'builder_name': 'linux_chromium_rel_ng', 'swarming': { 'override_builder_cfg': { # Override cores dimension. 'dimensions': ['cores:16'], 'recipe': { 'revision': 'badcoffee' }, }, } }, ) self.json_response = { 'task_id': 'deadbeef', 'request': { 'properties': { 'dimensions': [ { 'key': 'cores', 'value': '16' }, { 'key': 'os', 'value': 'Linux' }, { 'key': 'pool', 'value': 'Chrome' }, ], }, 'tags': [ 'build_address:bucket/linux_chromium_rel_ng/1', 'builder:linux_chromium_rel_ng', 'buildertag:yes', 'commontag:yes', 'master:master.bucket', 'priority:108', 'recipe_name:recipe', 'recipe_repository:https://example.com/repo', 'recipe_revision:badcoffee', ] } } swarming.create_task_async(build).get_result() actual_task_def = net.json_request_async.call_args[1]['payload'] self.assertIn({ 'key': 'cores', 'value': '16' }, actual_task_def['properties']['dimensions'])
def test_enqueue_callback_task_if_needed(self, enqueue_task_async): build = model.Build( id=1, bucket='chromium', create_time=datetime.datetime(2017, 1, 1), pubsub_callback=model.PubSubCallback( topic='projects/example/topic/buildbucket', user_data='hello', auth_token='secret', ), ) @ndb.transactional def txn(): build.put() events.on_build_completing_async(build).get_result() txn() enqueue_task_async.assert_called_with( 'backend-default', '/internal/task/buildbucket/notify/1', json.dumps({ 'topic': 'projects/example/topic/buildbucket', 'message': { 'build_id': '1', 'user_data': 'hello', }, 'attrs': { 'build_id': '1', 'auth_token': 'secret', }, }, sort_keys=True), model.BUILD_TIMEOUT.total_seconds())
def test_retry(self, retry): build = model.Build( bucket='chromium', parameters={'builder_name': 'debug'}, tags=['a:b'], retry_of=2, ) build.put() retry.return_value = build req = { 'id': build.key.id(), 'client_operation_id': '42', 'pubsub_callback': { 'topic': 'projects/foo/topic/bar', 'user_data': 'hello', 'auth_token': 'secret', } } resp = self.call_api('retry', req).json_body retry.assert_called_once_with( build.key.id(), client_operation_id='42', lease_expiration_date=None, pubsub_callback=model.PubSubCallback( topic='projects/foo/topic/bar', user_data='hello', auth_token='secret', ), ) self.assertEqual(resp['build']['id'], str(build.key.id())) self.assertEqual(resp['build']['bucket'], build.bucket) self.assertEqual(json.loads(resp['build']['parameters_json']), build.parameters) self.assertEqual(resp['build']['retry_of'], '2')
def test_canceled(self): self.compare( model.Build(proto=build_pb2.Build(status=common_pb2.CANCELED), status_legacy=model.BuildStatus.COMPLETED, result=model.BuildResult.CANCELED, cancelation_reason=model.CancelationReason. CANCELED_EXPLICITLY), )
def test_segment_full(self, enqueue_tasks): ndb.put_multi([ model.Build(id=i, bucket='chromium', tags=['buildset:%d' % (i % 3)]) for i in xrange(50, 52) ]) self.post({ 'action': 'segment', 'tag': 'buildset', 'seg_index': 0, 'seg_start': 50, 'seg_end': 60, 'started_ts': utils.datetime_to_timestamp(self.now), }) self.assertEqual(enqueue_tasks.call_count, 1) enqueue_tasks.assert_called_with('backfill-tag-index', [( None, self.task_url + 'tag:buildset-flush', utils.encode_to_json({ 'action': 'flush', 'tag': 'buildset', 'new_entries': { '0': [['chromium', 51]], '2': [['chromium', 50]], }, }), )])
def compare(self, build): actual = model.Build(proto=build.proto) actual.update_v1_status_fields() self.assertEqual(actual.status_legacy, build.status_legacy) self.assertEqual(actual.result, build.result) self.assertEqual(actual.failure_reason, build.failure_reason) self.assertEqual(actual.cancelation_reason, build.cancelation_reason)
def test_shared_cache(self): builder_cfg = self.bucket_cfg.swarming.builders[0] builder_cfg.caches.add(path='builder', name='shared_builder_cache') build = model.Build( id=1, bucket='bucket', create_time=utils.utcnow(), created_by=auth.Identity('user', '*****@*****.**'), parameters={ 'builder_name': 'linux_chromium_rel_ng', }, ) _, _, task_def = swarming.prepare_task_def_async(build).get_result() self.assertEqual(task_def['properties']['caches'], [ { 'path': 'cache/a', 'name': 'a' }, { 'path': 'cache/builder', 'name': 'shared_builder_cache' }, { 'path': 'cache/git_cache', 'name': 'git_chromium' }, { 'path': 'cache/out', 'name': 'build_chromium' }, ])
def test_search_bucket(self): self.test_build.put() build2 = model.Build(bucket='other bucket', ) build2.put() builds, _ = self.service.search(buckets=[self.test_build.bucket]) self.assertEqual(builds, [self.test_build])
def test_send_build_status_metric(self): buf = mock.Mock() ndb.put_multi([ model.Build(bucket='chromium', status=model.BuildStatus.SCHEDULED), model.Build(bucket='chromium', status=model.BuildStatus.SCHEDULED), model.Build(bucket='v8', status=model.BuildStatus.SCHEDULED), model.Build(bucket='chromium', status=model.BuildStatus.STARTED), ]) send_future = metrics.send_build_status_metric( buf, 'chromium', metrics.METRIC_PENDING_BUILDS, model.BuildStatus.SCHEDULED) send_future.get_result() buf.set_gauge.assert_called_once_with( metrics.METRIC_PENDING_BUILDS, 2, {metrics.LABEL_BUCKET: 'chromium'})
def test_fields_for(self): build = model.Build( bucket='master.x', tags=['builder:release', 'user_agent:cq', 'something:else'], status=model.BuildStatus.COMPLETED, result=model.BuildResult.FAILURE, failure_reason=model.FailureReason.BUILD_FAILURE, ) expected = { 'bucket': 'master.x', 'builder': 'release', 'user_agent': 'cq', 'status': 'COMPLETED', 'result': 'FAILURE', 'failure_reason': 'BUILD_FAILURE', 'cancelation_reason': '', } self.assertEqual(set(expected), set(metrics._ALL_FIELD_NAMES)) actual = metrics._fields_for(build, expected.keys()) self.assertEqual(expected, actual) self.assertEqual({k: '' for k in expected}, metrics._fields_for(None, expected.keys())) with self.assertRaises(ValueError): metrics._fields_for(build, ['wrong field'])
def test_timeout(self): self.compare( model.Build(proto=build_pb2.Build( status=common_pb2.INFRA_FAILURE, status_details=dict(timeout=dict())), status_legacy=model.BuildStatus.COMPLETED, result=model.BuildResult.CANCELED, cancelation_reason=model.CancelationReason.TIMEOUT), )
def test_create_task_async_on_leased_build(self): build = model.Build( id=1, bucket='bucket', parameters={'builder_name': 'linux_chromium_rel_ng'}, lease_key=12345, ) with self.assertRaises(errors.InvalidInputError): swarming.create_task_async(build).get_result()
def test_create_task_async_for_non_swarming_bucket(self): self.bucket_cfg.ClearField('swarming') build = model.Build( id=1, bucket='bucket', parameters={'builder_name': 'linux_chromium_rel_ng'}, ) with self.assertRaises(errors.InvalidInputError): swarming.create_task_async(build).get_result()
def test_search_by_created_by(self): self.test_build.put() build2 = model.Build( bucket=self.test_build.bucket, created_by=auth.Identity.from_bytes('user:[email protected]')) build2.put() builds, _ = self.service.search(created_by='*****@*****.**', buckets=[self.test_build.bucket]) self.assertEqual(builds, [build2])
def test_search(self): build2 = model.Build(bucket=self.test_build.bucket) build2.put() self.test_build.tags = ['important:true'] self.test_build.put() builds, _ = self.service.search( buckets=[self.test_build.bucket], tags=self.test_build.tags, ) self.assertEqual(builds, [self.test_build])
def test_create_task_async_without_template(self): self.task_template = None self.task_template_canary = None build = model.Build( id=1, bucket='bucket', parameters={'builder_name': 'linux_chromium_rel_ng'}, ) with self.assertRaises(swarming.TemplateNotFound): swarming.create_task_async(build).get_result()
def test_set_build_lease_latency(self, utcnow): utcnow.return_value = datetime.datetime(2015, 1, 4) ndb.put_multi([ model.Build( bucket='chromium', status=model.BuildStatus.SCHEDULED, never_leased=True, create_time=datetime.datetime(2015, 1, 1), ), model.Build( bucket='chromium', status=model.BuildStatus.SCHEDULED, never_leased=True, create_time=datetime.datetime(2015, 1, 3), ), model.Build( bucket='chromium', status=model.BuildStatus.COMPLETED, result=model.BuildResult.CANCELED, cancelation_reason=model.CancelationReason.TIMEOUT, never_leased=True, create_time=datetime.datetime(2015, 1, 3), complete_time=datetime.datetime(2015, 1, 4), ), model.Build( bucket='chromium', status=model.BuildStatus.SCHEDULED, create_time=datetime.datetime(2015, 1, 3), ), model.Build(bucket='v8', status=model.BuildStatus.SCHEDULED, never_leased=True, create_time=datetime.datetime(2015, 1, 3)), ]) metrics.set_build_latency(metrics.LEASE_LATENCY_SEC, 'chromium', True).get_result() dist = metrics.LEASE_LATENCY_SEC.get( {'bucket': 'chromium'}, target_fields=metrics.GLOBAL_TARGET_FIELDS) self.assertEquals(dist.sum, 4.0 * 24 * 3600) # 4 days
def test_create_task_async_no_canary_template_implicit( self, should_use_canary_template): should_use_canary_template.return_value = True self.task_template_canary = None self.bucket_cfg.swarming.task_template_canary_percentage.value = 54 self.json_response = { 'task_id': 'deadbeef', 'request': { 'properties': { 'dimensions': [ { 'key': 'cores', 'value': '8' }, { 'key': 'os', 'value': 'Linux' }, { 'key': 'pool', 'value': 'Chrome' }, ], }, 'tags': [ 'build_address:bucket/linux_chromium_rel_ng/1', 'builder:linux_chromium_rel_ng', 'buildertag:yes', 'commontag:yes', 'master:master.bucket', 'priority:108', 'recipe_name:recipe', 'recipe_repository:https://example.com/repo', 'recipe_revision:HEAD', ] } } build = model.Build( id=1, bucket='bucket', create_time=utils.utcnow(), created_by=auth.Identity('user', '*****@*****.**'), parameters={'builder_name': 'linux_chromium_rel_ng'}, ) swarming.create_task_async(build).get_result() actual_task_def = net.json_request_async.call_args[1]['payload'] self.assertIn('buildbucket_template_canary:false', actual_task_def['tags']) should_use_canary_template.assert_called_with(54)
def setUpTests(self): gae_ts_mon.reset_for_unittest(disable=True) auth.disable_process_cache() self.future_date = utils.utcnow() + datetime.timedelta(minutes=1) # future_ts is str because INT64 values are formatted as strings. self.future_ts = str(utils.datetime_to_timestamp(self.future_date)) self.test_build = model.Build( id=1, bucket='chromium', parameters={ 'buildername': 'linux_rel', }, )
def test_start_many_shards(self, enqueue_tasks): ndb.put_multi([ model.Build(id=i, bucket='chromium', create_time=self.now - datetime.timedelta(minutes=i)) for i in xrange(1, 150) ]) self.post({ 'action': 'start', 'tag': 'buildset', 'shards': 100, }) self.assertEqual(enqueue_tasks.call_count, 2)
def test_search_many_tags(self): self.test_build.tags = ['important:true', 'author:ivan'] self.test_build.put() build2 = model.Build( bucket=self.test_build.bucket, tags=self.test_build.tags[:1], # only one of two tags. ) build2.put() # Search by both tags. builds, _ = self.service.search( tags=self.test_build.tags, buckets=[self.test_build.bucket], ) self.assertEqual(builds, [self.test_build])
def test_search_by_buildset(self): self.test_build.tags = ['buildset:x'] self.test_build.put() build2 = model.Build( bucket='secret.bucket', tags=self.test_build.tags, # only one of two tags. ) build2.put() get_available_buckets = mock.Mock( return_value=[self.test_build.bucket]) self.mock(acl, 'get_available_buckets', get_available_buckets) builds, _ = self.service.search(tags=['buildset:x']) self.assertEqual(builds, [self.test_build])
def test_create_task_async_bad_request(self): build = model.Build(id=1, bucket='bucket') with self.assertRaises(errors.InvalidInputError): swarming.create_task_async(build).get_result() with self.assertRaises(errors.InvalidInputError): build.parameters = { 'builder_name': 'non-existent builder', } swarming.create_task_async(build).get_result() with self.assertRaises(errors.InvalidInputError): build.parameters['builder_name'] = 2 swarming.create_task_async(build).get_result()
def setUp(self): super(BuildBucketApiTest, self).setUp() self.service = mock.Mock() self.mock(api.BuildBucketApi, 'service_factory', lambda _: self.service) self.future_date = utils.utcnow() + datetime.timedelta(minutes=1) # future_ts is str because INT64 values are formatted as strings. self.future_ts = str(utils.datetime_to_timestamp(self.future_date)) self.test_build = model.Build( id=1, bucket='chromium', parameters={ 'buildername': 'linux_rel', }, )
def test_heartbeat_batch(self, heartbeat_batch): self.test_build.lease_expiration_date = self.future_date build2 = model.Build( id=2, bucket='chromium', lease_expiration_date=self.future_date, ) heartbeat_batch.return_value = [ (self.test_build.key.id(), self.test_build, None), (build2.key.id(), None, errors.LeaseExpiredError()) ] req = { 'heartbeats': [{ 'build_id': self.test_build.key.id(), 'lease_key': 42, 'lease_expiration_ts': self.future_ts, }, { 'build_id': build2.key.id(), 'lease_key': 42, 'lease_expiration_ts': self.future_ts, }], } res = self.call_api('heartbeat_batch', req).json_body heartbeat_batch.assert_called_with([{ 'build_id': self.test_build.key.id(), 'lease_key': 42, 'lease_expiration_date': self.future_date, }, { 'build_id': build2.key.id(), 'lease_key': 42, 'lease_expiration_date': self.future_date, }]) result1 = res['results'][0] self.assertEqual(int(result1['build_id']), self.test_build.key.id()) self.assertEqual(result1['lease_expiration_ts'], self.future_ts) result2 = res['results'][1] self.assertEqual(int(result2['build_id']), build2.key.id()) self.assertTrue(result2['error']['reason'] == 'LEASE_EXPIRED')
def test_create_task_async_no_canary_template_explicit(self): build = model.Build( id=1, bucket='bucket', create_time=utils.utcnow(), created_by=auth.Identity('user', '*****@*****.**'), parameters={ 'builder_name': 'linux_chromium_rel_ng', 'swarming': { 'canary_template': True, } }, ) self.task_template_canary = None with self.assertRaises(errors.InvalidInputError): swarming.create_task_async(build).get_result()
def test_search_by_status(self): self.test_build.put() build2 = model.Build( bucket=self.test_build.bucket, status=model.BuildStatus.COMPLETED, result=model.BuildResult.SUCCESS, ) build2.put() builds, _ = self.service.search(buckets=[self.test_build.bucket], status=model.BuildStatus.SCHEDULED) self.assertEqual(builds, [self.test_build]) builds, _ = self.service.search(buckets=[self.test_build.bucket], status=model.BuildStatus.COMPLETED, result=model.BuildResult.FAILURE) self.assertEqual(builds, [])
def setUp(self): super(CronUpdateTest, self).setUp() self.build = model.Build( id=1, bucket='bucket', create_time=datetime.datetime(2017, 1, 1), start_time=datetime.datetime(2017, 1, 1), parameters={ 'builder_name': 'release', }, swarming_hostname='chromium-swarm.appsot.com', swarming_task_id='deadeef', status=model.BuildStatus.STARTED, lease_key=123, lease_expiration_date=utils.utcnow() + datetime.timedelta(minutes=5), leasee=auth.Anonymous, ) self.build.put()