Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/createrelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ jobs:
run: |
echo "ASPNETCORE_ENVIRONMENT are > ${ASPNETCORE_ENVIRONMENT}"
dotnet test "EstateReportingAPI.Tests\EstateReportingAPI.Tests.csproj"

- name: Run Integration Tests
run: |
dotnet test "EstateReportingAPI.IntegrationTests\EstateReportingAPI.IntegrationTests.csproj"

- name: Publish Images to Docker Hub - Pre Release
if: ${{ github.event.release.prerelease == true }}
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/nightlybuild.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ jobs:
- name: Build Docker Image
run: docker build . --file EstateReportingAPI/Dockerfile --tag estatereportingapi:latest

#- name: Run Integration Tests
#run: dotnet test "EstateReportingAPI.IntegrationTests\EstateReportingAPI.IntegrationTests.csproj"
- name: Run Integration Tests
run: |
dotnet test "EstateReportingAPI.IntegrationTests\EstateReportingAPI.IntegrationTests.csproj"

- uses: actions/upload-artifact@v2
if: ${{ failure() }}
Expand Down
10 changes: 4 additions & 6 deletions .github/workflows/pullrequest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,10 @@ jobs:
run: |
echo "ASPNETCORE_ENVIRONMENT are > ${ASPNETCORE_ENVIRONMENT}"
dotnet test "EstateReportingAPI.Tests\EstateReportingAPI.Tests.csproj"

- name: Build Docker Image
run: docker build . --file EstateReportingAPI/Dockerfile --tag estatereportingapi:latest

#- name: Run Integration Tests
#run: dotnet test "EstateReportingAPI.IntegrationTests\EstateReportingAPI.IntegrationTests.csproj" --filter Category=PRTest

- name: Run Integration Tests
run: |
dotnet test "EstateReportingAPI.IntegrationTests\EstateReportingAPI.IntegrationTests.csproj"

- uses: actions/upload-artifact@v2
if: ${{ failure() }}
Expand Down
4 changes: 3 additions & 1 deletion EstateReportingAPI.BusinessLogic/ReportingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class ReportingManager : IReportingManager{

private readonly Shared.EntityFramework.IDbContextFactory<EstateManagementGenericContext> ContextFactory;

private Guid Id;

#endregion

#region Constructors
Expand Down Expand Up @@ -76,7 +78,7 @@ public async Task<List<Calendar>> GetCalendarDates(Guid estateId, CancellationTo

public async Task<List<Int32>> GetCalendarYears(Guid estateId, CancellationToken cancellationToken){
EstateManagementGenericContext? context = await this.ContextFactory.GetContext(estateId, ReportingManager.ConnectionStringIdentifier, cancellationToken);

List<Int32> years = context.Calendar.Where(c => c.Date <= DateTime.Now.Date).GroupBy(c => c.Year).Select(y => y.Key).ToList();

return years;
Expand Down
63 changes: 63 additions & 0 deletions EstateReportingAPI.IntegrationTests/ControllerTestsBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
namespace EstateReportingAPI.IntegrationTests;

using Common;
using Ductus.FluentDocker.Services;
using Ductus.FluentDocker.Services.Extensions;
using NLog;
using Shared.IntegrationTesting;
using Shared.Logger;

public abstract class ControllerTestsBase{

protected readonly HttpClient Client;

protected readonly CustomWebApplicationFactory<Startup> factory;

protected readonly Guid TestId;

public ControllerTestsBase(){
this.StartSqlContainer();

this.TestId = Guid.NewGuid();
String dbConnString = GetLocalConnectionString($"EstateReportingReadModel{this.TestId}");

this.factory = new CustomWebApplicationFactory<Startup>(dbConnString);
this.Client = this.factory.CreateClient();
}

internal async Task<HttpResponseMessage> CreateAndSendHttpRequestMessage(String url)
{
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
requestMessage.Headers.Add("estateId", this.TestId.ToString());

HttpResponseMessage result = await this.Client.SendAsync(requestMessage, CancellationToken.None);

return result;
}
public static IContainerService DatabaseServerContainer;
public static INetworkService DatabaseServerNetwork;
public static (String usename, String password) SqlCredentials = ("sa", "thisisalongpassword123!");

public static String GetLocalConnectionString(String databaseName)
{
Int32 databaseHostPort = DatabaseServerContainer.ToHostExposedEndpoint("1433/tcp").Port;

return $"server=localhost,{databaseHostPort};database={databaseName};user id={SqlCredentials.usename};password={SqlCredentials.password};Encrypt=false";
}

internal void StartSqlContainer(){
DockerHelper dockerHelper = new DockerHelper();

NlogLogger logger = new NlogLogger();
logger.Initialise(LogManager.GetLogger("Specflow"), "Specflow");
LogManager.AddHiddenAssembly(typeof(NlogLogger).Assembly);
dockerHelper.Logger = logger;
dockerHelper.SqlCredentials = SqlCredentials;
dockerHelper.SqlServerContainerName = "sharedsqlserver";

DatabaseServerNetwork = dockerHelper.SetupTestNetwork("sharednetwork", true);
Retry.For(async () => {
DatabaseServerContainer = dockerHelper.SetupSqlServerContainer(DatabaseServerNetwork);
});
}
}
40 changes: 40 additions & 0 deletions EstateReportingAPI.IntegrationTests/CustomWebApplicationFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace EstateReportingAPI.IntegrationTests;

using BusinessLogic;
using EstateManagement.Database.Contexts;
using EstateReportingAPI.Common;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.DependencyInjection;
using Shared.EntityFramework;
using Shouldly;

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
private readonly string DatabaseConnectionString;

public CustomWebApplicationFactory(string databaseConnectionString)
{
DatabaseConnectionString = databaseConnectionString;
Environment.SetEnvironmentVariable("InTestMode", "true");
}

protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(containerBuilder =>
{
var context = new EstateManagementSqlServerContext(DatabaseConnectionString);
Func<string, EstateManagementGenericContext> f = connectionString => context;

IDbContextFactory<EstateManagementGenericContext> factory = new DbContextFactory<EstateManagementGenericContext>(new ConfigurationReaderConnectionStringRepository(), f);

IReportingManager manager = new ReportingManager(factory);

containerBuilder.AddSingleton(manager);

bool b = context.Database.EnsureCreated();

b.ShouldBeTrue();
});
}
}
148 changes: 148 additions & 0 deletions EstateReportingAPI.IntegrationTests/DatabaseHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
namespace EstateReportingAPI.IntegrationTests;

using EstateManagement.Database.Contexts;
using EstateManagement.Database.Entities;
using EstateManagement.Database.Migrations.MySql;
using Microsoft.EntityFrameworkCore;

public class DatabaseHelper{
private readonly EstateManagementGenericContext Context;

public DatabaseHelper(EstateManagementGenericContext context){
this.Context = context;
}

public async Task AddCalendarYear(Int32 year){
List<DateTime> datesInYear = this.GetDatesForYear(year);
await this.AddCalendarDates(datesInYear);
}

public async Task AddCalendarDates(List<DateTime> dates){
foreach (DateTime dateTime in dates){
EstateManagement.Database.Entities.Calendar c = dateTime.ToCalendar();
await this.Context.Calendar.AddAsync(c);
}

await this.Context.SaveChangesAsync();
}

public async Task AddCalendarDate(DateTime date){
Calendar c = date.ToCalendar();
await this.Context.Calendar.AddAsync(c);
await this.Context.SaveChangesAsync();
}

public List<DateTime> GetDatesForYear(Int32 year){
List<DateTime> datesInYear = new List<DateTime>();
DateTime startDate = new DateTime(year, 1, 1);
DateTime endDate = new DateTime(year, 12, 31);

for (DateTime currentDate = startDate; currentDate <= endDate; currentDate = currentDate.AddDays(1))
{
datesInYear.Add(currentDate);
}
return datesInYear;
}

public async Task AddSettlementRecordWithFees(DateTime dateTime, Int32 estateReportingId, Int32 merchantReportingId,
List<(Decimal feeValue, Decimal calulatedValue, Int32 transactionFeeReportingId)> feesList){
Settlement settlementRecord = new Settlement{
ProcessingStarted = true,
IsCompleted = true,
EstateReportingId = estateReportingId,
MerchantReportingId = merchantReportingId,
ProcessingStartedDateTIme = dateTime,
SettlementDate = dateTime,
SettlementId = Guid.NewGuid(),
};
await this.Context.Settlements.AddAsync(settlementRecord, CancellationToken.None);

await this.Context.SaveChangesAsync(CancellationToken.None);

var settlement = await this.Context.Settlements.Where(s => s.SettlementId == settlementRecord.SettlementId).SingleAsync(CancellationToken.None);

Int32 counter = 1;
foreach ((Decimal feeValue, Decimal calulatedValue, Int32 transactionFeeReportingId) fee in feesList){
MerchantSettlementFee merchantSettlementFee = new MerchantSettlementFee{
MerchantReportingId = merchantReportingId,
SettlementReportingId = settlement.SettlementReportingId,
IsSettled = true,
FeeCalculatedDateTime = dateTime,
TransactionReportingId = counter,
TransactionFeeReportingId = fee.transactionFeeReportingId,
CalculatedValue = fee.calulatedValue,
FeeValue = fee.feeValue
};
counter++;
await this.Context.MerchantSettlementFees.AddAsync(merchantSettlementFee, CancellationToken.None);
}

await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task<Transaction> AddTransaction(DateTime dateTime, Int32 merchantReportingId,String operatorIdentifier, Int32 contractProductReportingId,
String responseCode, Decimal transactionAmount){

Transaction transaction = new Transaction{
MerchantReportingId = merchantReportingId,
TransactionDate = dateTime.Date,
TransactionDateTime = dateTime,
IsCompleted = true,
AuthorisationCode = "ABCD1234",
DeviceIdentifier = "testdevice1",
OperatorIdentifier = operatorIdentifier,
ContractReportingId = 1,
ContractProductReportingId = contractProductReportingId,
IsAuthorised = responseCode == "0000",
ResponseCode = responseCode,
TransactionAmount = transactionAmount,
TransactionId = Guid.NewGuid(),
TransactionTime = dateTime.TimeOfDay,
TransactionType = "Sale"
};
await this.Context.Transactions.AddAsync(transaction, CancellationToken.None);
await this.Context.SaveChangesAsync(CancellationToken.None);
return transaction;
}

public async Task AddMerchant(Int32 estateReportingId, String merchantName, DateTime lastSaleDateTime){
Merchant merchant = new Merchant{
EstateReportingId = estateReportingId,
MerchantId = Guid.NewGuid(),
Name = merchantName,
LastSaleDate = lastSaleDateTime.Date,
LastSaleDateTime = lastSaleDateTime
};

await this.Context.Merchants.AddAsync(merchant);
await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task AddContractProduct(String productName){
ContractProduct contractProduct = new ContractProduct{
ContractReportingId = 1,
DisplayText = productName,
ProductId = Guid.NewGuid(),
ProductName = productName,
ProductType = 1,
Value = null
};

await this.Context.ContractProducts.AddAsync(contractProduct);
await this.Context.SaveChangesAsync(CancellationToken.None);
}

public async Task AddEstateOperator(String operatorIdentifier){
EstateOperator estateOperator = new EstateOperator{
EstateReportingId = 1,
Name = operatorIdentifier,
OperatorId = Guid.NewGuid(),
RequireCustomMerchantNumber = false,
RequireCustomTerminalNumber = false
};

await this.Context.EstateOperators.AddAsync(estateOperator);
await this.Context.SaveChangesAsync(CancellationToken.None);
}

}
Loading