Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions tests/unit/executor/attack/multi_turn/test_crescendo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

import asyncio
import json
import uuid
from pathlib import Path
Expand Down Expand Up @@ -2548,19 +2549,35 @@ async def test_concurrent_context_isolation(
context1 = CrescendoAttackContext(params=AttackParameters(objective="Objective 1"))
context2 = CrescendoAttackContext(params=AttackParameters(objective="Objective 2"))

# Mock conversation manager for both setups
mock_state1 = ConversationState(turn_count=0)
mock_state2 = ConversationState(turn_count=0)
setup_started: set[str] = set()
both_setups_started = asyncio.Event()

async def initialize_context_async(
*,
context: CrescendoAttackContext,
**_kwargs: object,
) -> ConversationState:
setup_started.add(context.objective)
if len(setup_started) == 2:
both_setups_started.set()
await both_setups_started.wait()
return ConversationState(turn_count=0)

with patch.object(
attack._conversation_manager, "initialize_context_async", side_effect=[mock_state1, mock_state2]
attack._conversation_manager,
"initialize_context_async",
new_callable=AsyncMock,
side_effect=initialize_context_async,
):
# Simulate concurrent setup - both contexts use the same attack instance
await attack._setup_async(context=context1)
await attack._setup_async(context=context2)
# The first setup waits for the second to start, guaranteeing real overlap.
await asyncio.gather(
attack._setup_async(context=context1),
attack._setup_async(context=context2),
)

# Verify contexts remain independent
# Each should maintain its own state without interference
assert setup_started == {"Objective 1", "Objective 2"}
assert context1.objective == "Objective 1"
assert context2.objective == "Objective 2"
# Most importantly, they should have different conversation IDs
Expand Down