microsoft/teams.net

Public

mirrored from https://github.com/microsoft/teams.netAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
next/oauth-card-null-ref-bug

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/test/Microsoft.Teams.Bot.Apps.UnitTests/TeamsActivityTests.cs

429lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.Teams.Bot.Apps.Schema;
5using Microsoft.Teams.Bot.Apps.Schema.Entities;
6using Microsoft.Teams.Bot.Core.Schema;
7namespace Microsoft.Teams.Bot.Apps.UnitTests;
8
9public class TeamsActivityTests
10{
11 [Fact]
12 public void DownCastTeamsActivity_To_CoreActivity()
13 {
14 CoreActivity activity = CoreActivity.FromJsonString(json);
15 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", activity.Conversation!.Id);
16 TeamsActivity teamsActivity = TeamsActivity.FromActivity(activity);
17 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", teamsActivity.Conversation!.Id);
18
19 static void AssertCid(CoreActivity a)
20 {
21 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", a.Conversation!.Id);
22 }
23 AssertCid(teamsActivity);
24
25 }
26
27 [Fact]
28 public void DownCastTeamsActivity_To_CoreActivity_FromBuilder()
29 {
30
31 TeamsActivity teamsActivity = TeamsActivity
32 .CreateBuilder()
33 .WithConversation(new Conversation() { Id = "19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856" })
34 .Build();
35
36 static void AssertCid(CoreActivity a)
37 {
38 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", a.Conversation!.Id);
39 }
40 AssertCid(teamsActivity);
41 }
42
43 [Fact]
44 public void DownCastTeamsActivity_To_CoreActivity_WithoutRebase()
45 {
46 TeamsActivity teamsActivity = new()
47 {
48 Conversation = new TeamsConversation()
49 {
50 Id = "19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856"
51 }
52 };
53 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", teamsActivity.Conversation!.Id);
54
55 static void AssertCid(CoreActivity a)
56 {
57 Assert.Equal("19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856", a.Conversation!.Id);
58 }
59 AssertCid(teamsActivity);
60
61 }
62
63
64 [Fact]
65 public void AddMentionEntity_To_TeamsActivity()
66 {
67 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
68 activity
69 .AddMention(new ConversationAccount
70 {
71 Id = "user-id-01",
72 Name = "rido"
73 }, "ridotest");
74
75
76
77 Assert.NotNull(activity.Entities);
78 Assert.Single(activity.Entities);
79 Assert.Equal("mention", activity.Entities[0].Type);
80 MentionEntity? mention = activity.Entities[0] as MentionEntity;
81 Assert.NotNull(mention);
82 Assert.Equal("user-id-01", mention.Mentioned?.Id);
83 Assert.Equal("rido", mention.Mentioned?.Name);
84 Assert.Equal("<at>ridotest</at>", mention.Text);
85
86 string jsonResult = activity.ToJson();
87 Assert.Contains("user-id-01", jsonResult);
88 }
89
90 [Fact]
91 public void AddMentionEntity_Serialize_From_CoreActivity()
92 {
93 TeamsActivity activity = TeamsActivity.FromActivity(new CoreActivity(ActivityType.Message));
94 activity.AddMention(new ConversationAccount
95 {
96 Id = "user-id-01",
97 Name = "rido"
98 }, "ridotest");
99
100
101
102 Assert.NotNull(activity.Entities);
103 Assert.Single(activity.Entities);
104 Assert.Equal("mention", activity.Entities[0].Type);
105 MentionEntity? mention = activity.Entities[0] as MentionEntity;
106 Assert.NotNull(mention);
107 Assert.Equal("user-id-01", mention.Mentioned?.Id);
108 Assert.Equal("rido", mention.Mentioned?.Name);
109 Assert.Equal("<at>ridotest</at>", mention.Text);
110
111 static void SerializeAndAssert(CoreActivity a)
112 {
113 string json = a.ToJson();
114 Assert.Contains("user-id-01", json);
115 }
116
117 SerializeAndAssert(activity);
118 }
119
120
121 [Fact]
122 public void TeamsActivityBuilder_FluentAPI()
123 {
124 TeamsActivity activity = TeamsActivity.CreateBuilder()
125 .WithType(TeamsActivityType.Message)
126 .WithText("Hello World")
127 .WithChannelId("msteams")
128 .AddMention(new ConversationAccount
129 {
130 Id = "user-123",
131 Name = "TestUser"
132 })
133 .Build();
134
135 Assert.Equal(ActivityType.Message, activity.Type);
136 Assert.Equal("<at>TestUser</at> Hello World", activity.Properties["text"]);
137 Assert.Equal("msteams", activity.ChannelId);
138 Assert.NotNull(activity.Entities);
139 Assert.Single(activity.Entities);
140
141 MentionEntity? mention = activity.Entities[0] as MentionEntity;
142 Assert.NotNull(mention);
143 Assert.Equal("user-123", mention.Mentioned?.Id);
144 Assert.Equal("TestUser", mention.Mentioned?.Name);
145 }
146
147 [Fact]
148 public void Serialize_TeamsActivity_WithEntities()
149 {
150 TeamsActivity activity = TeamsActivity.CreateBuilder()
151 .WithType(ActivityType.Message)
152 .WithText("Hello World")
153 .WithChannelId("msteams")
154 .Build();
155
156 activity.AddClientInfo("Web", "US", "America/Los_Angeles", "en-US");
157
158 string jsonResult = activity.ToJson();
159 Assert.Contains("clientInfo", jsonResult);
160 Assert.Contains("Web", jsonResult);
161 Assert.Contains("Hello World", jsonResult);
162 }
163
164 [Fact]
165 public void Deserialize_TeamsActivity_Invoke_WithValue()
166 {
167 //TeamsActivity activity = CoreActivity.FromJsonString<TeamsActivity>(jsonInvoke);
168 TeamsActivity activity = TeamsActivity.FromActivity(CoreActivity.FromJsonString(jsonInvoke));
169 Assert.NotNull(activity.Value);
170 string feedback = activity.Value?["action"]?["data"]?["feedback"]?.ToString()!;
171 Assert.Equal("test invokes", feedback);
172 }
173
174 [Fact]
175 public void Serialize_Does_Not_Repeat_AAdObjectId()
176 {
177 CoreActivity coreActivity = CoreActivity.FromJsonString("""
178 {
179 "type": "message",
180 "recipient": {
181 "id": "rec1",
182 "name": "recname",
183 "aadObjectId": "rec-aadId-1"
184 }
185 }
186 """);
187 TeamsActivity teamsActivity = TeamsActivity.FromActivity(coreActivity);
188 string json = teamsActivity.ToJson();
189 string[] found = json.Split("aadObjectId");
190 Assert.Equal(1, found.Length - 1); // only one occurrence
191 }
192
193 [Fact]
194 public void FromActivity_Overrides_Recipient()
195 {
196 CoreActivity coreActivity = CoreActivity.FromJsonString("""
197 {
198 "type": "message",
199 "recipient": {
200 "id": "rec1",
201 "name": "recname",
202 "agenticUserId": "0d5eb8a3-1642-4e63-9ccc-a89aa461716c",
203 "agenticAppId": "3fc62d4f-b04e-4c71-878b-02a2fa395fe2",
204 "agenticAppBlueprintId": "24fff850-d7fb-4d32-a6e7-a1178874430e"
205 }
206 }
207 """);
208 TeamsActivity teamsActivity = TeamsActivity.FromActivity(coreActivity);
209 Assert.Equal("rec1", teamsActivity.Recipient?.Id);
210 Assert.Equal("recname", teamsActivity.Recipient?.Name);
211 AgenticIdentity? agenticIdentity = AgenticIdentity.FromProperties(teamsActivity.Recipient?.Properties);
212 Assert.NotNull(agenticIdentity);
213 Assert.Equal("0d5eb8a3-1642-4e63-9ccc-a89aa461716c", agenticIdentity.AgenticUserId);
214 Assert.Equal("3fc62d4f-b04e-4c71-878b-02a2fa395fe2", agenticIdentity.AgenticAppId);
215 Assert.Equal("24fff850-d7fb-4d32-a6e7-a1178874430e", agenticIdentity.AgenticAppBlueprintId);
216 }
217
218 [Fact]
219 public void FromActivity_ReturnsDerivedType_WhenRegistered()
220 {
221 CoreActivity coreActivity = new(ActivityType.Message);
222 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
223
224 Assert.IsType<MessageActivity>(activity);
225 }
226
227 [Fact]
228 public void FromActivity_ReturnsBaseType_WhenNotRegistered()
229 {
230 CoreActivity coreActivity = new("unknownType");
231 TeamsActivity activity = TeamsActivity.FromActivity(coreActivity);
232
233 Assert.Equal(typeof(TeamsActivity), activity.GetType());
234 Assert.Equal("unknownType", activity.Type);
235 }
236
237 [Fact]
238 public void EmptyTeamsActivity()
239 {
240 string minActivityJson = """
241 {
242 "type": "message"
243 }
244 """;
245
246 TeamsActivity teamsActivity = TeamsActivity.CreateBuilder().Build();
247 Assert.NotNull(teamsActivity);
248 string json = teamsActivity.ToJson();
249 Assert.Equal(minActivityJson, json);
250 }
251
252 [Fact]
253 public void BaseFieldsAsBaseTypes()
254 {
255 CoreActivity ca = new();
256 ca.Conversation = new Conversation() { Id = "conv1" };
257 ca.Conversation.Properties.Add("tenantId", "tenant-1");
258 CoreActivity ta = TeamsActivity.FromActivity(ca);
259 if (ta.Conversation is not null)
260 {
261 Assert.NotNull(ta.Conversation);
262 Assert.Equal("conv1", ta.Conversation.Id);
263 Assert.Empty(ta.Conversation.Properties);
264 }
265 else
266 {
267 Assert.Fail("Conversation not set");
268 }
269 }
270
271 [Fact]
272 public void Deserialize_with_Conversation_and_Tenant()
273 {
274 string json = """
275 {
276 "type" : "message",
277 "conversation": {
278 "id" : "conv1",
279 "tenantId" : "tenant-1"
280 }
281 }
282 """;
283 CoreActivity ca = CoreActivity.FromJsonString(json);
284 Assert.NotNull(ca);
285 Assert.NotNull(ca.Conversation);
286 Assert.Equal("conv1", ca.Conversation.Id);
287 if (ca.Conversation.Properties.TryGetValue("tenantId", out object? outTenantId))
288 {
289 Assert.Equal("tenant-1", outTenantId?.ToString());
290 }
291 else
292 {
293 Assert.Fail("conversation tenant not set");
294 }
295 TeamsActivity ta = TeamsActivity.FromActivity(ca);
296 Assert.NotNull(ta);
297 Assert.NotNull(ta.Conversation);
298 Assert.Equal("conv1", ta.Conversation.Id);
299 Assert.Equal("tenant-1", ta.Conversation.TenantId);
300 }
301
302
303 private const string jsonInvoke = """
304 {
305 "type": "invoke",
306 "channelId": "msteams",
307 "id": "f:17b96347-e8b4-f340-10bc-eb52fc1a6ad4",
308 "serviceUrl": "https://smba.trafficmanager.net/amer/56653e9d-2158-46ee-90d7-675c39642038/",
309 "channelData": {
310 "tenant": {
311 "id": "56653e9d-2158-46ee-90d7-675c39642038"
312 },
313 "source": {
314 "name": "message"
315 },
316 "legacy": {
317 "replyToId": "1:12SWreU4430kJA9eZCb1kXDuo6A8KdDEGB6d9TkjuDYM"
318 }
319 },
320 "from": {
321 "id": "29:1uMVvhoAyfTqdMsyvHL0qlJTTfQF9MOUSI8_cQts2kdSWEZVDyJO2jz-CsNOhQcdYq1Bw4cHT0__O6XDj4AZ-Jw",
322 "name": "Rido",
323 "aadObjectId": "c5e99701-2a32-49c1-a660-4629ceeb8c61"
324 },
325 "recipient": {
326 "id": "28:aabdbd62-bc97-4afb-83ee-575594577de5",
327 "name": "ridobotlocal"
328 },
329 "conversation": {
330 "id": "a:17vxw6pGQOb3Zfh8acXT8m_PqHycYpaFgzu2mFMUfkT-h0UskMctq5ZPPc7FIQxn2bx7rBSm5yE_HeUXsCcKZBrv77RgorB3_1_pAdvMhi39ClxQgawzyQ9GBFkdiwOxT",
331 "conversationType": "personal",
332 "tenantId": "56653e9d-2158-46ee-90d7-675c39642038"
333 },
334 "entities": [
335 {
336 "locale": "en-US",
337 "country": "US",
338 "platform": "Web",
339 "timezone": "America/Los_Angeles",
340 "type": "clientInfo"
341 }
342 ],
343 "value": {
344 "action": {
345 "type": "Action.Execute",
346 "title": "Submit Feedback",
347 "data": {
348 "feedback": "test invokes"
349 }
350 },
351 "trigger": "manual"
352 },
353 "name": "adaptiveCard/action",
354 "timestamp": "2026-01-07T06:04:59.89Z",
355 "localTimestamp": "2026-01-06T22:04:59.89-08:00",
356 "replyToId": "1767765488332",
357 "locale": "en-US",
358 "localTimezone": "America/Los_Angeles"
359 }
360 """;
361
362 private const string json = """
363 {
364 "type": "message",
365 "channelId": "msteams",
366 "text": "\u003Cat\u003Eridotest\u003C/at\u003E reply to thread",
367 "id": "1759944781430",
368 "serviceUrl": "https://smba.trafficmanager.net/amer/50612dbb-0237-4969-b378-8d42590f9c00/",
369 "channelData": {
370 "teamsChannelId": "19:6848757105754c8981c67612732d9aa7@thread.tacv2",
371 "teamsTeamId": "19:66P469zibfbsGI-_a0aN_toLTZpyzS6u7CT3TsXdgPw1@thread.tacv2",
372 "channel": {
373 "id": "19:6848757105754c8981c67612732d9aa7@thread.tacv2"
374 },
375 "team": {
376 "id": "19:66P469zibfbsGI-_a0aN_toLTZpyzS6u7CT3TsXdgPw1@thread.tacv2"
377 },
378 "tenant": {
379 "id": "50612dbb-0237-4969-b378-8d42590f9c00"
380 }
381 },
382 "from": {
383 "id": "29:17bUvCasIPKfQIXHvNzcPjD86fwm6GkWc1PvCGP2-NSkNb7AyGYpjQ7Xw-XgTwaHW5JxZ4KMNDxn1kcL8fwX1Nw",
384 "name": "rido",
385 "aadObjectId": "b15a9416-0ad3-4172-9210-7beb711d3f70"
386 },
387 "recipient": {
388 "id": "28:0b6fe6d1-fece-44f7-9a48-56465e2d5ab8",
389 "name": "ridotest"
390 },
391 "conversation": {
392 "id": "19:6848757105754c8981c67612732d9aa7@thread.tacv2;messageid=1759881511856",
393 "isGroup": true,
394 "conversationType": "channel",
395 "tenantId": "50612dbb-0237-4969-b378-8d42590f9c00"
396 },
397 "entities": [
398 {
399 "mentioned": {
400 "id": "28:0b6fe6d1-fece-44f7-9a48-56465e2d5ab8",
401 "name": "ridotest"
402 },
403 "text": "\u003Cat\u003Eridotest\u003C/at\u003E",
404 "type": "mention"
405 },
406 {
407 "locale": "en-US",
408 "country": "US",
409 "platform": "Web",
410 "timezone": "America/Los_Angeles",
411 "type": "clientInfo"
412 }
413 ],
414 "textFormat": "plain",
415 "attachments": [
416 {
417 "contentType": "text/html",
418 "content": "\u003Cp\u003E\u003Cspan itemtype=\u0022http://schema.skype.com/Mention\u0022 itemscope=\u0022\u0022 itemid=\u00220\u0022\u003Eridotest\u003C/span\u003E\u0026nbsp;reply to thread\u003C/p\u003E"
419 }
420 ],
421 "timestamp": "2025-10-08T17:33:01.4953744Z",
422 "localTimestamp": "2025-10-08T10:33:01.4953744-07:00",
423 "locale": "en-US",
424 "localTimezone": "America/Los_Angeles"
425 }
426 """;
427
428
429}
430