microsoft/teams.net

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
dev

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 · modeblame

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