Skip to content

Commit b7b2e33

Browse files
add tests
1 parent 1b36023 commit b7b2e33

4 files changed

Lines changed: 374 additions & 0 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
from unittest.mock import MagicMock
5+
6+
from microsoft_agents_a365.observability.core.constants import GEN_AI_CALLER_ID_KEY
7+
from microsoft_agents_a365.observability.core.middleware.baggage_builder import BaggageBuilder
8+
from microsoft_agents_a365.observability.hosting.scope_helpers.populate_baggage import populate
9+
10+
11+
def test_populate():
12+
"""Test populate populates BaggageBuilder from turn context."""
13+
# Create a mock turn context with activity
14+
turn_context = MagicMock()
15+
activity = MagicMock()
16+
activity.from_property = MagicMock(
17+
aad_object_id="caller-id",
18+
name="Caller",
19+
agentic_user_id="caller-upn",
20+
tenant_id="tenant-id",
21+
)
22+
activity.recipient = MagicMock(tenant_id="tenant-id", role="user")
23+
activity.conversation = MagicMock(id="conv-id")
24+
activity.service_url = "https://example.com"
25+
activity.channel_id = "test-channel"
26+
turn_context.activity = activity
27+
28+
builder = BaggageBuilder()
29+
30+
result = populate(builder, turn_context)
31+
32+
assert result == builder
33+
# Verify builder was populated by checking its internal _pairs dict
34+
assert len(builder._pairs) > 0
35+
# Verify specific expected baggage keys were set
36+
assert GEN_AI_CALLER_ID_KEY in builder._pairs
37+
assert builder._pairs[GEN_AI_CALLER_ID_KEY] == "caller-id"
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
import os
5+
from unittest.mock import MagicMock
6+
7+
import pytest
8+
from microsoft_agents_a365.observability.core.agent_details import AgentDetails
9+
from microsoft_agents_a365.observability.core.constants import (
10+
GEN_AI_AGENT_ID_KEY,
11+
GEN_AI_CALLER_ID_KEY,
12+
GEN_AI_CONVERSATION_ID_KEY,
13+
GEN_AI_EXECUTION_SOURCE_NAME_KEY,
14+
GEN_AI_EXECUTION_TYPE_KEY,
15+
GEN_AI_INPUT_MESSAGES_KEY,
16+
TENANT_ID_KEY,
17+
)
18+
from microsoft_agents_a365.observability.core.invoke_agent_details import InvokeAgentDetails
19+
from microsoft_agents_a365.observability.core.invoke_agent_scope import InvokeAgentScope
20+
from microsoft_agents_a365.observability.core.tenant_details import TenantDetails
21+
from microsoft_agents_a365.observability.hosting.scope_helpers.populate_invoke_agent_scope import (
22+
populate,
23+
set_caller_tags,
24+
set_conversation_id_tags,
25+
set_execution_type_tags,
26+
set_input_message_tags,
27+
set_source_metadata_tags,
28+
set_target_agent_tags,
29+
set_tenant_id_tags,
30+
)
31+
from opentelemetry import trace
32+
from opentelemetry.sdk.trace import TracerProvider
33+
34+
35+
@pytest.fixture(autouse=True)
36+
def enable_telemetry():
37+
"""Enable telemetry and set up tracer provider for all tests in this module."""
38+
# Set environment variable to enable telemetry
39+
os.environ["ENABLE_OBSERVABILITY"] = "true"
40+
41+
# Set up a proper tracer provider
42+
provider = TracerProvider()
43+
trace.set_tracer_provider(provider)
44+
45+
yield
46+
47+
# Clean up
48+
os.environ.pop("ENABLE_OBSERVABILITY", None)
49+
50+
51+
def test_populate():
52+
"""Test populate populates scope from turn context."""
53+
# Create real InvokeAgentScope with minimal required parameters
54+
invoke_agent_details = InvokeAgentDetails(
55+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
56+
)
57+
tenant_details = TenantDetails(tenant_id="test-tenant")
58+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
59+
60+
# Use mock for TurnContext to avoid dependency on microsoft_agents package
61+
turn_context = MagicMock()
62+
activity = MagicMock()
63+
activity.from_property = MagicMock()
64+
activity.recipient = MagicMock()
65+
activity.conversation = MagicMock()
66+
activity.text = "Test message"
67+
turn_context.activity = activity
68+
69+
result = populate(scope, turn_context)
70+
71+
# Verify function completes without error and returns the scope
72+
assert result == scope
73+
74+
75+
def test_set_caller_tags():
76+
"""Test set_caller_tags sets caller attributes on scope."""
77+
# Create real InvokeAgentScope
78+
invoke_agent_details = InvokeAgentDetails(
79+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
80+
)
81+
tenant_details = TenantDetails(tenant_id="test-tenant")
82+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
83+
84+
activity = MagicMock()
85+
activity.from_property = MagicMock(
86+
aad_object_id="caller-id", name="Caller", agentic_user_id="upn", tenant_id="tenant"
87+
)
88+
89+
# Verify function completes without error
90+
set_caller_tags(scope, activity)
91+
92+
# Verify attributes were set on the span (if telemetry is enabled)
93+
if scope._span and hasattr(scope._span, "_attributes"):
94+
assert GEN_AI_CALLER_ID_KEY in scope._span._attributes
95+
assert scope._span._attributes[GEN_AI_CALLER_ID_KEY] == "caller-id"
96+
97+
98+
def test_set_execution_type_tags():
99+
"""Test set_execution_type_tags sets execution type on scope."""
100+
# Create real InvokeAgentScope
101+
invoke_agent_details = InvokeAgentDetails(
102+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
103+
)
104+
tenant_details = TenantDetails(tenant_id="test-tenant")
105+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
106+
107+
activity = MagicMock()
108+
activity.from_property = MagicMock(role="user")
109+
activity.recipient = MagicMock(role="agenticUser")
110+
111+
# Verify function completes without error
112+
set_execution_type_tags(scope, activity)
113+
114+
# Verify attributes were set on the span (if telemetry is enabled)
115+
if scope._span and hasattr(scope._span, "_attributes"):
116+
assert GEN_AI_EXECUTION_TYPE_KEY in scope._span._attributes
117+
118+
119+
def test_set_target_agent_tags():
120+
"""Test set_target_agent_tags sets target agent attributes on scope."""
121+
# Create real InvokeAgentScope
122+
invoke_agent_details = InvokeAgentDetails(
123+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
124+
)
125+
tenant_details = TenantDetails(tenant_id="test-tenant")
126+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
127+
128+
activity = MagicMock()
129+
activity.recipient = MagicMock(
130+
agentic_app_id="agent-id", name="Agent", aad_object_id="auid", agentic_user_id="upn"
131+
)
132+
133+
# Verify function completes without error
134+
set_target_agent_tags(scope, activity)
135+
136+
# Verify attributes were set on the span (if telemetry is enabled)
137+
if scope._span and hasattr(scope._span, "_attributes"):
138+
assert GEN_AI_AGENT_ID_KEY in scope._span._attributes
139+
assert scope._span._attributes[GEN_AI_AGENT_ID_KEY] == "agent-id"
140+
141+
142+
def test_set_tenant_id_tags():
143+
"""Test set_tenant_id_tags sets tenant ID on scope."""
144+
# Create real InvokeAgentScope
145+
invoke_agent_details = InvokeAgentDetails(
146+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
147+
)
148+
tenant_details = TenantDetails(tenant_id="test-tenant")
149+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
150+
151+
activity = MagicMock()
152+
activity.recipient = MagicMock(tenant_id="tenant-123")
153+
154+
# Verify function completes without error
155+
set_tenant_id_tags(scope, activity)
156+
157+
# Verify attributes were set on the span (if telemetry is enabled)
158+
if scope._span and hasattr(scope._span, "_attributes"):
159+
assert TENANT_ID_KEY in scope._span._attributes
160+
assert scope._span._attributes[TENANT_ID_KEY] == "tenant-123"
161+
162+
163+
def test_set_source_metadata_tags():
164+
"""Test set_source_metadata_tags sets source metadata on scope."""
165+
# Create real InvokeAgentScope
166+
invoke_agent_details = InvokeAgentDetails(
167+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
168+
)
169+
tenant_details = TenantDetails(tenant_id="test-tenant")
170+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
171+
172+
activity = MagicMock()
173+
activity.channel_id = "test-channel"
174+
175+
# Verify function completes without error
176+
set_source_metadata_tags(scope, activity)
177+
178+
# Verify attributes were set on the span (if telemetry is enabled)
179+
if scope._span and hasattr(scope._span, "_attributes"):
180+
assert GEN_AI_EXECUTION_SOURCE_NAME_KEY in scope._span._attributes
181+
assert scope._span._attributes[GEN_AI_EXECUTION_SOURCE_NAME_KEY] == "test-channel"
182+
183+
184+
def test_set_conversation_id_tags():
185+
"""Test set_conversation_id_tags sets conversation attributes on scope."""
186+
# Create real InvokeAgentScope
187+
invoke_agent_details = InvokeAgentDetails(
188+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
189+
)
190+
tenant_details = TenantDetails(tenant_id="test-tenant")
191+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
192+
193+
activity = MagicMock()
194+
activity.conversation = MagicMock(id="conv-123")
195+
activity.service_url = "https://example.com"
196+
197+
# Verify function completes without error
198+
set_conversation_id_tags(scope, activity)
199+
200+
# Verify attributes were set on the span (if telemetry is enabled)
201+
if scope._span and hasattr(scope._span, "_attributes"):
202+
assert GEN_AI_CONVERSATION_ID_KEY in scope._span._attributes
203+
assert scope._span._attributes[GEN_AI_CONVERSATION_ID_KEY] == "conv-123"
204+
205+
206+
def test_set_input_message_tags():
207+
"""Test set_input_message_tags sets input message on scope."""
208+
# Create real InvokeAgentScope
209+
invoke_agent_details = InvokeAgentDetails(
210+
details=AgentDetails(agent_id="test-agent", agent_name="Test Agent")
211+
)
212+
tenant_details = TenantDetails(tenant_id="test-tenant")
213+
scope = InvokeAgentScope(invoke_agent_details, tenant_details)
214+
215+
activity = MagicMock()
216+
activity.text = "Test input message"
217+
218+
# Verify function completes without error
219+
set_input_message_tags(scope, activity)
220+
221+
# Verify attributes were set on the span (if telemetry is enabled)
222+
if scope._span and hasattr(scope._span, "_attributes"):
223+
assert GEN_AI_INPUT_MESSAGES_KEY in scope._span._attributes
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT License.
3+
4+
from microsoft_agents.activity import Activity, ChannelAccount, ConversationAccount
5+
from microsoft_agents_a365.observability.core.constants import (
6+
GEN_AI_AGENT_AUID_KEY,
7+
GEN_AI_AGENT_DESCRIPTION_KEY,
8+
GEN_AI_AGENT_ID_KEY,
9+
GEN_AI_AGENT_NAME_KEY,
10+
GEN_AI_AGENT_UPN_KEY,
11+
GEN_AI_CALLER_ID_KEY,
12+
GEN_AI_CALLER_NAME_KEY,
13+
GEN_AI_CALLER_TENANT_ID_KEY,
14+
GEN_AI_CALLER_UPN_KEY,
15+
GEN_AI_CONVERSATION_ID_KEY,
16+
GEN_AI_CONVERSATION_ITEM_LINK_KEY,
17+
GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY,
18+
GEN_AI_EXECUTION_SOURCE_NAME_KEY,
19+
GEN_AI_EXECUTION_TYPE_KEY,
20+
TENANT_ID_KEY,
21+
)
22+
from microsoft_agents_a365.observability.core.execution_type import ExecutionType
23+
from microsoft_agents_a365.observability.hosting.scope_helpers.utils import (
24+
get_caller_pairs,
25+
get_conversation_pairs,
26+
get_execution_type_pair,
27+
get_source_metadata_pairs,
28+
get_target_agent_pairs,
29+
get_tenant_id_pair,
30+
)
31+
32+
33+
def test_get_caller_pairs():
34+
"""Test get_caller_pairs extracts caller information from activity."""
35+
from_account = ChannelAccount(
36+
aad_object_id="caller-aad-id",
37+
name="Test Caller",
38+
agentic_user_id="caller-upn",
39+
tenant_id="caller-tenant-id",
40+
)
41+
activity = Activity(type="message", from_property=from_account)
42+
43+
result = list(get_caller_pairs(activity))
44+
45+
assert (GEN_AI_CALLER_ID_KEY, "caller-aad-id") in result
46+
assert (GEN_AI_CALLER_NAME_KEY, "Test Caller") in result
47+
assert (GEN_AI_CALLER_UPN_KEY, "caller-upn") in result
48+
assert (GEN_AI_CALLER_TENANT_ID_KEY, "caller-tenant-id") in result
49+
50+
51+
def test_get_execution_type_pair():
52+
"""Test get_execution_type_pair determines execution type correctly."""
53+
from_account = ChannelAccount(role="agenticUser")
54+
recipient = ChannelAccount(role="agenticUser")
55+
activity = Activity(type="message", from_property=from_account, recipient=recipient)
56+
57+
result = list(get_execution_type_pair(activity))
58+
59+
assert (GEN_AI_EXECUTION_TYPE_KEY, ExecutionType.AGENT_TO_AGENT.value) in result
60+
61+
62+
def test_get_target_agent_pairs():
63+
"""Test get_target_agent_pairs extracts target agent information."""
64+
recipient = ChannelAccount(
65+
agentic_app_id="agent-app-id",
66+
name="Test Agent",
67+
aad_object_id="agent-auid",
68+
agentic_user_id="agent-upn",
69+
role="Assistant",
70+
)
71+
activity = Activity(type="message", recipient=recipient)
72+
73+
result = list(get_target_agent_pairs(activity))
74+
75+
assert (GEN_AI_AGENT_ID_KEY, "agent-app-id") in result
76+
assert (GEN_AI_AGENT_NAME_KEY, "Test Agent") in result
77+
assert (GEN_AI_AGENT_AUID_KEY, "agent-auid") in result
78+
assert (GEN_AI_AGENT_UPN_KEY, "agent-upn") in result
79+
assert (GEN_AI_AGENT_DESCRIPTION_KEY, "Assistant") in result
80+
81+
82+
def test_get_tenant_id_pair():
83+
"""Test get_tenant_id_pair extracts tenant ID from recipient."""
84+
recipient = ChannelAccount(tenant_id="test-tenant-id")
85+
activity = Activity(type="message", recipient=recipient)
86+
87+
result = list(get_tenant_id_pair(activity))
88+
89+
assert (TENANT_ID_KEY, "test-tenant-id") in result
90+
91+
92+
def test_get_source_metadata_pairs():
93+
"""Test get_source_metadata_pairs extracts channel metadata."""
94+
activity = Activity(type="message", channel_id="test-channel")
95+
96+
result = list(get_source_metadata_pairs(activity))
97+
98+
assert (GEN_AI_EXECUTION_SOURCE_NAME_KEY, "test-channel") in result
99+
assert (GEN_AI_EXECUTION_SOURCE_DESCRIPTION_KEY, None) in result
100+
101+
102+
def test_get_conversation_pairs():
103+
"""Test get_conversation_pairs extracts conversation information."""
104+
conversation = ConversationAccount(id="conversation-123")
105+
activity = Activity(
106+
type="message", conversation=conversation, service_url="https://example.com"
107+
)
108+
109+
result = list(get_conversation_pairs(activity))
110+
111+
assert (GEN_AI_CONVERSATION_ID_KEY, "conversation-123") in result
112+
assert (GEN_AI_CONVERSATION_ITEM_LINK_KEY, "https://example.com") in result

0 commit comments

Comments
 (0)