Mercurial > libervia-backend
view tests/unit/frontends/test_webrtc.py @ 4219:1b5cf2ee1d86
plugin XEP-0384, XEP-0391: download missing devices list:
when a peer jid was not in our roster, devices list was not retrieved, resulting in failed
en/decryption. This patch does check it and download missing devices list in necessary.
There is no subscription managed yet, so the list won't be updated in case of new devices,
this should be addressed at some point.
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 05 Mar 2024 17:31:36 +0100 |
parents | 13dd5660c28f |
children | dfccc90cacc6 |
line wrap: on
line source
#!/usr/bin/env python3 # Libervia: an XMPP client # Copyright (C) 2009-2023 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from unittest.mock import AsyncMock, MagicMock from gi.repository import Gst import pytest from libervia.backend.core import exceptions from libervia.backend.tools.common import data_format from libervia.frontends.tools import webrtc as webrtc_mod @pytest.fixture def host(monkeypatch): host = MagicMock() host.bridge = AsyncMock() host.app.expand = lambda s: s return host @pytest.fixture(scope="function") def webrtc(host): """Fixture for WebRTC instantiation.""" profile = "test_profile" instance = webrtc_mod.WebRTC(host.bridge, profile) instance._set_media_types = MagicMock() instance.start_pipeline = MagicMock() instance.link_element_or_pad = MagicMock() instance.webrtcbin = MagicMock() instance.webrtcbin.emit = MagicMock() instance.GstSdp_SDPMessage_new_from_text = MagicMock() instance.GstWebRTC_WebRTCSessionDescription_new = MagicMock() instance.Gst_Promise_new_with_change_func = MagicMock() return instance class TestWebRtc: def test_get_payload_types(self, webrtc): """The method can identify the correct payload types for video and audio.""" fake_sdpmsg = MagicMock() fake_media = MagicMock() fake_caps = MagicMock() fake_structure = MagicMock() # This side effect will return 'fake_video_encoding' first, then # 'fake_audio_encoding'. fake_structure.__getitem__.side_effect = [ "fake_video_encoding", "fake_audio_encoding", ] fake_caps.get_structure.return_value = fake_structure fake_media.get_format.side_effect = ["webrtc-datachannel", "10", "20"] fake_media.get_caps_from_media.return_value = fake_caps fake_sdpmsg.get_media.return_value = fake_media fake_sdpmsg.medias_len.return_value = 1 fake_media.formats_len.return_value = 3 result = webrtc.get_payload_types( fake_sdpmsg, "fake_video_encoding", "fake_audio_encoding" ) expected_result = {"fake_video_encoding": 10, "fake_audio_encoding": 20} assert result == expected_result def test_on_accepted_call(self, webrtc): """The method correctly sets the remote SDP upon acceptance of an outgoing call.""" sdp_str = "mock_sdp_string" profile_str = "test_profile" webrtc.on_accepted_call(sdp_str, profile_str) # remote description must be set assert webrtc.webrtcbin.emit.call_count == 1 assert webrtc.webrtcbin.emit.call_args[0][0] == "set-remote-description" @pytest.mark.asyncio async def test_answer_call(self, webrtc, monkeypatch): """The method correctly answers an incoming call.""" mock_setup_call = AsyncMock() def mock_get_payload_types(sdpmsg, video_encoding, audio_encoding): return {"VP8": 96, "OPUS": 97} monkeypatch.setattr(webrtc, "setup_call", mock_setup_call) monkeypatch.setattr(webrtc, "get_payload_types", mock_get_payload_types) sdp_str = "mock_sdp_string" profile_str = "mock_profile" await webrtc.answer_call(sdp_str, profile_str) mock_setup_call.assert_called_once_with("responder", audio_pt=97, video_pt=96) # remote description must be set assert webrtc.webrtcbin.emit.call_count == 1 assert webrtc.webrtcbin.emit.call_args[0][0] == "set-remote-description" def test_on_remote_decodebin_stream_video(self, webrtc, monkeypatch): """The method correctly handles video streams from the remote decodebin.""" mock_pipeline = MagicMock() monkeypatch.setattr(webrtc, "pipeline", mock_pipeline) mock_pad = MagicMock() mock_caps = MagicMock() mock_structure = MagicMock() mock_pad.has_current_caps.return_value = True mock_pad.get_current_caps.return_value = mock_caps mock_caps.__len__.return_value = 1 mock_caps.__getitem__.return_value = mock_structure mock_structure.get_name.return_value = "video/x-h264" # We use non-standard resolution as example to trigger the workaround mock_structure.get_int.side_effect = lambda x: MagicMock( value=990 if x == "width" else 557 ) webrtc.on_remote_decodebin_stream(None, mock_pad) assert webrtc._remote_video_pad == mock_pad mock_pipeline.add.assert_called() mock_pad.link.assert_called() def test_on_remote_decodebin_stream_audio(self, webrtc, monkeypatch): """The method correctly handles audio streams from the remote decodebin.""" mock_pipeline = MagicMock() monkeypatch.setattr(webrtc, "pipeline", mock_pipeline) mock_pad = MagicMock() mock_caps = MagicMock() mock_structure = MagicMock() mock_pad.has_current_caps.return_value = True mock_pad.get_current_caps.return_value = mock_caps mock_caps.__len__.return_value = 1 mock_caps.__getitem__.return_value = mock_structure mock_structure.get_name.return_value = "audio/x-raw" webrtc.on_remote_decodebin_stream(None, mock_pad) mock_pipeline.add.assert_called() mock_pad.link.assert_called() @pytest.mark.asyncio async def test_setup_call_correct_role(self, host, webrtc, monkeypatch): """Roles are set in setup_call.""" monkeypatch.setattr(Gst, "parse_launch", MagicMock()) monkeypatch.setattr(data_format, "deserialise", MagicMock(return_value=[])) await webrtc.setup_call("initiator") assert webrtc.role == "initiator" await webrtc.setup_call("responder") assert webrtc.role == "responder" with pytest.raises(AssertionError): await webrtc.setup_call("invalid_role") @pytest.mark.asyncio async def test_setup_call_test_mode(self, host, webrtc, monkeypatch): """Test mode use fake video and audio in setup_call.""" monkeypatch.setattr(data_format, "deserialise", MagicMock(return_value=[])) monkeypatch.setattr(webrtc, "sources", webrtc_mod.SINKS_TEST) await webrtc.setup_call("initiator") assert "videotestsrc" in webrtc.gst_pipe_desc assert "audiotestsrc" in webrtc.gst_pipe_desc @pytest.mark.asyncio async def test_setup_call_normal_mode(self, host, webrtc, monkeypatch): """Normal mode use real video and audio in setup_call.""" monkeypatch.setattr(data_format, "deserialise", MagicMock(return_value=[])) monkeypatch.setattr(webrtc, "sources", webrtc_mod.SOURCES_AUTO) await webrtc.setup_call("initiator") assert "v4l2src" in webrtc.gst_pipe_desc assert "pulsesrc" in webrtc.gst_pipe_desc @pytest.mark.asyncio async def test_setup_call_with_stun_and_turn(self, host, webrtc, monkeypatch): """STUN and TURN server configurations are done in setup_call.""" mock_pipeline = MagicMock() mock_parse_launch = MagicMock() mock_parse_launch.return_value = mock_pipeline monkeypatch.setattr(Gst, "parse_launch", mock_parse_launch) mock_pipeline.get_by_name.return_value = webrtc.webrtcbin mock_external_disco = [ {"type": "stun", "transport": "udp", "host": "stun.host", "port": "3478"}, { "type": "turn", "transport": "udp", "host": "turn.host", "port": "3478", "username": "user", "password": "pass", }, ] monkeypatch.setattr( data_format, "deserialise", MagicMock(return_value=mock_external_disco) ) mock_emit = AsyncMock() monkeypatch.setattr(webrtc.webrtcbin, "emit", mock_emit) mock_set_property = AsyncMock() monkeypatch.setattr(webrtc.webrtcbin, "set_property", mock_set_property) await webrtc.setup_call("initiator") host.bridge.external_disco_get.assert_called_once_with("", webrtc.profile) mock_set_property.assert_any_call("stun-server", "stun://stun.host:3478") mock_emit.assert_called_once_with( "add-turn-server", "turn://user:pass@turn.host:3478" ) @pytest.mark.asyncio async def test_setup_call_gstreamer_pipeline_failure(self, webrtc, monkeypatch): """Test setup_call method handling Gstreamer pipeline failure.""" monkeypatch.setattr(Gst, "parse_launch", lambda _: None) with pytest.raises(exceptions.InternalError): await webrtc.setup_call("initiator")