From 660cac9ee5d18d471953b6ef0a66cbfe8e49fa98 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 4 May 2025 07:12:26 +0330 Subject: [PATCH] feat(flight):add initial Unit.Test project --- .../src/Modules/Flight/src/Flight.csproj | 13 +- .../Fakes/FakeCreateAircraftCommand.cs | 15 +++ .../Fakes/FakeCreateAirportCommand.cs | 14 ++ .../Fakes/FakeCreateFlightCommand.cs | 22 ++++ .../Fakes/FakeCreateFlightMongoCommand.cs | 23 ++++ .../Fakes/FakeCreateSeatCommand.cs | 19 +++ .../Fakes/FakeCreateSeatMongoCommand.cs | 19 +++ .../Fakes/FakeUpdateFlightCommand.cs | 20 +++ .../FlightIntegrationTestBase.cs | 20 +++ .../Integration.Test/FlightTestDataSeeder.cs | 85 ++++++++++++ .../Integration.Test/Integration.Test.csproj | 22 ++++ .../Seat/Features/GetAvailableSeatsTests.cs | 43 ++++++ .../Seat/Features/ReserveSeatTests.cs | 43 ++++++ .../tests/Integration.Test/xunit.runner.json | 4 + .../CreateAircraftCommandHandlerTests.cs | 53 ++++++++ .../CreateAircraftCommandValidatorTests.cs | 30 +++++ .../CreateAirportCommandHandlerTests.cs | 55 ++++++++ .../CreateAirportCommandValidatorTests.cs | 30 +++++ .../Unit.Test/Common/DbContextFactory.cs | 96 ++++++++++++++ .../tests/Unit.Test/Common/MapperFactory.cs | 18 +++ .../tests/Unit.Test/Common/UnitTestFixture.cs | 26 ++++ .../Fakes/FakeCreateAircraftCommand.cs | 15 +++ .../Fakes/FakeCreateAirportCommand.cs | 14 ++ .../Fakes/FakeCreateFlightCommand.cs | 20 +++ .../Unit.Test/Fakes/FakeCreateSeatCommand.cs | 21 +++ .../tests/Unit.Test/Fakes/FakeFlightCreate.cs | 18 +++ .../tests/Unit.Test/Fakes/FakeFlightUpdate.cs | 13 ++ .../FakeValidateCreateAircraftCommand.cs | 15 +++ .../Fakes/FakeValidateCreateAirportCommand.cs | 15 +++ .../Fakes/FakeValidateCreateFlightCommand.cs | 21 +++ .../Fakes/FakeValidateCreateSeatCommand.cs | 17 +++ .../Features/Domains/CreateFlightTests.cs | 34 +++++ .../Features/Domains/UpdateFlightTests.cs | 40 ++++++ .../CreateFlightCommandHandlerTests.cs | 56 ++++++++ .../CreateFlightCommandValidatorTests.cs | 33 +++++ .../Unit.Test/Flight/FlightMappingTests.cs | 39 ++++++ .../Features/CreateSeatCommandHandlerTests.cs | 57 ++++++++ .../CreateSeatCommandValidatorTests.cs | 30 +++++ .../tests/Unit.Test/Seat/SeatMappingTests.cs | 40 ++++++ .../Flight/tests/Unit.Test/Unit.Test.csproj | 23 ++++ .../Flight/tests/Unit.Test/xunit.runner.json | 4 + monolith-to-cloud-architecture.sln | 122 ++++++++++-------- 42 files changed, 1265 insertions(+), 52 deletions(-) create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAircraftCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAirportCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightMongoCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatMongoCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeUpdateFlightCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightIntegrationTestBase.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightTestDataSeeder.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Integration.Test.csproj create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/GetAvailableSeatsTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/ReserveSeatTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/xunit.runner.json create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandHandlerTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandValidatorTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandValidatorTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/DbContextFactory.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/MapperFactory.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/UnitTestFixture.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAircraftCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAirportCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateFlightCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateSeatCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightCreate.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightUpdate.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAircraftCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAirportCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateFlightCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateSeatCommand.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/CreateFlightTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/UpdateFlightTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandValidatorTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/FlightMappingTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandHandlerTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandValidatorTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/SeatMappingTests.cs create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Unit.Test.csproj create mode 100644 2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/xunit.runner.json diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/src/Flight.csproj b/2-modular-monolith-architecture-style/src/Modules/Flight/src/Flight.csproj index 6781597..32de653 100644 --- a/2-modular-monolith-architecture-style/src/Modules/Flight/src/Flight.csproj +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/src/Flight.csproj @@ -1,4 +1,4 @@ - + @@ -21,6 +21,17 @@ + + + <_Parameter1>Unit.Test + + + + + <_Parameter1>Integration.Test + + + diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAircraftCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAircraftCommand.cs new file mode 100644 index 0000000..646ced6 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAircraftCommand.cs @@ -0,0 +1,15 @@ +using AutoBogus; + +namespace Integration.Test.Fakes; + +using global::Flight.Aircrafts.Features.CreatingAircraft.V1; +using MassTransit; + +public class FakeCreateAircraftCommand : AutoFaker +{ + public FakeCreateAircraftCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.ManufacturingYear, _ => 2000); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAirportCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAirportCommand.cs new file mode 100644 index 0000000..2cc7ae2 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateAirportCommand.cs @@ -0,0 +1,14 @@ +using AutoBogus; + +namespace Integration.Test.Fakes; + +using global::Flight.Airports.Features.CreatingAirport.V1; +using MassTransit; + +public class FakeCreateAirportCommand : AutoFaker +{ + public FakeCreateAirportCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightCommand.cs new file mode 100644 index 0000000..5e2793e --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightCommand.cs @@ -0,0 +1,22 @@ +using AutoBogus; +using Flight.Flights.Enums; + +namespace Integration.Test.Fakes; + +using System.Linq; +using global::Flight.Data.Seed; +using global::Flight.Flights.Features.CreatingFlight.V1; +using MassTransit; + +public sealed class FakeCreateFlightCommand : AutoFaker +{ + public FakeCreateFlightCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString()); + RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id); + RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id); + RuleFor(r => r.Status, _ => FlightStatus.Flying); + RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightMongoCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightMongoCommand.cs new file mode 100644 index 0000000..921b810 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateFlightMongoCommand.cs @@ -0,0 +1,23 @@ +namespace Integration.Test.Fakes; + +using System.Linq; +using AutoBogus; +using global::Flight.Data.Seed; +using global::Flight.Flights.Enums; +using global::Flight.Flights.Features.CreatingFlight.V1; +using MassTransit; + +public sealed class FakeCreateFlightMongoCommand : AutoFaker +{ + public FakeCreateFlightMongoCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightNumber, r => "12FF"); + RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id); + RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id); + RuleFor(r => r.Status, _ => FlightStatus.Flying); + RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id); + RuleFor(r => r.IsDeleted, _ => false); + } +} + diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatCommand.cs new file mode 100644 index 0000000..1f68428 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatCommand.cs @@ -0,0 +1,19 @@ +using AutoBogus; +using Flight.Seats.Enums; + +namespace Integration.Test.Fakes; + +using System; +using global::Flight.Seats.Features.CreatingSeat.V1; +using MassTransit; + +public class FakeCreateSeatCommand : AutoFaker +{ + public FakeCreateSeatCommand(Guid flightId) + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightId, _ => flightId); + RuleFor(r => r.Class, _ => SeatClass.Economy); + RuleFor(r => r.Type, _ => SeatType.Middle); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatMongoCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatMongoCommand.cs new file mode 100644 index 0000000..441d090 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeCreateSeatMongoCommand.cs @@ -0,0 +1,19 @@ +namespace Integration.Test.Fakes; + +using System; +using AutoBogus; +using global::Flight.Seats.Enums; +using global::Flight.Seats.Features.CreatingSeat.V1; +using MassTransit; + +public class FakeCreateSeatMongoCommand : AutoFaker +{ + public FakeCreateSeatMongoCommand(Guid flightId) + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightId, _ => flightId); + RuleFor(r => r.Class, _ => SeatClass.Economy); + RuleFor(r => r.Type, _ => SeatType.Middle); + RuleFor(r => r.IsDeleted, _ => false); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeUpdateFlightCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeUpdateFlightCommand.cs new file mode 100644 index 0000000..e6ca140 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Fakes/FakeUpdateFlightCommand.cs @@ -0,0 +1,20 @@ +using AutoBogus; + +namespace Integration.Test.Fakes; + +using global::Flight.Flights.Features.UpdatingFlight.V1; + +public class FakeUpdateFlightCommand : AutoFaker +{ + public FakeUpdateFlightCommand(global::Flight.Flights.Models.Flight flight) + { + RuleFor(r => r.Id, _ => flight.Id); + RuleFor(r => r.DepartureAirportId, _ => flight.DepartureAirportId); + RuleFor(r => r.ArriveAirportId, _ => flight.ArriveAirportId); + RuleFor(r => r.AircraftId, _ => flight.AircraftId); + RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString()); + RuleFor(r => r.Price, _ => 800); + RuleFor(r => r.Status, _ => flight.Status); + RuleFor(r => r.ArriveDate, _ => flight.ArriveDate); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightIntegrationTestBase.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightIntegrationTestBase.cs new file mode 100644 index 0000000..b51f114 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightIntegrationTestBase.cs @@ -0,0 +1,20 @@ +using Api; +using BuildingBlocks.TestBase; +using Flight.Data; +using Xunit; + +namespace Integration.Test; + +[Collection(IntegrationTestCollection.Name)] +public class FlightIntegrationTestBase : TestBase +{ + public FlightIntegrationTestBase(TestFixture integrationTestFixture) : base(integrationTestFixture) + { + } +} + +[CollectionDefinition(Name)] +public class IntegrationTestCollection : ICollectionFixture> +{ + public const string Name = "Flight Integration Test"; +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightTestDataSeeder.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightTestDataSeeder.cs new file mode 100644 index 0000000..3121315 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/FlightTestDataSeeder.cs @@ -0,0 +1,85 @@ +using BuildingBlocks.EFCore; +using Flight.Aircrafts.Models; +using Flight.Airports.Models; +using Flight.Data; +using Flight.Data.Seed; +using Flight.Flights.Models; +using Flight.Seats.Models; +using MapsterMapper; +using Microsoft.EntityFrameworkCore; +using MongoDB.Driver; +using MongoDB.Driver.Linq; + +namespace Integration.Test; + +public class FlightTestDataSeeder( + FlightDbContext flightDbContext, + FlightReadDbContext flightReadDbContext, + IMapper mapper +) : ITestDataSeeder +{ + public async Task SeedAllAsync() + { + await SeedAirportAsync(); + await SeedAircraftAsync(); + await SeedFlightAsync(); + await SeedSeatAsync(); + } + + private async Task SeedAirportAsync() + { + if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Airports)) + { + await flightDbContext.Airports.AddRangeAsync(InitialData.Airports); + await flightDbContext.SaveChangesAsync(); + + if (!await MongoQueryable.AnyAsync(flightReadDbContext.Airport.AsQueryable())) + { + await flightReadDbContext.Airport.InsertManyAsync(mapper.Map>(InitialData.Airports)); + } + } + } + + private async Task SeedAircraftAsync() + { + if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Aircraft)) + { + await flightDbContext.Aircraft.AddRangeAsync(InitialData.Aircrafts); + await flightDbContext.SaveChangesAsync(); + + if (!await MongoQueryable.AnyAsync(flightReadDbContext.Aircraft.AsQueryable())) + { + await flightReadDbContext.Aircraft.InsertManyAsync(mapper.Map>(InitialData.Aircrafts)); + } + } + } + + + private async Task SeedSeatAsync() + { + if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Seats)) + { + await flightDbContext.Seats.AddRangeAsync(InitialData.Seats); + await flightDbContext.SaveChangesAsync(); + + if (!await MongoQueryable.AnyAsync(flightReadDbContext.Seat.AsQueryable())) + { + await flightReadDbContext.Seat.InsertManyAsync(mapper.Map>(InitialData.Seats)); + } + } + } + + private async Task SeedFlightAsync() + { + if (!await EntityFrameworkQueryableExtensions.AnyAsync(flightDbContext.Flights)) + { + await flightDbContext.Flights.AddRangeAsync(InitialData.Flights); + await flightDbContext.SaveChangesAsync(); + + if (!await MongoQueryable.AnyAsync(flightReadDbContext.Flight.AsQueryable())) + { + await flightReadDbContext.Flight.InsertManyAsync(mapper.Map>(InitialData.Flights)); + } + } + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Integration.Test.csproj b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Integration.Test.csproj new file mode 100644 index 0000000..9dbbc5b --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Integration.Test.csproj @@ -0,0 +1,22 @@ + + + + + PreserveNewest + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/GetAvailableSeatsTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/GetAvailableSeatsTests.cs new file mode 100644 index 0000000..e870d8c --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/GetAvailableSeatsTests.cs @@ -0,0 +1,43 @@ +//using System.Threading.Tasks; +//using BuildingBlocks.TestBase; +//using Flight; +//using Flight.Data; +//using FluentAssertions; +//using Integration.Test.Fakes; +//using Xunit; + +//namespace Integration.Test.Seat.Features; + +//using Api; +//using global::Flight.Flights.Features.CreatingFlight.V1; +//using global::Flight.Seats.Features.CreatingSeat.V1; + +//public class GetAvailableSeatsTests : FlightIntegrationTestBase +//{ +// public GetAvailableSeatsTests( +// TestFixture integrationTestFactory) : base(integrationTestFactory) +// { +// } + +// [Fact] +// public async Task should_return_available_seats_from_grpc_service() +// { +// // Arrange +// var flightCommand = new FakeCreateFlightMongoCommand().Generate(); + +// await Fixture.SendAsync(flightCommand); + +// var seatCommand = new FakeCreateSeatMongoCommand(flightCommand.Id).Generate(); + +// await Fixture.SendAsync(seatCommand); + +// var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel); + +// // Act +// var response = await flightGrpcClient.GetAvailableSeatsAsync(new GetAvailableSeatsRequest { FlightId = flightCommand.Id.ToString() }); + +// // Assert +// response?.Should().NotBeNull(); +// response?.SeatDtos?.Count.Should().BeGreaterOrEqualTo(1); +// } +//} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/ReserveSeatTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/ReserveSeatTests.cs new file mode 100644 index 0000000..7460aa4 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/Seat/Features/ReserveSeatTests.cs @@ -0,0 +1,43 @@ +//using System.Threading.Tasks; +//using Api; +//using BuildingBlocks.TestBase; +//using Flight; +//using Flight.Data; +//using FluentAssertions; +//using Integration.Test.Fakes; +//using Xunit; + +//namespace Integration.Test.Seat.Features; +//public class ReserveSeatTests : FlightIntegrationTestBase +//{ +// public ReserveSeatTests( +// TestFixture integrationTestFactory) : base(integrationTestFactory) +// { +// } + +// [Fact] +// public async Task should_return_valid_reserve_seat_from_grpc_service() +// { +// // Arrange +// var flightCommand = new FakeCreateFlightCommand().Generate(); + +// await Fixture.SendAsync(flightCommand); + +// var seatCommand = new FakeCreateSeatCommand(flightCommand.Id).Generate(); + +// await Fixture.SendAsync(seatCommand); + +// var flightGrpcClient = new FlightGrpcService.FlightGrpcServiceClient(Fixture.Channel); + +// // Act +// var response = await flightGrpcClient.ReserveSeatAsync(new ReserveSeatRequest() +// { +// FlightId = seatCommand.FlightId.ToString(), +// SeatNumber = seatCommand.SeatNumber +// }); + +// // Assert +// response?.Should().NotBeNull(); +// response?.Id.Should().Be(seatCommand?.Id.ToString()); +// } +//} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/xunit.runner.json b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/xunit.runner.json new file mode 100644 index 0000000..9db029b --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Integration.Test/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandHandlerTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandHandlerTests.cs new file mode 100644 index 0000000..10c9f3f --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandHandlerTests.cs @@ -0,0 +1,53 @@ +using FluentAssertions; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Aircraft.Features.CreateAircraftTests; + +using global::Flight.Aircrafts.Features.CreatingAircraft.V1; + +[Collection(nameof(UnitTestFixture))] +public class CreateAircraftCommandHandlerTests +{ + private readonly UnitTestFixture _fixture; + private readonly CreateAircraftHandler _handler; + + public Task Act(CreateAircraft command, CancellationToken cancellationToken) => + _handler.Handle(command, cancellationToken); + + public CreateAircraftCommandHandlerTests(UnitTestFixture fixture) + { + _fixture = fixture; + _handler = new CreateAircraftHandler(_fixture.DbContext); + } + + [Fact] + public async Task handler_with_valid_command_should_create_new_aircraft_and_return_currect_aircraft_dto() + { + // Arrange + var command = new FakeCreateAircraftCommand().Generate(); + + // Act + var response = await Act(command, CancellationToken.None); + + // Assert + var entity = await _fixture.DbContext.Aircraft.FindAsync(response?.Id); + + entity?.Should().NotBeNull(); + response?.Id.Should().Be(entity.Id); + } + + [Fact] + public async Task handler_with_null_command_should_throw_argument_exception() + { + // Arrange + CreateAircraft command = null; + + // Act + Func act = async () => { await Act(command, CancellationToken.None); }; + + // Assert + await act.Should().ThrowAsync(); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandValidatorTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandValidatorTests.cs new file mode 100644 index 0000000..c68142a --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Aircraft/Features/CreateAircraftTests/CreateAircraftCommandValidatorTests.cs @@ -0,0 +1,30 @@ +using FluentAssertions; +using FluentValidation.TestHelper; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Aircraft.Features.CreateAircraftTests; + +using global::Flight.Aircrafts.Features.CreatingAircraft.V1; + +[Collection(nameof(UnitTestFixture))] +public class CreateAircraftCommandValidatorTests +{ + [Fact] + public void is_valid_should_be_false_when_have_invalid_parameter() + { + // Arrange + var command = new FakeValidateCreateAircraftCommand().Generate(); + var validator = new CreateAircraftValidator(); + + // Act + var result = validator.TestValidate(command); + + // Assert + result.IsValid.Should().BeFalse(); + result.ShouldHaveValidationErrorFor(x => x.Model); + result.ShouldHaveValidationErrorFor(x => x.ManufacturingYear); + result.ShouldHaveValidationErrorFor(x => x.Name); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs new file mode 100644 index 0000000..d6a4137 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandHandlerTests.cs @@ -0,0 +1,55 @@ +using FluentAssertions; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Airport.Features.CreateAirportTests; + +using global::Flight.Airports.Features.CreatingAirport.V1; +using global::Flight.Airports.ValueObjects; + +[Collection(nameof(UnitTestFixture))] +public class CreateAirportCommandHandlerTests +{ + private readonly UnitTestFixture _fixture; + private readonly CreateAirportHandler _handler; + + + public CreateAirportCommandHandlerTests(UnitTestFixture fixture) + { + _fixture = fixture; + _handler = new CreateAirportHandler(_fixture.DbContext); + } + + public Task Act(CreateAirport command, CancellationToken cancellationToken) => + _handler.Handle(command, cancellationToken); + + [Fact] + public async Task handler_with_valid_command_should_create_new_airport_and_return_currect_airport_dto() + { + // Arrange + var command = new FakeCreateAirportCommand().Generate(); + + // Act + var response = await Act(command, CancellationToken.None); + + // Assert + var entity = await _fixture.DbContext.Airports.FindAsync(AirportId.Of(response.Id)); + + entity?.Should().NotBeNull(); + response?.Id.Should().Be(entity.Id); + } + + [Fact] + public async Task handler_with_null_command_should_throw_argument_exception() + { + // Arrange + CreateAirport command = null; + + // Act + var act = async () => { await Act(command, CancellationToken.None); }; + + // Assert + await act.Should().ThrowAsync(); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandValidatorTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandValidatorTests.cs new file mode 100644 index 0000000..9fa877e --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Airport/Features/CreateAirportTests/CreateAirportCommandValidatorTests.cs @@ -0,0 +1,30 @@ +using FluentAssertions; +using FluentValidation.TestHelper; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Airport.Features.CreateAirportTests; + +using global::Flight.Airports.Features.CreatingAirport.V1; + +[Collection(nameof(UnitTestFixture))] +public class CreateAirportCommandValidatorTests +{ + [Fact] + public void is_valid_should_be_false_when_have_invalid_parameter() + { + // Arrange + var command = new FakeValidateCreateAirportCommand().Generate(); + var validator = new CreateAirportValidator(); + + // Act + var result = validator.TestValidate(command); + + // Assert + result.IsValid.Should().BeFalse(); + result.ShouldHaveValidationErrorFor(x => x.Code); + result.ShouldHaveValidationErrorFor(x => x.Address); + result.ShouldHaveValidationErrorFor(x => x.Name); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/DbContextFactory.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/DbContextFactory.cs new file mode 100644 index 0000000..f11753a --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/DbContextFactory.cs @@ -0,0 +1,96 @@ +using Flight.Data; +using Flight.Flights.Enums; +using Flight.Seats.Enums; +using Microsoft.EntityFrameworkCore; + +namespace Unit.Test.Common; + +using global::Flight.Aircrafts.ValueObjects; +using global::Flight.Airports.ValueObjects; +using global::Flight.Flights.ValueObjects; +using global::Flight.Seats.ValueObjects; +using MassTransit; +using AirportName = global::Flight.Airports.ValueObjects.Name; +using Name = global::Flight.Aircrafts.ValueObjects.Name; + +public static class DbContextFactory +{ + private static readonly Guid _airportId1 = NewId.NextGuid(); + private static readonly Guid _airportId2 = NewId.NextGuid(); + private static readonly Guid _aircraft1 = NewId.NextGuid(); + private static readonly Guid _aircraft2 = NewId.NextGuid(); + private static readonly Guid _aircraft3 = NewId.NextGuid(); + private static readonly Guid _flightId1 = NewId.NextGuid(); + + public static FlightDbContext Create() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()).Options; + + var context = new FlightDbContext(options, currentUserProvider: null, null); + + // Seed our data + FlightDataSeeder(context); + + return context; + } + + private static void FlightDataSeeder(FlightDbContext context) + { + var airports = new List + { + global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId1), AirportName.Of("Lisbon International Airport"), Address.Of("LIS"), + Code.Of("12988")), + global::Flight.Airports.Models.Airport.Create(AirportId.Of(_airportId2), AirportName.Of("Sao Paulo International Airport"), Address.Of("BRZ"), + Code.Of("11200")) + }; + + context.Airports.AddRange(airports); + + var aircrafts = new List + { + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft1), Name.Of("Boeing 737"), Model.Of("B737"), ManufacturingYear.Of(2005)), + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft2), Name.Of("Airbus 300"), Model.Of("A300"), ManufacturingYear.Of(2000)), + global::Flight.Aircrafts.Models.Aircraft.Create(AircraftId.Of(_aircraft3), Name.Of("Airbus 320"), Model.Of("A320"), ManufacturingYear.Of(2003)) + }; + + context.Aircraft.AddRange(aircrafts); + + var flights = new List + { + global::Flight.Flights.Models.Flight.Create(FlightId.Of(_flightId1), FlightNumber.Of( "BD467"), AircraftId.Of(_aircraft1), AirportId.Of( _airportId1), + DepartureDate.Of( new DateTime(2022, 1, 31, 12, 0, 0)), + ArriveDate.Of( new DateTime(2022, 1, 31, 14, 0, 0)), + AirportId.Of( _airportId2), DurationMinutes.Of(120m), + FlightDate.Of( new DateTime(2022, 1, 31)), FlightStatus.Completed, + Price.Of(8000)) + }; + context.Flights.AddRange(flights); + + var seats = new List + { + global::Flight.Seats.Models.Seat.Create(SeatId.Of( NewId.NextGuid()), SeatNumber.Of("12A"), SeatType.Window, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12B"), SeatType.Window, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12C"), SeatType.Middle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12D"), SeatType.Middle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12E"), SeatType.Aisle, SeatClass.Economy, + FlightId.Of(_flightId1)), + global::Flight.Seats.Models.Seat.Create(SeatId.Of(NewId.NextGuid()), SeatNumber.Of("12F"), SeatType.Aisle, SeatClass.Economy, + FlightId.Of(_flightId1)) + }; + + context.Seats.AddRange(seats); + + context.SaveChanges(); + } + + public static void Destroy(FlightDbContext context) + { + context.Database.EnsureDeleted(); + context.Dispose(); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/MapperFactory.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/MapperFactory.cs new file mode 100644 index 0000000..b848805 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/MapperFactory.cs @@ -0,0 +1,18 @@ +using Flight; +using Mapster; +using MapsterMapper; + +namespace Unit.Test.Common +{ + public static class MapperFactory + { + public static IMapper Create() + { + var typeAdapterConfig = TypeAdapterConfig.GlobalSettings; + typeAdapterConfig.Scan(typeof(FlightRoot).Assembly); + IMapper instance = new Mapper(typeAdapterConfig); + + return instance; + } + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/UnitTestFixture.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/UnitTestFixture.cs new file mode 100644 index 0000000..102d755 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Common/UnitTestFixture.cs @@ -0,0 +1,26 @@ +using Flight.Data; +using MapsterMapper; +using Xunit; + +namespace Unit.Test.Common +{ + [CollectionDefinition(nameof(UnitTestFixture))] + public class FixtureCollection : ICollectionFixture { } + + public class UnitTestFixture : IDisposable + { + public UnitTestFixture() + { + Mapper = MapperFactory.Create(); + DbContext = DbContextFactory.Create(); + } + + public IMapper Mapper { get; } + public FlightDbContext DbContext { get; } + + public void Dispose() + { + DbContextFactory.Destroy(DbContext); + } + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAircraftCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAircraftCommand.cs new file mode 100644 index 0000000..cafba2c --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAircraftCommand.cs @@ -0,0 +1,15 @@ +using AutoBogus; + +namespace Unit.Test.Fakes; + +using global::Flight.Aircrafts.Features.CreatingAircraft.V1; +using MassTransit; + +public class FakeCreateAircraftCommand : AutoFaker +{ + public FakeCreateAircraftCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.ManufacturingYear, _ => 2000); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAirportCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAirportCommand.cs new file mode 100644 index 0000000..f1fd415 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateAirportCommand.cs @@ -0,0 +1,14 @@ +using AutoBogus; + +namespace Unit.Test.Fakes; + +using global::Flight.Airports.Features.CreatingAirport.V1; +using MassTransit; + +public class FakeCreateAirportCommand : AutoFaker +{ + public FakeCreateAirportCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateFlightCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateFlightCommand.cs new file mode 100644 index 0000000..1362b10 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateFlightCommand.cs @@ -0,0 +1,20 @@ +using AutoBogus; + +namespace Unit.Test.Fakes; + +using System.Linq; +using global::Flight.Data.Seed; +using global::Flight.Flights.Features.CreatingFlight.V1; +using MassTransit; + +public sealed class FakeCreateFlightCommand : AutoFaker +{ + public FakeCreateFlightCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightNumber, r => r.Random.Number(1000, 2000).ToString()); + RuleFor(r => r.DepartureAirportId, _ => InitialData.Airports.First().Id); + RuleFor(r => r.ArriveAirportId, _ => InitialData.Airports.Last().Id); + RuleFor(r => r.AircraftId, _ => InitialData.Aircrafts.First().Id); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateSeatCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateSeatCommand.cs new file mode 100644 index 0000000..7810d1b --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeCreateSeatCommand.cs @@ -0,0 +1,21 @@ +using AutoBogus; +using Flight.Seats.Enums; + +namespace Unit.Test.Fakes; + +using System.Linq; +using global::Flight.Data.Seed; +using global::Flight.Seats.Features.CreatingSeat.V1; +using MassTransit; + +public class FakeCreateSeatCommand : AutoFaker +{ + public FakeCreateSeatCommand() + { + RuleFor(r => r.Id, _ => NewId.NextGuid()); + RuleFor(r => r.FlightId, _ => InitialData.Flights.First().Id); + RuleFor(r => r.SeatNumber, _ => "F99"); + RuleFor(r => r.Type, _ => SeatType.Window); + RuleFor(r => r.Class, _ => SeatClass.Economy); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightCreate.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightCreate.cs new file mode 100644 index 0000000..d9c5e70 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightCreate.cs @@ -0,0 +1,18 @@ +namespace Unit.Test.Fakes; + +using global::Flight.Aircrafts.ValueObjects; +using global::Flight.Airports.ValueObjects; +using global::Flight.Flights.ValueObjects; + +public static class FakeFlightCreate +{ + public static global::Flight.Flights.Models.Flight Generate() + { + var command = new FakeCreateFlightCommand().Generate(); + + return global::Flight.Flights.Models.Flight.Create(FlightId.Of(command.Id), FlightNumber.Of(command.FlightNumber), + AircraftId.Of(command.AircraftId), AirportId.Of(command.DepartureAirportId), DepartureDate.Of(command.DepartureDate), + ArriveDate.Of(command.ArriveDate), AirportId.Of(command.ArriveAirportId), DurationMinutes.Of(command.DurationMinutes), + FlightDate.Of(command.FlightDate), command.Status, Price.Of(command.Price)); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightUpdate.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightUpdate.cs new file mode 100644 index 0000000..0996583 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeFlightUpdate.cs @@ -0,0 +1,13 @@ +namespace Unit.Test.Fakes; + +using global::Flight.Flights.Models; +using global::Flight.Flights.ValueObjects; + +public static class FakeFlightUpdate +{ + public static void Generate(Flight flight) + { + flight.Update(flight.Id, flight.FlightNumber, flight.AircraftId, flight.DepartureAirportId, flight.DepartureDate, + flight.ArriveDate, flight.ArriveAirportId, flight.DurationMinutes, flight.FlightDate, flight.Status, Price.Of(1000), flight.IsDeleted); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAircraftCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAircraftCommand.cs new file mode 100644 index 0000000..d233486 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAircraftCommand.cs @@ -0,0 +1,15 @@ +using AutoBogus; + +namespace Unit.Test.Fakes; + +using global::Flight.Aircrafts.Features.CreatingAircraft.V1; + +public class FakeValidateCreateAircraftCommand : AutoFaker +{ + public FakeValidateCreateAircraftCommand() + { + RuleFor(r => r.ManufacturingYear, _ => 0); + RuleFor(r => r.Name, _ => null); + RuleFor(r => r.Model, _ => null); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAirportCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAirportCommand.cs new file mode 100644 index 0000000..508e85c --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateAirportCommand.cs @@ -0,0 +1,15 @@ +using AutoBogus; + +namespace Unit.Test.Fakes; + +using global::Flight.Airports.Features.CreatingAirport.V1; + +public class FakeValidateCreateAirportCommand : AutoFaker +{ + public FakeValidateCreateAirportCommand() + { + RuleFor(r => r.Code, _ => null); + RuleFor(r => r.Name, _ => null); + RuleFor(r => r.Address, _ => null); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateFlightCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateFlightCommand.cs new file mode 100644 index 0000000..007d7fd --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateFlightCommand.cs @@ -0,0 +1,21 @@ +using System; +using AutoBogus; +using Flight.Flights.Enums; + +namespace Unit.Test.Fakes; + +using global::Flight.Flights.Features.CreatingFlight.V1; + +public class FakeValidateCreateFlightCommand : AutoFaker +{ + public FakeValidateCreateFlightCommand() + { + RuleFor(r => r.Price, _ => -10); + RuleFor(r => r.Status, _ => (FlightStatus)10); + RuleFor(r => r.AircraftId, _ => Guid.Empty); + RuleFor(r => r.DepartureAirportId, _ => Guid.Empty); + RuleFor(r => r.ArriveAirportId, _ => Guid.Empty); + RuleFor(r => r.DurationMinutes, _ => 0); + RuleFor(r => r.FlightDate, _ => new DateTime()); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateSeatCommand.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateSeatCommand.cs new file mode 100644 index 0000000..f7985a9 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Fakes/FakeValidateCreateSeatCommand.cs @@ -0,0 +1,17 @@ +using AutoBogus; +using Flight.Seats.Enums; + +namespace Unit.Test.Fakes; + +using System; +using global::Flight.Seats.Features.CreatingSeat.V1; + +public class FakeValidateCreateSeatCommand : AutoFaker +{ + public FakeValidateCreateSeatCommand() + { + RuleFor(r => r.SeatNumber, _ => null); + RuleFor(r => r.FlightId, _ => Guid.Empty); + RuleFor(r => r.Class, _ => (SeatClass)10); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/CreateFlightTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/CreateFlightTests.cs new file mode 100644 index 0000000..bd4b3f6 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/CreateFlightTests.cs @@ -0,0 +1,34 @@ +namespace Unit.Test.Flight.Features.Domains +{ + using System.Linq; + using FluentAssertions; + using global::Flight.Flights.Features.CreatingFlight.V1; + using Unit.Test.Common; + using Unit.Test.Fakes; + using Xunit; + + [Collection(nameof(UnitTestFixture))] + public class CreateFlightTests + { + [Fact] + public void can_create_valid_flight() + { + // Arrange + Act + var fakeFlight = FakeFlightCreate.Generate(); + + // Assert + fakeFlight.Should().NotBeNull(); + } + + [Fact] + public void queue_domain_event_on_create() + { + // Arrange + Act + var fakeFlight = FakeFlightCreate.Generate(); + + // Assert + fakeFlight.DomainEvents.Count.Should().Be(1); + fakeFlight.DomainEvents.FirstOrDefault().Should().BeOfType(typeof(FlightCreatedDomainEvent)); + } + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/UpdateFlightTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/UpdateFlightTests.cs new file mode 100644 index 0000000..d0aaadd --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Domains/UpdateFlightTests.cs @@ -0,0 +1,40 @@ +namespace Unit.Test.Flight.Features.Domains; + +using System.Linq; +using FluentAssertions; +using global::Flight.Flights.Features.UpdatingFlight.V1; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +[Collection(nameof(UnitTestFixture))] +public class UpdateFlightTests +{ + [Fact] + public void can_update_valid_flight() + { + // Arrange + var fakeFlight = FakeFlightCreate.Generate(); + + // Act + FakeFlightUpdate.Generate(fakeFlight); + + // Assert + fakeFlight.Price.Value.Should().Be(1000); + } + + [Fact] + public void queue_domain_event_on_update() + { + // Arrange + var fakeFlight = FakeFlightCreate.Generate(); + fakeFlight.ClearDomainEvents(); + + // Act + FakeFlightUpdate.Generate(fakeFlight); + + // Assert + fakeFlight.DomainEvents.Count.Should().Be(1); + fakeFlight.DomainEvents.FirstOrDefault().Should().BeOfType(typeof(FlightUpdatedDomainEvent)); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs new file mode 100644 index 0000000..6a37fb4 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandHandlerTests.cs @@ -0,0 +1,56 @@ +namespace Unit.Test.Flight.Features.Handlers.CreateFlight; + +using System; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using global::Flight.Flights.Features.CreatingFlight.V1; +using global::Flight.Flights.ValueObjects; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +[Collection(nameof(UnitTestFixture))] +public class CreateFlightCommandHandlerTests +{ + private readonly UnitTestFixture _fixture; + private readonly CreateFlightHandler _handler; + + public Task Act(CreateFlight command, CancellationToken cancellationToken) => + _handler.Handle(command, cancellationToken); + + public CreateFlightCommandHandlerTests(UnitTestFixture fixture) + { + _fixture = fixture; + _handler = new CreateFlightHandler(fixture.DbContext); + } + + [Fact] + public async Task handler_with_valid_command_should_create_new_flight_and_return_currect_flight_dto() + { + // Arrange + var command = new FakeCreateFlightCommand().Generate(); + + // Act + var response = await Act(command, CancellationToken.None); + + // Assert + var entity = await _fixture.DbContext.Flights.FindAsync(FlightId.Of(response.Id)); + + entity?.Should().NotBeNull(); + response?.Id.Should().Be(entity.Id); + } + + [Fact] + public async Task handler_with_null_command_should_throw_argument_exception() + { + // Arrange + CreateFlight command = null; + + // Act + Func act = async () => { await Act(command, CancellationToken.None); }; + + // Assert + await act.Should().ThrowAsync(); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandValidatorTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandValidatorTests.cs new file mode 100644 index 0000000..c339532 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/Features/Handlers/CreateFlight/CreateFlightCommandValidatorTests.cs @@ -0,0 +1,33 @@ +namespace Unit.Test.Flight.Features.Handlers.CreateFlight; + +using FluentAssertions; +using FluentValidation.TestHelper; +using global::Flight.Flights.Features.CreatingFlight.V1; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +[Collection(nameof(UnitTestFixture))] +public class CreateFlightCommandValidatorTests +{ + [Fact] + public void is_valid_should_be_false_when_have_invalid_parameter() + { + // Arrange + var command = new FakeValidateCreateFlightCommand().Generate(); + var validator = new CreateFlightValidator(); + + // Act + var result = validator.TestValidate(command); + + // Assert + result.IsValid.Should().BeFalse(); + result.ShouldHaveValidationErrorFor(x => x.Price); + result.ShouldHaveValidationErrorFor(x => x.Status); + result.ShouldHaveValidationErrorFor(x => x.AircraftId); + result.ShouldHaveValidationErrorFor(x => x.DepartureAirportId); + result.ShouldHaveValidationErrorFor(x => x.ArriveAirportId); + result.ShouldHaveValidationErrorFor(x => x.DurationMinutes); + result.ShouldHaveValidationErrorFor(x => x.FlightDate); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/FlightMappingTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/FlightMappingTests.cs new file mode 100644 index 0000000..4c1e26e --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Flight/FlightMappingTests.cs @@ -0,0 +1,39 @@ +using Flight.Flights.Dtos; +using MapsterMapper; +using Unit.Test.Common; +using Xunit; + +namespace Unit.Test.Flight; + +[Collection(nameof(UnitTestFixture))] +public class FlightMappingTests +{ + private readonly IMapper _mapper; + + public FlightMappingTests(UnitTestFixture fixture) + { + _mapper = fixture.Mapper; + } + + public static IEnumerable Data + { + get + { + yield return new object[] + { + // these types will instantiate with reflection in the future + typeof(global::Flight.Flights.Models.FlightReadModel), typeof(FlightDto) + }; + } + } + + [Theory] + [MemberData(nameof(Data))] + public void should_support_mapping_from_source_to_destination(Type source, Type destination, + params object[] parameters) + { + var instance = Activator.CreateInstance(source, parameters); + + _mapper.Map(instance, source, destination); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandHandlerTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandHandlerTests.cs new file mode 100644 index 0000000..ad9d85a --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandHandlerTests.cs @@ -0,0 +1,57 @@ +using FluentAssertions; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Seat.Features; + +using global::Flight.Seats.Features.CreatingSeat.V1; +using global::Flight.Seats.ValueObjects; + +[Collection(nameof(UnitTestFixture))] +public class CreateSeatCommandHandlerTests +{ + private readonly UnitTestFixture _fixture; + private readonly CreateSeatCommandHandler _handler; + + + public CreateSeatCommandHandlerTests(UnitTestFixture fixture) + { + _fixture = fixture; + _handler = new CreateSeatCommandHandler(_fixture.DbContext); + } + + public Task Act(CreateSeat command, CancellationToken cancellationToken) + { + return _handler.Handle(command, cancellationToken); + } + + [Fact] + public async Task handler_with_valid_command_should_create_new_seat_and_return_currect_seat_dto() + { + // Arrange + var command = new FakeCreateSeatCommand().Generate(); + + // Act + var response = await Act(command, CancellationToken.None); + + // Assert + var entity = await _fixture.DbContext.Seats.FindAsync(SeatId.Of(response.Id)); + + entity?.Should().NotBeNull(); + response?.Id.Should().Be(entity.Id); + } + + [Fact] + public async Task handler_with_null_command_should_throw_argument_exception() + { + // Arrange + CreateSeat command = null; + + // Act + var act = async () => { await Act(command, CancellationToken.None); }; + + // Assert + await act.Should().ThrowAsync(); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandValidatorTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandValidatorTests.cs new file mode 100644 index 0000000..79bb087 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/Features/CreateSeatCommandValidatorTests.cs @@ -0,0 +1,30 @@ +using FluentAssertions; +using FluentValidation.TestHelper; +using Unit.Test.Common; +using Unit.Test.Fakes; +using Xunit; + +namespace Unit.Test.Seat.Features; + +using global::Flight.Seats.Features.CreatingSeat.V1; + +[Collection(nameof(UnitTestFixture))] +public class CreateSeatCommandValidatorTests +{ + [Fact] + public void is_valid_should_be_false_when_have_invalid_parameter() + { + // Arrange + var command = new FakeValidateCreateSeatCommand().Generate(); + var validator = new CreateSeatValidator(); + + // Act + var result = validator.TestValidate(command); + + // Assert + result.IsValid.Should().BeFalse(); + result.ShouldHaveValidationErrorFor(x => x.SeatNumber); + result.ShouldHaveValidationErrorFor(x => x.FlightId); + result.ShouldHaveValidationErrorFor(x => x.Class); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/SeatMappingTests.cs b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/SeatMappingTests.cs new file mode 100644 index 0000000..4652665 --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Seat/SeatMappingTests.cs @@ -0,0 +1,40 @@ +using Flight.Seats.Dtos; +using MapsterMapper; +using Unit.Test.Common; +using Xunit; + +namespace Unit.Test.Seat; + +[Collection(nameof(UnitTestFixture))] +public class SeatMappingTests +{ + private readonly UnitTestFixture _fixture; + private readonly IMapper _mapper; + + public SeatMappingTests(UnitTestFixture fixture) + { + _mapper = fixture.Mapper; + } + + public static IEnumerable Data + { + get + { + yield return new object[] + { + // these types will instantiate with reflection in the future + typeof(global::Flight.Seats.Models.SeatReadModel), typeof(SeatDto) + }; + } + } + + + [Theory] + [MemberData(nameof(Data))] + public void should_support_mapping_from_source_to_destination(Type source, Type destination, params object[] parameters) + { + var instance = Activator.CreateInstance(source, parameters); + + _mapper.Map(instance, source, destination); + } +} diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Unit.Test.csproj b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Unit.Test.csproj new file mode 100644 index 0000000..be2a92d --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/Unit.Test.csproj @@ -0,0 +1,23 @@ + + + + + PreserveNewest + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + diff --git a/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/xunit.runner.json b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/xunit.runner.json new file mode 100644 index 0000000..9db029b --- /dev/null +++ b/2-modular-monolith-architecture-style/src/Modules/Flight/tests/Unit.Test/xunit.runner.json @@ -0,0 +1,4 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false +} diff --git a/monolith-to-cloud-architecture.sln b/monolith-to-cloud-architecture.sln index 8e921b5..dbd5d44 100644 --- a/monolith-to-cloud-architecture.sln +++ b/monolith-to-cloud-architecture.sln @@ -103,62 +103,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Api", "Api", "{EAAC4A89-D71 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Api", "1-monolith-architecture-style\src\Api\src\Api.csproj", "{E7BA185C-B26D-4ACB-A24A-70AB730DD2A0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Flight", "Flight", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit.Test", "2-modular-monolith-architecture-style\src\Modules\Flight\tests\Unit.Test\Unit.Test.csproj", "{E7B7E65D-DB14-494C-A748-EF90666FB0B1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integration.Test", "2-modular-monolith-architecture-style\src\Modules\Flight\tests\Integration.Test\Integration.Test.csproj", "{AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {57366225-A26A-4715-A690-DA641B0C0450} = {33F5E6F6-FACB-4D34-8E48-B80E0497D239} - {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} = {33F5E6F6-FACB-4D34-8E48-B80E0497D239} - {570274DD-E84A-4F22-9079-D60B59EC9ED2} = {F1BEC66C-B321-45D8-95C1-8DCD4743275D} - {AD2FB7C1-8641-47E9-B62D-B3A2D74147D8} = {F1BEC66C-B321-45D8-95C1-8DCD4743275D} - {DBAE70CC-011A-4997-9612-58AFAFF73291} = {96913068-5EFE-4D13-8B00-924AFED16439} - {FB529C7A-F884-42D1-BE41-2A6B7CC4101B} = {96913068-5EFE-4D13-8B00-924AFED16439} - {5A2A9F1C-245A-4978-93A0-E00120FEE765} = {57366225-A26A-4715-A690-DA641B0C0450} - {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} = {57366225-A26A-4715-A690-DA641B0C0450} - {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} = {57366225-A26A-4715-A690-DA641B0C0450} - {A1786514-35EB-4AFA-87E1-2FB89D748C02} = {57366225-A26A-4715-A690-DA641B0C0450} - {A5E49049-0DFF-4D87-9188-2B0ACBC0D59B} = {57366225-A26A-4715-A690-DA641B0C0450} - {6538BDF3-A741-46E9-8988-C859ABB2FBB2} = {A5E49049-0DFF-4D87-9188-2B0ACBC0D59B} - {B851799B-A328-4E40-9095-C56C11A6235E} = {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} - {674C0974-11C4-4BF7-B2DF-8ED753919224} = {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} - {FB8AA20B-0D31-4241-A126-07992BCF7E2A} = {5A2A9F1C-245A-4978-93A0-E00120FEE765} - {0EB6B262-197D-450C-A56E-634D2D428FCB} = {5A2A9F1C-245A-4978-93A0-E00120FEE765} - {694E763C-E076-4F36-A3CE-3A55D794C871} = {A1786514-35EB-4AFA-87E1-2FB89D748C02} - {E18BC5D2-5A32-469A-9E0B-5ACFE3B6639B} = {A1786514-35EB-4AFA-87E1-2FB89D748C02} - {1F2CE508-42D0-437B-83AB-0D5FEBE324F8} = {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} - {77410EA7-739C-475B-B460-CCEF5CEE1AD1} = {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} - {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} - {D2F19D7F-A9DA-47D2-A445-F9ED8D4479C1} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} - {51EE0C7A-6D1A-4538-957A-34B6906FC932} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} - {3FD37B50-3C7D-49E9-9456-A3E82675227D} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} - {5D3D2499-0732-4545-87F5-C26AF1FE827B} = {51EE0C7A-6D1A-4538-957A-34B6906FC932} - {EE5ECF6A-0D4F-4737-BAD3-AE66D1B53D83} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} - {0A74D3F2-7814-4FB4-890D-4899749B67A2} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} - {FDA41108-8194-49B2-8F78-9F8AECABB7BC} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} - {B6D11E8B-CAAE-4452-B3AE-A49DA7E68FE0} = {3FD37B50-3C7D-49E9-9456-A3E82675227D} - {6D17EFCC-63DB-4E51-8073-25D5E59B2170} = {D2F19D7F-A9DA-47D2-A445-F9ED8D4479C1} - {5ED78466-4114-48ED-9A6E-02143984E7A1} = {B85B39B5-B341-4117-8626-C5DD4F375569} - {D1907049-C23E-47CB-9DF1-0D9EDB7CE117} = {570274DD-E84A-4F22-9079-D60B59EC9ED2} - {5F943131-E273-474E-891E-6386C4B10D00} = {570274DD-E84A-4F22-9079-D60B59EC9ED2} - {183FF15D-1B24-4FA4-A5E4-505825919113} = {5F943131-E273-474E-891E-6386C4B10D00} - {3CB44FE8-8DC1-49BD-864A-72FB6A8229C5} = {5F943131-E273-474E-891E-6386C4B10D00} - {254C235E-7E2D-4FEE-9EB4-50E48BDB1295} = {5F943131-E273-474E-891E-6386C4B10D00} - {6C250353-B112-42F5-BBE9-FA2A725870FD} = {5F943131-E273-474E-891E-6386C4B10D00} - {99914C87-B2FC-4DB2-9BFC-AA2D63B3024F} = {183FF15D-1B24-4FA4-A5E4-505825919113} - {18FAA2C9-5B3B-41D4-83F4-F91B0F2355A0} = {D1907049-C23E-47CB-9DF1-0D9EDB7CE117} - {301AB091-1BBB-4D95-9A54-AA7A8EE928EF} = {3CB44FE8-8DC1-49BD-864A-72FB6A8229C5} - {3020E2CD-C6E5-4489-914E-96083705AF0E} = {6C250353-B112-42F5-BBE9-FA2A725870FD} - {1CD81080-9F44-49AA-94F9-EFEBFD8073E4} = {254C235E-7E2D-4FEE-9EB4-50E48BDB1295} - {DB31E41A-D441-4BB8-B96C-F70395FBFB95} = {DBAE70CC-011A-4997-9612-58AFAFF73291} - {ECBE72AF-7F47-4086-A3F8-AF011085E253} = {DB31E41A-D441-4BB8-B96C-F70395FBFB95} - {EAAC4A89-D71D-426F-ABB0-127C3E777E54} = {DBAE70CC-011A-4997-9612-58AFAFF73291} - {E7BA185C-B26D-4ACB-A24A-70AB730DD2A0} = {EAAC4A89-D71D-426F-ABB0-127C3E777E54} - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6538BDF3-A741-46E9-8988-C859ABB2FBB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6538BDF3-A741-46E9-8988-C859ABB2FBB2}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -252,5 +207,70 @@ Global {E7BA185C-B26D-4ACB-A24A-70AB730DD2A0}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7BA185C-B26D-4ACB-A24A-70AB730DD2A0}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7BA185C-B26D-4ACB-A24A-70AB730DD2A0}.Release|Any CPU.Build.0 = Release|Any CPU + {E7B7E65D-DB14-494C-A748-EF90666FB0B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E7B7E65D-DB14-494C-A748-EF90666FB0B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7B7E65D-DB14-494C-A748-EF90666FB0B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E7B7E65D-DB14-494C-A748-EF90666FB0B1}.Release|Any CPU.Build.0 = Release|Any CPU + {AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {57366225-A26A-4715-A690-DA641B0C0450} = {33F5E6F6-FACB-4D34-8E48-B80E0497D239} + {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} = {33F5E6F6-FACB-4D34-8E48-B80E0497D239} + {570274DD-E84A-4F22-9079-D60B59EC9ED2} = {F1BEC66C-B321-45D8-95C1-8DCD4743275D} + {AD2FB7C1-8641-47E9-B62D-B3A2D74147D8} = {F1BEC66C-B321-45D8-95C1-8DCD4743275D} + {DBAE70CC-011A-4997-9612-58AFAFF73291} = {96913068-5EFE-4D13-8B00-924AFED16439} + {FB529C7A-F884-42D1-BE41-2A6B7CC4101B} = {96913068-5EFE-4D13-8B00-924AFED16439} + {5A2A9F1C-245A-4978-93A0-E00120FEE765} = {57366225-A26A-4715-A690-DA641B0C0450} + {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} = {57366225-A26A-4715-A690-DA641B0C0450} + {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} = {57366225-A26A-4715-A690-DA641B0C0450} + {A1786514-35EB-4AFA-87E1-2FB89D748C02} = {57366225-A26A-4715-A690-DA641B0C0450} + {A5E49049-0DFF-4D87-9188-2B0ACBC0D59B} = {57366225-A26A-4715-A690-DA641B0C0450} + {6538BDF3-A741-46E9-8988-C859ABB2FBB2} = {A5E49049-0DFF-4D87-9188-2B0ACBC0D59B} + {B851799B-A328-4E40-9095-C56C11A6235E} = {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} + {674C0974-11C4-4BF7-B2DF-8ED753919224} = {D0A6E1E7-DFB6-4940-A254-F2E24897C4AC} + {FB8AA20B-0D31-4241-A126-07992BCF7E2A} = {5A2A9F1C-245A-4978-93A0-E00120FEE765} + {0EB6B262-197D-450C-A56E-634D2D428FCB} = {5A2A9F1C-245A-4978-93A0-E00120FEE765} + {694E763C-E076-4F36-A3CE-3A55D794C871} = {A1786514-35EB-4AFA-87E1-2FB89D748C02} + {E18BC5D2-5A32-469A-9E0B-5ACFE3B6639B} = {A1786514-35EB-4AFA-87E1-2FB89D748C02} + {1F2CE508-42D0-437B-83AB-0D5FEBE324F8} = {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} + {77410EA7-739C-475B-B460-CCEF5CEE1AD1} = {F77CA77C-49CE-49B5-BE5A-FCCF6C63D65A} + {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} + {D2F19D7F-A9DA-47D2-A445-F9ED8D4479C1} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} + {51EE0C7A-6D1A-4538-957A-34B6906FC932} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} + {3FD37B50-3C7D-49E9-9456-A3E82675227D} = {39BAB0A0-3C16-49B1-B817-9EC5C600BF5E} + {5D3D2499-0732-4545-87F5-C26AF1FE827B} = {51EE0C7A-6D1A-4538-957A-34B6906FC932} + {EE5ECF6A-0D4F-4737-BAD3-AE66D1B53D83} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} + {0A74D3F2-7814-4FB4-890D-4899749B67A2} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} + {FDA41108-8194-49B2-8F78-9F8AECABB7BC} = {7D81CAA6-6DEF-43C1-AE1B-D0F0B7B09CE7} + {B6D11E8B-CAAE-4452-B3AE-A49DA7E68FE0} = {3FD37B50-3C7D-49E9-9456-A3E82675227D} + {6D17EFCC-63DB-4E51-8073-25D5E59B2170} = {D2F19D7F-A9DA-47D2-A445-F9ED8D4479C1} + {5ED78466-4114-48ED-9A6E-02143984E7A1} = {B85B39B5-B341-4117-8626-C5DD4F375569} + {D1907049-C23E-47CB-9DF1-0D9EDB7CE117} = {570274DD-E84A-4F22-9079-D60B59EC9ED2} + {5F943131-E273-474E-891E-6386C4B10D00} = {570274DD-E84A-4F22-9079-D60B59EC9ED2} + {183FF15D-1B24-4FA4-A5E4-505825919113} = {5F943131-E273-474E-891E-6386C4B10D00} + {3CB44FE8-8DC1-49BD-864A-72FB6A8229C5} = {5F943131-E273-474E-891E-6386C4B10D00} + {254C235E-7E2D-4FEE-9EB4-50E48BDB1295} = {5F943131-E273-474E-891E-6386C4B10D00} + {6C250353-B112-42F5-BBE9-FA2A725870FD} = {5F943131-E273-474E-891E-6386C4B10D00} + {99914C87-B2FC-4DB2-9BFC-AA2D63B3024F} = {183FF15D-1B24-4FA4-A5E4-505825919113} + {18FAA2C9-5B3B-41D4-83F4-F91B0F2355A0} = {D1907049-C23E-47CB-9DF1-0D9EDB7CE117} + {301AB091-1BBB-4D95-9A54-AA7A8EE928EF} = {3CB44FE8-8DC1-49BD-864A-72FB6A8229C5} + {3020E2CD-C6E5-4489-914E-96083705AF0E} = {6C250353-B112-42F5-BBE9-FA2A725870FD} + {1CD81080-9F44-49AA-94F9-EFEBFD8073E4} = {254C235E-7E2D-4FEE-9EB4-50E48BDB1295} + {DB31E41A-D441-4BB8-B96C-F70395FBFB95} = {DBAE70CC-011A-4997-9612-58AFAFF73291} + {ECBE72AF-7F47-4086-A3F8-AF011085E253} = {DB31E41A-D441-4BB8-B96C-F70395FBFB95} + {EAAC4A89-D71D-426F-ABB0-127C3E777E54} = {DBAE70CC-011A-4997-9612-58AFAFF73291} + {E7BA185C-B26D-4ACB-A24A-70AB730DD2A0} = {EAAC4A89-D71D-426F-ABB0-127C3E777E54} + {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {AD2FB7C1-8641-47E9-B62D-B3A2D74147D8} + {E7B7E65D-DB14-494C-A748-EF90666FB0B1} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + {AE7E4AE8-4A5C-44AE-B1FC-2A04824EE29B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BF29DFD4-25EC-44C4-9DA6-E3AC4B292257} EndGlobalSection EndGlobal