Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FAI-2021 APIM Delete search alerts Dormant Account #1859

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
@@ -0,0 +1,52 @@
using AutoFixture.NUnit3;
using FluentAssertions;
using FluentAssertions.Execution;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Moq;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.Api.Controllers;
using SFA.DAS.FindApprenticeshipJobs.Application.Queries.SavedSearch.GetCandidatesByActivity;
using SFA.DAS.Testing.AutoFixture;
using System.Net;

namespace SFA.DAS.FindApprenticeshipJobs.Api.UnitTests.Controllers
{
[TestFixture]
public class WhenGettingCandidatesByActivity
{
[Test, MoqAutoData]
public async Task Then_Candidates_Returned_From_Mediator(
DateTime cutOffDateTime,
GetCandidateByActivityQueryResult mockQueryResult,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] CandidatesController sut)
{
mockMediator.Setup(x => x.Send(It.IsAny<GetCandidateByActivityQuery>(), It.IsAny<CancellationToken>())).ReturnsAsync(mockQueryResult);

var actual = await sut.GetCandidatesByActivity(cutOffDateTime, It.IsAny<CancellationToken>()) as ObjectResult;
var actualValue = actual!.Value as GetCandidateByActivityQueryResult;

using (new AssertionScope())
{
actual.StatusCode.Should().Be((int)HttpStatusCode.OK);
actual.Value.Should().BeOfType<GetCandidateByActivityQueryResult>();
actualValue!.Candidates.Should().BeEquivalentTo(mockQueryResult.Candidates);
}
}

[Test, MoqAutoData]
public async Task And_Exception_Returned_Then_Returns_Internal_Server_Error(
DateTime cutOffDateTime,
GetCandidateByActivityQueryResult mockQueryResult,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] CandidatesController sut)
{
mockMediator.Setup(x => x.Send(It.IsAny<GetCandidateByActivityQuery>(), It.IsAny<CancellationToken>())).ThrowsAsync(new InvalidOperationException());

var actual = await sut.GetCandidatesByActivity(cutOffDateTime, It.IsAny<CancellationToken>()) as StatusCodeResult;

actual!.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using AutoFixture.NUnit3;
using FluentAssertions;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Moq;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.Api.Controllers;
using SFA.DAS.FindApprenticeshipJobs.Api.Models;
using SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.UnsubscribeSavedSearch;
using SFA.DAS.Testing.AutoFixture;
using System.Net;

namespace SFA.DAS.FindApprenticeshipJobs.Api.UnitTests.Controllers
{
[TestFixture]
public class WhenPostingUnsubscribeSavedSearch
{
[Test, MoqAutoData]
public async Task Then_NoContent_Returned_From_Mediator(
PostUnsubscribeSavedSearchApiRequest mockApiRequest,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] SavedSearchesController sut)
{
var actual = await sut.PostUnsubscribeSavedSearch(mockApiRequest, It.IsAny<CancellationToken>()) as ObjectResult;

mockMediator.Verify(x => x.Send(It.IsAny<UnsubscribeSavedSearchCommand>(),
It.IsAny<CancellationToken>()),
Times.Once);
}

[Test, MoqAutoData]
public async Task And_Exception_Returned_Then_Returns_Internal_Server_Error(
PostUnsubscribeSavedSearchApiRequest mockApiRequest,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] SavedSearchesController sut)
{
mockMediator.Setup(x => x.Send(It.IsAny<UnsubscribeSavedSearchCommand>(), It.IsAny<CancellationToken>())).ThrowsAsync(new InvalidOperationException());

var actual = await sut.PostUnsubscribeSavedSearch(mockApiRequest, It.IsAny<CancellationToken>()) as StatusCodeResult;

actual!.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using MediatR;
using Microsoft.AspNetCore.Mvc;
using SFA.DAS.FindApprenticeshipJobs.Application.Queries.SavedSearch.GetCandidatesByActivity;
using System.Net;

namespace SFA.DAS.FindApprenticeshipJobs.Api.Controllers
{
[ApiController]
[Route("[controller]")]
public class CandidatesController(
IMediator mediator,
ILogger<CandidatesController> logger) : ControllerBase
{
[HttpGet]
[Route("GetCandidatesByActivity")]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> GetCandidatesByActivity(
[FromQuery] DateTime cutOffDateTime,
CancellationToken cancellationToken = default)
{
logger.LogInformation("Get Candidates By Activity invoked");

try
{
var result = await mediator.Send(new GetCandidateByActivityQuery(cutOffDateTime),
cancellationToken);
return Ok(result);
}
catch (Exception ex)
{
logger.LogError(ex, "Error invoking Get Candidates By Activity");
return new StatusCodeResult((int)HttpStatusCode.InternalServerError);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using SFA.DAS.FindApprenticeshipJobs.Domain.Models;
using System.Net;
using SFA.DAS.FindApprenticeshipJobs.Api.Models;
using SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.UnsubscribeSavedSearch;

namespace SFA.DAS.FindApprenticeshipJobs.Api.Controllers
{
Expand Down Expand Up @@ -63,5 +64,28 @@ public async Task<IActionResult> SendNotification(
return new StatusCodeResult((int)HttpStatusCode.InternalServerError);
}
}

[HttpPost]
[Route("unsubscribe")]
[ProducesResponseType((int)HttpStatusCode.NoContent)]
[ProducesResponseType((int)HttpStatusCode.InternalServerError)]
public async Task<IActionResult> PostUnsubscribeSavedSearch(
[FromBody] PostUnsubscribeSavedSearchApiRequest request,
CancellationToken cancellationToken = default)
{
logger.LogInformation("Post un-subscribe saved search invoked");

try
{
await mediator.Send(new UnsubscribeSavedSearchCommand(request.SavedSearchId), cancellationToken);

return Ok();
}
catch (Exception ex)
{
logger.LogError(ex, "Post Unsubscribe Saved Search : An error occurred");
return new StatusCodeResult((int)HttpStatusCode.InternalServerError);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace SFA.DAS.FindApprenticeshipJobs.Api.Models
{
public record PostUnsubscribeSavedSearchApiRequest(Guid SavedSearchId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using AutoFixture.NUnit3;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.Application.Queries.SavedSearch.GetCandidatesByActivity;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Responses;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.Interfaces;
using SFA.DAS.Testing.AutoFixture;

namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.Candidates
{
[TestFixture]
public class WhenHandlingGetCandidatesByActivityQuery
{
[Test]
[MoqAutoData]
public async Task Then_The_Candidates_Are_Returned(
GetCandidateByActivityQuery query,
GetCandidatesByActivityApiResponse mockCandidatesByActivityApiResponse,
[Frozen] Mock<ICandidateApiClient<CandidateApiConfiguration>> mockCandidateApiClient,
GetCandidateByActivityQueryHandler handler)
{
var expectedGetCandidatesByActivityApiRequest =
new GetCandidatesByActivityApiRequest(query.CutOffDateTime);

mockCandidateApiClient
.Setup(client => client.Get<GetCandidatesByActivityApiResponse>(
It.Is<GetCandidatesByActivityApiRequest>(c =>
c.GetUrl == expectedGetCandidatesByActivityApiRequest.GetUrl)))
.ReturnsAsync(mockCandidatesByActivityApiResponse);


var actual = await handler.Handle(query, CancellationToken.None);

actual.Should().NotBeNull();
actual.Candidates.Should().BeEquivalentTo(mockCandidatesByActivityApiResponse.Candidates);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using AutoFixture.NUnit3;
using FluentAssertions;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;

namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.InnerApi
{
[TestFixture]
public class WhenBuildingDeleteSavedSearchRequest
{
[Test, AutoData]
public void Then_The_Url_Is_Correctly_Built(Guid id)
{
var actual = new DeleteSavedSearchRequest(id);

actual.DeleteUrl.Should().Be($"api/SavedSearches/{id}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using AutoFixture.NUnit3;
using FluentAssertions;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;

namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.InnerApi
{
[TestFixture]
public class WhenBuildingGetCandidatesByActivityApiRequest
{
[Test, AutoData]
public void Then_The_Url_Is_Correctly_Built(DateTime cutOffDateTime)
{
var actual = new GetCandidatesByActivityApiRequest(cutOffDateTime);

actual.GetUrl.Should().Be($"api/candidates/GetCandidatesByActivity?cutOffDateTime={cutOffDateTime:O}");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using AutoFixture.NUnit3;
using Moq;
using NUnit.Framework;
using SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.UnsubscribeSavedSearch;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.Interfaces;
using SFA.DAS.Testing.AutoFixture;


namespace SFA.DAS.FindApprenticeshipJobs.UnitTests.SavedSearches;

public class WhenHandlingUnsubscribeSavedSearchCommand
{
[Test, MoqAutoData]
public async Task Then_The_Command_Is_Handled_And_Delete_Called_With_Id(
UnsubscribeSavedSearchCommand command,
[Frozen] Mock<IFindApprenticeshipApiClient<FindApprenticeshipApiConfiguration>> client,
UnsubscribeSavedSearchCommandHandler handler)
{
await handler.Handle(command, CancellationToken.None);

client.Verify(x => x.Delete(It.Is<DeleteSavedSearchRequest>(c => c.Id.Equals(command.SavedSearchId))), Times.Once);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using MediatR;

namespace SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.UnsubscribeSavedSearch
{
public record UnsubscribeSavedSearchCommand(Guid SavedSearchId) : IRequest;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using MediatR;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.Interfaces;

namespace SFA.DAS.FindApprenticeshipJobs.Application.Commands.SavedSearch.UnsubscribeSavedSearch
{
public class UnsubscribeSavedSearchCommandHandler(
IFindApprenticeshipApiClient<FindApprenticeshipApiConfiguration> apiClient)
: IRequestHandler<UnsubscribeSavedSearchCommand>
{
public async Task Handle(UnsubscribeSavedSearchCommand request, CancellationToken cancellationToken)
{
await apiClient.Delete(new DeleteSavedSearchRequest(request.SavedSearchId));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using MediatR;

namespace SFA.DAS.FindApprenticeshipJobs.Application.Queries.SavedSearch.GetCandidatesByActivity
{
public record GetCandidateByActivityQuery(DateTime CutOffDateTime) : IRequest<GetCandidateByActivityQueryResult>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using MediatR;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Requests;
using SFA.DAS.FindApprenticeshipJobs.InnerApi.Responses;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.Interfaces;

namespace SFA.DAS.FindApprenticeshipJobs.Application.Queries.SavedSearch.GetCandidatesByActivity
{
public class GetCandidateByActivityQueryHandler(
ICandidateApiClient<CandidateApiConfiguration> candidateApiClient)
: IRequestHandler<GetCandidateByActivityQuery, GetCandidateByActivityQueryResult>
{
public async Task<GetCandidateByActivityQueryResult> Handle(GetCandidateByActivityQuery request, CancellationToken cancellationToken)
{
return await candidateApiClient.Get<GetCandidatesByActivityApiResponse>(
new GetCandidatesByActivityApiRequest(request.CutOffDateTime));
}
}
}
Loading