chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:21:23 +08:00
commit b957a53def
5423 changed files with 863745 additions and 0 deletions
@@ -0,0 +1,59 @@
# Copyright (c) Microsoft. All rights reserved.
from collections.abc import AsyncIterable
from unittest.mock import AsyncMock
from semantic_kernel.agents import Agent
from semantic_kernel.agents.channels.agent_channel import AgentChannel
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
class MockAgentChannel(AgentChannel):
async def receive(self, history: list[ChatMessageContent]) -> None:
pass
async def invoke(self, agent: "Agent") -> AsyncIterable[ChatMessageContent]:
yield ChatMessageContent(role=AuthorRole.SYSTEM, content="test message")
async def get_history(self) -> AsyncIterable[ChatMessageContent]:
yield ChatMessageContent(role=AuthorRole.SYSTEM, content="test history message")
async def test_receive():
mock_channel = AsyncMock(spec=MockAgentChannel)
history = [
ChatMessageContent(role=AuthorRole.SYSTEM, content="test message 1"),
ChatMessageContent(role=AuthorRole.USER, content="test message 2"),
]
await mock_channel.receive(history)
mock_channel.receive.assert_called_once_with(history)
async def test_invoke():
mock_channel = AsyncMock(spec=MockAgentChannel)
agent = AsyncMock()
async def async_generator():
yield ChatMessageContent(role=AuthorRole.SYSTEM, content="test message")
mock_channel.invoke.return_value = async_generator()
async for message in mock_channel.invoke(agent):
assert message.content == "test message"
mock_channel.invoke.assert_called_once_with(agent)
async def test_get_history():
mock_channel = AsyncMock(spec=MockAgentChannel)
async def async_generator():
yield ChatMessageContent(role=AuthorRole.SYSTEM, content="test history message")
mock_channel.get_history.return_value = async_generator()
async for message in mock_channel.get_history():
assert message.content == "test history message"
mock_channel.get_history.assert_called_once()
@@ -0,0 +1,245 @@
# Copyright (c) Microsoft. All rights reserved.
from unittest import mock
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from semantic_kernel.agents.channels.agent_channel import AgentChannel
from semantic_kernel.agents.group_chat.agent_chat import AgentChat
from semantic_kernel.agents.group_chat.broadcast_queue import ChannelReference
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.exceptions.agent_exceptions import AgentChatException
@pytest.fixture
def agent_chat():
return AgentChat()
@pytest.fixture
def agent():
mock_agent = MagicMock()
mock_agent.name = "TestAgent"
return mock_agent
@pytest.fixture
def chat_message():
mock_chat_message = MagicMock(spec=ChatMessageContent)
mock_chat_message.role = "user"
return mock_chat_message
async def test_set_activity_or_throw_when_inactive(agent_chat):
agent_chat._is_active = False
agent_chat.set_activity_or_throw()
assert agent_chat.is_active
async def test_set_activity_or_throw_when_active(agent_chat):
agent_chat._is_active = True
with pytest.raises(Exception, match="Unable to proceed while another agent is active."):
agent_chat.set_activity_or_throw()
async def test_clear_activity_signal(agent_chat):
agent_chat._is_active = True
agent_chat.clear_activity_signal()
assert not agent_chat.is_active
async def test_get_messages_in_descending_order(agent_chat, chat_message):
agent_chat.history.messages = [chat_message, chat_message, chat_message]
messages = []
async for message in agent_chat.get_messages_in_descending_order():
messages.append(message)
assert len(messages) == 3
async def test_get_chat_messages_without_agent(agent_chat, chat_message):
agent_chat.history.messages = [chat_message]
with patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat.get_messages_in_descending_order",
return_value=AsyncMock(),
) as mock_get_messages:
async for _ in agent_chat.get_chat_messages():
pass
mock_get_messages.assert_called_once()
async def test_get_chat_messages_with_agent(agent_chat, agent, chat_message):
agent_chat.channel_map[agent] = "test_channel"
mock_channel = mock.MagicMock(spec=AgentChannel)
agent_chat.agent_channels["test_channel"] = mock_channel
with (
patch("semantic_kernel.agents.group_chat.agent_chat.AgentChat._get_agent_hash", return_value="test_channel"),
patch("semantic_kernel.agents.group_chat.agent_chat.AgentChat._synchronize_channel", return_value=mock_channel),
patch.object(mock_channel, "get_history", return_value=AsyncMock()),
):
async for _ in agent_chat.get_chat_messages(agent):
pass
async def test_add_chat_message(agent_chat, chat_message):
with patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat.add_chat_messages",
return_value=AsyncMock(),
) as mock_add_chat_messages:
await agent_chat.add_chat_message(chat_message)
mock_add_chat_messages.assert_called_once_with([chat_message])
async def test_add_chat_messages(agent_chat, chat_message):
with patch("semantic_kernel.agents.group_chat.broadcast_queue.BroadcastQueue.enqueue", return_value=AsyncMock()):
await agent_chat.add_chat_messages([chat_message])
assert chat_message in agent_chat.history.messages
async def test_invoke_agent(agent_chat, agent, chat_message):
mock_channel = mock.MagicMock(spec=AgentChannel)
async def mock_invoke(*args, **kwargs):
yield True, chat_message
mock_channel.invoke.side_effect = mock_invoke
with (
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._get_or_create_channel", return_value=mock_channel
),
patch(
"semantic_kernel.agents.group_chat.broadcast_queue.BroadcastQueue.enqueue",
return_value=AsyncMock(),
),
):
async for _ in agent_chat.invoke_agent(agent):
pass
mock_channel.invoke.assert_called_once_with(agent)
await agent_chat.reset()
async def test_invoke_streaming_agent(agent_chat, agent, chat_message):
mock_channel = mock.MagicMock(spec=AgentChannel)
async def mock_invoke(*args, **kwargs):
yield chat_message
mock_channel.invoke_stream.side_effect = mock_invoke
with (
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._get_or_create_channel", return_value=mock_channel
),
patch(
"semantic_kernel.agents.group_chat.broadcast_queue.BroadcastQueue.enqueue",
return_value=AsyncMock(),
),
):
async for _ in agent_chat.invoke_agent_stream(agent):
pass
mock_channel.invoke_stream.assert_called_once_with(agent, [])
await agent_chat.reset()
async def test_synchronize_channel_with_existing_channel(agent_chat):
mock_channel = MagicMock(spec=AgentChannel)
channel_key = "test_channel_key"
agent_chat.agent_channels[channel_key] = mock_channel
with patch(
"semantic_kernel.agents.group_chat.broadcast_queue.BroadcastQueue.ensure_synchronized", return_value=AsyncMock()
) as mock_ensure_synchronized:
result = await agent_chat._synchronize_channel(channel_key)
assert result == mock_channel
mock_ensure_synchronized.assert_called_once_with(ChannelReference(channel=mock_channel, hash=channel_key))
async def test_synchronize_channel_with_nonexistent_channel(agent_chat):
channel_key = "test_channel_key"
result = await agent_chat._synchronize_channel(channel_key)
assert result is None
def test_get_agent_hash_with_existing_hash(agent_chat, agent):
expected_hash = "existing_hash"
agent_chat.channel_map[agent] = expected_hash
result = agent_chat._get_agent_hash(agent)
assert result == expected_hash
def test_get_agent_hash_generates_new_hash(agent_chat, agent):
expected_hash = "new_hash"
agent.get_channel_keys = MagicMock(return_value=["key1", "key2"])
with patch(
"semantic_kernel.agents.group_chat.agent_chat.KeyEncoder.generate_hash", return_value=expected_hash
) as mock_generate_hash:
result = agent_chat._get_agent_hash(agent)
assert result == expected_hash
mock_generate_hash.assert_called_once_with(["key1", "key2"])
assert agent_chat.channel_map[agent] == expected_hash
async def test_add_chat_messages_throws_exception_for_system_role(agent_chat):
system_message = MagicMock(spec=ChatMessageContent)
system_message.role = AuthorRole.SYSTEM
with pytest.raises(AgentChatException, match="System messages cannot be added to the chat history."):
await agent_chat.add_chat_messages([system_message])
async def test_get_or_create_channel_creates_new_channel(agent_chat, agent):
agent_chat.history.messages = [MagicMock(spec=ChatMessageContent)]
channel_key = "test_channel_key"
mock_channel = AsyncMock(spec=AgentChannel)
with (
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._get_agent_hash", return_value=channel_key
) as mock_get_agent_hash,
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._synchronize_channel", return_value=None
) as mock_synchronize_channel,
):
agent.create_channel = AsyncMock(return_value=mock_channel)
with patch.object(mock_channel, "receive", return_value=AsyncMock()) as mock_receive:
result = await agent_chat._get_or_create_channel(agent)
assert result == mock_channel
mock_get_agent_hash.assert_called_once_with(agent)
mock_synchronize_channel.assert_called_once_with(channel_key)
agent.create_channel.assert_called_once()
mock_receive.assert_called_once_with(agent_chat.history.messages)
assert agent_chat.agent_channels[channel_key] == mock_channel
async def test_get_or_create_channel_reuses_existing_channel(agent_chat, agent):
channel_key = "test_channel_key"
mock_channel = MagicMock(spec=AgentChannel)
with (
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._get_agent_hash", return_value=channel_key
) as mock_get_agent_hash,
patch(
"semantic_kernel.agents.group_chat.agent_chat.AgentChat._synchronize_channel", return_value=mock_channel
) as mock_synchronize_channel,
):
result = await agent_chat._get_or_create_channel(agent)
assert result == mock_channel
mock_get_agent_hash.assert_called_once_with(agent)
mock_synchronize_channel.assert_called_once_with(channel_key)
agent.create_channel.assert_not_called()
@@ -0,0 +1,27 @@
# Copyright (c) Microsoft. All rights reserved.
import base64
from hashlib import sha256
import pytest
from semantic_kernel.agents.group_chat.agent_chat_utils import KeyEncoder
from semantic_kernel.exceptions.agent_exceptions import AgentExecutionException
def test_generate_hash_valid_keys():
keys = ["key1", "key2", "key3"]
expected_joined_keys = ":".join(keys).encode("utf-8")
expected_hash = sha256(expected_joined_keys).digest()
expected_base64 = base64.b64encode(expected_hash).decode("utf-8")
result = KeyEncoder.generate_hash(keys)
assert result == expected_base64
def test_generate_hash_empty_keys():
with pytest.raises(
AgentExecutionException, match="Channel Keys must not be empty. Unable to generate channel hash."
):
KeyEncoder.generate_hash([])
@@ -0,0 +1,341 @@
# Copyright (c) Microsoft. All rights reserved.
from unittest import mock
from unittest.mock import AsyncMock, MagicMock
import pytest
from semantic_kernel.agents.agent import Agent
from semantic_kernel.agents.group_chat.agent_chat import AgentChat
from semantic_kernel.agents.group_chat.agent_group_chat import AgentGroupChat
from semantic_kernel.agents.strategies.selection.selection_strategy import SelectionStrategy
from semantic_kernel.agents.strategies.selection.sequential_selection_strategy import SequentialSelectionStrategy
from semantic_kernel.agents.strategies.termination.default_termination_strategy import DefaultTerminationStrategy
from semantic_kernel.agents.strategies.termination.termination_strategy import TerminationStrategy
from semantic_kernel.contents.utils.author_role import AuthorRole
from semantic_kernel.exceptions.agent_exceptions import AgentChatException
@pytest.fixture
def agents():
"""Fixture that provides a list of mock agents."""
return [MagicMock(spec=Agent, id=f"agent-{i}") for i in range(3)]
@pytest.fixture
def termination_strategy():
"""Fixture that provides a mock termination strategy."""
return AsyncMock(spec=TerminationStrategy)
@pytest.fixture
def selection_strategy():
"""Fixture that provides a mock selection strategy."""
return AsyncMock(spec=SelectionStrategy)
# region Non-Streaming
def test_agent_group_chat_initialization(agents, termination_strategy, selection_strategy):
group_chat = AgentGroupChat(
agents=agents, termination_strategy=termination_strategy, selection_strategy=selection_strategy
)
assert group_chat.agents == agents
assert group_chat.agent_ids == {agent.id for agent in agents}
assert group_chat.termination_strategy == termination_strategy
assert group_chat.selection_strategy == selection_strategy
def test_agent_group_chat_initialization_defaults():
group_chat = AgentGroupChat()
assert group_chat.agents == []
assert group_chat.agent_ids == set()
assert isinstance(group_chat.termination_strategy, DefaultTerminationStrategy)
assert isinstance(group_chat.selection_strategy, SequentialSelectionStrategy)
def test_add_agent(agents):
group_chat = AgentGroupChat()
group_chat.add_agent(agents[0])
assert agents[0] in group_chat.agents
assert agents[0].id in group_chat.agent_ids
def test_add_duplicate_agent(agents):
group_chat = AgentGroupChat(agents=[agents[0]])
group_chat.add_agent(agents[0])
assert len(group_chat.agents) == 1
assert len(group_chat.agent_ids) == 1
async def test_invoke_single_turn(agents, termination_strategy):
group_chat = AgentGroupChat(termination_strategy=termination_strategy)
async def mock_invoke(agent, is_joining=True):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentGroupChat, "invoke", side_effect=mock_invoke):
termination_strategy.should_terminate.return_value = False
async for message in group_chat.invoke_single_turn(agents[0]):
assert message.role == AuthorRole.ASSISTANT
termination_strategy.should_terminate.assert_awaited_once()
async def test_invoke_single_turn_sets_complete(agents, termination_strategy):
group_chat = AgentGroupChat(termination_strategy=termination_strategy)
async def mock_invoke(agent, is_joining=True):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentGroupChat, "invoke", side_effect=mock_invoke):
termination_strategy.should_terminate.return_value = True
async for _ in group_chat.invoke_single_turn(agents[0]):
pass
assert group_chat.is_complete is True
termination_strategy.should_terminate.assert_awaited_once()
async def test_invoke_with_agent_joining(agents, termination_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
group_chat = AgentGroupChat(termination_strategy=termination_strategy)
with (
mock.patch.object(AgentGroupChat, "add_agent", autospec=True) as mock_add_agent,
mock.patch.object(AgentChat, "invoke_agent", autospec=True) as mock_invoke_agent,
):
async def mock_invoke_gen(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
mock_invoke_agent.side_effect = mock_invoke_gen
async for _ in group_chat.invoke(agents[0], is_joining=True):
pass
mock_add_agent.assert_called_once_with(group_chat, agents[0])
async def test_invoke_with_complete_chat(agents, termination_strategy):
termination_strategy.automatic_reset = False
group_chat = AgentGroupChat(agents=agents, termination_strategy=termination_strategy)
group_chat.is_complete = True
with pytest.raises(AgentChatException, match="Chat is already complete"):
async for _ in group_chat.invoke():
pass
async def test_invoke_agent_with_none_defined_errors(agents):
group_chat = AgentGroupChat()
with pytest.raises(AgentChatException, match="No agents are available"):
async for _ in group_chat.invoke():
pass
async def test_invoke_selection_strategy_error(agents, selection_strategy):
group_chat = AgentGroupChat(agents=agents, selection_strategy=selection_strategy)
selection_strategy.next.side_effect = Exception("Selection failed")
with pytest.raises(AgentChatException, match="Failed to select agent"):
async for _ in group_chat.invoke():
pass
async def test_invoke_iterations(agents, termination_strategy, selection_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
termination_strategy.maximum_iterations = 2
group_chat = AgentGroupChat(
agents=agents, termination_strategy=termination_strategy, selection_strategy=selection_strategy
)
selection_strategy.next.side_effect = lambda agents, history: agents[0]
async def mock_invoke_agent(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentChat, "invoke_agent", side_effect=mock_invoke_agent):
termination_strategy.should_terminate.return_value = False
iteration_count = 0
async for _ in group_chat.invoke():
iteration_count += 1
assert iteration_count == 2
async def test_invoke_is_complete_then_reset(agents, termination_strategy, selection_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
termination_strategy.maximum_iterations = 2
termination_strategy.automatic_reset = True
group_chat = AgentGroupChat(
agents=agents, termination_strategy=termination_strategy, selection_strategy=selection_strategy
)
group_chat.is_complete = True
selection_strategy.next.side_effect = lambda agents, history: agents[0]
async def mock_invoke_agent(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentChat, "invoke_agent", side_effect=mock_invoke_agent):
termination_strategy.should_terminate.return_value = False
iteration_count = 0
async for _ in group_chat.invoke():
iteration_count += 1
assert iteration_count == 2
# endregion
# region Streaming
async def test_invoke_streaming_single_turn(agents, termination_strategy):
group_chat = AgentGroupChat(termination_strategy=termination_strategy)
async def mock_invoke(agent, is_joining=True):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentGroupChat, "invoke_stream", side_effect=mock_invoke):
termination_strategy.should_terminate.return_value = False
async for message in group_chat.invoke_stream_single_turn(agents[0]):
assert message.role == AuthorRole.ASSISTANT
termination_strategy.should_terminate.assert_awaited_once()
async def test_invoke_stream_with_agent_joining(agents, termination_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
group_chat = AgentGroupChat(termination_strategy=termination_strategy)
with (
mock.patch.object(AgentGroupChat, "add_agent", autospec=True) as mock_add_agent,
mock.patch.object(AgentChat, "invoke_agent_stream", autospec=True) as mock_invoke_agent,
):
async def mock_invoke_gen(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
mock_invoke_agent.side_effect = mock_invoke_gen
async for _ in group_chat.invoke_stream(agents[0], is_joining=True):
pass
mock_add_agent.assert_called_once_with(group_chat, agents[0])
async def test_invoke_stream_with_complete_chat(agents, termination_strategy):
termination_strategy.automatic_reset = False
group_chat = AgentGroupChat(agents=agents, termination_strategy=termination_strategy)
group_chat.is_complete = True
with pytest.raises(AgentChatException, match="Chat is already complete"):
async for _ in group_chat.invoke_stream():
pass
async def test_invoke_stream_selection_strategy_error(agents, selection_strategy):
group_chat = AgentGroupChat(agents=agents, selection_strategy=selection_strategy)
selection_strategy.next.side_effect = Exception("Selection failed")
with pytest.raises(AgentChatException, match="Failed to select agent"):
async for _ in group_chat.invoke_stream():
pass
async def test_invoke_stream_iterations(agents, termination_strategy, selection_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
termination_strategy.maximum_iterations = 2
group_chat = AgentGroupChat(
agents=agents, termination_strategy=termination_strategy, selection_strategy=selection_strategy
)
selection_strategy.next.side_effect = lambda agents, history: agents[0]
async def mock_invoke_agent(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentChat, "invoke_agent_stream", side_effect=mock_invoke_agent):
termination_strategy.should_terminate.return_value = False
iteration_count = 0
async for _ in group_chat.invoke_stream():
iteration_count += 1
assert iteration_count == 2
async def test_invoke_stream_is_complete_then_reset(agents, termination_strategy, selection_strategy):
for agent in agents:
agent.name = f"Agent {agent.id}"
agent.id = f"agent-{agent.id}"
termination_strategy.maximum_iterations = 2
termination_strategy.automatic_reset = True
group_chat = AgentGroupChat(
agents=agents, termination_strategy=termination_strategy, selection_strategy=selection_strategy
)
group_chat.is_complete = True
selection_strategy.next.side_effect = lambda agents, history: agents[0]
async def mock_invoke_agent(*args, **kwargs):
yield MagicMock(role=AuthorRole.ASSISTANT)
with mock.patch.object(AgentChat, "invoke_agent_stream", side_effect=mock_invoke_agent):
termination_strategy.should_terminate.return_value = False
iteration_count = 0
async for _ in group_chat.invoke_stream():
iteration_count += 1
assert iteration_count == 2
async def test_invoke_streaming_agent_with_none_defined_errors(agents):
group_chat = AgentGroupChat()
with pytest.raises(AgentChatException, match="No agents are available"):
async for _ in group_chat.invoke_stream():
pass
# endregion
@@ -0,0 +1,172 @@
# Copyright (c) Microsoft. All rights reserved.
import asyncio
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from semantic_kernel.agents.channels.agent_channel import AgentChannel
from semantic_kernel.agents.group_chat.broadcast_queue import BroadcastQueue, ChannelReference, QueueReference
from semantic_kernel.contents.chat_message_content import ChatMessageContent
@pytest.fixture
def channel_ref():
"""Fixture that provides a mock ChannelReference."""
mock_channel = AsyncMock(spec=AgentChannel)
return ChannelReference(channel=mock_channel, hash="test-hash")
@pytest.fixture
def message():
"""Fixture that provides a mock ChatMessageContent."""
return MagicMock(spec=ChatMessageContent)
# region QueueReference Tests
def test_queue_reference_is_empty_true():
queue_ref = QueueReference()
assert queue_ref.is_empty is True
def test_queue_reference_is_empty_false():
queue_ref = QueueReference()
queue_ref.queue.append(MagicMock())
assert queue_ref.is_empty is False
# endregion
# region BroadcastQueue Tests
async def test_enqueue_new_channel(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
assert channel_ref.hash in broadcast_queue.queues
queue_ref = broadcast_queue.queues[channel_ref.hash]
assert queue_ref.queue[0] == [message]
assert queue_ref.receive_task is not None
assert not queue_ref.receive_task.done()
async def test_enqueue_existing_channel(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
await broadcast_queue.enqueue([channel_ref], [message])
queue_ref = broadcast_queue.queues[channel_ref.hash]
assert len(queue_ref.queue) == 2
assert queue_ref.queue[1] == [message]
assert queue_ref.receive_task is not None
assert not queue_ref.receive_task.done()
async def test_ensure_synchronized_channel_empty(channel_ref):
broadcast_queue = BroadcastQueue()
await broadcast_queue.ensure_synchronized(channel_ref)
assert channel_ref.hash not in broadcast_queue.queues
async def test_ensure_synchronized_with_messages(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
await broadcast_queue.ensure_synchronized(channel_ref)
queue_ref = broadcast_queue.queues[channel_ref.hash]
assert queue_ref.is_empty is True
async def test_ensure_synchronized_with_failure(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
queue_ref = broadcast_queue.queues[channel_ref.hash]
queue_ref.receive_failure = Exception("Simulated failure")
with pytest.raises(Exception, match="Unexpected failure broadcasting to channel"):
await broadcast_queue.ensure_synchronized(channel_ref)
assert queue_ref.receive_failure is None
async def test_ensure_synchronized_creates_new_task(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
queue_ref = broadcast_queue.queues[channel_ref.hash]
queue_ref.receive_task = None
with patch(
"semantic_kernel.agents.group_chat.broadcast_queue.BroadcastQueue.receive", new_callable=AsyncMock
) as mock_receive:
mock_receive.return_value = await asyncio.sleep(0.1)
await broadcast_queue.ensure_synchronized(channel_ref)
assert queue_ref.receive_task is None
async def test_receive_processes_queue(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
queue_ref = broadcast_queue.queues[channel_ref.hash]
await broadcast_queue.receive(channel_ref, queue_ref)
assert queue_ref.is_empty is True
assert channel_ref.channel.receive.await_count >= 1
channel_ref.channel.receive.assert_any_await([message])
async def test_receive_handles_failure(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
channel_ref.channel.receive.side_effect = Exception("Simulated failure")
queue_ref = broadcast_queue.queues[channel_ref.hash]
await broadcast_queue.receive(channel_ref, queue_ref)
assert queue_ref.receive_failure is not None
assert str(queue_ref.receive_failure) == "Simulated failure"
async def test_receive_breaks_when_queue_is_empty(channel_ref, message):
broadcast_queue = BroadcastQueue()
await broadcast_queue.enqueue([channel_ref], [message])
queue_ref = broadcast_queue.queues[channel_ref.hash]
assert not queue_ref.is_empty
channel_ref.channel.receive = AsyncMock()
queue_ref.queue.clear()
await broadcast_queue.receive(channel_ref, queue_ref)
channel_ref.channel.receive.assert_not_awaited()
assert queue_ref.is_empty
# endregion