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
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ public class ProgressDataServiceTests
private SqlConnection connection = null!;
private ProgressDataService progressDataService = null!;
private TutorialContentTestHelper tutorialContentTestHelper = null!;
private ProgressTestHelper progressTestHelper = null!;

[SetUp]
public void SetUp()
{
connection = ServiceTestHelper.GetDatabaseConnection();
progressDataService = new ProgressDataService(connection);
tutorialContentTestHelper = new TutorialContentTestHelper(connection);
progressTestHelper = new ProgressTestHelper(connection);
}

[Test]
Expand Down Expand Up @@ -221,5 +223,28 @@ public void
transaction.Dispose();
}
}

[Test]
public void ClearAspProgressVerificationRequest_updates_aspProgress_records()
{
// Given
const int progressId = 285046;
const int aspProgressId = 8509834;

using var transaction = new TransactionScope();
try
{
// When
progressDataService.ClearAspProgressVerificationRequest(progressId);
var result = progressTestHelper.GetSupervisorVerificationRequestedByAspProgressId(aspProgressId);

// Then
result.Should().BeNull();
}
finally
{
transaction.Dispose();
}
}
}
}
107 changes: 107 additions & 0 deletions DigitalLearningSolutions.Data.Tests/Services/ProgressServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
namespace DigitalLearningSolutions.Data.Tests.Services
{
using System;
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.Exceptions;
using DigitalLearningSolutions.Data.Models.Courses;
using DigitalLearningSolutions.Data.Services;
using FakeItEasy;
using NUnit.Framework;

public class ProgressServiceTests
{
private ICourseDataService courseDataService = null!;
private IProgressDataService progressDataService = null!;
private IProgressService progressService = null!;

[SetUp]
public void SetUp()
{
courseDataService = A.Fake<ICourseDataService>();
progressDataService = A.Fake<IProgressDataService>();

progressService = new ProgressService(courseDataService, progressDataService);
}

[Test]
public void UpdateSupervisor_does_not_update_records_if_new_supervisor_matches_current()
{
// Given
const int supervisorId = 1;
const int progressId = 1;
var courseInfo = new DelegateCourseInfo { SupervisorAdminId = supervisorId };
A.CallTo(() => courseDataService.GetDelegateCourseInfoByProgressId(progressId)).Returns(courseInfo);

// When
progressService.UpdateSupervisor(progressId, supervisorId);

// Then
A.CallTo(
() => progressDataService.UpdateProgressSupervisorAndCompleteByDate(A<int>._, A<int>._, A<DateTime?>._)
).MustNotHaveHappened();
A.CallTo(
() => progressDataService.ClearAspProgressVerificationRequest(A<int>._)
).MustNotHaveHappened();
}

[Test]
public void UpdateSupervisor_updates_records_if_new_supervisor_does_not_match_current()
{
// Given
const int oldSupervisorId = 1;
const int newSupervisorId = 6;
const int progressId = 1;
var courseInfo = new DelegateCourseInfo { SupervisorAdminId = oldSupervisorId };
A.CallTo(() => courseDataService.GetDelegateCourseInfoByProgressId(progressId)).Returns(courseInfo);

// When
progressService.UpdateSupervisor(progressId, newSupervisorId);

// Then
A.CallTo(
() => progressDataService.UpdateProgressSupervisorAndCompleteByDate(progressId, newSupervisorId, A<DateTime?>._)
).MustHaveHappened();
A.CallTo(
() => progressDataService.ClearAspProgressVerificationRequest(progressId)
).MustHaveHappened();
}

[Test]
public void UpdateSupervisor_sets_supervisor_id_to_0_if_new_supervisor_is_null()
{
// Given
const int oldSupervisorId = 1;
const int progressId = 1;
var courseInfo = new DelegateCourseInfo { SupervisorAdminId = oldSupervisorId };
A.CallTo(() => courseDataService.GetDelegateCourseInfoByProgressId(progressId)).Returns(courseInfo);

// When
progressService.UpdateSupervisor(progressId, null);

// Then
A.CallTo(
() => progressDataService.UpdateProgressSupervisorAndCompleteByDate(progressId, 0, A<DateTime?>._)
).MustHaveHappened();
A.CallTo(
() => progressDataService.ClearAspProgressVerificationRequest(progressId)
).MustHaveHappened();
}

[Test]
public void UpdateSupervisor_throws_exception_if_no_progress_record_found()
{
// Given
const int progressId = 1;
A.CallTo(() => courseDataService.GetDelegateCourseInfoByProgressId(progressId)).Returns(null);

// Then
Assert.Throws<ProgressNotFoundException>(() => progressService.UpdateSupervisor(progressId, null));
A.CallTo(
() => progressDataService.UpdateProgressSupervisorAndCompleteByDate(A<int>._, A<int>._, A<DateTime?>._)
).MustNotHaveHappened();
A.CallTo(
() => progressDataService.ClearAspProgressVerificationRequest(A<int>._)
).MustNotHaveHappened();
}
}
}
18 changes: 18 additions & 0 deletions DigitalLearningSolutions.Data.Tests/Services/UserServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using DigitalLearningSolutions.Data.Services;
using DigitalLearningSolutions.Data.Tests.TestHelpers;
using FakeItEasy;
using FizzWare.NBuilder;
using FluentAssertions;
using FluentAssertions.Common;
using NUnit.Framework;
Expand Down Expand Up @@ -904,6 +905,23 @@ public void UpdateUserAccountDetailsViaDelegateAccount_updates_name_and_email_on
).MustHaveHappened();
}

[Test]
public void GetSupervisorsAtCentre_returns_expected_admins()
{
// Given
var adminUsers = Builder<AdminUser>.CreateListOfSize(10)
.TheFirst(5).With(au => au.IsSupervisor = true)
.TheRest().With(au => au.IsSupervisor = false).Build().ToList();
A.CallTo(() => userDataService.GetAdminUsersByCentreId(A<int>._)).Returns(adminUsers);

// When
var result = userService.GetSupervisorsAtCentre(1).ToList();

// Then
result.Count().Should().Be(5);
result.All(au => au.IsSupervisor).Should().BeTrue();
}

private void AssertAdminPermissionsCalledCorrectly(
int adminId,
AdminRoles adminRoles,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
namespace DigitalLearningSolutions.Data.Tests.TestHelpers
{
using System;
using System.Linq;
using Dapper;
using DigitalLearningSolutions.Data.Models;
using Microsoft.Data.SqlClient;

public static class ProgressTestHelper
public class ProgressTestHelper
{
private readonly SqlConnection connection;

public ProgressTestHelper(SqlConnection connection)
{
this.connection = connection;
}

public static Progress GetDefaultProgress(
int progressId = 1,
int candidateId = 1,
Expand All @@ -26,5 +36,15 @@ public static Progress GetDefaultProgress(
CompleteByDate = completeByDate
};
}

public DateTime? GetSupervisorVerificationRequestedByAspProgressId(int aspProgressId)
{
return connection.Query<DateTime?>(
@"SELECT SupervisorVerificationRequested
FROM aspProgress
WHERE aspProgressId = @aspProgressId",
new { aspProgressId }
).Single();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this must work since the tests pass, but my understanding of the Single() LINQ operator is that it throws if there's not exactly one result, so this can never return null. Can you tell me what I've got wrong here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The column SupervisorVerificationRequested is a nullable datetime, so if the aspProgress record exists but has null it will return null, hence the DateTime? return type.
As you say, this will throw an exception if there is not exactly one result, but since we are looking it up by aspProgressId and using it in a unit test this is the behaviour we would want. i.e. this will only throw an exception if the aspProgress record gets deleted from the database for some reason.

}
}
}
11 changes: 11 additions & 0 deletions DigitalLearningSolutions.Data/DataServices/ProgressDataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ int supervisorAdminId

void CreateNewAspProgress(int tutorialId, int progressId);
void InsertNewAspProgressRecordsForTutorialIfNoneExist(int tutorialId, int customisationId);
void ClearAspProgressVerificationRequest(int progressId);
}

public class ProgressDataService : IProgressDataService
Expand Down Expand Up @@ -150,5 +151,15 @@ FROM aspProgress
new { tutorialId, customisationId }
);
}

public void ClearAspProgressVerificationRequest(int progressId)
{
connection.Execute(
@"UPDATE aspProgress SET
SupervisorVerificationRequested = NULL
WHERE ProgressID = @progressId",
new { progressId }
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace DigitalLearningSolutions.Data.Exceptions
{
using System;

public class ProgressNotFoundException : Exception
{
public ProgressNotFoundException(string message)
: base(message) { }
}
}
52 changes: 52 additions & 0 deletions DigitalLearningSolutions.Data/Services/ProgressService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
namespace DigitalLearningSolutions.Data.Services
{
using System.Transactions;
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.Exceptions;

public interface IProgressService
{
void UpdateSupervisor(int progressId, int? newSupervisorId);
}

public class ProgressService : IProgressService
{
private readonly ICourseDataService courseDataService;
private readonly IProgressDataService progressDataService;

public ProgressService(ICourseDataService courseDataService, IProgressDataService progressDataService)
{
this.courseDataService = courseDataService;
this.progressDataService = progressDataService;
}

public void UpdateSupervisor(int progressId, int? newSupervisorId)
{
var courseInfo = courseDataService.GetDelegateCourseInfoByProgressId(progressId);

if (courseInfo == null)
{
throw new ProgressNotFoundException($"No progress record found for ProgressID {progressId}");
}

if (courseInfo.SupervisorAdminId == newSupervisorId)
{
return;
}

var supervisorId = newSupervisorId ?? 0;

using var transaction = new TransactionScope();

progressDataService.UpdateProgressSupervisorAndCompleteByDate(
progressId,
supervisorId,
courseInfo.CompleteBy
);

progressDataService.ClearAspProgressVerificationRequest(progressId);

transaction.Complete();
}
}
}
7 changes: 7 additions & 0 deletions DigitalLearningSolutions.Data/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ void UpdateUserAccountDetailsViaDelegateAccount(
EditDelegateDetailsData editDelegateDetailsData,
CentreAnswersData centreAnswersData
);

IEnumerable<AdminUser> GetSupervisorsAtCentre(int centreId);
}

public class UserService : IUserService
Expand Down Expand Up @@ -362,6 +364,11 @@ CentreAnswersData centreAnswersData
);
}

public IEnumerable<AdminUser> GetSupervisorsAtCentre(int centreId)
{
return userDataService.GetAdminUsersByCentreId(centreId).Where(au => au.IsSupervisor);
}

private static bool UserEmailHasChanged(User? user, string emailAddress)
{
return user != null && !emailAddress.Equals(user.EmailAddress, StringComparison.InvariantCultureIgnoreCase);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public BasicAuthenticatedAccessibilityTests(AuthenticatedAccessibilityTestsFixtu
[InlineData("/TrackingSystem/Delegates/Email", "Send welcome messages")]
[InlineData("/TrackingSystem/Delegates/CourseDelegates", "Course delegates")]
[InlineData("/TrackingSystem/Delegates/CourseDelegates/DelegateProgress/243104", "Delegate progress")]
[InlineData(
"/TrackingSystem/Delegates/CourseDelegates/DelegateProgress/243104/EditSupervisor",
"Edit supervisor for Digital Literacy for the Workplace - CC Test"
)]
[InlineData("/NotificationPreferences", "Notification preferences")]
[InlineData("/NotificationPreferences/Edit/AdminUser", "Update notification preferences")]
[InlineData("/NotificationPreferences/Edit/DelegateUser", "Update notification preferences")]
Expand Down
Loading