microsoft/teams.net

Public

mirrored fromhttps://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
kavin/agents-sdk-interop

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

core/test/IntegrationTests/CreateConversationDiagnosticTests.cs

333lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text.Json;
5using Microsoft.Extensions.DependencyInjection;
6using Microsoft.Teams.Core;
7using Microsoft.Teams.Core.Schema;
8using Xunit.Abstractions;
9
10namespace IntegrationTests;
11
12/// <summary>
13/// Diagnostic tests exploring CreateConversation parameter combinations.
14/// These tests document what the Teams Bot Framework API accepts and rejects,
15/// capturing full request/response details including headers.
16/// </summary>
17public class CreateConversationDiagnosticTests : IClassFixture<IntegrationTestFixture>
18{
19 private static readonly JsonSerializerOptions JsonOpts = new()
20 {
21 PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
22 WriteIndented = true,
23 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
24 };
25
26 private readonly IntegrationTestFixture _f;
27 private readonly ITestOutputHelper _output;
28
29 public CreateConversationDiagnosticTests(IntegrationTestFixture fixture, ITestOutputHelper output)
30 {
31 _f = fixture;
32 _f.OutputHelper = output;
33 _output = output;
34 }
35
36 private async Task<(string first, string? second, string? third)> GetMemberMrisAsync()
37 {
38 IList<ConversationAccount> members = await _f.ConversationClient.GetConversationMembersAsync(
39 _f.ConversationId, _f.ServiceUrl, _f.AgenticIdentity);
40 return (
41 members[0].Id!,
42 members.Count >= 2 ? members[1].Id : null,
43 members.Count >= 3 ? members[2].Id : null
44 );
45 }
46
47 /// <summary>
48 /// Sends a CreateConversation request using a raw HttpClient to capture full request/response details.
49 /// </summary>
50 private async Task<DiagnosticResult> SendDiagnosticRequestAsync(string label, ConversationParameters parameters)
51 {
52 string url = $"{_f.ServiceUrl.ToString().TrimEnd('/')}/v3/conversations";
53 string requestBody = JsonSerializer.Serialize(parameters, JsonOpts);
54
55 // Use the DI-configured HttpClient (has BotAuthenticationHandler for token)
56 HttpClient httpClient = _f.ServiceProvider.GetRequiredService<IHttpClientFactory>()
57 .CreateClient("BotConversationClient");
58
59 using HttpRequestMessage request = new(HttpMethod.Post, url);
60 request.Content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
61
62 if (_f.AgenticIdentity is not null)
63 {
64 request.Options.Set(new HttpRequestOptionsKey<AgenticIdentity?>("AgenticIdentity"), _f.AgenticIdentity);
65 }
66
67 _output.WriteLine($"=== {label} ===");
68 _output.WriteLine($"POST {url}");
69 _output.WriteLine($"Request body:\n{requestBody}");
70
71 using HttpResponseMessage response = await httpClient.SendAsync(request);
72
73 string responseBody = await response.Content.ReadAsStringAsync();
74
75 _output.WriteLine($"\nHTTP {(int)response.StatusCode} {response.StatusCode}");
76
77 _output.WriteLine("\nResponse headers:");
78 foreach (KeyValuePair<string, IEnumerable<string>> header in response.Headers)
79 {
80 _output.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}");
81 }
82 foreach (KeyValuePair<string, IEnumerable<string>> header in response.Content.Headers)
83 {
84 _output.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}");
85 }
86
87 // Pretty-print JSON response
88 try
89 {
90 JsonElement parsed = JsonSerializer.Deserialize<JsonElement>(responseBody);
91
92 string pretty = JsonSerializer.Serialize(parsed, JsonOpts);
93 _output.WriteLine($"\nResponse body:\n{pretty}");
94 }
95 catch
96 {
97 _output.WriteLine($"\nResponse body:\n{responseBody}");
98 }
99
100 _output.WriteLine("");
101
102 return new DiagnosticResult
103 {
104 Label = label,
105 StatusCode = (int)response.StatusCode,
106 RequestBody = requestBody,
107 ResponseBody = responseBody,
108 ResponseHeaders = response.Headers.ToDictionary(h => h.Key, h => string.Join(", ", h.Value))
109 };
110 }
111
112 private record DiagnosticResult
113 {
114 public required string Label { get; init; }
115 public required int StatusCode { get; init; }
116 public required string RequestBody { get; init; }
117 public required string ResponseBody { get; init; }
118 public required Dictionary<string, string> ResponseHeaders { get; init; }
119 }
120
121 // =========================================================================
122 // 1:1 personal chat — baseline (known working)
123 // =========================================================================
124
125 [Fact(Timeout = 5000)]
126 public async Task PersonalChat_MinimalParams()
127 {
128 (string memberMri, _, _) = await GetMemberMrisAsync();
129 DiagnosticResult result = await SendDiagnosticRequestAsync("1:1 Personal Chat (minimal)", new()
130 {
131 IsGroup = false,
132 Members = [new() { Id = memberMri }],
133 TenantId = _f.TenantId
134 });
135 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
136 }
137
138 [Fact(Timeout = 5000)]
139 public async Task PersonalChat_WithBot()
140 {
141 (string memberMri, _, _) = await GetMemberMrisAsync();
142 DiagnosticResult result = await SendDiagnosticRequestAsync("1:1 Personal Chat (with bot)", new()
143 {
144 IsGroup = false,
145 Bot = new() { Id = $"28:{_f.BotAppId}" },
146 Members = [new() { Id = memberMri }],
147 TenantId = _f.TenantId
148 });
149 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
150 }
151
152 [Fact(Timeout = 5000)]
153 public async Task PersonalChat_WithInitialActivity()
154 {
155 (string memberMri, _, _) = await GetMemberMrisAsync();
156 DiagnosticResult result = await SendDiagnosticRequestAsync("1:1 Personal Chat (with activity)", new()
157 {
158 IsGroup = false,
159 Members = [new() { Id = memberMri }],
160 TenantId = _f.TenantId,
161 Activity = CoreActivity.CreateBuilder()
162 .WithType(ActivityType.Message)
163 .WithProperty("text", "[Diagnostic] 1:1 with initial activity")
164 .Build()
165 });
166 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
167 }
168
169 // =========================================================================
170 // Group chat variations
171 // =========================================================================
172
173 [Fact(Timeout = 5000)]
174 public async Task GroupChat_TwoMembers_NoBotNoChannelData()
175 {
176 (string first, string? second, _) = await GetMemberMrisAsync();
177 Assert.NotNull(second);
178 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, no bot, no channelData", new()
179 {
180 IsGroup = true,
181 Members = [new() { Id = first }, new() { Id = second! }],
182 TenantId = _f.TenantId
183 });
184 Assert.Equal(400, result.StatusCode);
185 }
186
187 [Fact(Timeout = 5000)]
188 public async Task GroupChat_TwoMembers_WithBot()
189 {
190 (string first, string? second, _) = await GetMemberMrisAsync();
191 Assert.NotNull(second);
192 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot=28:appId", new()
193 {
194 IsGroup = true,
195 Bot = new() { Id = $"28:{_f.BotAppId}" },
196 Members = [new() { Id = first }, new() { Id = second! }],
197 TenantId = _f.TenantId
198 });
199 Assert.Equal(400, result.StatusCode);
200 }
201
202 [Fact(Timeout = 5000)]
203 public async Task GroupChat_TwoMembers_WithBotAndChannelData()
204 {
205 (string first, string? second, _) = await GetMemberMrisAsync();
206 Assert.NotNull(second);
207 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot, channelData.tenant", new()
208 {
209 IsGroup = true,
210 Bot = new() { Id = $"28:{_f.BotAppId}" },
211 Members = [new() { Id = first }, new() { Id = second! }],
212 TenantId = _f.TenantId,
213 ChannelData = new { tenant = new { id = _f.TenantId } }
214 });
215 Assert.Equal(400, result.StatusCode);
216 }
217
218 [Fact(Timeout = 5000)]
219 public async Task GroupChat_TwoMembers_WithTopicAndActivity()
220 {
221 (string first, string? second, _) = await GetMemberMrisAsync();
222 Assert.NotNull(second);
223 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot, topic, activity, channelData", new()
224 {
225 IsGroup = true,
226 Bot = new() { Id = $"28:{_f.BotAppId}" },
227 Members = [new() { Id = first }, new() { Id = second! }],
228 TenantId = _f.TenantId,
229 TopicName = "Diagnostic group test",
230 ChannelData = new { tenant = new { id = _f.TenantId } },
231 Activity = CoreActivity.CreateBuilder()
232 .WithType(ActivityType.Message)
233 .WithProperty("text", "group chat init")
234 .Build()
235 });
236 Assert.Equal(400, result.StatusCode);
237 }
238
239 [Fact(Timeout = 5000)]
240 public async Task GroupChat_OneMember_IsGroupTrue()
241 {
242 (string memberMri, _, _) = await GetMemberMrisAsync();
243 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 1 member, isGroup=true", new()
244 {
245 IsGroup = true,
246 Members = [new() { Id = memberMri }],
247 TenantId = _f.TenantId
248 });
249 Assert.Equal(400, result.StatusCode);
250 }
251
252 [Fact(Timeout = 5000)]
253 public async Task GroupChat_OneMember_WithBot()
254 {
255 (string memberMri, _, _) = await GetMemberMrisAsync();
256 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 1 member, bot, channelData.tenant", new()
257 {
258 IsGroup = true,
259 Bot = new() { Id = $"28:{_f.BotAppId}" },
260 Members = [new() { Id = memberMri }],
261 TenantId = _f.TenantId,
262 ChannelData = new { tenant = new { id = _f.TenantId } }
263 });
264 Assert.Equal(400, result.StatusCode);
265 }
266
267 [Fact(Timeout = 5000)]
268 public async Task GroupChat_ThreeMembers()
269 {
270 (string first, string? second, string? third) = await GetMemberMrisAsync();
271 Assert.NotNull(second);
272 Assert.NotNull(third);
273 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 3 members, bot", new()
274 {
275 IsGroup = true,
276 Bot = new() { Id = $"28:{_f.BotAppId}" },
277 Members = [new() { Id = first }, new() { Id = second! }, new() { Id = third! }],
278 TenantId = _f.TenantId,
279 ChannelData = new { tenant = new { id = _f.TenantId } }
280 });
281 Assert.Equal(400, result.StatusCode);
282 }
283
284 // =========================================================================
285 // Channel thread variations
286 // =========================================================================
287
288 [Fact(Timeout = 5000)]
289 public async Task ChannelThread_WithActivity()
290 {
291 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: with activity", new()
292 {
293 IsGroup = true,
294 ChannelData = new { channel = new { id = _f.ChannelId } },
295 Activity = CoreActivity.CreateBuilder()
296 .WithType(ActivityType.Message)
297 .WithProperty("text", "[Diagnostic] channel thread")
298 .Build(),
299 TenantId = _f.TenantId
300 });
301 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
302 }
303
304 [Fact(Timeout = 5000)]
305 public async Task ChannelThread_NoActivity()
306 {
307 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: without activity", new()
308 {
309 IsGroup = true,
310 ChannelData = new { channel = new { id = _f.ChannelId } },
311 TenantId = _f.TenantId
312 });
313 Assert.Equal(400, result.StatusCode);
314 }
315
316 [Fact(Timeout = 5000)]
317 public async Task ChannelThread_WithMembersAndActivity()
318 {
319 (string memberMri, _, _) = await GetMemberMrisAsync();
320 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: with members and activity", new()
321 {
322 IsGroup = true,
323 Members = [new() { Id = memberMri }],
324 ChannelData = new { channel = new { id = _f.ChannelId } },
325 Activity = CoreActivity.CreateBuilder()
326 .WithType(ActivityType.Message)
327 .WithProperty("text", "[Diagnostic] channel thread with members")
328 .Build(),
329 TenantId = _f.TenantId
330 });
331 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
332 }
333}
334