Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using SFA.DAS.CommitmentsV2.Types;
using CommonEmployerType = SFA.DAS.Common.Domain.Types.ApprenticeshipEmployerType;
using SFA.DAS.EmployerAccounts.Messages.Events;
using ApprenticeshipEmployerType = SFA.DAS.Common.Domain.Types.ApprenticeshipEmployerType;
using SFA.DAS.EmployerAccounts.Types.Models;
using SFA.DAS.EmployerFinance.Messages.Events;
using SFA.DAS.Payments.ProviderPayments.Messages;
Expand Down Expand Up @@ -65,6 +66,7 @@ public async Task Run()
Console.WriteLine("Z - ApprenticeshipStopDateChangedEvent Event");
Console.WriteLine("1 - ChangeOfPartyRequestCreatedEvent Event");
Console.WriteLine("2 - ApprenticeshipStartDateChangedEvent Event");
Console.WriteLine("3 - ApprenticeshipEmployerTypeChangeEvent (NonLevy)");
Console.WriteLine("X - Exit");
Console.WriteLine("Press [Key] for Test Option");
key = Console.ReadKey().Key;
Expand Down Expand Up @@ -172,16 +174,6 @@ await _publisher.Publish(new ApprenticeshipEmailAddressConfirmedEvent()
Console.WriteLine($"Sent {nameof(ApprenticeshipEmailAddressConfirmedEvent)}");
break;

case ConsoleKey.D3:
await _publisher.Publish(new ApprenticeshipEmployerTypeChangeEvent
{
AccountId = accountId,
ApprenticeshipEmployerType = CommonEmployerType.NonLevy,
Created = DateTime.UtcNow
});
Console.WriteLine();
Console.WriteLine($"Published {nameof(ApprenticeshipEmployerTypeChangeEvent)}");
break;
case ConsoleKey.S:
await _publisher.Publish(new LevyAddedToAccount { AccountId = accountId, Amount = 10, Created = DateTime.UtcNow });
Console.WriteLine();
Expand Down Expand Up @@ -242,7 +234,17 @@ await _publisher.Publish(new ApprenticeshipStopDateChangedEvent()
Console.WriteLine();
Console.WriteLine($"Sent {nameof(ChangeOfPartyRequestCreatedEvent)}");
break;
}
case ConsoleKey.D3:
await _publisher.Publish(new ApprenticeshipEmployerTypeChangeEvent
{
AccountId = accountId,
ApprenticeshipEmployerType = ApprenticeshipEmployerType.NonLevy,
Created = DateTime.UtcNow
});
Console.WriteLine();
Console.WriteLine($"Published {nameof(ApprenticeshipEmployerTypeChangeEvent)} (NonLevy)");
break;
}
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Moq;
using NServiceBus;
using NUnit.Framework;
using SFA.DAS.CommitmentsV2.Data;
using SFA.DAS.CommitmentsV2.MessageHandlers.EventHandlers;
using SFA.DAS.CommitmentsV2.Messages.Commands;
using SFA.DAS.CommitmentsV2.Models;
using SFA.DAS.CommitmentsV2.Types;
using SFA.DAS.EmployerAccounts.Messages.Events;
using ApprenticeshipEmployerType = SFA.DAS.Common.Domain.Types.ApprenticeshipEmployerType;

namespace SFA.DAS.CommitmentsV2.MessageHandlers.UnitTests.EventHandlers;

[TestFixture]
[Parallelizable(ParallelScope.All)]
public class ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTests
{
private const long SenderAccountId = 1001;
private const long FirstTransferRequestId = 501;
private const long SecondTransferRequestId = 502;

private static bool IsRejectCommand(object message, long transferRequestId) =>
message is RejectTransferRequestCommand command
&& command.TransferRequestId == transferRequestId
&& command.UserInfo.IsSystem();

[Test]
public async Task Handle_WhenEmployerBecomesNonLevy_ThenRejectTransferRequestCommandsAreSentForPendingSenderRequests()
{
// Arrange
var fixture = new ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture()
.WithPendingTransferRequestForSender(SenderAccountId, FirstTransferRequestId)
.WithPendingTransferRequestForSender(SenderAccountId, SecondTransferRequestId)
.WithPendingTransferRequestForSender(9999, 503);

var sentCommands = new List<RejectTransferRequestCommand>();
fixture.MessageHandlerContext
.Setup(m => m.Send(
It.Is<object>(o => o is RejectTransferRequestCommand),
It.Is<SendOptions>(_ => true)))
.Callback<object, SendOptions>((command, _) => sentCommands.Add((RejectTransferRequestCommand)command))
.Returns(Task.CompletedTask);

// Act
await fixture.Handle();

// Assert
Assert.That(sentCommands.Select(c => c.TransferRequestId), Is.EquivalentTo(new[] { FirstTransferRequestId, SecondTransferRequestId }));

Check warning on line 55 in src/CommitmentsV2/SFA.DAS.CommitmentsV2.MessageHandlers.UnitTests/EventHandlers/ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Call independent Assert statements from inside an Assert.Multiple

See more on https://sonarcloud.io/project/issues?id=SkillsFundingAgency_das-commitments&issues=AZ9djbL7BbwD4N7BGK-U&open=AZ9djbL7BbwD4N7BGK-U&pullRequest=1557
Assert.That(sentCommands, Has.All.Matches<RejectTransferRequestCommand>(c => c.UserInfo.IsSystem()));
}

[Test]
public async Task Handle_WhenEmployerBecomesLevy_ThenNoRejectTransferRequestCommandsAreSent()
{
// Arrange
var fixture = new ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture()
.WithPendingTransferRequestForSender(SenderAccountId, FirstTransferRequestId)
.WithEmployerType(ApprenticeshipEmployerType.Levy);

// Act
await fixture.Handle();

// Assert
fixture.MessageHandlerContext.Verify(m => m.Send(
It.Is<object>(o => IsRejectCommand(o, FirstTransferRequestId)),
It.Is<SendOptions>(_ => true)),
Times.Never);
}

[Test]
public async Task Handle_WhenEmployerTypeIsUnknown_ThenNoRejectTransferRequestCommandsAreSent()
{
// Arrange
var fixture = new ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture()
.WithPendingTransferRequestForSender(SenderAccountId, FirstTransferRequestId)
.WithEmployerType(ApprenticeshipEmployerType.Unknown);

// Act
await fixture.Handle();

// Assert
fixture.MessageHandlerContext.Verify(m => m.Send(
It.Is<object>(o => IsRejectCommand(o, FirstTransferRequestId)),
It.Is<SendOptions>(_ => true)),
Times.Never);
}

[Test]
public async Task Handle_WhenTransferRequestIsApprovedOrRejected_ThenNoRejectTransferRequestCommandIsSent()
{
// Arrange
var fixture = new ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture()
.WithTransferRequestForSender(SenderAccountId, 601, TransferApprovalStatus.Approved)
.WithTransferRequestForSender(SenderAccountId, 602, TransferApprovalStatus.Rejected);

// Act
await fixture.Handle();

// Assert
fixture.MessageHandlerContext.Verify(m => m.Send(
It.Is<object>(o => IsRejectCommand(o, 601)),
It.Is<SendOptions>(_ => true)),
Times.Never);

fixture.MessageHandlerContext.Verify(m => m.Send(
It.Is<object>(o => IsRejectCommand(o, 602)),
It.Is<SendOptions>(_ => true)),
Times.Never);
}
}

public class ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture : IDisposable
{
private readonly ProviderCommitmentsDbContext _db;
private readonly ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfers _handler;

public Mock<IMessageHandlerContext> MessageHandlerContext { get; } = new();
public ApprenticeshipEmployerTypeChangeEvent Event { get; private set; } = new()
{
AccountId = 1001,
ApprenticeshipEmployerType = ApprenticeshipEmployerType.NonLevy,
Created = DateTime.UtcNow
};

public ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture()
{
_db = new ProviderCommitmentsDbContext(new DbContextOptionsBuilder<ProviderCommitmentsDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString(), b => b.EnableNullChecks(false))
.Options);

_handler = new ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfers(
new Lazy<ProviderCommitmentsDbContext>(() => _db),
Mock.Of<ILogger<ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfers>>());
}

public ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture WithEmployerType(ApprenticeshipEmployerType employerType)
{
Event.ApprenticeshipEmployerType = employerType;
return this;
}

public ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture WithPendingTransferRequestForSender(long senderAccountId, long transferRequestId)
{
return WithTransferRequestForSender(senderAccountId, transferRequestId, TransferApprovalStatus.Pending);
}

public ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture WithTransferRequestForSender(
long senderAccountId,
long transferRequestId,
TransferApprovalStatus status)
{
var cohort = new Cohort
{
Id = transferRequestId + 1000,
TransferSenderId = senderAccountId,
EmployerAccountId = senderAccountId + 1
};

var transferRequest = new TransferRequest
{
Id = transferRequestId,
Status = status,
Cohort = cohort,
CommitmentId = cohort.Id
};

_db.Cohorts.Add(cohort);
_db.TransferRequests.Add(transferRequest);
_db.SaveChanges();

return this;
}

public Task Handle() => _handler.Handle(Event, MessageHandlerContext.Object);

public void Dispose() => _db.Dispose();

Check warning on line 183 in src/CommitmentsV2/SFA.DAS.CommitmentsV2.MessageHandlers.UnitTests/EventHandlers/ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Change ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfersTestsFixture.Dispose() to call GC.SuppressFinalize(object). This will prevent derived types that introduce a finalizer from needing to re-implement 'IDisposable' to call it.

See more on https://sonarcloud.io/project/issues?id=SkillsFundingAgency_das-commitments&issues=AZ9djbL7BbwD4N7BGK-V&open=AZ9djbL7BbwD4N7BGK-V&pullRequest=1557
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using SFA.DAS.CommitmentsV2.Data;
using SFA.DAS.CommitmentsV2.Messages.Commands;
using SFA.DAS.CommitmentsV2.Types;
using SFA.DAS.EmployerAccounts.Messages.Events;
using ApprenticeshipEmployerType = SFA.DAS.Common.Domain.Types.ApprenticeshipEmployerType;

namespace SFA.DAS.CommitmentsV2.MessageHandlers.EventHandlers;

public class ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfers(
Lazy<ProviderCommitmentsDbContext> dbContext,
ILogger<ApprenticeshipEmployerTypeChangeEventHandlerToAutoRejectTransfers> logger)
: IHandleMessages<ApprenticeshipEmployerTypeChangeEvent>
{
public async Task Handle(ApprenticeshipEmployerTypeChangeEvent message, IMessageHandlerContext context)
{
if (message.ApprenticeshipEmployerType != ApprenticeshipEmployerType.NonLevy)
{
logger.LogInformation(
"Ignoring ApprenticeshipEmployerTypeChangeEvent for account {AccountId} because employer type is {EmployerType}",
message.AccountId,
message.ApprenticeshipEmployerType);
return;
}

logger.LogInformation("Handling ApprenticeshipEmployerTypeChangeEvent for account {AccountId}", message.AccountId);

var transferRequestIds = await dbContext.Value.TransferRequests
.Where(tr => tr.Status == TransferApprovalStatus.Pending
&& tr.Cohort.TransferSenderId == message.AccountId)
.Select(tr => tr.Id)
.ToListAsync();

var rejectedOn = DateTime.UtcNow;

foreach (var transferRequestId in transferRequestIds)
{
await context.Send(
new RejectTransferRequestCommand(transferRequestId, rejectedOn, UserInfo.System),
new SendOptions());
}

logger.LogInformation(
"Queued {TransferRequestCount} transfer request rejections for account {AccountId}",
transferRequestIds.Count,
message.AccountId);
}
}
Loading