Skip to content

Commit 6d3dd1e

Browse files
authored
Merge pull request #1104 from syucream/fix/enum-based-job-status
Make job status enum
2 parents 706c88b + 243a7c7 commit 6d3dd1e

25 files changed

+259
-251
lines changed

airone/celery.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ def celery_task_failure_email(**kwargs):
6464
@task_failure.connect()
6565
def celery_task_failure_update_job_status(**kwargs):
6666
"""This event handler is update job status when an exception error in celery."""
67-
from job.models import Job
67+
from job.models import Job, JobStatus
6868

6969
job_id = kwargs["args"][0]
7070
job = Job.objects.get(id=job_id)
71-
job.status = Job.STATUS["ERROR"]
71+
job.status = JobStatus.ERROR.value
7272
job.save(update_fields=["status"])

airone/lib/http.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from airone.lib.types import AttrTypes, AttrTypeValue
1414
from entity import models as entity_models
1515
from entry import models as entry_models
16-
from job.models import Job, JobOperation
16+
from job.models import JobOperation, JobStatus
1717
from user.models import History, User
1818

1919

@@ -155,7 +155,7 @@ def render(request, template, context={}):
155155

156156
# set constracts for job
157157
context["JOB"] = {
158-
"STATUS": Job.STATUS,
158+
"STATUS": {s.name: s.value for s in JobStatus},
159159
"OPERATION": {
160160
"CREATE": JobOperation.CREATE_ENTRY.value,
161161
"EDIT": JobOperation.EDIT_ENTRY.value,

airone/lib/job.py

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
11
import functools
2+
from typing import Any, Callable
23

3-
from job.models import Job
4+
from job.models import Job, JobStatus
45

56

6-
def may_schedule_until_job_is_ready(func):
7+
def may_schedule_until_job_is_ready(
8+
func: Callable[[Any, Job], JobStatus | tuple[JobStatus, str] | None],
9+
):
710
@functools.wraps(func)
8-
def wrapper(kls, job_id):
11+
def wrapper(kls, job_id: int):
912
job = Job.objects.get(id=job_id)
1013
if job.proceed_if_ready():
1114
# update Job status from PREPARING to PROCEEDING
12-
job.update(Job.STATUS["PROCESSING"])
15+
job.update(JobStatus.PROCESSING.value)
1316

1417
try:
1518
# running Job processing
16-
ret: int | tuple = func(kls, job)
19+
ret: JobStatus | tuple[int, str] | None = func(kls, job)
1720
except Exception:
18-
ret = Job.STATUS["ERROR"]
21+
ret = JobStatus.ERROR
1922

2023
# update Job status after finishing Job processing
21-
if isinstance(ret, int):
22-
job.update(status=ret)
23-
elif isinstance(ret, tuple) and len(ret) == 2:
24-
job.update(status=ret[0], text=ret[1])
24+
if isinstance(ret, JobStatus):
25+
job.update(status=ret.value)
26+
elif (
27+
isinstance(ret, tuple) and isinstance(ret[0], JobStatus) and isinstance(ret[1], str)
28+
):
29+
job.update(status=ret[0].value, text=ret[1])
2530
elif not job.is_canceled():
26-
job.update(Job.STATUS["DONE"])
31+
job.update(JobStatus.DONE.value)
2732

2833
return wrapper

airone/tests/test_celery.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from airone.celery import celery_task_failure_email, celery_task_failure_update_job_status
55
from airone.lib.test import AironeViewTest
6-
from job.models import Job
6+
from job.models import Job, JobStatus
77

88

99
class CeleryTest(AironeViewTest):
@@ -33,7 +33,7 @@ def test_celery_task_failure_email(self):
3333

3434
def test_celery_task_failure_update_job_status(self):
3535
user = self.guest_login()
36-
job: Job = Job.objects.create(user=user, status=Job.STATUS["PROCESSING"])
36+
job: Job = Job.objects.create(user=user, status=JobStatus.PREPARING.value)
3737
celery_task_failure_update_job_status(
3838
task_id="test_task_id",
3939
exception=Exception("Test"),
@@ -43,4 +43,4 @@ def test_celery_task_failure_update_job_status(self):
4343
einfo=ExceptionInfo,
4444
)
4545
job.refresh_from_db()
46-
self.assertEqual(job.status, Job.STATUS["ERROR"])
46+
self.assertEqual(job.status, JobStatus.ERROR.value)

api_v1/job/views.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from rest_framework.response import Response
66
from rest_framework.views import APIView
77

8-
from job.models import Job, JobOperation
8+
from job.models import Job, JobOperation, JobStatus
99
from job.settings import CONFIG as JOB_CONFIG
1010

1111

@@ -18,10 +18,10 @@ def get(self, request, format=None):
1818

1919
constant = {
2020
"status": {
21-
"processing": Job.STATUS["PROCESSING"],
22-
"done": Job.STATUS["DONE"],
23-
"error": Job.STATUS["ERROR"],
24-
"timeout": Job.STATUS["TIMEOUT"],
21+
"processing": JobStatus.PROCESSING.value,
22+
"done": JobStatus.DONE.value,
23+
"error": JobStatus.ERROR.value,
24+
"timeout": JobStatus.TIMEOUT.value,
2525
},
2626
"operation": {
2727
"create": JobOperation.CREATE_ENTRY.value,
@@ -72,14 +72,14 @@ def delete(self, request, format=None):
7272
"Failed to find Job(id=%s)" % job_id, status=status.HTTP_400_BAD_REQUEST
7373
)
7474

75-
if job.status == Job.STATUS["DONE"]:
75+
if job.status == JobStatus.DONE.value:
7676
return Response("Target job has already been done")
7777

7878
if job.operation not in Job.CANCELABLE_OPERATIONS:
7979
return Response("Target job cannot be canceled", status=status.HTTP_400_BAD_REQUEST)
8080

8181
# update job.status to be canceled
82-
job.update(Job.STATUS["CANCELED"])
82+
job.update(JobStatus.CANCELED.value)
8383

8484
return Response("Success to cancel job")
8585

@@ -93,9 +93,9 @@ def post(self, request, job_id, format=None):
9393
)
9494

9595
# check job status before starting processing
96-
if job.status == Job.STATUS["DONE"]:
96+
if job.status == JobStatus.DONE.value:
9797
return Response("Target job has already been done")
98-
elif job.status == Job.STATUS["PROCESSING"]:
98+
elif job.status == JobStatus.PROCESSING.value:
9999
return Response("Target job is under processing", status=status.HTTP_400_BAD_REQUEST)
100100

101101
# check job target status

api_v1/tests/job/test_api.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from airone.lib.types import AttrTypeValue
66
from entity.models import Entity, EntityAttr
77
from entry.models import Entry
8-
from job.models import Job, JobOperation
8+
from job.models import Job, JobOperation, JobStatus
99
from job.settings import CONFIG
1010

1111
# constants using this tests
@@ -64,10 +64,10 @@ def test_get_jobs(self):
6464
self.assertEqual(
6565
results["constant"]["status"],
6666
{
67-
"processing": Job.STATUS["PROCESSING"],
68-
"done": Job.STATUS["DONE"],
69-
"error": Job.STATUS["ERROR"],
70-
"timeout": Job.STATUS["TIMEOUT"],
67+
"processing": JobStatus.PROCESSING.value,
68+
"done": JobStatus.DONE.value,
69+
"error": JobStatus.ERROR.value,
70+
"timeout": JobStatus.TIMEOUT.value,
7171
},
7272
)
7373

@@ -119,7 +119,7 @@ def test_rerun_jobs(self):
119119
self.assertEqual(resp.content, b'"Success to run command"')
120120

121121
job = Job.objects.get(id=job.id)
122-
self.assertEqual(job.status, Job.STATUS["DONE"])
122+
self.assertEqual(job.status, JobStatus.DONE.value)
123123
self.assertEqual(entry.attrs.count(), 1)
124124

125125
attrv = entry.attrs.first().get_latest_value()
@@ -152,7 +152,7 @@ def test_rerun_jobs(self):
152152

153153
self.assertEqual(resp.status_code, 200)
154154
self.assertEqual(resp.content, b'"Success to run command"')
155-
self.assertEqual(Job.objects.get(id=job.id).status, Job.STATUS["DONE"])
155+
self.assertEqual(Job.objects.get(id=job.id).status, JobStatus.DONE.value)
156156
self.assertEqual(entry.attrs.first().get_latest_value().value, "fuga")
157157

158158
# make and send a job to copy entry
@@ -161,7 +161,7 @@ def test_rerun_jobs(self):
161161

162162
self.assertEqual(resp.status_code, 200)
163163
self.assertEqual(resp.content, b'"Success to run command"')
164-
self.assertEqual(Job.objects.get(id=job.id).status, Job.STATUS["DONE"])
164+
self.assertEqual(Job.objects.get(id=job.id).status, JobStatus.DONE.value)
165165

166166
# checks it's success to clone entry
167167
new_entry = Entry.objects.get(name="new_entry", schema=entity)
@@ -225,7 +225,7 @@ def test_cancel_job(self):
225225

226226
# make a job
227227
job = Job.new_delete(user, entry)
228-
self.assertEqual(job.status, Job.STATUS["PREPARING"])
228+
self.assertEqual(job.status, JobStatus.PREPARING.value)
229229

230230
# send request without any parameters
231231
resp = self.client.delete("/api/v1/job/", json.dumps({}), "application/json")
@@ -246,7 +246,7 @@ def test_cancel_job(self):
246246

247247
# send request with proper parameter
248248
job = Job.new_create(user, entry)
249-
self.assertEqual(job.status, Job.STATUS["PREPARING"])
249+
self.assertEqual(job.status, JobStatus.PREPARING.value)
250250

251251
resp = self.client.delete(
252252
"/api/v1/job/", json.dumps({"job_id": job.id}), "application/json"
@@ -255,7 +255,7 @@ def test_cancel_job(self):
255255
self.assertEqual(resp.content, b'"Success to cancel job"')
256256

257257
job.refresh_from_db()
258-
self.assertEqual(job.status, Job.STATUS["CANCELED"])
258+
self.assertEqual(job.status, JobStatus.CANCELED.value)
259259

260260
def test_hidden_jobs_is_not_shown(self):
261261
user = self.guest_login()

api_v1/tests/test_api.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from entry.models import Attribute, AttributeValue, Entry
1818
from entry.settings import CONFIG as ENTRY_CONFIG
1919
from group.models import Group
20-
from job.models import Job, JobOperation
20+
from job.models import Job, JobOperation, JobStatus
2121
from role.models import Role
2222
from trigger import tasks as trigger_tasks
2323
from trigger.models import TriggerCondition
@@ -1182,7 +1182,7 @@ def test_notify_event_of_creating_entry_when_create_entry(self):
11821182
# check notification event was invoked
11831183
entry = Entry.objects.get(id=resp.json()["result"])
11841184
job_notify = Job.objects.get(target=entry, operation=JobOperation.NOTIFY_CREATE_ENTRY.value)
1185-
self.assertEqual(job_notify.status, Job.STATUS["DONE"])
1185+
self.assertEqual(job_notify.status, JobStatus.DONE.value)
11861186

11871187
@mock.patch("entry.tasks.notify_entry_update", mock.Mock(return_value=mock.Mock()))
11881188
@mock.patch(
@@ -1234,7 +1234,7 @@ def test_notify_event_of_updating_entry_with_specifying_id(self):
12341234

12351235
# check creating NOTIFY_UPDATE_ENTRY is created because of changing Entry name
12361236
job_notify = Job.objects.get(target=entry, operation=JobOperation.NOTIFY_UPDATE_ENTRY.value)
1237-
self.assertEqual(job_notify.status, Job.STATUS["DONE"])
1237+
self.assertEqual(job_notify.status, JobStatus.DONE.value)
12381238

12391239
@mock.patch("entry.tasks.delete_entry.delay", mock.Mock(side_effect=tasks.delete_entry))
12401240
@mock.patch("entry.tasks.notify_entry_delete", mock.Mock(return_value=mock.Mock()))
@@ -1260,7 +1260,7 @@ def test_notify_event_of_deleting_entry(self):
12601260
self.assertEqual(resp.status_code, 200)
12611261

12621262
job_notify = Job.objects.get(target=entry, operation=JobOperation.NOTIFY_DELETE_ENTRY.value)
1263-
self.assertEqual(job_notify.status, Job.STATUS["DONE"])
1263+
self.assertEqual(job_notify.status, JobStatus.DONE.value)
12641264

12651265
def test_update_entry_that_has_deleted_attribute(self):
12661266
"""
@@ -1342,7 +1342,7 @@ def test_create_entry_when_trigger_is_set(self):
13421342
# check trigger action was worked properly
13431343
job_query = Job.objects.filter(operation=JobOperation.MAY_INVOKE_TRIGGER.value)
13441344
self.assertEqual(job_query.count(), 1)
1345-
self.assertEqual(job_query.first().status, Job.STATUS["DONE"])
1345+
self.assertEqual(job_query.first().status, JobStatus.DONE.value)
13461346

13471347
# check created Entry has expected value that is set by TriggerAction
13481348
entry = Entry.objects.get(id=resp.json()["result"])
@@ -1392,7 +1392,7 @@ def test_update_entry_when_trigger_is_set(self):
13921392
# check trigger action was worked properly
13931393
job_query = Job.objects.filter(operation=JobOperation.MAY_INVOKE_TRIGGER.value)
13941394
self.assertEqual(job_query.count(), 1)
1395-
self.assertEqual(job_query.first().status, Job.STATUS["DONE"])
1395+
self.assertEqual(job_query.first().status, JobStatus.DONE.value)
13961396

13971397
# check created Entry has expected value that is set by TriggerAction
13981398
self.assertEqual(entry.get_attrv("val").value, "hoge")

dashboard/tasks.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from airone.celery import app
1111
from airone.lib.types import AttrTypeValue
1212
from entry.models import Entry
13-
from job.models import Job
13+
from job.models import Job, JobStatus
1414

1515

1616
def _csv_export(job: Job, values, recv_data: dict, has_referral: bool) -> Optional[io.StringIO]:
@@ -170,7 +170,7 @@ def export_search_result(self, job_id):
170170
return
171171

172172
# set flag to indicate that this job starts processing
173-
job.update(Job.STATUS["PROCESSING"])
173+
job.update(JobStatus.PROCESSING.value)
174174

175175
user = job.user
176176
recv_data = json.loads(job.params)
@@ -202,4 +202,4 @@ def export_search_result(self, job_id):
202202

203203
# update job status and save it except for the case that target job is canceled.
204204
if not job.is_canceled():
205-
job.update(Job.STATUS["DONE"])
205+
job.update(JobStatus.DONE.value)

dashboard/tests/test_view.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from entry import tasks as entry_tasks
2525
from entry.models import Attribute, AttributeValue, Entry
2626
from group.models import Group
27-
from job.models import Job, JobOperation
27+
from job.models import Job, JobOperation, JobStatus
2828
from role.models import Role
2929
from user.models import User
3030

@@ -273,7 +273,7 @@ def test_show_advanced_search_results(self):
273273
# check export task is executed
274274
job = Job.objects.last()
275275
self.assertEqual(job.operation, JobOperation.EXPORT_SEARCH_RESULT.value)
276-
self.assertEqual(job.status, Job.STATUS["DONE"])
276+
self.assertEqual(job.status, JobStatus.DONE.value)
277277
self.assertEqual(json.loads(job.params), export_params)
278278

279279
# check result is set at cache
@@ -1450,7 +1450,7 @@ def test_duplicate_export(self):
14501450
self.assertEqual(resp.status_code, 200)
14511451

14521452
# When the job is finished, the processing is passed.
1453-
job.status = Job.STATUS["DONE"]
1453+
job.status = JobStatus.DONE.value
14541454
job.save(update_fields=["status"])
14551455
resp = self.client.post(
14561456
reverse("dashboard:export_search_result"),

dashboard/views.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from entry.admin import AttrResource, AttrValueResource, EntryResource
1515
from entry.models import AttributeValue, Entry
1616
from entry.settings import CONFIG as CONFIG_ENTRY
17-
from job.models import Job
17+
from job.models import Job, JobStatus
1818

1919
from .settings import CONFIG
2020

@@ -305,7 +305,7 @@ def advanced_search_result(request):
305305
)
306306
def export_search_result(request, recv_data):
307307
# check whether same job is sent
308-
job_status_not_finished = [Job.STATUS["PREPARING"], Job.STATUS["PROCESSING"]]
308+
job_status_not_finished = [JobStatus.PREPARING.value, JobStatus.PROCESSING.value]
309309
if (
310310
Job.get_job_with_params(request.user, recv_data)
311311
.filter(status__in=job_status_not_finished)

0 commit comments

Comments
 (0)