Created
June 26, 2021 04:20
-
-
Save jezzsantos/7db509963a174668607a2070fff539ba to your computer and use it in GitHub Desktop.
Availabilities.IntegrationTests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ServiceStack; | |
namespace Availabilities.Api.IntegrationTests | |
{ | |
public static class ApiClient | |
{ | |
public static JsonServiceClient Create(string serviceUrl) | |
{ | |
return new JsonServiceClient($"{serviceUrl.WithTrailingSlash()}api/"); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Net; | |
using System.Net.Sockets; | |
using Funq; | |
using Microsoft.AspNetCore; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.Extensions.Logging; | |
using ServiceStack; | |
namespace Availabilities.Api.IntegrationTests | |
{ | |
public class ApiSpecSetup<TStartup> : IDisposable where TStartup : class | |
{ | |
private readonly Container container; | |
private readonly IWebHost webHost; | |
public ApiSpecSetup() | |
{ | |
ServiceStackHost.Instance?.Dispose(); | |
ServiceUrl = $"https://localhost:{GetNextAvailablePort()}/"; | |
webHost = WebHost.CreateDefaultBuilder(null) | |
.UseModularStartup<TStartup>() | |
.UseUrls(ServiceUrl) | |
.UseKestrel() | |
.ConfigureLogging((ctx, builder) => builder.AddConsole()) | |
.Build(); | |
webHost.Start(); | |
container = HostContext.Container; | |
Api = ApiClient.Create(ServiceUrl); | |
} | |
public JsonServiceClient Api { get; } | |
private string ServiceUrl { get; } | |
public void Dispose() | |
{ | |
webHost?.StopAsync().GetAwaiter().GetResult(); | |
webHost?.Dispose(); | |
} | |
public TService Resolve<TService>() | |
{ | |
return container.Resolve<TService>(); | |
} | |
private static int GetNextAvailablePort() | |
{ | |
var listener = new TcpListener(IPAddress.Loopback, 0); | |
listener.Start(); | |
var port = ((IPEndPoint) listener.LocalEndpoint).Port; | |
listener.Stop(); | |
return port; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"Logging": { | |
"LogLevel": { | |
"Default": "Debug", | |
"System": "Information", | |
"Microsoft": "Information" | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<TargetFramework>netcoreapp3.1</TargetFramework> | |
<IsPackable>false</IsPackable> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="FluentAssertions" Version="5.10.3" /> | |
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> | |
<PackageReference Include="xunit" Version="2.4.0" /> | |
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> | |
<PackageReference Include="coverlet.collector" Version="1.2.0" /> | |
</ItemGroup> | |
<ItemGroup> | |
<ProjectReference Include="..\Availabilities.Api\Availabilities.Api.csproj" /> | |
</ItemGroup> | |
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Availabilities.Apis.ServiceOperations.Availabilities; | |
using Availabilities.Apis.ServiceOperations.Bookings; | |
using Availabilities.Other; | |
using Availabilities.Resources; | |
using Availabilities.Storage; | |
using FluentAssertions; | |
using Xunit; | |
namespace Availabilities.Api.IntegrationTests.Apis | |
{ | |
[Trait("Category", "Integration")] | |
[Collection("ThisAssembly")] | |
public class AvailabilitiesApiSpec : IClassFixture<ApiSpecSetup<TestStartup>> | |
{ | |
private readonly ApiSpecSetup<TestStartup> setup; | |
public AvailabilitiesApiSpec(ApiSpecSetup<TestStartup> setup) | |
{ | |
this.setup = setup; | |
this.setup.Resolve<IStorage<Booking>>().DestroyAll(); | |
this.setup.Resolve<IStorage<Availability>>().DestroyAll(); | |
} | |
[Fact] | |
public void WhenGetAllAvailabilitiesAndNoBookings_ThenReturnsOneSlot() | |
{ | |
var availabilities = setup.Api.Get(new GetAllAvailabilitiesRequest()) | |
.Availabilities; | |
availabilities.Should().HaveCount(1); | |
availabilities[0].StartUtc.Should().Be(DateTime.MinValue); | |
availabilities[0].EndUtc.Should().Be(DateTime.MaxValue); | |
} | |
[Fact] | |
public void WhenGetAllAvailabilitiesAndBookingCreated_ThenReturnsBothSlotsOrdered() | |
{ | |
var start = DateTime.UtcNow.ToNearestQuarterHour(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
var availabilities = setup.Api.Get(new GetAllAvailabilitiesRequest()) | |
.Availabilities; | |
availabilities.Should().HaveCount(2); | |
availabilities[0].StartUtc.Should().Be(DateTime.MinValue); | |
availabilities[0].EndUtc.Should().Be(start); | |
availabilities[1].StartUtc.Should().Be(end); | |
availabilities[1].EndUtc.Should().Be(DateTime.MaxValue); | |
} | |
[Fact] | |
public void WhenGetAllAvailabilitiesAndAdjacentBookingsCreated_ThenReturnsBothSlotsOrdered() | |
{ | |
var start1 = DateTime.UtcNow.ToNearestQuarterHour(); | |
var end1 = start1.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start1, | |
EndUtc = end1, | |
Description = "adescription1" | |
}); | |
var start2 = end1; | |
var end2 = start2.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start2, | |
EndUtc = end2, | |
Description = "adescription2" | |
}); | |
var availabilities = setup.Api.Get(new GetAllAvailabilitiesRequest()) | |
.Availabilities; | |
availabilities.Should().HaveCount(2); | |
availabilities[0].StartUtc.Should().Be(DateTime.MinValue); | |
availabilities[0].EndUtc.Should().Be(start1); | |
availabilities[1].StartUtc.Should().Be(end2); | |
availabilities[1].EndUtc.Should().Be(DateTime.MaxValue); | |
} | |
[Fact] | |
public void WhenGetAllAvailabilitiesAndDetachedBookingsCreated_ThenReturnsAllThreeSlotsOrdered() | |
{ | |
var start1 = DateTime.UtcNow.ToNearestQuarterHour(); | |
var end1 = start1.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start1, | |
EndUtc = end1, | |
Description = "adescription1" | |
}); | |
var start2 = end1.AnHourLater(); | |
var end2 = start2.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start2, | |
EndUtc = end2, | |
Description = "adescription2" | |
}); | |
var availabilities = setup.Api.Get(new GetAllAvailabilitiesRequest()) | |
.Availabilities; | |
availabilities.Should().HaveCount(3); | |
availabilities[0].StartUtc.Should().Be(DateTime.MinValue); | |
availabilities[0].EndUtc.Should().Be(start1); | |
availabilities[1].StartUtc.Should().Be(end1); | |
availabilities[1].EndUtc.Should().Be(start2); | |
availabilities[2].StartUtc.Should().Be(end2); | |
availabilities[2].EndUtc.Should().Be(DateTime.MaxValue); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Net; | |
using Availabilities.Apis.ServiceOperations.Bookings; | |
using Availabilities.Apis.Validators; | |
using Availabilities.Other; | |
using Availabilities.Resources; | |
using Availabilities.Storage; | |
using FluentAssertions; | |
using ServiceStack; | |
using Xunit; | |
namespace Availabilities.Api.IntegrationTests.Apis | |
{ | |
[Trait("Category", "Integration")] | |
[Collection("ThisAssembly")] | |
public class BookingsApiSpec : IClassFixture<ApiSpecSetup<TestStartup>> | |
{ | |
private readonly ApiSpecSetup<TestStartup> setup; | |
public BookingsApiSpec(ApiSpecSetup<TestStartup> setup) | |
{ | |
this.setup = setup; | |
this.setup.Resolve<IStorage<Booking>>().DestroyAll(); | |
this.setup.Resolve<IStorage<Availability>>().DestroyAll(); | |
} | |
[Fact] | |
public void WhenCreateBookingAndStartsInPast_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.SubtractMinutes(1); | |
var end = start.AnHourLater(); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndStartsAfterEnds_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AnHourEarlier(); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndTooShort_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.SubtractMinutes(Validations.Bookings.MinimumBookingLengthInMinutes + 1); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndTooLong_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AddMinutes(Validations.Bookings.MaximumBookingLengthInMinutes + 1); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndAllAvailability_ThenCreatesBookingToNearestQuarterHour() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AnHourLater(); | |
var booking = setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription" | |
}).Booking; | |
booking.Id.Should().NotBeEmpty(); | |
booking.StartUtc.Should().Be(start.ToNearestQuarterHour()); | |
booking.EndUtc.Should().Be(end.ToNearestQuarterHour()); | |
booking.Description.Should().Be("adescription"); | |
} | |
[Fact] | |
public void WhenCreateBookingAndExactlyNoAvailability_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription2" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndWithinNoAvailability_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.ToNextQuarterHour(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start.FiveMinutesLater(), | |
EndUtc = end.FiveMinutesEarlier(), | |
Description = "adescription2" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndOutsideNoAvailability_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.ToNextQuarterHour(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start.FiveMinutesEarlier(), | |
EndUtc = end.FiveMinutesLater(), | |
Description = "adescription2" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndNoAvailabilityAtStart_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.ToNextQuarterHour(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start.FiveMinutesLater(), | |
EndUtc = end.FiveMinutesEarlier(), | |
Description = "adescription2" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenCreateBookingAndNoAvailabilityAtEnd_ThenThrows() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AnHourLater(); | |
setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}); | |
setup.Api | |
.Invoking(x => x.Post(new CreateBookingRequest | |
{ | |
StartUtc = start.FiveMinutesEarlier(), | |
EndUtc = end.FiveMinutesEarlier(), | |
Description = "adescription2" | |
})) | |
.Should().Throw<WebServiceException>() | |
.Which.HasStatus(HttpStatusCode.BadRequest); | |
} | |
[Fact] | |
public void WhenGetAllBookingsAndNoBookings_ThenReturnsNone() | |
{ | |
var bookings = setup.Api.Get(new GetAllBookingsRequest()) | |
.Bookings; | |
bookings.Should().HaveCount(0); | |
} | |
[Fact] | |
public void WhenGetAllBookingsAndSingleBooking_ThenReturnsOne() | |
{ | |
var start = DateTime.UtcNow.FiveMinutesLater(); | |
var end = start.AnHourLater(); | |
var booking = setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}).Booking; | |
var bookings = setup.Api.Get(new GetAllBookingsRequest()) | |
.Bookings; | |
bookings.Should().HaveCount(1); | |
bookings[0].Id.Should().Be(booking.Id); | |
bookings[0].StartUtc.Should().Be(booking.StartUtc); | |
bookings[0].EndUtc.Should().Be(booking.EndUtc); | |
bookings[0].Description.Should().Be(booking.Description); | |
} | |
[Fact] | |
public void WhenGetAllBookingsAndAdjacentBookings_ThenReturnsBothOrdered() | |
{ | |
var start = DateTime.UtcNow.ToNextQuarterHour(); | |
var end = start.AnHourLater(); | |
var booking1 = setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = start, | |
EndUtc = end, | |
Description = "adescription1" | |
}).Booking; | |
var booking2 = setup.Api.Post(new CreateBookingRequest | |
{ | |
StartUtc = end, | |
EndUtc = end.AnHourLater(), | |
Description = "adescription2" | |
}).Booking; | |
var bookings = setup.Api.Get(new GetAllBookingsRequest()) | |
.Bookings; | |
bookings.Should().HaveCount(2); | |
bookings[0].Id.Should().Be(booking1.Id); | |
bookings[1].Id.Should().Be(booking2.Id); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
using ServiceStack; | |
using ServiceStack.Configuration; | |
namespace Availabilities.Api.IntegrationTests | |
{ | |
public class TestStartup : ModularStartup | |
{ | |
public new void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); | |
} | |
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
var appSettings = new NetCoreAppSettings(Configuration); | |
app.UseServiceStack(new ServiceHost | |
{ | |
BeforeConfigure = | |
{ | |
host => | |
{ | |
var container = host.GetContainer(); | |
container.AddSingleton<IAppSettings>(appSettings); | |
host.AppSettings = appSettings; | |
} | |
}, | |
AfterConfigure = | |
{ | |
host => | |
{ | |
// Override services for testing | |
host.Config.DebugMode = true; | |
} | |
} | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment