microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feature/extended-markdown-text-format

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/test/IntegrationTests/CreateConversationDiagnosticTests.cs

344lines · 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 Task<(string first, string? second, string? third)> GetMemberMrisAsync()
37 {
38 return Task.FromResult((
39 _f.MemberMri1!,
40 _f.MemberMri2,
41 _f.MemberMri3
42 ));
43 }
44
45 /// <summary>
46 /// Sends a CreateConversation request using a raw HttpClient to capture full request/response details.
47 /// </summary>
48 private async Task<DiagnosticResult> SendDiagnosticRequestAsync(string label, ConversationParameters parameters)
49 {
50 string url = $"{_f.ServiceUrl.ToString().TrimEnd('/')}/v3/conversations";
51 string requestBody = JsonSerializer.Serialize(parameters, JsonOpts);
52
53 // Use the DI-configured HttpClient (has BotAuthenticationHandler for token)
54 HttpClient httpClient = _f.ServiceProvider.GetRequiredService<IHttpClientFactory>()
55 .CreateClient("BotConversationClient");
56
57 using HttpRequestMessage request = new(HttpMethod.Post, url);
58 request.Content = new StringContent(requestBody, System.Text.Encoding.UTF8, "application/json");
59
60 if (_f.AgenticIdentity is not null)
61 {
62 request.Options.Set(new HttpRequestOptionsKey<AgenticIdentity?>("AgenticIdentity"), _f.AgenticIdentity);
63 }
64
65 _output.WriteLine($"=== {label} ===");
66 _output.WriteLine($"POST {url}");
67 _output.WriteLine($"Request body:\n{requestBody}");
68
69 using HttpResponseMessage response = await httpClient.SendAsync(request);
70
71 string responseBody = await response.Content.ReadAsStringAsync();
72
73 _output.WriteLine($"\nHTTP {(int)response.StatusCode} {response.StatusCode}");
74
75 _output.WriteLine("\nResponse headers:");
76 foreach (KeyValuePair<string, IEnumerable<string>> header in response.Headers)
77 {
78 _output.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}");
79 }
80 foreach (KeyValuePair<string, IEnumerable<string>> header in response.Content.Headers)
81 {
82 _output.WriteLine($" {header.Key}: {string.Join(", ", header.Value)}");
83 }
84
85 // Pretty-print JSON response
86 try
87 {
88 JsonElement parsed = JsonSerializer.Deserialize<JsonElement>(responseBody);
89
90 string pretty = JsonSerializer.Serialize(parsed, JsonOpts);
91 _output.WriteLine($"\nResponse body:\n{pretty}");
92 }
93 catch
94 {
95 _output.WriteLine($"\nResponse body:\n{responseBody}");
96 }
97
98 _output.WriteLine("");
99
100 return new DiagnosticResult
101 {
102 Label = label,
103 StatusCode = (int)response.StatusCode,
104 RequestBody = requestBody,
105 ResponseBody = responseBody,
106 ResponseHeaders = response.Headers.ToDictionary(h => h.Key, h => string.Join(", ", h.Value))
107 };
108 }
109
110 private record DiagnosticResult
111 {
112 public required string Label { get; init; }
113 public required int StatusCode { get; init; }
114 public required string RequestBody { get; init; }
115 public required string ResponseBody { get; init; }
116 public required Dictionary<string, string> ResponseHeaders { get; init; }
117 }
118
119 // =========================================================================
120 // 1:1 personal chat — baseline (known working)
121 // =========================================================================
122
123 [Fact(Timeout = 5000)]
124 [Trait("Category", "Diagnostic")]
125 public async Task PersonalChat_MinimalParams()
126 {
127 (string memberMri, _, _) = await GetMemberMrisAsync();
128 DiagnosticResult result = await SendDiagnosticRequestAsync("1:1 Personal Chat (minimal)", new()
129 {
130 IsGroup = false,
131 Members = [new() { Id = memberMri }],
132 TenantId = _f.TenantId
133 });
134 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
135 }
136
137 [Fact(Timeout = 5000)]
138 [Trait("Category", "Diagnostic")]
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 [Trait("Category", "Diagnostic")]
154 public async Task PersonalChat_WithInitialActivity()
155 {
156 (string memberMri, _, _) = await GetMemberMrisAsync();
157 DiagnosticResult result = await SendDiagnosticRequestAsync("1:1 Personal Chat (with activity)", new()
158 {
159 IsGroup = false,
160 Members = [new() { Id = memberMri }],
161 TenantId = _f.TenantId,
162 Activity = CoreActivity.CreateBuilder()
163 .WithType(ActivityType.Message)
164 .WithProperty("text", "[Diagnostic] 1:1 with initial activity")
165 .Build()
166 });
167 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
168 }
169
170 // =========================================================================
171 // Group chat variations
172 // =========================================================================
173
174 [Fact(Timeout = 5000)]
175 [Trait("Category", "Diagnostic")]
176 public async Task GroupChat_TwoMembers_NoBotNoChannelData()
177 {
178 (string first, string? second, _) = await GetMemberMrisAsync();
179 Assert.NotNull(second);
180 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, no bot, no channelData", new()
181 {
182 IsGroup = true,
183 Members = [new() { Id = first }, new() { Id = second! }],
184 TenantId = _f.TenantId
185 });
186 Assert.Equal(400, result.StatusCode);
187 }
188
189 [Fact(Timeout = 5000)]
190 [Trait("Category", "Diagnostic")]
191 public async Task GroupChat_TwoMembers_WithBot()
192 {
193 (string first, string? second, _) = await GetMemberMrisAsync();
194 Assert.NotNull(second);
195 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot=28:appId", new()
196 {
197 IsGroup = true,
198 Bot = new() { Id = $"28:{_f.BotAppId}" },
199 Members = [new() { Id = first }, new() { Id = second! }],
200 TenantId = _f.TenantId
201 });
202 Assert.Equal(400, result.StatusCode);
203 }
204
205 [Fact(Timeout = 5000)]
206 [Trait("Category", "Diagnostic")]
207 public async Task GroupChat_TwoMembers_WithBotAndChannelData()
208 {
209 (string first, string? second, _) = await GetMemberMrisAsync();
210 Assert.NotNull(second);
211 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot, channelData.tenant", new()
212 {
213 IsGroup = true,
214 Bot = new() { Id = $"28:{_f.BotAppId}" },
215 Members = [new() { Id = first }, new() { Id = second! }],
216 TenantId = _f.TenantId,
217 ChannelData = new { tenant = new { id = _f.TenantId } }
218 });
219 Assert.Equal(400, result.StatusCode);
220 }
221
222 [Fact(Timeout = 5000)]
223 [Trait("Category", "Diagnostic")]
224 public async Task GroupChat_TwoMembers_WithTopicAndActivity()
225 {
226 (string first, string? second, _) = await GetMemberMrisAsync();
227 Assert.NotNull(second);
228 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 2 members, bot, topic, activity, channelData", new()
229 {
230 IsGroup = true,
231 Bot = new() { Id = $"28:{_f.BotAppId}" },
232 Members = [new() { Id = first }, new() { Id = second! }],
233 TenantId = _f.TenantId,
234 TopicName = "Diagnostic group test",
235 ChannelData = new { tenant = new { id = _f.TenantId } },
236 Activity = CoreActivity.CreateBuilder()
237 .WithType(ActivityType.Message)
238 .WithProperty("text", "group chat init")
239 .Build()
240 });
241 Assert.Equal(400, result.StatusCode);
242 }
243
244 [Fact(Timeout = 5000)]
245 [Trait("Category", "Diagnostic")]
246 public async Task GroupChat_OneMember_IsGroupTrue()
247 {
248 (string memberMri, _, _) = await GetMemberMrisAsync();
249 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 1 member, isGroup=true", new()
250 {
251 IsGroup = true,
252 Members = [new() { Id = memberMri }],
253 TenantId = _f.TenantId
254 });
255 Assert.Equal(400, result.StatusCode);
256 }
257
258 [Fact(Timeout = 5000)]
259 [Trait("Category", "Diagnostic")]
260 public async Task GroupChat_OneMember_WithBot()
261 {
262 (string memberMri, _, _) = await GetMemberMrisAsync();
263 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 1 member, bot, channelData.tenant", new()
264 {
265 IsGroup = true,
266 Bot = new() { Id = $"28:{_f.BotAppId}" },
267 Members = [new() { Id = memberMri }],
268 TenantId = _f.TenantId,
269 ChannelData = new { tenant = new { id = _f.TenantId } }
270 });
271 Assert.Equal(400, result.StatusCode);
272 }
273
274 [Fact(Timeout = 5000)]
275 [Trait("Category", "Diagnostic")]
276 public async Task GroupChat_ThreeMembers()
277 {
278 (string first, string? second, string? third) = await GetMemberMrisAsync();
279 Assert.NotNull(second);
280 Assert.NotNull(third);
281 DiagnosticResult result = await SendDiagnosticRequestAsync("Group Chat: 3 members, bot", new()
282 {
283 IsGroup = true,
284 Bot = new() { Id = $"28:{_f.BotAppId}" },
285 Members = [new() { Id = first }, new() { Id = second! }, new() { Id = third! }],
286 TenantId = _f.TenantId,
287 ChannelData = new { tenant = new { id = _f.TenantId } }
288 });
289 Assert.Equal(400, result.StatusCode);
290 }
291
292 // =========================================================================
293 // Channel thread variations
294 // =========================================================================
295
296 [Fact(Timeout = 5000)]
297 [Trait("Category", "Diagnostic")]
298 public async Task ChannelThread_WithActivity()
299 {
300 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: with activity", new()
301 {
302 IsGroup = true,
303 ChannelData = new { channel = new { id = _f.ChannelId } },
304 Activity = CoreActivity.CreateBuilder()
305 .WithType(ActivityType.Message)
306 .WithProperty("text", "[Diagnostic] channel thread")
307 .Build(),
308 TenantId = _f.TenantId
309 });
310 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
311 }
312
313 [Fact(Timeout = 5000)]
314 [Trait("Category", "Diagnostic")]
315 public async Task ChannelThread_NoActivity()
316 {
317 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: without activity", new()
318 {
319 IsGroup = true,
320 ChannelData = new { channel = new { id = _f.ChannelId } },
321 TenantId = _f.TenantId
322 });
323 Assert.Equal(400, result.StatusCode);
324 }
325
326 [Fact(Timeout = 5000)]
327 [Trait("Category", "Diagnostic")]
328 public async Task ChannelThread_WithMembersAndActivity()
329 {
330 (string memberMri, _, _) = await GetMemberMrisAsync();
331 DiagnosticResult result = await SendDiagnosticRequestAsync("Channel Thread: with members and activity", new()
332 {
333 IsGroup = true,
334 Members = [new() { Id = memberMri }],
335 ChannelData = new { channel = new { id = _f.ChannelId } },
336 Activity = CoreActivity.CreateBuilder()
337 .WithType(ActivityType.Message)
338 .WithProperty("text", "[Diagnostic] channel thread with members")
339 .Build(),
340 TenantId = _f.TenantId
341 });
342 Assert.True(result.StatusCode is 200 or 201, $"Expected 2xx, got {result.StatusCode}");
343 }
344}
345