Skip to content

Commit

Permalink
Test message sender with fake handler (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
magnus-tretton37 committed Mar 19, 2019
1 parent 9eb6bff commit 98d64b4
Show file tree
Hide file tree
Showing 14 changed files with 310 additions and 42 deletions.
13 changes: 6 additions & 7 deletions .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ version: '{build}'
skip_branch_with_pr: true
image: Visual Studio 2017
install:
- cmd: cd src
build_script:
- cmd: dotnet build Castle.Sdk -c Release -f netstandard2.0
- cmd: dotnet build Castle.Sdk -c Release -f net461
test_script:
- ps: nuget install OpenCover -OutputDirectory packages -Version 4.7.922
- ps: dotnet tool install coveralls.net --tool-path tools
- ps: .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register:user -target:dotnet.exe -targetargs:"test Tests\Tests.csproj" -filter:"+[Castle.Sdk*]*" -oldStyle -output:opencoverCoverage.xml
- ps: .\tools\csmacnz.coveralls.exe --opencover --useRelativePaths --basePath "src" -i opencoverCoverage.xml --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID
build_script:
- cmd: dotnet build src/Castle.Sdk -c Release -f netstandard2.0
- cmd: dotnet build src/Castle.Sdk -c Release -f net461
test_script:
- ps: .\packages\OpenCover.4.7.922\tools\OpenCover.Console.exe -register:user -target:dotnet.exe -targetargs:"test src/Tests/Tests.csproj" -filter:"+[Castle.Sdk*]*" -oldStyle -output:opencoverCoverage.xml
- ps: .\tools\csmacnz.coveralls.exe --opencover -i opencoverCoverage.xml --useRelativePaths --repoToken $env:COVERALLS_REPO_TOKEN --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_JOB_ID
4 changes: 2 additions & 2 deletions src/Castle.Sdk/CastleClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public async Task Track(ActionRequest request)

public async Task<DeviceList> GetDevicesForUser(string userId, string clientId = null)
{
var clientIdQuery = string.IsNullOrEmpty(clientId) ? "" : $"?client_id={clientId}";
return await TryRequest(() => _messageSender.Get<DeviceList>($"/v1/users/{userId}/devices{clientIdQuery}"));
var endpoint = QueryStringBuilder.Append($"/v1/users/{userId}/devices", "client_id", clientId);
return await TryRequest(() => _messageSender.Get<DeviceList>(endpoint));
}

public async Task<Device> GetDevice(string deviceToken)
Expand Down
22 changes: 16 additions & 6 deletions src/Castle.Sdk/Infrastructure/HttpMessageSender.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,25 @@ internal class HttpMessageSender : IMessageSender
private readonly IInternalLogger _logger;
private readonly HttpClient _httpClient;

public HttpMessageSender(CastleConfiguration configuration, IInternalLogger logger)
public HttpMessageSender(
CastleConfiguration configuration,
IInternalLogger logger)
: this(configuration, logger, null)
{

}

internal HttpMessageSender(
CastleConfiguration configuration,
IInternalLogger logger,
HttpMessageHandler handler)
{
_logger = logger;

_httpClient = new HttpClient()
{
BaseAddress = new Uri(configuration.BaseUrl),
Timeout = TimeSpan.FromMilliseconds(configuration.Timeout)
};
_httpClient = handler != null ? new HttpClient(handler) : new HttpClient();

_httpClient.BaseAddress = new Uri(configuration.BaseUrl);
_httpClient.Timeout = TimeSpan.FromMilliseconds(configuration.Timeout);

var authToken = Convert.ToBase64String(Encoding.UTF8.GetBytes(":" + configuration.ApiSecret));
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authToken);
Expand Down
2 changes: 1 addition & 1 deletion src/Castle.Sdk/Infrastructure/IInternalLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Castle.Infrastructure
{
public interface IInternalLogger
internal interface IInternalLogger
{
void Info(Func<string> createMessage);
void Warn(Func<string> createMessage);
Expand Down
16 changes: 16 additions & 0 deletions src/Castle.Sdk/Infrastructure/QueryStringBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Castle.Infrastructure
{
internal static class QueryStringBuilder
{
public static string Append(string url, string key, string value)
{
if (string.IsNullOrEmpty(value))
return url;

var prefix = url.Contains("?") ? "&" : "?";
return $"{url}{prefix}{key}={value}";
}
}
}
24 changes: 12 additions & 12 deletions src/Tests/Actions/When_authenticating.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public class When_authenticating
public async Task Should_return_response_if_successful(
JObject request,
CastleConfiguration configuration,
Verdict response,
IInternalLogger logger)
Verdict response)
{
Task<Verdict> Send(JObject req) => Task.FromResult(response);
var logger = Substitute.For<IInternalLogger>();

var result = await Authenticate.Execute(Send, request, configuration, logger);

Expand All @@ -34,10 +34,10 @@ public class When_authenticating
public async Task Should_return_failover_response_if_timeout(
JObject request,
string requestUri,
CastleConfiguration configuration,
IInternalLogger logger)
CastleConfiguration configuration)
{
configuration.FailOverStrategy = ActionType.Allow;
var logger = Substitute.For<IInternalLogger>();

Task<Verdict> Send(JObject req) => throw new CastleTimeoutException(requestUri, configuration.Timeout);

Expand All @@ -51,10 +51,10 @@ public class When_authenticating
public async Task Should_return_failover_response_if_any_exception(
JObject request,
Exception exception,
CastleConfiguration configuration,
IInternalLogger logger)
CastleConfiguration configuration)
{
configuration.FailOverStrategy = ActionType.Allow;
var logger = Substitute.For<IInternalLogger>();

Task<Verdict> Send(JObject req) => throw exception;

Expand All @@ -68,10 +68,10 @@ public class When_authenticating
public async Task Should_log_failover_exception_as_warning(
JObject request,
Exception exception,
CastleConfiguration configuration,
IInternalLogger logger)
CastleConfiguration configuration)
{
configuration.FailOverStrategy = ActionType.Allow;
var logger = Substitute.For<IInternalLogger>();

Task<Verdict> Send(JObject req) => throw exception;

Expand All @@ -84,10 +84,10 @@ public class When_authenticating
public async Task Should_throw_exception_if_failing_over_with_no_strategy(
JObject request,
Exception exception,
CastleConfiguration configuration,
IInternalLogger logger)
CastleConfiguration configuration)
{
configuration.FailOverStrategy = ActionType.None;
var logger = Substitute.For<IInternalLogger>();

Task<Verdict> Send(JObject req) => throw exception;

Expand All @@ -100,11 +100,11 @@ public class When_authenticating
public async Task Should_return_failover_response_if_do_not_track_is_set(
JObject request,
CastleConfiguration configuration,
Verdict response,
IInternalLogger logger)
Verdict response)
{
configuration.DoNotTrack = true;
configuration.FailOverStrategy = ActionType.Allow;
var logger = Substitute.For<IInternalLogger>();

Task<Verdict> Send(JObject req) => Task.FromResult(response);

Expand Down
21 changes: 17 additions & 4 deletions src/Tests/SetUp/AutoFakeDataAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
using AutoFixture;
using System;
using AutoFixture;
using AutoFixture.AutoNSubstitute;
using AutoFixture.Xunit2;

namespace Tests.SetUp
{
public class AutoFakeDataAttribute : AutoDataAttribute
{
public AutoFakeDataAttribute()
: base(() => new Fixture().Customize(Customizations.Get()))
public AutoFakeDataAttribute(params Type[] customizationTypes)
: base(() =>
{
var standard = Customizations.Get();
var fixture = new Fixture().Customize(standard);
foreach (var type in customizationTypes)
{
var customization = Activator.CreateInstance(type) as ICustomization;
fixture.Customize(customization);
}
return fixture;
})
{

}
}
}

public class InlineAutoFakeDataAttribute : InlineAutoDataAttribute
Expand Down
40 changes: 40 additions & 0 deletions src/Tests/SetUp/FakeHttpMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace Tests.SetUp
{
public class FakeHttpMessageHandler : HttpMessageHandler
{
private readonly Exception _throws;
private readonly HttpStatusCode _statusCode = HttpStatusCode.OK;

public FakeHttpMessageHandler()
{

}

public FakeHttpMessageHandler(HttpStatusCode statusCode)
{
_statusCode = statusCode;
}

public FakeHttpMessageHandler(Exception throws)
{
_throws = throws;
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_throws != null)
throw _throws;

return Task.FromResult(new HttpResponseMessage(_statusCode)
{
Content = new StringContent("{\"prop\":\"fake\"}")
});
}
}
}
31 changes: 31 additions & 0 deletions src/Tests/SetUp/HttpMessageHandlerCustomization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Net;
using System.Net.Http;
using AutoFixture;

namespace Tests.SetUp
{
public class HttpMessageHandlerSuccessCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<HttpMessageHandler>(() => new FakeHttpMessageHandler());
}
}

public class HttpMessageHandlerFailureCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<HttpMessageHandler>(() => new FakeHttpMessageHandler(HttpStatusCode.InternalServerError));
}
}

public class HttpMessageHandlerCancelledCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<HttpMessageHandler>(() => new FakeHttpMessageHandler(new OperationCanceledException()));
}
}
}
48 changes: 48 additions & 0 deletions src/Tests/When_building_query_strings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Castle.Infrastructure;
using FluentAssertions;
using Xunit;

namespace Tests
{
public class When_building_query_strings
{
[Fact]
public void Should_append_with_questionmark_if_first_param()
{
const string url = "http://test.com";
const string key = "my_param";
const string value = "my_value";
const string expected = "http://test.com?my_param=my_value";

var result = QueryStringBuilder.Append(url, key, value);

result.Should().Be(expected);
}

[Fact]
public void Should_append_with_ampersand_if_not_first_param()
{
const string url = "http://test.com?other_param=other_value";
const string key = "my_param";
const string value = "my_value";
const string expected = "http://test.com?other_param=other_value&my_param=my_value";

var result = QueryStringBuilder.Append(url, key, value);

result.Should().Be(expected);
}

[Fact]
public void Should_not_append_empty_value()
{
const string url = "http://test.com";
const string key = "my_param";
const string value = null;
const string expected = "http://test.com";

var result = QueryStringBuilder.Append(url, key, value);

result.Should().Be(expected);
}
}
}
7 changes: 5 additions & 2 deletions src/Tests/When_creating_message_sender.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Castle.Config;
using Castle.Infrastructure;
using FluentAssertions;
using NSubstitute;
using Tests.SetUp;
using Xunit;

Expand All @@ -9,17 +10,19 @@ namespace Tests
public class When_creating_message_sender
{
[Theory, AutoFakeData]
public void Should_create_real_sender_if_do_not_track_is_disabled(CastleConfiguration configuration, IInternalLogger logger)
public void Should_create_real_sender_if_do_not_track_is_disabled(CastleConfiguration configuration)
{
var logger = Substitute.For<IInternalLogger>();
configuration.DoNotTrack = false;
var result = MessageSenderFactory.Create(configuration, logger);

result.Should().BeOfType<HttpMessageSender>();
}

[Theory, AutoFakeData]
public void Should_create_fake_sender_if_do_not_track_is_enabled(CastleConfiguration configuration, IInternalLogger logger)
public void Should_create_fake_sender_if_do_not_track_is_enabled(CastleConfiguration configuration)
{
var logger = Substitute.For<IInternalLogger>();
configuration.DoNotTrack = true;
var result = MessageSenderFactory.Create(configuration, logger);

Expand Down
Loading

0 comments on commit 98d64b4

Please sign in to comment.