microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
feature/oauthflow-fixes

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/test/Microsoft.Teams.Apps.BotBuilder.UnitTests/CompatBotAdapterTests.cs

291lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using Microsoft.AspNetCore.Http;
5using Microsoft.Bot.Builder;
6using Microsoft.Bot.Schema;
7using Microsoft.Extensions.Configuration;
8using Microsoft.Extensions.Logging.Abstractions;
9using Microsoft.Teams.Core;
10using Microsoft.Teams.Core.Schema;
11using Moq;
12
13namespace Microsoft.Teams.Apps.BotBuilder.UnitTests
14{
15 public class TeamsBotAdapterTests
16 {
17 [Fact]
18 public async Task DeleteActivityAsync_UsesConversationReferenceValues()
19 {
20 // Arrange
21 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
22 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
23
24 ConversationReference reference = new()
25 {
26 ActivityId = "activity-123",
27 ServiceUrl = "https://smba.trafficmanager.net/teams/",
28 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-456" },
29 ChannelId = "msteams"
30 };
31
32 ITurnContext turnContext = CreateMockTurnContext("https://different-service-url.com/");
33
34 // Act
35 await adapter.DeleteActivityAsync(turnContext, reference, CancellationToken.None);
36
37 // Assert
38 mockConversationClient.Verify(
39 c => c.DeleteActivityAsync(
40 "conversation-456",
41 "activity-123",
42 It.Is<Uri>(u => u.ToString().TrimEnd('/') == "https://smba.trafficmanager.net/teams"),
43 It.IsAny<AgenticIdentity>(),
44 null,
45 It.IsAny<CancellationToken>()),
46 Times.Once);
47 }
48
49 [Fact]
50 public async Task DeleteActivityAsync_FallsBackToTurnContextServiceUrl_WhenReferenceServiceUrlIsNull()
51 {
52 // Arrange
53 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
54 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
55
56 ConversationReference reference = new()
57 {
58 ActivityId = "activity-123",
59 ServiceUrl = null, // Not set in reference
60 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-456" },
61 ChannelId = "msteams"
62 };
63
64 ITurnContext turnContext = CreateMockTurnContext("https://fallback-service-url.com/");
65
66 // Act
67 await adapter.DeleteActivityAsync(turnContext, reference, CancellationToken.None);
68
69 // Assert
70 mockConversationClient.Verify(
71 c => c.DeleteActivityAsync(
72 "conversation-456",
73 "activity-123",
74 It.Is<Uri>(u => u.ToString().TrimEnd('/') == "https://fallback-service-url.com"),
75 It.IsAny<AgenticIdentity>(),
76 null,
77 It.IsAny<CancellationToken>()),
78 Times.Once);
79 }
80
81 [Fact]
82 public async Task DeleteActivityAsync_ThrowsArgumentException_WhenConversationIdIsNull()
83 {
84 // Arrange
85 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
86 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
87
88 ConversationReference reference = new()
89 {
90 ActivityId = "activity-123",
91 ServiceUrl = "https://smba.trafficmanager.net/teams/",
92 Conversation = null, // No conversation
93 ChannelId = "msteams"
94 };
95
96 ITurnContext turnContext = CreateMockTurnContext("https://service-url.com/");
97
98 // Act & Assert
99 await Assert.ThrowsAsync<ArgumentException>(
100 async () => await adapter.DeleteActivityAsync(turnContext, reference, CancellationToken.None));
101 }
102
103 [Fact]
104 public async Task DeleteActivityAsync_ThrowsArgumentException_WhenActivityIdIsNull()
105 {
106 // Arrange
107 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
108 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
109
110 ConversationReference reference = new()
111 {
112 ActivityId = null, // No activity ID
113 ServiceUrl = "https://smba.trafficmanager.net/teams/",
114 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-456" },
115 ChannelId = "msteams"
116 };
117
118 ITurnContext turnContext = CreateMockTurnContext("https://service-url.com/");
119
120 // Act & Assert
121 await Assert.ThrowsAsync<ArgumentException>(
122 async () => await adapter.DeleteActivityAsync(turnContext, reference, CancellationToken.None));
123 }
124
125 [Fact]
126 public async Task DeleteActivityAsync_ThrowsArgumentException_WhenServiceUrlIsNull()
127 {
128 // Arrange
129 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
130 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
131
132 ConversationReference reference = new()
133 {
134 ActivityId = "activity-123",
135 ServiceUrl = null, // No service URL in reference
136 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-456" },
137 ChannelId = "msteams"
138 };
139
140 ITurnContext turnContext = CreateMockTurnContext(null); // No service URL in turn context either
141
142 // Act & Assert
143 await Assert.ThrowsAsync<ArgumentException>(
144 async () => await adapter.DeleteActivityAsync(turnContext, reference, CancellationToken.None));
145 }
146
147 [Fact]
148 public async Task SendActivitiesAsync_SetsServiceUrlFromTurnContext()
149 {
150 // Arrange
151 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
152 mockConversationClient.Setup(c => c.SendActivityAsync(
153 It.IsAny<CoreActivity>(),
154 It.IsAny<Dictionary<string, string>?>(),
155 It.IsAny<CancellationToken>()))
156 .ReturnsAsync(new SendActivityResponse { Id = "sent-123" });
157
158 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
159
160 Activity activity = new()
161 {
162 Type = ActivityTypes.Message,
163 Text = "Hello",
164 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-123" },
165 ServiceUrl = null // ServiceUrl not set on activity
166 };
167
168 ITurnContext turnContext = CreateMockTurnContext("https://turn-context-service-url.com/");
169
170 // Act
171 ResourceResponse[] responses = await adapter.SendActivitiesAsync(turnContext, [activity], CancellationToken.None);
172
173 // Assert
174 Assert.Single(responses);
175 Assert.Equal("sent-123", responses[0].Id);
176
177 mockConversationClient.Verify(
178 c => c.SendActivityAsync(
179 It.Is<CoreActivity>(a => a.ServiceUrl != null && a.ServiceUrl.ToString().TrimEnd('/') == "https://turn-context-service-url.com"),
180 It.IsAny<Dictionary<string, string>?>(),
181 It.IsAny<CancellationToken>()),
182 Times.Once);
183 }
184
185 [Fact]
186 public async Task UpdateActivityAsync_SetsServiceUrlFromTurnContext()
187 {
188 // Arrange
189 Mock<ConversationClient> mockConversationClient = CreateMockConversationClient();
190 mockConversationClient.Setup(c => c.UpdateActivityAsync(
191 It.IsAny<string>(),
192 It.IsAny<string>(),
193 It.IsAny<CoreActivity>(),
194 It.IsAny<bool>(),
195 It.IsAny<AgenticIdentity?>(),
196 It.IsAny<Dictionary<string, string>?>(),
197 It.IsAny<CancellationToken>()))
198 .ReturnsAsync(new UpdateActivityResponse { Id = "updated-123" });
199
200 TeamsBotAdapter adapter = CreateCompatBotAdapter(mockConversationClient.Object);
201
202 Activity activity = new()
203 {
204 Type = ActivityTypes.Message,
205 Id = "activity-123",
206 Text = "Updated message",
207 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "conversation-123" },
208 ServiceUrl = null // ServiceUrl not set on activity
209 };
210
211 ITurnContext turnContext = CreateMockTurnContext("https://turn-context-service-url.com/");
212
213 // Act
214 ResourceResponse response = await adapter.UpdateActivityAsync(turnContext, activity, CancellationToken.None);
215
216 // Assert
217 Assert.Equal("updated-123", response.Id);
218
219 mockConversationClient.Verify(
220 c => c.UpdateActivityAsync(
221 "conversation-123",
222 "activity-123",
223 It.Is<CoreActivity>(a => a.ServiceUrl != null && a.ServiceUrl.ToString().TrimEnd('/') == "https://turn-context-service-url.com"),
224 It.IsAny<bool>(),
225 It.IsAny<AgenticIdentity?>(),
226 It.IsAny<Dictionary<string, string>?>(),
227 It.IsAny<CancellationToken>()),
228 Times.Once);
229 }
230
231 private static Mock<ConversationClient> CreateMockConversationClient()
232 {
233 Mock<ConversationClient> mock = new(
234 new HttpClient(),
235 NullLogger<ConversationClient>.Instance);
236
237 mock.Setup(c => c.DeleteActivityAsync(
238 It.IsAny<string>(),
239 It.IsAny<string>(),
240 It.IsAny<Uri>(),
241 It.IsAny<AgenticIdentity>(),
242 It.IsAny<Dictionary<string, string>>(),
243 It.IsAny<CancellationToken>()))
244 .Returns(Task.CompletedTask);
245
246 mock.Setup(c => c.SendActivityAsync(
247 It.IsAny<CoreActivity>(),
248 It.IsAny<Dictionary<string, string>?>(),
249 It.IsAny<CancellationToken>()))
250 .ReturnsAsync(new SendActivityResponse { Id = "default-sent-id" });
251
252 return mock;
253 }
254
255 private static TeamsBotAdapter CreateCompatBotAdapter(ConversationClient conversationClient)
256 {
257 Mock<UserTokenClient> mockUserTokenClient = new(
258 new HttpClient(),
259 Mock.Of<IConfiguration>(),
260 NullLogger<UserTokenClient>.Instance);
261 BotApplication botApplication = new(
262 conversationClient,
263 mockUserTokenClient.Object,
264 NullLogger<BotApplication>.Instance);
265
266 return new TeamsBotAdapter(
267 botApplication,
268 Mock.Of<IHttpContextAccessor>(),
269 NullLogger<TeamsBotAdapter>.Instance);
270 }
271
272 private static ITurnContext CreateMockTurnContext(string? serviceUrl)
273 {
274 Activity activity = new()
275 {
276 Type = ActivityTypes.Message,
277 Id = "turn-activity-123",
278 ServiceUrl = serviceUrl,
279 Conversation = new Microsoft.Bot.Schema.ConversationAccount { Id = "turn-conversation-123" },
280 From = new ChannelAccount { Id = "user-123" },
281 Recipient = new ChannelAccount { Id = "bot-123" },
282 ChannelId = "msteams"
283 };
284
285 Mock<ITurnContext> mockTurnContext = new();
286 mockTurnContext.Setup(t => t.Activity).Returns(activity);
287
288 return mockTurnContext.Object;
289 }
290 }
291}
292