microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
docs/update-release-process

Branches

Tags

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

Clone

HTTPS

Download ZIP

Tests/Microsoft.Teams.Api.Tests/Activities/Events/MeetingEndActivityTests.cs

297lines · modecode

1using System.Text.Json;
2
3using Microsoft.Teams.Api.Activities;
4using Microsoft.Teams.Api.Activities.Events;
5
6namespace Microsoft.Teams.Api.Tests.Activities.Events;
7
8public class MeetingEndActivityTests
9{
10 private static readonly JsonSerializerOptions CachedJsonSerializerOptions = new JsonSerializerOptions()
11 {
12 WriteIndented = true,
13 IndentSize = 2,
14 DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
15 };
16
17 public MeetingEndActivity SetupMeetingEndActivity()
18 {
19 return new MeetingEndActivity()
20 {
21 Value = new MeetingEndActivityValue()
22 {
23 Id = "id",
24 MeetingType = "meetingType",
25 JoinUrl = "https://teams.meetingjoin.url/somevalues",
26 Title = "Meeting For Teams.net",
27 EndTime = new DateTime(2025, 1, 1, 5, 30, 00),
28 },
29 Recipient = new Account()
30 {
31 Id = "recipientId",
32 Name = "recipientName"
33 },
34 ChannelId = new ChannelId("msteams"),
35
36 };
37 }
38
39 [Fact]
40 public void MeetingEndActivity_Props()
41 {
42 var activity = SetupMeetingEndActivity();
43
44 Assert.NotNull(activity.ToMeetingEnd());
45 ActivityType expectedEventType = new ActivityType("event");
46 Assert.Equal(expectedEventType.ToString(), activity.Type.Value);
47 Assert.True(activity.Name.IsMeetingEnd);
48 Assert.False(activity.Name.IsMeetingStart);
49 Assert.False(activity.IsStreaming);
50 var expectedSubmitException = "Unable to cast object of type 'Microsoft.Teams.Api.Activities.Events.MeetingEndActivity' to type 'Microsoft.Teams.Api.Activities.MessageActivity'.";
51 var ex = Assert.Throws<System.InvalidCastException>(() => activity.ToMessage());
52 Assert.Equal(expectedSubmitException, ex.Message);
53 }
54
55 [Fact]
56 public void MeetingEndActivity_JsonSerialize()
57 {
58 var activity = SetupMeetingEndActivity();
59
60 var json = JsonSerializer.Serialize(activity, CachedJsonSerializerOptions);
61
62 Assert.Equal(File.ReadAllText(
63 @"../../../Json/Activity/Events/MeetingEndActivity.json"
64 ), json);
65 }
66
67
68 [Fact]
69 public void MeetingEndActivity_JsonSerialize_Object()
70 {
71 MeetingEndActivity activity = SetupMeetingEndActivity();
72
73 var json = JsonSerializer.Serialize(activity, CachedJsonSerializerOptions);
74
75 string expectedPath = "Activity.Event.Application/vnd.microsoft.meetingEnd";
76 Assert.Equal(expectedPath, activity.GetPath());
77 Assert.Equal(File.ReadAllText(
78 @"../../../Json/Activity/Events/MeetingEndActivity.json"
79 ), json);
80 }
81
82 [Fact]
83 public void MeetingEndActivity_JsonSerialize_Derived_From_Class()
84 {
85 EventActivity activity = SetupMeetingEndActivity();
86
87 var json = JsonSerializer.Serialize(activity, CachedJsonSerializerOptions);
88
89 string expectedPath = "Activity.Event.Application/vnd.microsoft.meetingEnd";
90 Assert.Equal(expectedPath, activity.GetPath());
91 Assert.False(activity.Name.IsMeetingStart);
92 Assert.True(activity.Name.IsMeetingEnd);
93 Assert.Equal(File.ReadAllText(
94 @"../../../Json/Activity/Events/MeetingEndActivity.json"
95 ), json);
96 }
97
98 [Fact]
99 public void MeetingEndActivity_JsonSerialize_Derived_From_Interface()
100 {
101 IActivity activity = SetupMeetingEndActivity();
102
103 var json = JsonSerializer.Serialize(activity, CachedJsonSerializerOptions);
104
105 string expectedPath = "Activity.Event.Application/vnd.microsoft.meetingEnd";
106 Assert.Equal(expectedPath, activity.GetPath());
107 Assert.Equal(File.ReadAllText(
108 @"../../../Json/Activity/Events/MeetingEndActivity.json"
109 ), json);
110 }
111
112 [Fact]
113 public void MeetingEndActivity_JsonDeserialize()
114 {
115 var json = File.ReadAllText(@"../../../Json/Activity/Events/MeetingEndActivity.json");
116 var activity = JsonSerializer.Deserialize<MeetingEndActivity>(json);
117 var expected = SetupMeetingEndActivity();
118
119 Assert.Equal(expected.ToString(), activity!.ToString());
120 Assert.Equal(typeof(MeetingEndActivity), activity.Name.ToType());
121 Assert.Equal("Application/vnd.microsoft.meetingEnd", activity.Name.ToPrettyString());
122 Assert.NotNull(activity.ToMeetingEnd());
123 }
124
125
126 [Fact]
127 public void MeetingEndActivity_JsonDeserialize_Derived()
128 {
129 var json = File.ReadAllText(@"../../../Json/Activity/Events/MeetingEndActivity.json");
130 var activity = JsonSerializer.Deserialize<EventActivity>(json);
131 var expected = SetupMeetingEndActivity();
132
133 Assert.Equal(expected.ToString(), activity!.ToString());
134 Assert.NotNull(activity.ToEvent());
135 Assert.Equal(typeof(MeetingEndActivity), activity.Name.ToType());
136 var expectedSubmitException = "Unable to cast object of type 'Microsoft.Teams.Api.Activities.Events.MeetingEndActivity' to type 'Microsoft.Teams.Api.Activities.InstallUpdateActivity'.";
137 var ex = Assert.Throws<System.InvalidCastException>(() => activity.ToInstallUpdate());
138 Assert.Equal(expectedSubmitException, ex.Message);
139 }
140
141 [Fact]
142 public void MeetingEndActivity_JsonDeserialize_Activity_Derived()
143 {
144 var json = File.ReadAllText(@"../../../Json/Activity/Events/MeetingEndActivity.json");
145 var activity = JsonSerializer.Deserialize<Activity>(json);
146 var expected = SetupMeetingEndActivity();
147
148 Assert.Equal(expected.ToString(), activity!.ToString());
149 Assert.NotNull(activity.ToEvent());
150 var expectedSubmitException = "Unable to cast object of type 'Microsoft.Teams.Api.Activities.Events.MeetingEndActivity' to type 'Microsoft.Teams.Api.Activities.InstallUpdateActivity'.";
151 var ex = Assert.Throws<System.InvalidCastException>(() => activity.ToInstallUpdate());
152 Assert.Equal(expectedSubmitException, ex.Message);
153 }
154
155 [Fact]
156 public void MeetingEndActivity_JsonDeserialize_TeamsPayload_PascalCase()
157 {
158 // This test verifies that we can deserialize the actual JSON payload sent by Teams
159 // which uses PascalCase for value object properties (as reported in the issue)
160 var json = @"{
161 ""name"": ""application/vnd.microsoft.meetingEnd"",
162 ""type"": ""event"",
163 ""timestamp"": ""2025-10-31T11:38:15.5375726Z"",
164 ""id"": ""1761910695513"",
165 ""channelId"": ""msteams"",
166 ""serviceUrl"": ""https://smba.trafficmanager.net/emea/167c22a9-1b2e-439c-ad74-cc77e9e118d8/"",
167 ""from"": {
168 ""id"": ""29:1geTNfcvfJus0De5z4gr7HeHGMOuln9LY8aHFGtwBqhOl7ZYQFcM2CL1ODjhgHE1XTq3vBeeRlGGGPvFWi0BzRw"",
169 ""name"": """",
170 ""aadObjectId"": ""86a23cfc-f78e-424a-8947-7ae0ce242da1""
171 },
172 ""conversation"": {
173 ""isGroup"": true,
174 ""conversationType"": ""groupChat"",
175 ""tenantId"": ""167c22a9-1b2e-439c-ad74-cc77e9e118d8"",
176 ""id"": ""19:meeting_MTRmMTQ5NDYtMTYyYi00NmNlLWI4ZTQtN2I1MTYzM2RkYTg3@thread.v2""
177 },
178 ""recipient"": {
179 ""id"": ""28:c9a052ed-f68c-4227-b081-01da0669c49c"",
180 ""name"": ""teams-bot""
181 },
182 ""value"": {
183 ""MeetingType"": ""Scheduled"",
184 ""Title"": ""asdasd"",
185 ""Id"": ""MCMxOTptZWV0aW5nX01UUm1NVFE1TkRZdE1UWXlZaTAwTm1ObExXSTRaVFF0TjJJMU1UWXpNMlJrWVRnM0B0aHJlYWQudjIjMA=="",
186 ""JoinUrl"": ""https://teams.microsoft.com/l/meetup-join/19%3ameeting_MTRmMTQ5NDYtMTYyYi00NmNlLWI4ZTQtN2I1MTYzM2RkYTg3%40thread.v2/0?context=%7b%22Tid%22%3a%22167c22a9-1b2e-439c-ad74-cc77e9e118d8%22%2c%22Oid%22%3a%2286a23cfc-f78e-424a-8947-7ae0ce242da1%22%7d"",
187 ""EndTime"": ""2025-10-31T11:38:15.5375726Z""
188 },
189 ""locale"": ""en-US""
190 }";
191
192 var activity = JsonSerializer.Deserialize<MeetingEndActivity>(json);
193
194 Assert.NotNull(activity);
195 Assert.NotNull(activity.Value);
196 Assert.Equal("MCMxOTptZWV0aW5nX01UUm1NVFE1TkRZdE1UWXlZaTAwTm1ObExXSTRaVFF0TjJJMU1UWXpNMlJrWVRnM0B0aHJlYWQudjIjMA==", activity.Value.Id);
197 Assert.Equal("Scheduled", activity.Value.MeetingType);
198 Assert.Equal("asdasd", activity.Value.Title);
199 Assert.Equal("https://teams.microsoft.com/l/meetup-join/19%3ameeting_MTRmMTQ5NDYtMTYyYi00NmNlLWI4ZTQtN2I1MTYzM2RkYTg3%40thread.v2/0?context=%7b%22Tid%22%3a%22167c22a9-1b2e-439c-ad74-cc77e9e118d8%22%2c%22Oid%22%3a%2286a23cfc-f78e-424a-8947-7ae0ce242da1%22%7d", activity.Value.JoinUrl);
200 Assert.Equal(new DateTime(2025, 10, 31, 11, 38, 15, 537, DateTimeKind.Utc).AddTicks(5726), activity.Value.EndTime);
201 }
202
203 [Fact]
204 public void MeetingEndActivity_JsonSerialize_PascalCase_RoundTrip()
205 {
206 // Verify that serialization produces PascalCase and can be deserialized back
207 var activity = new MeetingEndActivity()
208 {
209 Value = new MeetingEndActivityValue()
210 {
211 Id = "testId123",
212 MeetingType = "Scheduled",
213 JoinUrl = "https://teams.microsoft.com/l/meetup-join/test",
214 Title = "Test Meeting",
215 EndTime = new DateTime(2025, 12, 10, 15, 0, 0, DateTimeKind.Utc),
216 },
217 Recipient = new Account()
218 {
219 Id = "recipientId",
220 Name = "recipientName"
221 },
222 ChannelId = new ChannelId("msteams"),
223 };
224
225 var json = JsonSerializer.Serialize(activity, CachedJsonSerializerOptions);
226
227 // Verify PascalCase in serialized JSON
228 Assert.Contains("\"Id\":", json);
229 Assert.Contains("\"MeetingType\":", json);
230 Assert.Contains("\"JoinUrl\":", json);
231 Assert.Contains("\"Title\":", json);
232 Assert.Contains("\"EndTime\":", json);
233
234 // Verify round-trip deserialization
235 var deserialized = JsonSerializer.Deserialize<MeetingEndActivity>(json);
236 Assert.NotNull(deserialized);
237 Assert.Equal(activity.Value.Id, deserialized.Value.Id);
238 Assert.Equal(activity.Value.MeetingType, deserialized.Value.MeetingType);
239 Assert.Equal(activity.Value.Title, deserialized.Value.Title);
240 Assert.Equal(activity.Value.JoinUrl, deserialized.Value.JoinUrl);
241 Assert.Equal(activity.Value.EndTime, deserialized.Value.EndTime);
242 }
243
244 [Fact]
245 public void MeetingEndActivity_JsonDeserialize_TeamsPayload_As_EventActivity()
246 {
247 // Verify deserialization works when deserializing as EventActivity base class
248 var json = @"{
249 ""name"": ""application/vnd.microsoft.meetingEnd"",
250 ""type"": ""event"",
251 ""channelId"": ""msteams"",
252 ""value"": {
253 ""MeetingType"": ""Scheduled"",
254 ""Title"": ""Test Meeting"",
255 ""Id"": ""testId"",
256 ""JoinUrl"": ""https://teams.microsoft.com/test"",
257 ""EndTime"": ""2025-12-10T15:00:00Z""
258 }
259 }";
260
261 var activity = JsonSerializer.Deserialize<EventActivity>(json);
262
263 Assert.NotNull(activity);
264 Assert.True(activity.Name.IsMeetingEnd);
265 var meetingEndActivity = activity as MeetingEndActivity;
266 Assert.NotNull(meetingEndActivity);
267 Assert.Equal("testId", meetingEndActivity.Value.Id);
268 Assert.Equal("Scheduled", meetingEndActivity.Value.MeetingType);
269 }
270
271 [Fact]
272 public void MeetingEndActivity_JsonDeserialize_TeamsPayload_As_IActivity()
273 {
274 // Verify deserialization works when deserializing as IActivity interface
275 var json = @"{
276 ""name"": ""application/vnd.microsoft.meetingEnd"",
277 ""type"": ""event"",
278 ""channelId"": ""msteams"",
279 ""value"": {
280 ""MeetingType"": ""Adhoc"",
281 ""Title"": ""Quick Meeting"",
282 ""Id"": ""meetingId456"",
283 ""JoinUrl"": ""https://teams.microsoft.com/join/456"",
284 ""EndTime"": ""2025-12-10T16:30:00Z""
285 }
286 }";
287
288 var activity = JsonSerializer.Deserialize<IActivity>(json);
289
290 Assert.NotNull(activity);
291 var meetingEndActivity = activity as MeetingEndActivity;
292 Assert.NotNull(meetingEndActivity);
293 Assert.Equal("meetingId456", meetingEndActivity.Value.Id);
294 Assert.Equal("Adhoc", meetingEndActivity.Value.MeetingType);
295 Assert.Equal("Quick Meeting", meetingEndActivity.Value.Title);
296 }
297}