microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
b9bc522d242ad42cba49791c95c73c0f2c1d2358

Branches

Tags

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

Clone

HTTPS

Download ZIP

Tests/Microsoft.Teams.Plugins.AspNetCore.Tests/AspNetCorePluginTests.cs

199lines · modecode

1using System.Net;
2using System.Text;
3using System.Text.Json;
4
5using Microsoft.AspNetCore.Http;
6using Microsoft.Teams.Api;
7using Microsoft.Teams.Api.Activities;
8using Microsoft.Teams.Api.Auth;
9using Microsoft.Teams.Apps;
10using Microsoft.Teams.Apps.Events;
11using Microsoft.Teams.Common.Logging;
12
13using Moq;
14
15namespace Microsoft.Teams.Plugins.AspNetCore.Tests;
16
17public class AspNetCorePluginTests
18{
19 private static AspNetCorePlugin CreatePlugin(Mock<ILogger>? loggerMock = null, EventFunction? events = null)
20 {
21 var plugin = new AspNetCorePlugin();
22 if (loggerMock is not null)
23 {
24 plugin.Logger = loggerMock.Object;
25 }
26 else
27 {
28 plugin.Logger = new ConsoleLogger("Test", LogLevel.Debug);
29 }
30 plugin.Client = new Mock<Microsoft.Teams.Common.Http.IHttpClient>().Object;
31 if (events is not null)
32 {
33 plugin.Events += events;
34 }
35 return plugin;
36 }
37
38 private static DefaultHttpContext CreateHttpContext(IActivity activity, string bearer = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQ3MDI1MTUyMDB9.signature")
39 {
40 var ctx = new DefaultHttpContext();
41 ctx.TraceIdentifier = Guid.NewGuid().ToString();
42 ctx.Request.Headers.Append("Authorization", $"Bearer {bearer}");
43 var json = JsonSerializer.Serialize(activity, new JsonSerializerOptions { DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull });
44 var bytes = Encoding.UTF8.GetBytes(json);
45 ctx.Request.Body = new MemoryStream(bytes);
46 ctx.Request.ContentLength = bytes.Length;
47 return ctx;
48 }
49
50 private static MessageActivity CreateMessageActivity()
51 {
52 return new MessageActivity("hi")
53 {
54 From = new() { Id = "user" },
55 Recipient = new() { Id = "bot" },
56 Conversation = new Conversation() { Id = "conv", Type = ConversationType.Personal }
57 };
58 }
59
60 [Fact]
61 public async Task Test_Do_Http_CallsExtractTokenAndActivity_AndCallsCoreDo()
62 {
63 // Arrange
64 var activity = CreateMessageActivity();
65 var coreResponse = new Response(HttpStatusCode.Accepted, new { ok = true });
66 var eventsCalled = new List<string>();
67
68 EventFunction events = (plugin, name, payload, ct) =>
69 {
70 eventsCalled.Add(name);
71 if (name == "activity") return Task.FromResult<object?>(coreResponse); // returned directly by core Do
72 return Task.FromResult<object?>(null);
73 };
74
75 var logger = new Mock<ILogger>();
76 var plugin = CreatePlugin(logger, events);
77 var ctx = CreateHttpContext(activity);
78
79 // Act
80 var result = await plugin.Do(ctx);
81
82 // Assert
83 Assert.Contains("activity", eventsCalled);
84 var jsonResult = Assert.IsType<Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult<object?>>(result);
85 Assert.Equal((int)coreResponse.Status, jsonResult.StatusCode);
86 }
87
88 [Fact]
89 public async Task Test_Do_Http_SetsHeadersFromResponseMeta()
90 {
91 // Arrange
92 var activity = CreateMessageActivity();
93 var response = new Response(HttpStatusCode.OK, new { hello = "world" });
94 response.Meta.Add("routes", 3);
95 response.Meta.Add("custom", "value");
96
97 EventFunction events = (plugin, name, payload, ct) =>
98 {
99 if (name == "activity") return Task.FromResult<object?>(response);
100 return Task.FromResult<object?>(null);
101 };
102
103 var plugin = CreatePlugin(new Mock<ILogger>(), events);
104 var ctx = CreateHttpContext(activity);
105
106 // Act
107 var result = await plugin.Do(ctx);
108
109 // Assert body result type
110 var jsonResult = Assert.IsType<Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult<object?>>(result);
111 Assert.Equal((int)HttpStatusCode.OK, jsonResult.StatusCode);
112 // Headers: routes & custom should be present
113 Assert.Contains("X-Teams-Routes", ctx.Response.Headers.Keys); // capitalized first char
114 Assert.Contains("X-Teams-Custom", ctx.Response.Headers.Keys);
115 }
116
117 [Fact]
118 public async Task Test_Do_Http_ErrorPath_ProducesProblemResult()
119 {
120 // Arrange -> throw inside events
121 EventFunction events = (plugin, name, payload, ct) =>
122 {
123 if (name == "activity") throw new InvalidOperationException("boom");
124 return Task.FromResult<object?>(null);
125 };
126
127 var logger = new Mock<ILogger>();
128 var plugin = CreatePlugin(logger, events);
129 var ctx = CreateHttpContext(CreateMessageActivity());
130
131 // Act
132 var result = await plugin.Do(ctx);
133
134 // Assert
135 var problem = Assert.IsType<Microsoft.AspNetCore.Http.HttpResults.JsonHttpResult<object>>(result);
136 Assert.Equal(500, problem.StatusCode);
137 Assert.Contains("boom", problem.Value!.ToString());
138 logger.Verify(l => l.Error(It.IsAny<object[]>()), Times.AtLeastOnce);
139 }
140
141 [Fact]
142 public void Test_ExtractToken_ReturnsToken()
143 {
144 var plugin = CreatePlugin();
145 var ctx = CreateHttpContext(CreateMessageActivity(), "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQ3MDI1MTUyMDB9.token123");
146
147 var token = plugin.ExtractToken(ctx.Request);
148 Assert.NotNull(token);
149 Assert.Contains("token123", token.ToString());
150 }
151
152 [Fact]
153 public async Task Test_ExtractActivity_ReturnsActivity()
154 {
155 var plugin = CreatePlugin();
156 var activity = CreateMessageActivity();
157 var ctx = CreateHttpContext(activity);
158
159 var extracted = await plugin.ParseActivity(ctx.Request);
160 Assert.NotNull(extracted);
161 Assert.True(activity.Type.Equals(extracted.Type));
162 }
163
164 [Fact]
165 public async Task Test_ExtractActivity_HttpRequestBodyAlreadyRead_ReturnsActivity()
166 {
167 var plugin = CreatePlugin();
168 var activity = CreateMessageActivity();
169 var ctx = CreateHttpContext(activity);
170 // simulate body already read by setting position to end
171 ctx.Request.Body.Position = ctx.Request.Body.Length;
172
173 var extracted = await plugin.ParseActivity(ctx.Request);
174 Assert.NotNull(extracted);
175 Assert.True(activity.Type.Equals(extracted.Type));
176 }
177
178 [Fact]
179 public async Task Test_Do_Core_ReturnsResponseAndLogs()
180 {
181 // Arrange core path tests the ActivityEvent Do(ActivityEvent)
182 var response = new Response(HttpStatusCode.OK, new { test = 1 });
183 EventFunction events = (plugin, name, payload, ct) =>
184 {
185 if (name == "activity") return Task.FromResult<object?>(response);
186 return Task.FromResult<object?>(null);
187 };
188 var logger = new Mock<ILogger>();
189 var plugin = CreatePlugin(logger, events);
190 var evt = new ActivityEvent() { Token = new JsonWebToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjQ3MDI1MTUyMDB9.signature"), Activity = CreateMessageActivity() };
191
192 // Act
193 var res = await plugin.Do(evt);
194
195 // Assert
196 Assert.Same(response, res);
197 logger.Verify(l => l.Debug(It.IsAny<object[]>()), Times.AtLeastOnce);
198 }
199}