33
44import pytest # type: ignore
55from 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+ )
614
715TEST_API_KEY = "myapikey"
816TEST_API_SECRET = "thiskeyistotallyunsafe"
@@ -79,3 +87,159 @@ def test_invalid_body():
7987 jwt = token .to_jwt ()
8088 with pytest .raises (Exception ):
8189 receiver .receive (body , jwt )
90+
91+
92+ # --- ADDITIONAL TESTS START HERE ---
93+
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."""
171+ token_verifier = TokenVerifier (TEST_API_KEY , TEST_API_SECRET )
172+ receiver = WebhookReceiver (token_verifier )
173+
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 )
209+
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"
220+
221+
222+ def test_webhook_receiver_room_ended_details ():
223+ """Test successful reception of a room_ended event with content verification."""
224+ token_verifier = TokenVerifier (TEST_API_KEY , TEST_API_SECRET )
225+ receiver = WebhookReceiver (token_verifier )
226+
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
234+
235+
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 ()
243+
244+ with pytest .raises (Exception , match = "sha256 was not found in the token" ):
245+ receiver .receive (TEST_EVENT , token_without_sha256 )
0 commit comments