Merge pull request #120 from mozilla/job-classification-events

add job classification socketio event
This commit is contained in:
camd 2014-03-14 06:54:43 -07:00
Родитель 2a7ba208c2 a3ebefef98
Коммит a256389446
9 изменённых файлов: 120 добавлений и 16 удалений

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

@ -254,3 +254,8 @@ def refdata():
add_test_procs_file(refdata.dhub, 'reference', proc_path)
return refdata
@pytest.fixture
def mock_message_broker(monkeypatch):
from django.conf import settings
monkeypatch.setattr(settings, 'BROKER_URL', 'memory://')

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

@ -26,7 +26,7 @@ def test_create_bug_job_map_no_auth(eleven_jobs_processed, jm):
assert resp.status_code == 403
def test_create_bug_job_map(eleven_jobs_processed, jm):
def test_create_bug_job_map(eleven_jobs_processed, mock_message_broker, jm):
"""
test creating a single note via endpoint
"""
@ -98,7 +98,8 @@ def test_bug_job_map_detail(webapp, jm, eleven_jobs_processed):
assert resp.json == {"job_id": job_id, "bug_id": bug_id, "type": "manual"}
def test_bug_job_map_delete(webapp, jm, eleven_jobs_processed):
def test_bug_job_map_delete(webapp, eleven_jobs_processed,
jm, mock_message_broker):
"""
test retrieving a list of bug_job_map
"""

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

@ -111,7 +111,7 @@ def test_note_detail_bad_project(webapp, jm):
assert resp.json == {"message": "No project with name foo"}
def test_create_note(webapp, eleven_jobs_processed, jm):
def test_create_note(webapp, eleven_jobs_processed, mock_message_broker, jm):
"""
test creating a single note via endpoint
"""
@ -168,3 +168,24 @@ def test_create_note_no_auth(eleven_jobs_processed, jm):
)
assert resp.status_code == 403
def test_delete_note(webapp, sample_notes, mock_message_broker, jm):
"""
test creating a single note via endpoint
"""
client = APIClient()
user = User.objects.create(username="MyName", is_staff=True)
client.force_authenticate(user=user)
notes = jm.get_job_note_list(job_id=1)
resp = client.delete(
reverse("note-detail", kwargs={"project": jm.project, "pk": notes[0]['id']}),
)
new_notes = jm.get_job_note_list(job_id=1)
user.delete()
assert resp.status_code == 200, resp
assert len(new_notes) == len(notes)-1

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

@ -93,3 +93,19 @@ class ResultsetPublisher(EventsPublisher):
super(ResultsetPublisher, self).publish(
message,
"events.{0}.resultset".format(branch))
class JobClassificationPublisher(EventsPublisher):
def publish(self, job_id, who, branch):
message = {
"id": job_id,
"who": who,
"event": "job_classification",
"branch": branch
}
super(JobClassificationPublisher, self).publish(
message,
"events.{0}.job_classification".format(branch)
)

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

@ -266,8 +266,23 @@ class JobsModel(TreeherderModelBase):
)
return data
def update_last_job_classification(self, job_id):
"""
Update failure_classification_id no the job table accordingly to
the latest annotation. If none is present it gets reverted to the
default value
"""
self.get_jobs_dhub().execute(
proc='jobs.updates.update_last_job_classification',
placeholders=[
job_id,
],
debug_show=self.DEBUG
)
def insert_job_note(self, job_id, failure_classification_id, who, note):
"""insert a new note for the job"""
"""insert a new note for a job and updates its failure classification"""
self.get_jobs_dhub().execute(
proc='jobs.inserts.insert_note',
placeholders=[
@ -279,17 +294,22 @@ class JobsModel(TreeherderModelBase):
],
debug_show=self.DEBUG
)
self.update_last_job_classification(job_id)
def delete_job_note(self, note_id, job_id):
"""
Delete a job note and updates the failure classification for that job
"""
self.get_jobs_dhub().execute(
proc='jobs.updates.update_last_job_classification',
proc='jobs.deletes.delete_note',
placeholders=[
failure_classification_id,
job_id,
note_id,
],
debug_show=self.DEBUG
)
self.update_last_job_classification(job_id)
def insert_bug_job_map(self, job_id, bug_id, assignment_type):
"""

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

@ -12,7 +12,7 @@
"pk": 2,
"model": "model.failureclassification",
"fields": {
"name": "expected fail",
"name": "fixed by backout",
"description": "",
"active_status": "active"
}

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

@ -3,6 +3,10 @@
"delete_bug_job_map":{
"sql":"DELETE FROM bug_job_map WHERE job_id = ? and bug_id = ?",
"host": "master_host"
},
"delete_note":{
"sql":"DELETE FROM job_note WHERE id = ?",
"host": "master_host"
}
},
"inserts":{
@ -172,9 +176,20 @@
"host":"master_host"
},
"update_last_job_classification":{
"sql":"UPDATE `job`
SET `failure_classification_id` = ?
WHERE `id` = ?",
"sql":"update job j
set failure_classification_id = (
select
IF(failure_classification_id IS NOT NULL, failure_classification_id, 1)
from
job_note jn
where
jn.job_id = j.id
order by
note_timestamp DESC
limit 0,1
)
where j.id = ?
",
"host":"master_host"
}

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

@ -103,7 +103,7 @@ CREATE TABLE `job` (
`option_collection_hash` varchar(64) COLLATE utf8_bin DEFAULT NULL,
`job_type_id` int(10) unsigned NOT NULL,
`product_id` int(10) unsigned DEFAULT NULL,
`failure_classification_id` int(10) unsigned DEFAULT NULL,
`failure_classification_id` int(10) unsigned DEFAULT 1,
`who` varchar(50) COLLATE utf8_bin NOT NULL,
`reason` varchar(125) COLLATE utf8_bin NOT NULL,
`result` varchar(25) COLLATE utf8_bin DEFAULT NULL,

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

@ -15,10 +15,9 @@ from treeherder.webapp.api.permissions import IsStaffOrReadOnly
from treeherder.model import models
from treeherder.model.derived import (JobsModel, DatasetNotFoundError,
RefDataManager, ObjectNotFoundException)
from treeherder.webapp.api.utils import UrlQueryFilter
from treeherder.etl.oauth_utils import OAuthCredentials
from treeherder.events.publisher import JobClassificationPublisher
def oauth_required(func):
@ -272,17 +271,44 @@ class NoteViewSet(viewsets.ViewSet):
POST method implementation
"""
jm.insert_job_note(
request.DATA['job_id'],
request.DATA['failure_classification_id'],
int(request.DATA['job_id']),
int(request.DATA['failure_classification_id']),
request.DATA['who'],
request.DATA.get('note', '')
)
publisher = JobClassificationPublisher(settings.BROKER_URL)
try:
publisher.publish(int(request.DATA['job_id']),
request.DATA['who'], project)
finally:
publisher.disconnect()
return Response(
{'message': 'note stored for job {0}'.format(
request.DATA['job_id']
)}
)
@with_jobs
def destroy(self, request, project, jm, pk=None):
"""
Delete a note entry
"""
objs = jm.get_job_note(pk)
if objs:
jm.delete_job_note(pk, objs[0]['job_id'])
publisher = JobClassificationPublisher(settings.BROKER_URL)
try:
publisher.publish(objs[0]['job_id'], objs[0]['who'], project)
finally:
publisher.disconnect()
return Response({"message": "Note deleted"})
else:
return Response("No note with id: {0}".format(pk), 404)
def get_option(obj, option_collections):
"""Get the option, if there is one. Otherwise, return None."""
opt = obj.get("option_collection_hash", None)