microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
74588b33035a67444a68e0299b0b92494fa76c4a

Branches

Tags

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

Clone

HTTPS

Download ZIP

core/test/Microsoft.Teams.Core.UnitTests/MiddlewareTests.cs

216lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4using System.Text;
5using Microsoft.AspNetCore.Http;
6using Microsoft.Extensions.Configuration;
7using Microsoft.Extensions.Logging.Abstractions;
8using Microsoft.Teams.Core.Schema;
9using Moq;
10
11namespace Microsoft.Teams.Core.UnitTests;
12
13public class MiddlewareTests
14{
15 [Fact]
16 public async Task BotApplication_Use_AddsMiddlewareToChain()
17 {
18 BotApplication botApp = CreateBotApplication();
19
20 Mock<ITurnMiddleware> mockMiddleware = new();
21
22 ITurnMiddleware result = botApp.UseMiddleware(mockMiddleware.Object);
23
24 Assert.NotNull(result);
25 }
26
27
28 [Fact]
29 public async Task Middleware_ExecutesInOrder()
30 {
31 BotApplication botApp = CreateBotApplication();
32
33 List<int> executionOrder = [];
34
35 Mock<ITurnMiddleware> mockMiddleware1 = new();
36 mockMiddleware1
37 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
38 .Callback<BotApplication, CoreActivity, NextTurn, CancellationToken>(async (app, act, next, ct) =>
39 {
40 executionOrder.Add(1);
41 await next(ct);
42 })
43 .Returns(Task.CompletedTask);
44
45 Mock<ITurnMiddleware> mockMiddleware2 = new();
46 mockMiddleware2
47 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
48 .Callback<BotApplication, CoreActivity, NextTurn, CancellationToken>(async (app, act, next, ct) =>
49 {
50 executionOrder.Add(2);
51 await next(ct);
52 })
53 .Returns(Task.CompletedTask);
54
55 botApp.UseMiddleware(mockMiddleware1.Object);
56 botApp.UseMiddleware(mockMiddleware2.Object);
57
58 CoreActivity activity = new()
59 {
60 Type = ActivityType.Message,
61 Id = "act123"
62 };
63
64 DefaultHttpContext httpContext = CreateHttpContextWithActivity(activity);
65
66 botApp.OnActivity = (act, ct) =>
67 {
68 executionOrder.Add(3);
69 return Task.CompletedTask;
70 };
71
72 await botApp.ProcessAsync(httpContext);
73 int[] expected = [1, 2, 3];
74 Assert.Equal(expected, executionOrder);
75 }
76
77 [Fact]
78 public async Task Middleware_CanShortCircuit()
79 {
80 BotApplication botApp = CreateBotApplication();
81
82 bool secondMiddlewareCalled = false;
83 bool onActivityCalled = false;
84
85 Mock<ITurnMiddleware> mockMiddleware1 = new();
86 mockMiddleware1
87 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
88 .Returns(Task.CompletedTask); // Don't call next
89
90 Mock<ITurnMiddleware> mockMiddleware2 = new();
91 mockMiddleware2
92 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
93 .Callback(() => secondMiddlewareCalled = true)
94 .Returns(Task.CompletedTask);
95
96 botApp.UseMiddleware(mockMiddleware1.Object);
97 botApp.UseMiddleware(mockMiddleware2.Object);
98
99 CoreActivity activity = new()
100 {
101 Type = ActivityType.Message,
102 Id = "act123"
103 };
104
105 DefaultHttpContext httpContext = CreateHttpContextWithActivity(activity);
106
107 botApp.OnActivity = (act, ct) =>
108 {
109 onActivityCalled = true;
110 return Task.CompletedTask;
111 };
112
113 await botApp.ProcessAsync(httpContext);
114
115 Assert.False(secondMiddlewareCalled);
116 Assert.False(onActivityCalled);
117 }
118
119 [Fact]
120 public async Task Middleware_ReceivesCancellationToken()
121 {
122 BotApplication botApp = CreateBotApplication();
123
124 CancellationToken receivedToken = default;
125
126 Mock<ITurnMiddleware> mockMiddleware = new();
127 mockMiddleware
128 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
129 .Callback<BotApplication, CoreActivity, NextTurn, CancellationToken>(async (app, act, next, ct) =>
130 {
131 receivedToken = ct;
132 await next(ct);
133 })
134 .Returns(Task.CompletedTask);
135
136 botApp.UseMiddleware(mockMiddleware.Object);
137
138 CoreActivity activity = new()
139 {
140 Type = ActivityType.Message,
141 Id = "act123"
142 };
143
144
145 DefaultHttpContext httpContext = CreateHttpContextWithActivity(activity);
146
147 await botApp.ProcessAsync(httpContext);
148
149 // ProcessAsync creates its own timeout-based CancellationToken instead of
150 // forwarding the caller's token, so the middleware should receive a valid
151 // (non-default) token that is not yet cancelled.
152 Assert.NotEqual(default, receivedToken);
153 Assert.False(receivedToken.IsCancellationRequested);
154 }
155
156 [Fact]
157 public async Task Middleware_ReceivesActivity()
158 {
159 BotApplication botApp = CreateBotApplication();
160
161 CoreActivity? receivedActivity = null;
162
163 Mock<ITurnMiddleware> mockMiddleware = new();
164 mockMiddleware
165 .Setup(m => m.OnTurnAsync(It.IsAny<BotApplication>(), It.IsAny<CoreActivity>(), It.IsAny<NextTurn>(), It.IsAny<CancellationToken>()))
166 .Callback<BotApplication, CoreActivity, NextTurn, CancellationToken>(async (app, act, next, ct) =>
167 {
168 receivedActivity = act;
169 await next(ct);
170 })
171 .Returns(Task.CompletedTask);
172
173 botApp.UseMiddleware(mockMiddleware.Object);
174
175 CoreActivity activity = new()
176 {
177 Type = ActivityType.Message,
178 Id = "act123"
179 };
180
181
182 DefaultHttpContext httpContext = CreateHttpContextWithActivity(activity);
183
184 await botApp.ProcessAsync(httpContext);
185
186 Assert.NotNull(receivedActivity);
187 Assert.Equal(ActivityType.Message, receivedActivity.Type);
188 }
189
190 private static BotApplication CreateBotApplication() =>
191 new(CreateMockConversationClient(), CreateMockUserTokenClient(), NullLogger<BotApplication>.Instance);
192
193 private static ConversationClient CreateMockConversationClient()
194 {
195 Mock<HttpClient> mockHttpClient = new();
196 return new ConversationClient(mockHttpClient.Object);
197 }
198
199 private static UserTokenClient CreateMockUserTokenClient()
200 {
201 Mock<HttpClient> mockHttpClient = new();
202 Mock<IConfiguration> mockConfig = new();
203 NullLogger<UserTokenClient> logger = NullLogger<UserTokenClient>.Instance;
204 return new UserTokenClient(mockHttpClient.Object, mockConfig.Object, logger);
205 }
206
207 private static DefaultHttpContext CreateHttpContextWithActivity(CoreActivity activity)
208 {
209 DefaultHttpContext httpContext = new();
210 string activityJson = activity.ToJson();
211 byte[] bodyBytes = Encoding.UTF8.GetBytes(activityJson);
212 httpContext.Request.Body = new MemoryStream(bodyBytes);
213 httpContext.Request.ContentType = "application/json";
214 return httpContext;
215 }
216}
217