Skip to content

Commit 7f837a9

Browse files
committed
Update tests
1 parent d21d290 commit 7f837a9

File tree

6 files changed

+456
-247
lines changed

6 files changed

+456
-247
lines changed

packages/examples/cvat/exchange-oracle/tests/api/test_cvat_webhook_api.py

Lines changed: 81 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
1-
from datetime import datetime, timedelta, timezone
1+
from datetime import datetime, timedelta
22
from unittest.mock import patch
33

4+
import pytest
45
from fastapi.testclient import TestClient
56

67
from src.core.types import AssignmentStatuses, JobStatuses
8+
from src.utils.time import utcnow
79

10+
from tests.utils.constants import WALLET_ADDRESS1, WALLET_ADDRESS2
811
from tests.utils.setup_cvat import (
9-
add_asignment_to_db,
12+
add_assignment_to_db,
1013
add_cvat_job_to_db,
1114
add_cvat_project_to_db,
1215
add_cvat_task_to_db,
1316
generate_cvat_signature,
1417
get_cvat_job_from_db,
1518
)
1619

17-
api_url = "http://localhost:8080/api/"
20+
API_URL = "http://localhost:8080/api/"
1821

22+
PING_EVENT_DATA = {
23+
"event": "ping",
24+
}
1925

20-
def test_ping_incoming_webhook(client: TestClient) -> None:
21-
data = {
22-
"event": "ping",
23-
}
24-
signature = generate_cvat_signature(data)
2526

27+
def test_ping_incoming_webhook(client: TestClient) -> None:
2628
# Should respond with 200 status to a "ping" event
2729
response = client.post(
2830
"/cvat-webhook",
29-
headers={"X-Signature-256": signature},
30-
json=data,
31+
headers={"X-Signature-256": generate_cvat_signature(PING_EVENT_DATA)},
32+
json=PING_EVENT_DATA,
3133
)
3234

3335
assert response.status_code == 200
@@ -36,13 +38,13 @@ def test_ping_incoming_webhook(client: TestClient) -> None:
3638
def test_incoming_webhook_200(client: TestClient) -> None:
3739
# Create some entities in test DB
3840
add_cvat_project_to_db(cvat_id=1)
39-
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1, status="annotation")
41+
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1)
4042

4143
# Payload for "create:job" event
4244
data = {
4345
"event": "create:job",
4446
"job": {
45-
"url": api_url + "jobs/1",
47+
"url": API_URL + "jobs/1",
4648
"id": 1,
4749
"task_id": 1,
4850
"project_id": 1,
@@ -71,107 +73,130 @@ def test_incoming_webhook_200(client: TestClient) -> None:
7173
assert job.cvat_project_id == 1
7274

7375

74-
def test_incoming_webhook_200_update_expired_assignmets(client: TestClient) -> None:
76+
@pytest.mark.parametrize("is_last_assignment", [True, False])
77+
def test_incoming_webhook_can_update_expired_assignment(
78+
client: TestClient, is_last_assignment: bool
79+
):
80+
# Check if an "update:job" event can update an expired assignment,
81+
# if the assignment is the last one for the job. Updates to other assignments should be ignored.
82+
7583
add_cvat_project_to_db(cvat_id=1)
76-
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1, status="annotation")
77-
add_cvat_job_to_db(cvat_id=1, cvat_task_id=1, cvat_project_id=1, status="new")
78-
(job, _) = get_cvat_job_from_db(1)
79-
# Check if "update:job" event works with expired assignments
80-
wallet_address = "0x86e83d346041E8806e352681f3F14549C0d2BC68"
81-
add_asignment_to_db(wallet_address, 1, job.cvat_id, datetime.now(tz=timezone.utc))
84+
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1)
85+
job = add_cvat_job_to_db(
86+
cvat_id=1, cvat_task_id=1, cvat_project_id=1, status=JobStatuses.in_progress
87+
)
88+
89+
user_cvat_id = 1
90+
add_assignment_to_db(WALLET_ADDRESS1, user_cvat_id, job.cvat_id, expires_at=utcnow())
91+
92+
if not is_last_assignment:
93+
user_cvat_id += 1
94+
add_assignment_to_db(WALLET_ADDRESS2, user_cvat_id, job.cvat_id, expires_at=utcnow())
8295

8396
data = {
8497
"event": "update:job",
8598
"job": {
86-
"url": api_url + "jobs/1",
99+
"url": API_URL + "jobs/1",
87100
"id": 1,
88101
"task_id": 1,
89102
"project_id": 1,
90103
"state": "completed",
91104
"start_frame": 0,
92105
"stop_frame": 1,
93106
"assignee": {
94-
"url": api_url + "users/1",
95-
"id": 1,
107+
"url": API_URL + f"users/{user_cvat_id}",
108+
"id": user_cvat_id,
96109
},
97-
"updated_date": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z",
110+
"updated_date": (utcnow() + timedelta(hours=1)).strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z",
98111
},
99112
"before_update": {"state": "new", "assignee": None},
100113
"webhook_id": 1,
101114
}
102115

103-
signature = generate_cvat_signature(data)
104-
105-
with patch("src.handlers.cvat_events.cvat_api"):
116+
with patch("src.handlers.cvat_events.cvat_api.update_job_assignee") as mock_update_job_assignee:
106117
response = client.post(
107118
"/cvat-webhook",
108-
headers={"X-Signature-256": signature},
119+
headers={"X-Signature-256": generate_cvat_signature(data)},
109120
json=data,
110121
)
111122

112123
assert response.status_code == 200
113124

114-
(job, asignees) = get_cvat_job_from_db(1)
115-
assert job.status == JobStatuses.new.value
116-
assert asignees[0].status == AssignmentStatuses.expired.value
125+
(job, assignments) = get_cvat_job_from_db(1)
126+
assert job.status == JobStatuses.new
127+
assert assignments[-1].status == AssignmentStatuses.expired
128+
mock_update_job_assignee.assert_called_once_with(job.cvat_id, assignee_id=None)
129+
130+
if not is_last_assignment:
131+
for assignment in assignments[:-1]:
132+
assert assignment.status == AssignmentStatuses.created
117133

118134

119-
def test_incoming_webhook_200_update(client: TestClient) -> None:
135+
@pytest.mark.parametrize("assignment_status", AssignmentStatuses)
136+
def test_incoming_webhook_can_update_active_assignment(
137+
client: TestClient, assignment_status: AssignmentStatuses
138+
):
120139
add_cvat_project_to_db(cvat_id=1)
121-
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1, status="annotation")
122-
add_cvat_job_to_db(cvat_id=1, cvat_task_id=1, cvat_project_id=1, status="new")
123-
(job, _) = get_cvat_job_from_db(1)
124-
# Check if "update:job" event works correctly
125-
wallet_address = "0x86e83d346041E8806e352681f3F14549C0d2BC69"
126-
add_asignment_to_db(wallet_address, 2, job.cvat_id, datetime.now() + timedelta(hours=1))
140+
add_cvat_task_to_db(cvat_id=1, cvat_project_id=1)
141+
job = add_cvat_job_to_db(
142+
cvat_id=1, cvat_task_id=1, cvat_project_id=1, status=JobStatuses.in_progress
143+
)
144+
add_assignment_to_db(
145+
WALLET_ADDRESS1,
146+
1,
147+
job.cvat_id,
148+
status=assignment_status,
149+
expires_at=datetime.now()
150+
if assignment_status == AssignmentStatuses.expired
151+
else datetime.now() + timedelta(hours=1),
152+
)
127153

128154
data = {
129155
"event": "update:job",
130156
"job": {
131-
"url": api_url + "jobs/1",
157+
"url": API_URL + "jobs/1",
132158
"id": 1,
133159
"task_id": 1,
134160
"project_id": 1,
135161
"state": "completed",
136162
"start_frame": 0,
137163
"stop_frame": 1,
138164
"assignee": {
139-
"url": api_url + "users/1",
140-
"id": 2,
165+
"url": API_URL + "users/1",
166+
"id": 1,
141167
},
142-
"updated_date": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z",
168+
"updated_date": utcnow().strftime("%Y-%m-%dT%H:%M:%S.%f") + "Z",
143169
},
144-
"before_update": {"state": "new", "assignee": None},
170+
"before_update": {"state": "in_progress", "assignee": None},
145171
"webhook_id": 1,
146172
}
147173

148-
signature = generate_cvat_signature(data)
149-
150-
with patch("src.handlers.cvat_events.cvat_api"):
174+
with patch("src.handlers.cvat_events.cvat_api.update_job_assignee") as mock_update_job_assignee:
151175
response = client.post(
152176
"/cvat-webhook",
153-
headers={"X-Signature-256": signature},
177+
headers={"X-Signature-256": generate_cvat_signature(data)},
154178
json=data,
155179
)
156180

157181
assert response.status_code == 200
158182

159-
(job, asignees) = get_cvat_job_from_db(1)
160-
assert job.status == JobStatuses.completed.value
161-
assert asignees[0].status == AssignmentStatuses.completed.value
162-
163-
164-
data = {
165-
"event": "ping",
166-
}
183+
(job, assignments) = get_cvat_job_from_db(1)
184+
if assignment_status == AssignmentStatuses.created:
185+
assert job.status == JobStatuses.completed
186+
assert assignments[0].status == AssignmentStatuses.completed
187+
mock_update_job_assignee.assert_called_once_with(job.cvat_id, assignee_id=None)
188+
else:
189+
assert job.status == JobStatuses.in_progress
190+
assert assignments[0].status == assignment_status
191+
mock_update_job_assignee.assert_not_called()
167192

168193

169194
def test_incoming_webhook_401_bad_signature(client: TestClient) -> None:
170195
# Send a request with bad signature
171196
response = client.post(
172197
"/cvat-webhook",
173198
headers={"X-Signature-256": "dummy_signature"},
174-
json=data,
199+
json=PING_EVENT_DATA,
175200
)
176201
assert response.status_code == 401
177202
assert response.json() == {"message": "Unauthorized"}
@@ -180,7 +205,7 @@ def test_incoming_webhook_401_bad_signature(client: TestClient) -> None:
180205
def test_incoming_webhook_401_without_signature(client: TestClient) -> None:
181206
response = client.post(
182207
"/cvat-webhook",
183-
json=data,
208+
json=PING_EVENT_DATA,
184209
)
185210

186211
# Send a request without a signature

0 commit comments

Comments
 (0)