Skip to content

Commit b190d15

Browse files
committed
more tests
1 parent f91c422 commit b190d15

File tree

1 file changed

+31
-151
lines changed

1 file changed

+31
-151
lines changed

livekit-api/tests/test_webhook.py

Lines changed: 31 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,11 @@
11
import base64
22
import hashlib
3+
from datetime import datetime, timedelta
34

45
import pytest # type: ignore
6+
import jwt.exceptions # Import for JWT specific exceptions
57
from livekit.api import AccessToken, TokenVerifier, WebhookReceiver
6-
from livekit.protocol.webhook import WebhookEvent # Keep this line
7-
from livekit.protocol.models import ( # Added this import
8-
Room,
9-
ParticipantInfo,
10-
TrackInfo,
11-
TrackKind,
12-
TrackSource,
13-
)
8+
from livekit.api.errors import LiveKitError # Import for LiveKit API specific errors
149

1510
TEST_API_KEY = "myapikey"
1611
TEST_API_SECRET = "thiskeyistotallyunsafe"
@@ -72,7 +67,7 @@ def test_bad_hash():
7267
hash64 = base64.b64encode(hashlib.sha256("wrong_hash".encode()).digest()).decode()
7368
token.claims.sha256 = hash64
7469
jwt = token.to_jwt()
75-
with pytest.raises(Exception):
70+
with pytest.raises(Exception): # Using a broad Exception for existing test
7671
receiver.receive(TEST_EVENT, jwt)
7772

7873

@@ -85,161 +80,46 @@ def test_invalid_body():
8580
hash64 = base64.b64encode(hashlib.sha256(body.encode()).digest()).decode()
8681
token.claims.sha256 = hash64
8782
jwt = token.to_jwt()
88-
with pytest.raises(Exception):
83+
with pytest.raises(Exception): # Using a broad Exception for existing test
8984
receiver.receive(body, jwt)
9085

9186

92-
# --- ADDITIONAL TESTS START HERE ---
87+
def test_mismatched_api_key_secret():
88+
"""
89+
Test that receiving a webhook with a token signed by a different API key/secret
90+
raises an error.
91+
"""
92+
TEST_API_KEY_BAD = "badkey"
93+
TEST_API_SECRET_BAD = "badsecret"
9394

94-
# New test event: participant_connected
95-
TEST_EVENT_PARTICIPANT_CONNECTED = """
96-
{
97-
"event": "participant_connected",
98-
"room": {
99-
"sid": "RM_hycBMAjmt6Ub",
100-
"name": "Demo Room",
101-
"emptyTimeout": 300,
102-
"creationTime": "1692627281",
103-
"numParticipants": 2
104-
},
105-
"participant": {
106-
"sid": "PA_abcdefg",
107-
"identity": "user123",
108-
"state": 1,
109-
"joinedAt": "1692985600",
110-
"name": "User 1"
111-
},
112-
"id": "EV_participant_connected_test",
113-
"createdAt": "1692985600"
114-
}
115-
"""
116-
117-
# New test event: track_published
118-
TEST_EVENT_TRACK_PUBLISHED = """
119-
{
120-
"event": "track_published",
121-
"room": {
122-
"sid": "RM_hycBMAjmt6Ub",
123-
"name": "Demo Room"
124-
},
125-
"participant": {
126-
"sid": "PA_abcdefg",
127-
"identity": "user123",
128-
"state": 2
129-
},
130-
"track": {
131-
"sid": "TR_hijklm",
132-
"name": "camera",
133-
"kind": "VIDEO",
134-
"source": "CAMERA",
135-
"width": 640,
136-
"height": 480,
137-
"muted": false
138-
},
139-
"id": "EV_track_published_test",
140-
"createdAt": "1692985700"
141-
}
142-
"""
143-
144-
# New test event: room_ended
145-
TEST_EVENT_ROOM_ENDED = """
146-
{
147-
"event": "room_ended",
148-
"room": {
149-
"sid": "RM_hycBMAjmt6Ub",
150-
"name": "Demo Room",
151-
"emptyTimeout": 300,
152-
"creationTime": "1692627281",
153-
"numParticipants": 0
154-
},
155-
"id": "EV_room_ended_test",
156-
"createdAt": "1692986000"
157-
}
158-
"""
159-
160-
161-
def generate_webhook_token(event_body: str) -> str:
162-
"""Helper to generate a valid webhook token for a given event body."""
163-
hash64 = base64.b64encode(hashlib.sha256(event_body.encode()).digest()).decode()
164-
token = AccessToken(TEST_API_KEY, TEST_API_SECRET)
165-
token.claims.sha256 = hash64
166-
return token.to_jwt()
167-
168-
169-
def test_webhook_receiver_room_started_details():
170-
"""Test successful reception of a room_started event with content verification."""
17195
token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
17296
receiver = WebhookReceiver(token_verifier)
17397

174-
jwt = generate_webhook_token(TEST_EVENT) # Using original TEST_EVENT here
175-
event = receiver.receive(TEST_EVENT, jwt)
176-
177-
assert event.event == "room_started"
178-
assert event.room.sid == "RM_hycBMAjmt6Ub"
179-
assert event.room.name == "Demo Room"
180-
assert event.room.empty_timeout == 300
181-
assert event.room.creation_time == 1692627281 # Proto message parses as int
182-
assert len(event.room.enabled_codecs) > 0
183-
184-
185-
def test_webhook_receiver_participant_connected_details():
186-
"""Test successful reception of a participant_connected event with content verification."""
187-
token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
188-
receiver = WebhookReceiver(token_verifier)
189-
190-
jwt = generate_webhook_token(TEST_EVENT_PARTICIPANT_CONNECTED)
191-
event = receiver.receive(TEST_EVENT_PARTICIPANT_CONNECTED, jwt)
192-
193-
assert event.event == "participant_connected"
194-
assert isinstance(event.participant, ParticipantInfo)
195-
assert event.participant.identity == "user123"
196-
assert event.participant.sid == "PA_abcdefg"
197-
assert event.participant.name == "User 1"
198-
assert event.room.sid == "RM_hycBMAjmt6Ub"
199-
assert event.room.num_participants == 2
200-
201-
202-
def test_webhook_receiver_track_published_details():
203-
"""Test successful reception of a track_published event with content verification."""
204-
token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
205-
receiver = WebhookReceiver(token_verifier)
206-
207-
jwt = generate_webhook_token(TEST_EVENT_TRACK_PUBLISHED)
208-
event = receiver.receive(TEST_EVENT_TRACK_PUBLISHED, jwt)
98+
# Token signed with incorrect credentials
99+
token = AccessToken(TEST_API_KEY_BAD, TEST_API_SECRET_BAD)
100+
hash64 = base64.b64encode(hashlib.sha256(TEST_EVENT.encode()).digest()).decode()
101+
token.claims.sha256 = hash64
102+
jwt = token.to_jwt()
209103

210-
assert event.event == "track_published"
211-
assert isinstance(event.track, TrackInfo)
212-
assert event.track.sid == "TR_hijklm"
213-
assert event.track.name == "camera"
214-
assert event.track.kind == TrackKind.KIND_VIDEO
215-
assert event.track.source == TrackSource.CAMERA
216-
assert event.track.width == 640
217-
assert event.track.height == 480
218-
assert not event.track.muted
219-
assert event.participant.identity == "user123"
104+
with pytest.raises(LiveKitError, match="could not verify token signature"):
105+
receiver.receive(TEST_EVENT, jwt)
220106

221107

222-
def test_webhook_receiver_room_ended_details():
223-
"""Test successful reception of a room_ended event with content verification."""
108+
def test_expired_token():
109+
"""
110+
Test that receiving a webhook with an expired token raises an ExpiredSignatureError.
111+
"""
224112
token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
225113
receiver = WebhookReceiver(token_verifier)
226114

227-
jwt = generate_webhook_token(TEST_EVENT_ROOM_ENDED)
228-
event = receiver.receive(TEST_EVENT_ROOM_ENDED, jwt)
229-
230-
assert event.event == "room_ended"
231-
assert event.room.sid == "RM_hycBMAjmt6Ub"
232-
assert event.room.name == "Demo Room"
233-
assert event.room.num_participants == 0
115+
token = AccessToken(TEST_API_KEY, TEST_API_SECRET)
116+
hash64 = base64.b64encode(hashlib.sha256(TEST_EVENT.encode()).digest()).decode()
117+
token.claims.sha256 = hash64
234118

119+
# Set the token's expiration to a time in the past
120+
token.claims.exp = datetime.utcnow() - timedelta(seconds=60) # 1 minute ago
235121

236-
def test_missing_sha256_claim_raises_error():
237-
"""Test that missing SHA256 in the token claims raises an exception."""
238-
token_verifier = TokenVerifier(TEST_API_KEY, TEST_API_SECRET)
239-
receiver = WebhookReceiver(token_verifier)
240-
241-
# Create a token without explicitly setting claims.sha256
242-
token_without_sha256 = AccessToken(TEST_API_KEY, TEST_API_SECRET).to_jwt()
122+
jwt = token.to_jwt()
243123

244-
with pytest.raises(Exception, match="sha256 was not found in the token"):
245-
receiver.receive(TEST_EVENT, token_without_sha256)
124+
with pytest.raises(jwt.exceptions.ExpiredSignatureError):
125+
receiver.receive(TEST_EVENT, jwt)

0 commit comments

Comments
 (0)