def get_build_async(req, res, _ctx, mask): """Retrieves a build by id or number.""" validation.validate_get_build_request(req) if req.id: logging.info('Build id: %s', req.id) build = yield service.get_async(req.id) else: logging.info( 'Build id: %s/%d', config.builder_id_string(req.builder), req.build_number, ) tag = buildtags.build_address_tag(req.builder, req.build_number) q = search.Query( bucket_ids=[bucket_id_string(req.builder)], tags=[tag], include_experimental=True, ) found, _ = yield search.search_async(q) build = found[0] if found else None if not build: raise not_found() yield build_to_proto_async(build, res, mask)
def search(self, request): """Searches for builds.""" assert isinstance(request.tag, list) builds, next_cursor = search.search_async( search.Query( bucket_ids=convert_bucket_list(request.bucket), tags=request.tag, status=request.status, result=request.result, failure_reason=request.failure_reason, cancelation_reason=request.cancelation_reason, max_builds=request.max_builds, created_by=request.created_by, start_cursor=request.start_cursor, retry_of=request.retry_of, canary=request.canary, create_time_low=parse_datetime(request.creation_ts_low), create_time_high=parse_datetime(request.creation_ts_high), include_experimental=request.include_experimental, ) ).get_result() return self.SearchResponseMessage( builds=builds_to_messages(builds), next_cursor=next_cursor, )
def search(self, term=None, page=1): """Search page contains searched items or "no results" message. Number of page is conditioned by total number of searched items and items per page (5). :param term: searched term :param page: page filter for searched terms """ tmpl = tmpl_lookup.get_template("index.html") results_num = 0 pages = 0 page = int(page) if term != None: # if term is empty then skip search query query = search.Query() data, results_num = query.search_term(searcher, parser, term, page) pages = math.ceil(results_num / 5) return tmpl.render_unicode(term=term, data=data, length=results_num, newest=query.get_newest(5), help=False, page=page, pages=pages)
def test_get_and_search(self, search_async, get_async): search_async.return_value = future( ([test_util.build(id=1), test_util.build(id=2)], '')) get_async.return_value = future(test_util.build(id=3)) req = rpc_pb2.BatchRequest(requests=[ dict(search_builds=dict(predicate=dict(builder=dict( project='chromium', bucket='try', builder='linux-rel', ), ), ), ), dict(get_build=dict(id=3)), ], ) res = self.call(self.api.Batch, req) search_async.assert_called_once_with( search.Query( bucket_ids=['chromium/try'], builder='linux-rel', status=common_pb2.STATUS_UNSPECIFIED, include_experimental=False, tags=[], start_cursor='', ), ) get_async.assert_called_once_with(3) self.assertEqual(len(res.responses), 2) self.assertEqual(len(res.responses[0].search_builds.builds), 2) self.assertEqual(res.responses[0].search_builds.builds[0].id, 1L) self.assertEqual(res.responses[0].search_builds.builds[1].id, 2L) self.assertEqual(res.responses[1].get_build.id, 3L)
def test_basic(self, search_async): builds = [test_util.build(id=54), test_util.build(id=55)] search_async.return_value = future((builds, 'next page token')) req = rpc_pb2.SearchBuildsRequest( predicate=dict(builder=dict(project='chromium', bucket='try', builder='linux-try'), ), page_size=10, page_token='page token', ) res = self.call(self.api.SearchBuilds, req) search_async.assert_called_once_with( search.Query( bucket_ids=['chromium/try'], builder='linux-try', include_experimental=False, tags=[], status=common_pb2.STATUS_UNSPECIFIED, max_builds=10, start_cursor='page token', )) self.assertEqual(len(res.builds), 2) self.assertEqual(res.builds[0].id, 54) self.assertEqual(res.builds[1].id, 55) self.assertEqual(res.next_page_token, 'next page token')
def test_two_ranges(self): q = search.Query( create_time_low=datetime.datetime(2018, 1, 1), build_high=1000, ) err_pattern = r'mutually exclusive' with self.assertRaisesRegexp(errors.InvalidInputError, err_pattern): q.validate()
def test_query__get_transformed_value__with_latex( value, language_conf, expected, mocker): mocker.patch( 'search.query.detector.detect_db_conf' ).return_value = language_conf q = search.Query('') assert expected == q.parse_value(value, language_conf)
def build_predicate_to_search_query(predicate): """Converts a rpc_pb2.BuildPredicate to search.Query. Assumes predicate is valid. """ q = search.Query( tags=[buildtags.unparse(p.key, p.value) for p in predicate.tags], created_by=predicate.created_by or None, include_experimental=predicate.include_experimental, status=(search.StatusFilter.COMPLETED if predicate.status == common_pb2.ENDED_MASK else predicate.status), ) # Filter by builder. if predicate.HasField('builder'): if predicate.builder.bucket: q.bucket_ids = [bucket_id_string(predicate.builder)] q.builder = predicate.builder.builder else: q.project = predicate.builder.project # Filter by gerrit changes. buildsets = [ buildtags.gerrit_change_buildset(c) for c in predicate.gerrit_changes ] q.tags.extend( buildtags.unparse(buildtags.BUILDSET_KEY, b) for b in buildsets) # Filter by creation time. if predicate.create_time.HasField('start_time'): q.create_time_low = predicate.create_time.start_time.ToDatetime() if predicate.create_time.HasField('end_time'): q.create_time_high = predicate.create_time.end_time.ToDatetime() # Filter by build range. if predicate.HasField('build'): # 0 means no boundary. # Convert BuildRange to search.Query.{build_low, build_high}. # Note that, unlike build_low/build_high, BuildRange encapsulates the fact # that build ids are decreasing. We need to reverse the order. if predicate.build.start_build_id: # pragma: no branch # Add 1 because start_build_id is inclusive and build_high is exclusive. q.build_high = predicate.build.start_build_id + 1 if predicate.build.end_build_id: # pragma: no branch # Subtract 1 because end_build_id is exclusive and build_low is inclusive. q.build_low = predicate.build.end_build_id - 1 # Filter by canary. if predicate.canary != common_pb2.UNSET: q.canary = predicate.canary == common_pb2.YES return q
def index(self): """Index page contains latest videos section. """ tmpl = tmpl_lookup.get_template("index.html") query = search.Query() return tmpl.render_unicode(term=None, data=None, length=-1, newest=query.get_newest(5), help=False)
def test_query__to_sql__with_config(mocker): mocker.patch( 'search.query.detector.detect_db_conf' ).return_value = 'simple' q = search.Query('hi there') compiler = Mock(compile=Mock(return_value=['simple', ['a', 'b']])) connection = Mock() template, params = q.as_sql(compiler, connection) assert template == 'to_tsquery(simple::regconfig, %s)' assert params == ['a', 'b', 'hi | there']
def test_query__auto_detects_language(mocker): mocker.patch( 'search.query.detector.detect_db_conf' ).return_value = 'polish' parse_value_mock = mocker.patch.object( search.Query, 'parse_value') parse_value_mock.return_value = 'witaj | świecie' compiler = Mock(compile=Mock(return_value=['polish', []])) q = search.Query('witaj świecie!') connection = Mock() template, params = q.as_sql(compiler, connection) assert template == 'to_tsquery(polish::regconfig, %s)' assert params == ['witaj | świecie'] assert ( parse_value_mock.call_args_list == [call('witaj świecie!', 'polish')])
def test_by_number(self, search_async): builder_id = build_pb2.BuilderID(project='chromium', bucket='try', builder='linux-try') build = test_util.build(id=1, builder=builder_id, number=2) search_async.return_value = future(([build], None)) req = rpc_pb2.GetBuildRequest(builder=builder_id, build_number=2) res = self.call(self.api.GetBuild, req) self.assertEqual(res.id, 1) self.assertEqual(res.builder, builder_id) self.assertEqual(res.number, 2) search_async.assert_called_once_with( search.Query( bucket_ids=['chromium/try'], tags=['build_address:luci.chromium.try/linux-try/2'], include_experimental=True, ))
def test_search(self, search_async): build = test_util.build(id=1) search_async.return_value = future(([build], 'the cursor')) time_low = model.BEGINING_OF_THE_WORLD time_high = datetime.datetime(2120, 5, 4) req = { 'bucket': ['luci.chromium.try'], 'cancelation_reason': 'CANCELED_EXPLICITLY', 'created_by': 'user:[email protected]', 'result': 'CANCELED', 'status': 'COMPLETED', 'tag': ['important'], 'retry_of': '42', 'canary': True, 'creation_ts_low': utils.datetime_to_timestamp(time_low), 'creation_ts_high': utils.datetime_to_timestamp(time_high), } res = self.call_api('search', req).json_body search_async.assert_called_once_with( search.Query( bucket_ids=['chromium/try'], tags=req['tag'], status=search.StatusFilter.COMPLETED, result=model.BuildResult.CANCELED, failure_reason=None, cancelation_reason=model.CancelationReason.CANCELED_EXPLICITLY, created_by='user:[email protected]', max_builds=None, start_cursor=None, retry_of=42, canary=True, create_time_low=time_low, create_time_high=time_high, ) ) self.assertEqual(len(res['builds']), 1) self.assertEqual(res['builds'][0]['id'], '1') self.assertEqual(res['next_cursor'], 'the cursor')
def search(self, **query_attrs): return search.search_async(search.Query(**query_attrs)).get_result()
def test_builder_without_bucket(self): q = search.Query(builder='linux-rel') err_pattern = r'builder requires non-empty bucket_ids' with self.assertRaisesRegexp(errors.InvalidInputError, err_pattern): q.validate()
def test_project_and_bucket_ids(self): q = search.Query(project='chromium', bucket_ids=['chromium/try']) err_pattern = r'mutually exclusive' with self.assertRaisesRegexp(errors.InvalidInputError, err_pattern): q.validate()
def test_query__parse_value(value, expected, mocker): mocker.patch('search.query.HASHTAG_ESCAPE_SEQUENCE', 'hh') q = search.Query('') assert expected == q.parse_value(value, 'simple')