Skip to content

Commit

Permalink
Merge pull request #74 from microsoft/southworks/add/authentication-m…
Browse files Browse the repository at this point in the history
…sal-tests

Add unit tests for the Microsoft.Agents.Authentication.Msal project
  • Loading branch information
tracyboehrer authored Jan 29, 2025
2 parents b0d56ce + 4715e1b commit a02d74f
Show file tree
Hide file tree
Showing 11 changed files with 1,162 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/Microsoft.Agents.SDK.sln
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InMeetingNotificationsBot",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TagMentionBot", "samples\Teams\bot-tag-mention\TagMentionBot.csproj", "{BC5EFA6C-7EB5-4803-B7C5-093892E9DBB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Agents.Authentication.Msal.Tests", "tests\Microsoft.Agents.Authentication.Msal.Tests\Microsoft.Agents.Authentication.Msal.Tests.csproj", "{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -330,6 +332,10 @@ Global
{BC5EFA6C-7EB5-4803-B7C5-093892E9DBB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC5EFA6C-7EB5-4803-B7C5-093892E9DBB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC5EFA6C-7EB5-4803-B7C5-093892E9DBB8}.Release|Any CPU.Build.0 = Release|Any CPU
{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -393,6 +399,7 @@ Global
{7D1A1CE5-6D9B-4D31-AC77-C3B1787F575D} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
{06E490F7-F0BB-E3C4-54FE-5210627292A1} = {183D0E91-B84E-46D7-B653-6D85B4CCF804}
{BC5EFA6C-7EB5-4803-B7C5-093892E9DBB8} = {183D0E91-B84E-46D7-B653-6D85B4CCF804}
{B9AD64EF-EA22-4CAC-B89B-03CEE46CFF4F} = {AD743B78-D61F-4FBF-B620-FA83CE599A50}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F1E8E538-309A-46F8-9CE7-AEC6589FAE60}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Microsoft.Agents.Authentication.Msal.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Moq;
using System;
using System.Net.Http;
using Xunit;

namespace Microsoft.Agents.Authentication.Msal.Tests
{
public class MSALHttpClientFactoryTests
{
private readonly Mock<IServiceProvider> _service = new();

[Fact]
public void Constructor_ShouldInstantiateCorrectly()
{
var factory = new MSALHttpClientFactory(_service.Object);

Assert.NotNull(factory);
}

[Fact]
public void GetHttpClient_ShouldThrowOnNullIHttpClientFactory()
{
var factory = new MSALHttpClientFactory(_service.Object);

Assert.Throws<InvalidOperationException>(factory.GetHttpClient);
}

[Fact]
public void GetHttpClient_ShouldReturnClient()
{
var baseAddress = new Uri("https://botframework.com");

_service.Setup(x => x.GetService(typeof(IHttpClientFactory)))
.Returns(new TestHttpClientFactory())
.Verifiable(Times.Once);

var factory = new MSALHttpClientFactory(_service.Object);
var client = factory.GetHttpClient();

Assert.NotNull(client);
Assert.Equal(baseAddress, client.BaseAddress);
Mock.Verify(_service);
}

private class TestHttpClient : HttpClient
{
public TestHttpClient()
{
BaseAddress = new Uri("https://botframework.com");
}
}

private class TestHttpClientFactory : IHttpClientFactory
{
public HttpClient CreateClient(string name)
{
return new TestHttpClient();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Microsoft.Agents.Authentication.Msal.Model;
using Microsoft.Extensions.Options;
using Moq;
using Moq.Protected;
using System;
using System.Net.Http;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace Microsoft.Agents.Authentication.Msal.Tests
{
public class MSALHttpRetryHandlerHelperTests
{
private readonly Mock<IOptions<MsalAuthConfigurationOptions>> _options;
private readonly Mock<IServiceProvider> _service = new();
private readonly MsalAuthConfigurationOptions _returnedOptions = new()
{
MSALRetryCount = 4
};

private readonly Mock<HttpMessageHandler> _handler = new();

private const string RequestUri = "http://test.com";

public MSALHttpRetryHandlerHelperTests()
{
_options = new Mock<IOptions<MsalAuthConfigurationOptions>>();
_options.Setup(x => x.Value)
.Returns(_returnedOptions)
.Verifiable(Times.Once);

_service.Setup(x => x.GetService(typeof(IOptions<MsalAuthConfigurationOptions>)))
.Returns(_options.Object)
.Verifiable(Times.Once);
}

[Fact]
public void Constructor_ShouldInstantiateCorrectly()
{
var retryHelper = new MSALHttpRetryHandlerHelper(_service.Object);

Assert.NotNull(retryHelper);
Mock.Verify(_service);
}

[Fact]
public async Task SendAsync_ShouldReturnSuccessfulResponse()
{
_handler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
.Verifiable(Times.Once);

var retryHandler = new MSALHttpRetryHandlerHelper(_service.Object)
{
InnerHandler = _handler.Object
};

var httpClient = new HttpClient(retryHandler);

var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, RequestUri));

Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Mock.Verify(_handler);
}

[Fact]
public async Task SendAsync_ShouldReturnSuccessfulResponseAfterRetries()
{
_handler.Protected()
.SetupSequence<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK));

var retryHandler = new MSALHttpRetryHandlerHelper(_service.Object)
{
InnerHandler = _handler.Object
};

var httpClient = new HttpClient(retryHandler);

var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, RequestUri));

Assert.Equal(HttpStatusCode.OK, response.StatusCode);
_handler.Protected().Verify("SendAsync", Times.Exactly(4), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
}

[Fact]
public async Task SendAsync_ShouldReturnResponseOnNonRetryableFailure()
{
_handler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.BadRequest))
.Verifiable(Times.Once);

var retryHandler = new MSALHttpRetryHandlerHelper(_service.Object)
{
InnerHandler = _handler.Object
};

var httpClient = new HttpClient(retryHandler);

var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, RequestUri));

Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Mock.Verify(_handler);
}

[Fact]
public async Task SendAsync_ShouldReturnResponseAfterExhaustsAllRetries()
{
_handler.Protected()
.SetupSequence<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout))
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.RequestTimeout));

var retryHandler = new MSALHttpRetryHandlerHelper(_service.Object)
{
InnerHandler = _handler.Object
};

var httpClient = new HttpClient(retryHandler);

var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, RequestUri));

Assert.Equal(HttpStatusCode.RequestTimeout, response.StatusCode);
_handler.Protected().Verify("SendAsync", Times.Exactly(4), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<LangVersion>latest</LangVersion>
<ComponentAreaName>CplTests.Authentication.Msal</ComponentAreaName>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<Import Project="..\..\Build.Common.core.props" />


<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="Moq" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
<PackageReference Include="coverlet.collector" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Extensions.Logging" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\libraries\Authentication\Authentication.Msal\Microsoft.Agents.Authentication.Msal.csproj" />
<ProjectReference Include="..\..\libraries\Core\Microsoft.Agents.Core\Microsoft.Agents.Core.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit a02d74f

Please sign in to comment.