Merge "Zuul-Web: substring search for builds, buildsets"
This commit is contained in:
@@ -396,6 +396,38 @@ class TestMysqlDatabase(DBBaseTestCase):
|
||||
tenant=tenant, uuid=buildset_uuid)
|
||||
self.assertEqual(db_buildset.result, 'SUCCESS')
|
||||
|
||||
def test_sanitize_subtring_query(self):
|
||||
session = self.connection.getSession()
|
||||
self.assertEqual(None, session._sanitizeSubstringQuery(None))
|
||||
self.assertEqual(
|
||||
"job-name", session._sanitizeSubstringQuery("job-name"))
|
||||
self.assertEqual(
|
||||
"$%job-$%name$%", session._sanitizeSubstringQuery("%job-%name%"))
|
||||
self.assertEqual(
|
||||
"job$_-$%name$%", session._sanitizeSubstringQuery("job_-%name%"))
|
||||
self.assertEqual(
|
||||
"job$_-$%name$%", session._sanitizeSubstringQuery("job_-%name%"))
|
||||
self.assertEqual(
|
||||
"$$$%job$_-$%name$%",
|
||||
session._sanitizeSubstringQuery("$%job_-%name%"))
|
||||
|
||||
def test_fuzzy_filter_op(self):
|
||||
col = sqlalchemy.Column("job_name")
|
||||
session = self.connection.getSession()
|
||||
|
||||
filter = session._getFuzzyFilterOp(col, "job-name")
|
||||
self.assertEqual(type(col == "foo"), type(filter))
|
||||
self.assertEqual("job-name", filter.right.value)
|
||||
|
||||
filter = session._getFuzzyFilterOp(col, "*job*name*")
|
||||
self.assertEqual(type(col.like("foo")), type(filter))
|
||||
self.assertEqual("$", filter.modifiers["escape"])
|
||||
self.assertEqual("%job%name%", filter.right.value)
|
||||
|
||||
filter = session._getFuzzyFilterOp(col, None)
|
||||
self.assertEqual(type(col.__eq__(None)), type(filter))
|
||||
self.assertEqual(sqlalchemy.sql.elements.Null, type(filter.right))
|
||||
|
||||
|
||||
class TestPostgresqlDatabase(DBBaseTestCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -1882,6 +1882,48 @@ class TestBuildInfo(BaseTestWeb):
|
||||
"idx_min=%i" % idx_max).json()
|
||||
self.assertEqual(len(builds_query), 1, builds_query)
|
||||
|
||||
def test_web_substring_search_builds(self):
|
||||
# Generate some build records in the db.
|
||||
self.add_base_changes()
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
builds = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"project=org/project*&"
|
||||
"branch=*aster").json()
|
||||
self.assertEqual(len(builds), 6)
|
||||
|
||||
builds = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"job_name=*-merge").json()
|
||||
self.assertEqual(len(builds), 2)
|
||||
|
||||
builds = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"job_name=*-merge&"
|
||||
"project=org/project1").json()
|
||||
self.assertEqual(len(builds), 1)
|
||||
|
||||
builds = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"pipeline=gat*&"
|
||||
"project=org/project1&"
|
||||
"job_name=*-merge&"
|
||||
"job_name=*test*").json()
|
||||
self.assertEqual(len(builds), 3)
|
||||
self.assertTrue(
|
||||
all(b["ref"]["project"] == "org/project1" for b in builds))
|
||||
self.assertEqual("project-test2", builds[0]["job_name"])
|
||||
self.assertEqual("project-test1", builds[1]["job_name"])
|
||||
self.assertEqual("project-merge", builds[2]["job_name"])
|
||||
|
||||
# sql wildcard chars (% and _), as well as the escape char ($) should
|
||||
# be treated literally, i.e. they are escpaed.
|
||||
# The below query would return builds for
|
||||
# branch LIKE "%master%" OR "%mast_r"
|
||||
# if they would not be escaped
|
||||
builds = self.get_url("api/tenant/tenant-one/builds?"
|
||||
"branch=%master%&"
|
||||
"branch=%mast_r").json()
|
||||
self.assertEqual(len(builds), 0)
|
||||
|
||||
def test_web_list_skipped_builds(self):
|
||||
# Test the exclude_result filter
|
||||
# Generate some build records in the db.
|
||||
@@ -2005,6 +2047,22 @@ class TestBuildInfo(BaseTestWeb):
|
||||
"idx_min=%i" % idx_max).json()
|
||||
self.assertEqual(len(buildsets_query), 1, buildsets_query)
|
||||
|
||||
def test_web_substring_search_buildsets(self):
|
||||
# Generate some build records in the db.
|
||||
self.add_base_changes()
|
||||
self.executor_server.hold_jobs_in_build = False
|
||||
self.executor_server.release()
|
||||
self.waitUntilSettled()
|
||||
|
||||
buildsets = self.get_url("api/tenant/tenant-one/buildsets?"
|
||||
"project=org/*&"
|
||||
"branch=*ster*&"
|
||||
"pipeline=check&"
|
||||
"pipeline=*ate").json()
|
||||
self.assertEqual(2, len(buildsets))
|
||||
self.assertEqual("org/project1", buildsets[0]["refs"][0]["project"])
|
||||
self.assertEqual("org/project", buildsets[1]["refs"][0]["project"])
|
||||
|
||||
def test_web_list_build_times(self):
|
||||
# Generate some build records in the db.
|
||||
self.add_base_changes()
|
||||
|
||||
@@ -119,6 +119,30 @@ class DatabaseSession(object):
|
||||
self.session().close()
|
||||
self.session = None
|
||||
|
||||
def _sanitizeSubstringQuery(self, value):
|
||||
if isinstance(value, str):
|
||||
escape_char = "$"
|
||||
for c in (escape_char, "%", "_"):
|
||||
value = value.replace(c, escape_char + c)
|
||||
return value
|
||||
return value
|
||||
|
||||
def _getFuzzyFilterOp(self, column, value):
|
||||
value = self._sanitizeSubstringQuery(value)
|
||||
if isinstance(value, str) and "*" in value:
|
||||
return column.like(value.replace("*", "%"), escape="$")
|
||||
else:
|
||||
return column == value
|
||||
|
||||
def listFilterFuzzy(self, query, column, value):
|
||||
if value is None:
|
||||
return query
|
||||
elif isinstance(value, list) or isinstance(value, tuple):
|
||||
return query.filter(
|
||||
sa.or_(*[self._getFuzzyFilterOp(column, v) for v in value])
|
||||
)
|
||||
return query.filter(self._getFuzzyFilterOp(column, value))
|
||||
|
||||
def listFilter(self, query, column, value):
|
||||
if value is None:
|
||||
return query
|
||||
@@ -191,10 +215,10 @@ class DatabaseSession(object):
|
||||
dialect_name='postgresql')
|
||||
|
||||
q = self.listFilter(q, buildset_table.c.tenant, tenant)
|
||||
q = self.listFilter(q, buildset_table.c.pipeline, pipeline)
|
||||
q = self.listFilter(q, ref_table.c.project, project)
|
||||
q = self.listFilterFuzzy(q, buildset_table.c.pipeline, pipeline)
|
||||
q = self.listFilterFuzzy(q, ref_table.c.project, project)
|
||||
q = self.listFilter(q, ref_table.c.change, change)
|
||||
q = self.listFilter(q, ref_table.c.branch, branch)
|
||||
q = self.listFilterFuzzy(q, ref_table.c.branch, branch)
|
||||
q = self.listFilter(q, ref_table.c.patchset, patchset)
|
||||
q = self.listFilter(q, ref_table.c.ref, ref)
|
||||
q = self.listFilter(q, ref_table.c.newrev, newrev)
|
||||
@@ -206,7 +230,7 @@ class DatabaseSession(object):
|
||||
q = self.listFilter(
|
||||
q, buildset_table.c.last_build_end_time, last_build_end_time)
|
||||
q = self.listFilter(q, build_table.c.uuid, uuid)
|
||||
q = self.listFilter(q, build_table.c.job_name, job_name)
|
||||
q = self.listFilterFuzzy(q, build_table.c.job_name, job_name)
|
||||
q = self.listFilter(q, build_table.c.voting, voting)
|
||||
q = self.listFilter(q, build_table.c.nodeset, nodeset)
|
||||
q = self.listFilter(q, build_table.c.result, result)
|
||||
@@ -390,10 +414,10 @@ class DatabaseSession(object):
|
||||
dialect_name='postgresql')
|
||||
|
||||
q = self.listFilter(q, buildset_table.c.tenant, tenant)
|
||||
q = self.listFilter(q, buildset_table.c.pipeline, pipeline)
|
||||
q = self.listFilter(q, ref_table.c.project, project)
|
||||
q = self.listFilterFuzzy(q, buildset_table.c.pipeline, pipeline)
|
||||
q = self.listFilterFuzzy(q, ref_table.c.project, project)
|
||||
q = self.listFilter(q, ref_table.c.change, change)
|
||||
q = self.listFilter(q, ref_table.c.branch, branch)
|
||||
q = self.listFilterFuzzy(q, ref_table.c.branch, branch)
|
||||
q = self.listFilter(q, ref_table.c.patchset, patchset)
|
||||
q = self.listFilter(q, ref_table.c.ref, ref)
|
||||
q = self.listFilter(q, ref_table.c.newrev, newrev)
|
||||
|
||||
Reference in New Issue
Block a user