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
@@ -0,0 +1,40 @@
namespace DigitalLearningSolutions.Data.Tests.DataServices.TutorialContentDataServiceTests
{
using System.Linq;
using System.Transactions;
using Dapper;
using FluentAssertions;
using FluentAssertions.Execution;
using NUnit.Framework;

internal partial class TutorialContentDataServiceTests
{
[Test]
public void GetNonArchivedObjectivesBySectionAndCustomisationId_returns_objectives_correctly()
{
using (new TransactionScope())
{
connection.Execute("UPDATE Tutorials SET OriginalTutorialID = 1 WHERE TutorialID = 1137");

// When
var result = tutorialContentDataService.GetNonArchivedObjectivesBySectionAndCustomisationId(248, 22062)
.ToList();

// Then
using (new AssertionScope())
{
result.Count.Should().Be(4);
result.First().TutorialId.Should().Be(1);
result.First().Interactions.Should().BeEquivalentTo(new[] { 0, 1, 2, 3 });
result.First().Possible.Should().Be(4);
result.First().MyScore.Should().Be(0);

result.Last().TutorialId.Should().Be(1257);
result.Last().Interactions.Should().BeEquivalentTo(new[] { 8, 9, 10 });
result.Last().Possible.Should().Be(3);
result.Last().MyScore.Should().Be(0);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@
{
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.Tests.TestHelpers;
using Microsoft.Data.SqlClient;
using NUnit.Framework;

internal partial class TutorialContentDataServiceTests
{
private TutorialContentDataService tutorialContentDataService;
private TutorialContentTestHelper tutorialContentTestHelper;
private SectionContentTestHelper sectionContentTestHelper;
private CourseContentTestHelper courseContentTestHelper;
private SqlConnection connection = null!;
private TutorialContentDataService tutorialContentDataService = null!;
private TutorialContentTestHelper tutorialContentTestHelper = null!;
private SectionContentTestHelper sectionContentTestHelper = null!;
private CourseContentTestHelper courseContentTestHelper = null!;

[SetUp]
public void Setup()
{
var connection = ServiceTestHelper.GetDatabaseConnection();
connection = ServiceTestHelper.GetDatabaseConnection();
tutorialContentDataService = new TutorialContentDataService(connection);
tutorialContentTestHelper = new TutorialContentTestHelper(connection);
sectionContentTestHelper = new SectionContentTestHelper(connection);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
namespace DigitalLearningSolutions.Data.Tests.Services
{
using System.Collections.Generic;
using DigitalLearningSolutions.Data.DataServices;
using DigitalLearningSolutions.Data.Models.Tracker;
using DigitalLearningSolutions.Data.Services;
using FakeItEasy;
using FluentAssertions;
using NUnit.Framework;

public class TrackerActionServiceTests
{
private ITutorialContentDataService dataService = null!;
private ITrackerActionService trackerActionService = null!;

[SetUp]
public void Setup()
{
dataService = A.Fake<ITutorialContentDataService>();

trackerActionService = new TrackerActionService(dataService);
}

[Test]
public void GetObjectiveArray_returns_results_in_specified_json_format()
{
// given
A.CallTo(() => dataService.GetNonArchivedObjectivesBySectionAndCustomisationId(A<int>._, A<int>._))
.Returns(
new[]
{
new Objective(1, new List<int> { 6, 7, 8 }, 4),
new Objective(2, new List<int> { 17, 18, 19 }, 0),
}
);

// when
var result = trackerActionService.GetObjectiveArray(1, 1);

// then
result.Should().BeEquivalentTo(
new TrackerObjectiveArray(
new[]
{
new Objective(1, new List<int> { 6, 7, 8 }, 4),
new Objective(2, new List<int> { 17, 18, 19 }, 0),
}
)
);
}

[Test]
public void GetObjectiveArray_returns_empty_object_json_if_no_results_found()
{
// given
A.CallTo(() => dataService.GetNonArchivedObjectivesBySectionAndCustomisationId(A<int>._, A<int>._))
.Returns(new List<Objective>());

// when
var result = trackerActionService.GetObjectiveArray(1, 1);

// then
result.Should().Be(null);
}

[Test]
[TestCase(null, null)]
[TestCase(1, null)]
[TestCase(null, 1)]
public void GetObjectiveArray_returns_null_if_parameter_missing(
int? customisationId,
int? sectionId
)
{
// given
A.CallTo(() => dataService.GetNonArchivedObjectivesBySectionAndCustomisationId(A<int>._, A<int>._))
.Returns(new[] { new Objective(1, new List<int> { 1 }, 9) });

// when
var result = trackerActionService.GetObjectiveArray(customisationId, sectionId);

// then
result.Should().Be(null);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
namespace DigitalLearningSolutions.Data.Tests.Services
{
using System.Collections.Generic;
using DigitalLearningSolutions.Data.Enums;
using DigitalLearningSolutions.Data.Models.Tracker;
using DigitalLearningSolutions.Data.Services;
Expand All @@ -10,15 +11,17 @@

public class TrackerServiceTests
{
private ITrackerActionService actionService = null!;
private ILogger<TrackerService> logger = null!;
private ITrackerService trackerService = null!;

[SetUp]
public void Setup()
{
logger = A.Fake<ILogger<TrackerService>>();
logger = A.Fake<ILogger<TrackerService>>();
actionService = A.Fake<ITrackerActionService>();

trackerService = new TrackerService(logger);
trackerService = new TrackerService(logger, actionService);
}

[Test]
Expand All @@ -38,13 +41,69 @@ public void ProcessQuery_with_null_action_returns_NullAction_response()
public void ProcessQuery_with_unknown_action_returns_InvalidAction_response()
{
// Given
var query = new TrackerEndpointQueryParams{Action = "InvalidAction"};
var query = new TrackerEndpointQueryParams { Action = "InvalidAction" };

// When
var result = trackerService.ProcessQuery(query);

// Then
result.Should().Be(TrackerEndpointErrorResponse.InvalidAction);
}

[Test]
public void ProcessQuery_with_GetObjectiveArray_action_passes_query_params()
{
// Given
var query = new TrackerEndpointQueryParams
{ Action = "GetObjectiveArray", CustomisationId = 1, SectionId = 2 };

// When
trackerService.ProcessQuery(query);

// Then
A.CallTo(() => actionService.GetObjectiveArray(1, 2)).MustHaveHappenedOnceExactly();
}

[Test]
public void ProcessQuery_with_GetObjectiveArray_action_correctly_serialises_contentful_response()
{
// Given
var dataToReturn = new TrackerObjectiveArray(
new[]
{
new Objective(1, new List<int> { 6, 7, 8 }, 4), new Objective(2, new List<int> { 17, 18, 19 }, 0),
}
);
var expectedJson =
"{\"objectives\":[{\"tutorialid\":1,\"interactions\":[6,7,8],\"possible\":4,\"myscore\":0}," +
"{\"tutorialid\":2,\"interactions\":[17,18,19],\"possible\":0,\"myscore\":0}]}";

var query = new TrackerEndpointQueryParams
{ Action = "GetObjectiveArray", CustomisationId = 1, SectionId = 1 };
A.CallTo(() => actionService.GetObjectiveArray(1, 1)).Returns(dataToReturn);

// When
var result = trackerService.ProcessQuery(query);

// Then
result.Should().Be(expectedJson);
}

[Test]
public void ProcessQuery_with_GetObjectiveArray_action_correctly_serialises_null_response()
{
// Given
TrackerObjectiveArray? dataToReturn = null;

var query = new TrackerEndpointQueryParams
{ Action = "GetObjectiveArray", CustomisationId = 1, SectionId = 1 };
A.CallTo(() => actionService.GetObjectiveArray(1, 1)).Returns(dataToReturn);

// When
var result = trackerService.ProcessQuery(query);

// Then
result.Should().Be("{}");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using System.Data;
using Dapper;
using DigitalLearningSolutions.Data.Exceptions;
using DigitalLearningSolutions.Data.Mappers;
using DigitalLearningSolutions.Data.Models;
using DigitalLearningSolutions.Data.Models.Tracker;
using DigitalLearningSolutions.Data.Models.TutorialContent;

public interface ITutorialContentDataService
Expand All @@ -20,7 +22,15 @@ int tutorialId
TutorialVideo? GetTutorialVideo(int customisationId, int sectionId, int tutorialId);
IEnumerable<Tutorial> GetTutorialsBySectionId(int sectionId, int customisationId);
IEnumerable<int> GetTutorialIdsForCourse(int customisationId);
void UpdateOrInsertCustomisationTutorialStatuses(int tutorialId, int customisationId, bool diagnosticEnabled, bool learningEnabled);

void UpdateOrInsertCustomisationTutorialStatuses(
int tutorialId,
int customisationId,
bool diagnosticEnabled,
bool learningEnabled
);

IEnumerable<Objective> GetNonArchivedObjectivesBySectionAndCustomisationId(int sectionId, int customisationId);
}

public class TutorialContentDataService : ITutorialContentDataService
Expand All @@ -30,6 +40,7 @@ public class TutorialContentDataService : ITutorialContentDataService
public TutorialContentDataService(IDbConnection connection)
{
this.connection = connection;
SqlMapper.AddTypeHandler(new EnumerableIntHandler());
}

public TutorialInformation? GetTutorialInformation(
Expand Down Expand Up @@ -338,5 +349,25 @@ INSERT INTO CustomisationTutorials (CustomisationID, TutorialID, [Status], DiagS
new { customisationId, tutorialId, learningEnabled, diagnosticEnabled }
);
}

public IEnumerable<Objective> GetNonArchivedObjectivesBySectionAndCustomisationId(int sectionId, int customisationId)
{
return connection.Query<Objective>(
@"SELECT
CASE
WHEN tu.OriginalTutorialID > 0 THEN tu.OriginalTutorialID
ELSE tu.TutorialID
END AS TutorialID,
tu.CMIInteractionIDs AS Interactions,
tu.DiagAssessOutOf AS Possible
FROM dbo.Tutorials AS tu
LEFT JOIN dbo.CustomisationTutorials AS ct
ON ct.TutorialID = tu.TutorialID
WHERE tu.SectionID = @sectionId
AND ct.CustomisationID = @customisationId
AND tu.ArchivedDate IS NULL",
new { sectionId, customisationId }
);
}
}
}
5 changes: 4 additions & 1 deletion DigitalLearningSolutions.Data/Enums/TrackerEndpointAction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace DigitalLearningSolutions.Data.Enums
{
public enum TrackerEndpointAction { }
public enum TrackerEndpointAction
{
GetObjectiveArray,
}
}
21 changes: 21 additions & 0 deletions DigitalLearningSolutions.Data/Mappers/EnumerableIntHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace DigitalLearningSolutions.Data.Mappers
{
using System.Data;
using System.Linq;
using System.Collections.Generic;
using Dapper;

public class EnumerableIntHandler : SqlMapper.TypeHandler<IEnumerable<int>>
{
public override void SetValue(IDbDataParameter parameter, IEnumerable<int> value)
{
parameter.DbType = DbType.String;
parameter.Value = string.Join(",", value);
}

public override IEnumerable<int> Parse(object value)
{
return value.ToString()?.Split(',').Select(int.Parse) ?? new List<int>();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DigitalLearningSolutions.Data.Models.Tracker
{
interface ITrackerEndpointDataModel
{
}
}
20 changes: 20 additions & 0 deletions DigitalLearningSolutions.Data/Models/Tracker/Objective.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
namespace DigitalLearningSolutions.Data.Models.Tracker
{
using System.Collections.Generic;

public class Objective
{
public Objective(int tutorialId, IEnumerable<int> interactions, int possible)
{
TutorialId = tutorialId;
Interactions = interactions;
Possible = possible;
MyScore = 0;
}

public int TutorialId { get; set; }
public IEnumerable<int> Interactions { get; set; }
public int Possible { get; set; }
public int MyScore { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
public class TrackerEndpointQueryParams
{
public string? Action { get; set; }
public int? CustomisationId { get; set; }
public int? SectionId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;

namespace DigitalLearningSolutions.Data.Models.Tracker
{
public class TrackerObjectiveArray : ITrackerEndpointDataModel
{
public TrackerObjectiveArray(IEnumerable<Objective> objectives)
{
Objectives = objectives;
}

public IEnumerable<Objective> Objectives { get; set; }
}
}
Loading