Skip to content

Commit

Permalink
Remove Moq
Browse files Browse the repository at this point in the history
Fixes #1369

Use mock test objects instead of Moq

Use reset events rather than sleeps
  • Loading branch information
lukebakken committed Sep 27, 2023
1 parent 6c68581 commit cbe5b73
Show file tree
Hide file tree
Showing 3 changed files with 222 additions and 74 deletions.
162 changes: 119 additions & 43 deletions projects/Unit/TestOAuth2ClientCredentialsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,93 +30,169 @@
//---------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.Threading;
using Moq;
using RabbitMQ.Client.OAuth2;
using Xunit;
using Xunit.Abstractions;

namespace RabbitMQ.Client.Unit
{
public class MockIOAuth2Client : IOAuth2Client
{
private readonly ITestOutputHelper _testOutputHelper;
private IToken _refreshToken;
private IToken _requestToken;

public MockIOAuth2Client(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

public IToken RefreshTokenValue
{
get { return _refreshToken; }
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}

_refreshToken = value;
}
}

public IToken RequestTokenValue
{
get { return _requestToken; }
set
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}

_requestToken = value;
}
}

public IToken RefreshToken(IToken initialToken)
{
Debug.Assert(Object.ReferenceEquals(_requestToken, initialToken));
return _refreshToken;
}

public IToken RequestToken()
{
return _requestToken;
}
}

public class TestOAuth2CredentialsProvider
{
protected OAuth2ClientCredentialsProvider _provider;
protected Mock<IOAuth2Client> _oAuth2Client;
private readonly ITestOutputHelper _testOutputHelper;

public TestOAuth2CredentialsProvider()
public TestOAuth2CredentialsProvider(ITestOutputHelper testOutputHelper)
{
_oAuth2Client = new Mock<IOAuth2Client>();
_provider = new OAuth2ClientCredentialsProvider("aName", _oAuth2Client.Object);
_testOutputHelper = testOutputHelper;
}

[Fact]
public void shouldHaveAName()
public void ShouldHaveAName()
{
Assert.Equal("aName", _provider.Name);
const string name = "aName";
IOAuth2Client oAuth2Client = new MockIOAuth2Client(_testOutputHelper);
var provider = new OAuth2ClientCredentialsProvider(name, oAuth2Client);

Assert.Equal(name, provider.Name);
}

[Fact]
public void ShouldRequestTokenWhenAskToRefresh()
{
_oAuth2Client.Setup(p => p.RequestToken()).Returns(newToken("the_access_token", TimeSpan.FromSeconds(60)));
_provider.Refresh();
Assert.Equal("the_access_token", _provider.Password);
const string newTokenValue = "the_access_token";
IToken newToken = NewToken(newTokenValue, TimeSpan.FromSeconds(60));
var oAuth2Client = new MockIOAuth2Client(_testOutputHelper);
oAuth2Client.RequestTokenValue = newToken;
var provider = new OAuth2ClientCredentialsProvider(nameof(ShouldRequestTokenWhenAskToRefresh), oAuth2Client);

provider.Refresh();

Assert.Equal(newTokenValue, provider.Password);
}

[Fact]
public void ShouldRequestTokenWhenGettingPasswordOrValidUntilForFirstTimeAccess()
{
IToken firstToken = newToken("the_access_token", "the_refresh_token", TimeSpan.FromSeconds(1));
_oAuth2Client.Setup(p => p.RequestToken()).Returns(firstToken);
Assert.Equal(firstToken.AccessToken, _provider.Password);
Assert.Equal(firstToken.ExpiresIn, _provider.ValidUntil.Value);
const string accessToken = "the_access_token";
const string refreshToken = "the_refresh_token";
IToken firstToken = NewToken(accessToken, refreshToken, TimeSpan.FromSeconds(1));
var oAuth2Client = new MockIOAuth2Client(_testOutputHelper);
oAuth2Client.RequestTokenValue = firstToken;
var provider = new OAuth2ClientCredentialsProvider(nameof(ShouldRequestTokenWhenGettingPasswordOrValidUntilForFirstTimeAccess), oAuth2Client);

Assert.Equal(firstToken.AccessToken, provider.Password);
Assert.Equal(firstToken.ExpiresIn, provider.ValidUntil.Value);
}

[Fact]
public void ShouldRefreshTokenUsingRefreshTokenWhenAvailable()
{
IToken firstToken = newToken("the_access_token", "the_refresh_token", TimeSpan.FromSeconds(1));
IToken refreshedToken = newToken("the_access_token2", "the_refresh_token_2", TimeSpan.FromSeconds(60));
_oAuth2Client.Setup(p => p.RequestToken()).Returns(firstToken);
_provider.Refresh();
Assert.Equal(firstToken.AccessToken, _provider.Password);
Assert.Equal(firstToken.ExpiresIn, _provider.ValidUntil.Value);

_oAuth2Client.Reset();
Thread.Sleep(1000);
_oAuth2Client.Setup(p => p.RefreshToken(firstToken)).Returns(refreshedToken);
_provider.Refresh();

Assert.Equal(refreshedToken.AccessToken, _provider.Password);
Assert.Equal(refreshedToken.ExpiresIn, _provider.ValidUntil.Value);
const string accessToken = "the_access_token";
const string refreshToken = "the_refresh_token";
const string accessToken2 = "the_access_token_2";
const string refreshToken2 = "the_refresh_token_2";

IToken firstToken = NewToken(accessToken, refreshToken, TimeSpan.FromSeconds(1));
IToken refreshedToken = NewToken(accessToken2, refreshToken2, TimeSpan.FromSeconds(60));
var oAuth2Client = new MockIOAuth2Client(_testOutputHelper);
oAuth2Client.RequestTokenValue = firstToken;
var provider = new OAuth2ClientCredentialsProvider(nameof(ShouldRequestTokenWhenGettingPasswordOrValidUntilForFirstTimeAccess), oAuth2Client);

provider.Refresh();

Assert.Equal(firstToken.AccessToken, provider.Password);
Assert.Equal(firstToken.ExpiresIn, provider.ValidUntil.Value);

oAuth2Client.RefreshTokenValue = refreshedToken;
provider.Refresh();

Assert.Equal(refreshedToken.AccessToken, provider.Password);
Assert.Equal(refreshedToken.ExpiresIn, provider.ValidUntil.Value);
}

[Fact]
public void ShouldRequestTokenWhenRefreshTokenNotAvailable()
{
IToken firstToken = newToken("the_access_token", null, TimeSpan.FromSeconds(1));
IToken refreshedToken = newToken("the_access_token2", null, TimeSpan.FromSeconds(1));
_oAuth2Client.SetupSequence(p => p.RequestToken())
.Returns(firstToken)
.Returns(refreshedToken);
_provider.Refresh();
const string accessToken = "the_access_token";
const string accessToken2 = "the_access_token_2";
IToken firstToken = NewToken(accessToken, null, TimeSpan.FromSeconds(1));
IToken secondToken = NewToken(accessToken2, null, TimeSpan.FromSeconds(60));

var oAuth2Client = new MockIOAuth2Client(_testOutputHelper);
oAuth2Client.RequestTokenValue = firstToken;
var provider = new OAuth2ClientCredentialsProvider(nameof(ShouldRequestTokenWhenRefreshTokenNotAvailable), oAuth2Client);

provider.Refresh();

Assert.Equal(firstToken.AccessToken, _provider.Password);
Assert.Equal(firstToken.ExpiresIn, _provider.ValidUntil.Value);
Assert.Equal(firstToken.AccessToken, provider.Password);
Assert.Equal(firstToken.ExpiresIn, provider.ValidUntil.Value);

_provider.Refresh();
oAuth2Client.RequestTokenValue = secondToken;
provider.Refresh();

Assert.Equal(refreshedToken.AccessToken, _provider.Password);
Assert.Equal(refreshedToken.ExpiresIn, _provider.ValidUntil.Value);
Mock.Verify(_oAuth2Client);
Assert.Equal(secondToken.AccessToken, provider.Password);
Assert.Equal(secondToken.ExpiresIn, provider.ValidUntil.Value);
}

private static Token newToken(string access_token, TimeSpan expiresIn)
private static Token NewToken(string access_token, TimeSpan expiresIn)
{
var token = new JsonToken(access_token, string.Empty, expiresIn);
return new Token(token);
}

private static Token newToken(string access_token, string refresh_token, TimeSpan expiresIn)
private static Token NewToken(string access_token, string refresh_token, TimeSpan expiresIn)
{
JsonToken token = new JsonToken(access_token, refresh_token, expiresIn);
return new Token(token);
Expand Down
133 changes: 103 additions & 30 deletions projects/Unit/TestTimerBasedCredentialRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,70 +30,143 @@
//---------------------------------------------------------------------------

using System;
using System.Reflection.Metadata.Ecma335;
using System.Threading;
using Moq;
using System.Threading.Tasks;
using Xunit;
using Xunit.Abstractions;

namespace RabbitMQ.Client.Unit
{
public class MockCredentialsProvider : ICredentialsProvider
{
private readonly ITestOutputHelper _testOutputHelper;
private readonly TimeSpan? _validUntil = TimeSpan.FromSeconds(1);
private Exception _ex = null;
private bool _refreshCalled = false;

public MockCredentialsProvider(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}

public MockCredentialsProvider(ITestOutputHelper testOutputHelper, TimeSpan validUntil)
{
_testOutputHelper = testOutputHelper;
_validUntil = validUntil;
}

public bool RefreshCalled
{
get
{
return _refreshCalled;
}
}

public string Name => this.GetType().Name;

public string UserName => "guest";

public string Password
{
get
{
if (_ex == null)
{
return "guest";
}
else
{
throw _ex;
}
}
}

public TimeSpan? ValidUntil => _validUntil;

public void Refresh()
{
_refreshCalled = true;
}

public void PasswordThrows(Exception ex)
{
_ex = ex;
}
}

public class TestTimerBasedCredentialsRefresher
{
protected TimerBasedCredentialRefresher _refresher;
protected Mock<ICredentialsProvider> _credentialsProvider;
protected Mock<ICredentialsRefresher.NotifyCredentialRefreshed> _callback = new Mock<ICredentialsRefresher.NotifyCredentialRefreshed>();
private readonly ITestOutputHelper _testOutputHelper;
private readonly TimerBasedCredentialRefresher _refresher = new TimerBasedCredentialRefresher();

public TestTimerBasedCredentialsRefresher()
public TestTimerBasedCredentialsRefresher(ITestOutputHelper testOutputHelper)
{
_refresher = new TimerBasedCredentialRefresher();
_credentialsProvider = new Mock<ICredentialsProvider>();
_testOutputHelper = testOutputHelper;
}

[Fact]
public void TestRegister()
{
_credentialsProvider.Setup(p => p.ValidUntil).Returns(TimeSpan.FromSeconds(1));
Assert.True(_credentialsProvider.Object == _refresher.Register(_credentialsProvider.Object, _callback.Object));
Assert.True(_refresher.Unregister(_credentialsProvider.Object));
ICredentialsRefresher.NotifyCredentialRefreshed cb = (bool unused) => { };
ICredentialsProvider credentialsProvider = new MockCredentialsProvider(_testOutputHelper);

Assert.True(credentialsProvider == _refresher.Register(credentialsProvider, cb));
Assert.True(_refresher.Unregister(credentialsProvider));
}

[Fact]
public void TestDoNotRegisterWhenHasNoExpiry()
{
ICredentialsProvider credentialsProvider = new MockCredentialsProvider(_testOutputHelper, TimeSpan.Zero);
ICredentialsRefresher.NotifyCredentialRefreshed cb = (bool unused) => { };

_credentialsProvider.Setup(p => p.ValidUntil).Returns(TimeSpan.Zero);
_refresher.Register(_credentialsProvider.Object, _callback.Object);
Assert.False(_refresher.Unregister(_credentialsProvider.Object));
_credentialsProvider.Verify();
_refresher.Register(credentialsProvider, cb);

Assert.False(_refresher.Unregister(credentialsProvider));
}

[Fact]
public void TestRefreshToken()
{
_credentialsProvider.Setup(p => p.ValidUntil).Returns(TimeSpan.FromSeconds(1));
_credentialsProvider.Setup(p => p.Password).Returns("the-token").Verifiable();
_callback.Setup(p => p.Invoke(true));
_refresher.Register(_credentialsProvider.Object, _callback.Object);
var cbevt = new ManualResetEvent(false);
bool? callbackArg = null;
var credentialsProvider = new MockCredentialsProvider(_testOutputHelper, TimeSpan.FromSeconds(1));
ICredentialsRefresher.NotifyCredentialRefreshed cb = (bool arg) =>
{
callbackArg = arg;
cbevt.Set();
};

_refresher.Register(credentialsProvider, cb);

Thread.Sleep(TimeSpan.FromSeconds(1));
cbevt.WaitOne(TimeSpan.FromSeconds(2));

_credentialsProvider.Verify();
_callback.Verify();
Assert.True(credentialsProvider.RefreshCalled);
Assert.True(callbackArg);
}

[Fact]
public void TestRefreshTokenFailed()
{
_credentialsProvider.Setup(p => p.ValidUntil).Returns(TimeSpan.FromSeconds(1));
_credentialsProvider.SetupSequence(p => p.Password)
.Returns("the-token")
.Throws(new Exception());
_callback.Setup(p => p.Invoke(false));
_refresher.Register(_credentialsProvider.Object, _callback.Object);
var cbevt = new ManualResetEvent(false);
bool? callbackArg = null;
var credentialsProvider = new MockCredentialsProvider(_testOutputHelper, TimeSpan.FromSeconds(1));
ICredentialsRefresher.NotifyCredentialRefreshed cb = (bool arg) =>
{
callbackArg = arg;
cbevt.Set();
};

var ex = new Exception();
credentialsProvider.PasswordThrows(ex);

Thread.Sleep(TimeSpan.FromSeconds(1));
_refresher.Register(credentialsProvider, cb);
cbevt.WaitOne(TimeSpan.FromSeconds(2));

_credentialsProvider.Verify();
_callback.Verify();
Assert.True(credentialsProvider.RefreshCalled);
Assert.False(callbackArg);
}
}
}
1 change: 0 additions & 1 deletion projects/Unit/Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="moq" Version="4.18.4" />
<PackageReference Include="PublicApiGenerator" Version="11.0.0" />
<PackageReference Include="xunit" Version="2.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.0" />
Expand Down

0 comments on commit cbe5b73

Please sign in to comment.