add bug_job_map endpoints and model methods

This commit is contained in:
mdoglio 2014-02-03 16:28:31 +00:00
Родитель 0853bdfda4
Коммит 78d46f1505
8 изменённых файлов: 278 добавлений и 65 удалений

Просмотреть файл

@ -391,7 +391,7 @@ def test_update_bugscache(refdata, sample_bugs):
assert len(bug_list) == len(row_data)
def test_get_suggested_bugs(refdata, sample_bugs):
def test_get_bugscache(refdata, sample_bugs):
"""
Test that at least one result is retrieved
for the right search terms

Просмотреть файл

@ -0,0 +1,89 @@
from django.core.urlresolvers import reverse
import random
def test_create_bug_job_map(webapp, eleven_jobs_processed, jm):
"""
test creating a single note via endpoint
"""
job = jm.get_job_list(0, 1)[0]
bug_job_map_obj = {
"job_id": job["id"],
"bug_id": 1,
"type": "manual"
}
resp = webapp.post_json(
reverse("bug-job-map-list", kwargs={"project": jm.project}),
bug_job_map_obj)
assert (bug_job_map_obj,) == jm.get_bug_job_map_list(0, 1)
def test_bug_job_map_list(webapp, jm, eleven_jobs_processed):
"""
test retrieving a list of bug_job_map
"""
jobs = jm.get_job_list(0, 10)
bugs = [random.randint(0, 100) for i in range(0, len(jobs))]
expected = list()
for i, v in enumerate(jobs):
jm.insert_bug_job_map(v["id"], bugs[i], "manual")
expected.append({
"job_id": v["id"],
"bug_id": bugs[i],
"type": "manual"})
resp = webapp.get(
reverse("bug-job-map-list", kwargs={"project": jm.project}))
for i, v in enumerate(expected):
assert v == resp.json[i]
def test_bug_job_map_detail(webapp, jm, eleven_jobs_processed):
"""
test retrieving a list of bug_job_map
"""
job_id = jm.get_job_list(0, 1)[0]["id"]
bug_id = random.randint(0, 100)
expected = list()
jm.insert_bug_job_map(job_id, bug_id, "manual")
pk = "{0}-{1}".format(job_id, bug_id)
resp = webapp.get(
reverse("bug-job-map-detail", kwargs={
"project": jm.project,
"pk": pk
})
)
assert resp.json == {"job_id": job_id, "bug_id": bug_id, "type": "manual"}
def test_bug_job_map_delete(webapp, jm, eleven_jobs_processed):
"""
test retrieving a list of bug_job_map
"""
job_id = jm.get_job_list(0, 1)[0]["id"]
bug_id = random.randint(0, 100)
jm.insert_bug_job_map(job_id, bug_id, "manual")
pk = "{0}-{1}".format(job_id, bug_id)
resp = webapp.delete_json(
reverse("bug-job-map-detail", kwargs={
"project": jm.project,
"pk": pk
})
)
assert resp.json == {"message": "Bug job map deleted"}

Просмотреть файл

@ -126,21 +126,3 @@ def test_job_detail_not_found(webapp, jm):
expect_errors=True
)
assert resp.status_int == 404
def test_retrieve_result_set(jm, webapp, eleven_jobs_processed):
resp = webapp.get(
reverse("resultset-list",
kwargs={"project": jm.project})
)
assert resp.status_int == 200
assert isinstance(resp.json, list)
def test_retrieve_result_set_detail(jm, webapp, eleven_jobs_processed):
job = jm.get_job_list(0, 1)[0]
resp = webapp.get(
reverse("resultset-detail",
kwargs={"project": jm.project, "pk": job["id"]})
)
assert resp.status_int == 200

Просмотреть файл

@ -1,9 +1,5 @@
import json
import pytest
from django.core.urlresolvers import reverse
xfail = pytest.mark.xfail
def test_note_list(webapp, sample_notes, jm):
"""
@ -142,5 +138,3 @@ def test_create_note(webapp, eleven_jobs_processed, jm):
u'active_status': u'active',
u'id': 1
}

Просмотреть файл

@ -63,6 +63,11 @@ class JobsModel(TreeherderModelBase):
],
"result_set": [
"id"
],
"bug_job_map": [
"job_id",
"bug_id",
"type"
]
}
@ -116,31 +121,18 @@ class JobsModel(TreeherderModelBase):
def get_job_list(self, offset, limit, full=True, conditions=None):
"""
Retrieve a list of jobs.
Mainly used by the restful api to list the jobs
joblist: a list of job ids to limit which jobs are returned.
full: whether to return all reference data or just what is
needed for the UI.
Retrieve a list of jobs. It's mainly used by the restful api to list
the jobs. The conditions parameter is a dict containing a set of
conditions for each key. e.g.:
{
'who': set([('=', 'john')]),
'result': set([('IN', ("success", "retry"))])
}
"""
placeholders = []
replace_str = ""
if conditions:
for column, condition in conditions.items():
if column in self.INDEXED_COLUMNS["job"]:
for operator, value in condition:
replace_str += "AND j.{0} {1}".format(column, operator)
if operator == "IN":
# create a list of placeholders of the same length
# as the list of values
replace_str += "({0})".format(
",".join(["%s"] * len(value))
)
placeholders += value
else:
replace_str += " %s "
placeholders.append(value)
replace_str, placeholders = self._process_conditions(
conditions, self.INDEXED_COLUMNS['job'], prefix="j."
)
repl = [self.refdata_model.get_db_name(), replace_str]
@ -157,6 +149,27 @@ class JobsModel(TreeherderModelBase):
)
return data
def _process_conditions(self, conditions, allowed_fields=None, prefix=""):
"""Transform a list of conditions into a list of placeholders and
replacement strings to feed a datahub.execute statement."""
placeholders = []
replace_str = ""
if conditions:
for column, condition in conditions.items():
if allowed_fields is None or column in allowed_fields:
for operator, value in condition:
replace_str += "AND {0}{1} {2}".format(prefix, column, operator)
if operator == "IN":
# create a list of placeholders of the same length
# as the list of values
replace_str += "({0})".format(
",".join(["%s"] * len(value))
)
placeholders += value
else:
replace_str += " %s "
placeholders.append(value)
return replace_str, placeholders
def set_state(self, job_id, state):
"""Update the state of an existing job"""
@ -230,6 +243,7 @@ class JobsModel(TreeherderModelBase):
debug_show=self.DEBUG
)
self.get_jobs_dhub().execute(
proc='jobs.updates.update_last_job_classification',
placeholders=[
@ -239,6 +253,64 @@ class JobsModel(TreeherderModelBase):
debug_show=self.DEBUG
)
def insert_bug_job_map(self, job_id, bug_id, assignment_type):
"""
Store a new relation between the given job and bug ids.
"""
self.get_jobs_dhub().execute(
proc='jobs.inserts.insert_bug_job_map',
placeholders=[
job_id,
bug_id,
assignment_type
],
debug_show=self.DEBUG
)
def delete_bug_job_map(self, job_id, bug_id):
"""
Delete a bug-job entry identified by bug_id and job_id
"""
self.get_jobs_dhub().execute(
proc='jobs.deletes.delete_bug_job_map',
placeholders=[
job_id,
bug_id
],
debug_show=self.DEBUG
)
def get_bug_job_map_list(self, offset, limit, conditions=None):
"""
Retrieve a list of bug_job_map entries. The conditions parameter is a
dict containing a set of conditions for each key. e.g.:
{
'job_id': set([('IN', (1, 2))])
}
"""
replace_str, placeholders = self._process_conditions(
conditions, self.INDEXED_COLUMNS['bug_job_map']
)
repl = [replace_str]
proc = "jobs.selects.get_bug_job_map"
print repl
print placeholders
data = self.get_jobs_dhub().execute(
proc=proc,
replace=repl,
placeholders=placeholders,
limit="{0},{1}".format(offset, limit),
debug_show=self.DEBUG,
)
return data
def get_result_set_ids(self, revision_hashes, where_in_list):
"""Return the a dictionary of revision_hash to id mappings given
a list of revision_hashes and a where_in_list.
@ -277,24 +349,10 @@ class JobsModel(TreeherderModelBase):
Mainly used by the restful api to list the pushes in the UI
"""
placeholders = []
replace_str = ""
if conditions:
for column, condition in conditions.items():
if column in self.INDEXED_COLUMNS["result_set"]:
for operator, value in condition:
replace_str += "AND rs.{0} {1}".format(column, operator)
if operator == "IN":
# create a list of placeholders of the same length
# as the list of values
replace_str += "({0})".format(
",".join(["%s"] * len(value))
)
placeholders += value
else:
replace_str += " %s "
placeholders.append(value)
replace_str, placeholders = self._process_conditions(
conditions, self.INDEXED_COLUMNS['result_set'], prefix="rs."
)
# If a push doesn't have jobs we can just
# message the user, it would save us a very expensive join

Просмотреть файл

@ -1,4 +1,10 @@
{
"deletes":{
"delete_bug_job_map":{
"sql":"DELETE FROM bug_job_map WHERE job_id = ? and bug_id = ?",
"host": "master_host"
}
},
"inserts":{
"create_job_data":{
@ -110,9 +116,19 @@
`note_timestamp`)
VALUES (?,?,?,?,?)",
"host":"master_host"
},
"insert_bug_job_map":{
"sql":"INSERT INTO `bug_job_map` (
`job_id`,
`bug_id`,
`type`,
`active_status`)
VALUES (?,?,?,'active')",
"host":"master_host"
}
},
"updates": {
@ -482,6 +498,13 @@
"sql":"SELECT `name`, `type`, `blob` FROM `job_artifact`",
"host":"read_host"
},
"get_bug_job_map":{
"sql":"SELECT `job_id`, `bug_id`, `type`
FROM `bug_job_map`
WHERE 1
REP0",
"host": "read_host"
}
}
}

Просмотреть файл

@ -40,6 +40,12 @@ project_bound_router.register(
base_name='revision-lookup',
)
project_bound_router.register(
r'bug-job-map',
views.BugJobMapViewSet,
base_name='bug-job-map',
)
# this is the default router for plain restful endpoints

Просмотреть файл

@ -564,6 +564,67 @@ class RevisionLookupSetViewSet(viewsets.ViewSet):
return Response(jm.get_revision_resultset_lookup(revision_list))
class BugJobMapViewSet(viewsets.ViewSet):
@with_jobs
def create(self, request, project, jm):
"""
Add a new relation between a job and a bug
"""
jm.insert_bug_job_map(
request.DATA['job_id'],
request.DATA['bug_id'],
request.DATA['type']
)
return Response({"message": "Bug job map stored"})
@with_jobs
def destroy(self, request, project, jm, pk=None):
"""
Delete bug-job-map entry. pk is a composite key in the form
bug_id-job_id
"""
job_id, bug_id = pk.split("-")
jm.delete_bug_job_map(job_id, bug_id)
return Response({"message": "Bug job map deleted"})
@with_jobs
def retrieve(self, request, project, jm, pk=None):
"""
Retrieve a bug-job-map entry. pk is a composite key in the form
bug_id-job_id
"""
job_id, bug_id = pk.split("-")
params = {
"bug_id": bug_id,
"job_id": job_id
}
params.update(request.QUERY_PARAMS)
filters = UrlQueryFilter(params).parse()
obj = jm.get_bug_job_map_list(0, 1, filters)
if obj:
return Response(obj[0])
else:
return Response("Object not found", 404)
@with_jobs
def list(self, request, project, jm):
filters = UrlQueryFilter(request.QUERY_PARAMS).parse()
limit_condition = filters.pop("limit", set([("=", "0,10")])).pop()
offset, limit = limit_condition[1].split(",")
objs = jm.get_bug_job_map_list(
offset,
limit,
filters
)
return Response(objs)
#####################
# Refdata ViewSets