зеркало из https://github.com/mozilla/treeherder.git
Merge pull request #120 from mozilla/job-classification-events
add job classification socketio event
This commit is contained in:
Коммит
a256389446
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче