926688cd2e
Backend CI / build-and-test (push) Successful in 51s
Frontend CI / build-and-check (push) Failing after 5m11s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 14s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 1m20s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Successful in 23s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 11s
135 lines
5.6 KiB
C#
135 lines
5.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using NSubstitute;
|
|
using UniVerse.Application.DTOs.Lectures;
|
|
using UniVerse.Application.DTOs.Notifications;
|
|
using UniVerse.Application.Interfaces;
|
|
using UniVerse.Domain.Entities;
|
|
using UniVerse.Infrastructure.Data;
|
|
using UniVerse.Infrastructure.Services;
|
|
using Xunit;
|
|
|
|
namespace UniVerse.Api.Tests.Lectures;
|
|
|
|
public class LectureServiceTests
|
|
{
|
|
[Fact]
|
|
public async Task GetAllAsync_MarksLecturesEnrolledByCurrentUser()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var service = new LectureService(db, Substitute.For<IGamificationService>(), Substitute.For<INotificationScheduler>());
|
|
var startsAt = DateTime.UtcNow.AddDays(1);
|
|
|
|
db.Users.Add(new User { Id = 1, Email = "student@test.local" });
|
|
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
|
db.Lectures.AddRange(
|
|
Lecture(1, startsAt),
|
|
Lecture(2, startsAt.AddDays(1)));
|
|
db.LectureEnrollments.Add(new LectureEnrollment { LectureId = 1, UserId = 1 });
|
|
await db.SaveChangesAsync();
|
|
|
|
var result = await service.GetAllAsync(new LectureFilterRequest(null, null, null, null, null, null, null, null), 1);
|
|
|
|
Assert.True(result.Items.Single(item => item.Id == 1).IsEnrolled);
|
|
Assert.False(result.Items.Single(item => item.Id == 2).IsEnrolled);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnrollAsync_SchedulesLectureReminders()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var scheduler = Substitute.For<INotificationScheduler>();
|
|
var service = new LectureService(db, Substitute.For<IGamificationService>(), scheduler);
|
|
var startsAt = DateTime.UtcNow.AddHours(4);
|
|
|
|
db.Users.Add(new User { Id = 1, Email = "student@test.local", DisplayName = "Student" });
|
|
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
|
db.Lectures.Add(Lecture(1, startsAt));
|
|
await db.SaveChangesAsync();
|
|
|
|
await service.EnrollAsync(1, 1);
|
|
|
|
await scheduler.Received(1).ScheduleAsync(
|
|
Arg.Is<NotificationMessage>(m => m.Recipient == "student@test.local" && m.Subject.Contains("через 3 часа")),
|
|
Arg.Is<DateTimeOffset>(d => d == new DateTimeOffset(startsAt.AddHours(-3))),
|
|
"lecture-1-user-1-starts-in-3-hours",
|
|
Arg.Any<CancellationToken>());
|
|
await scheduler.Received(1).ScheduleAsync(
|
|
Arg.Is<NotificationMessage>(m => m.Recipient == "student@test.local" && m.Subject.Contains("через 1 час")),
|
|
Arg.Is<DateTimeOffset>(d => d == new DateTimeOffset(startsAt.AddHours(-1))),
|
|
"lecture-1-user-1-starts-in-1-hour",
|
|
Arg.Any<CancellationToken>());
|
|
await scheduler.Received(1).ScheduleAsync(
|
|
Arg.Is<NotificationMessage>(m => m.Recipient == "student@test.local" && m.Subject.Contains("Оцените")),
|
|
Arg.Is<DateTimeOffset>(d => d == new DateTimeOffset(startsAt.AddHours(2))),
|
|
"lecture-1-user-1-ended",
|
|
Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task EnrollAsync_SkipsPastLectureReminders()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var scheduler = Substitute.For<INotificationScheduler>();
|
|
var service = new LectureService(db, Substitute.For<IGamificationService>(), scheduler);
|
|
var startsAt = DateTime.UtcNow.AddMinutes(90);
|
|
|
|
db.Users.Add(new User { Id = 1, Email = "student@test.local" });
|
|
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
|
db.Lectures.Add(Lecture(1, startsAt));
|
|
await db.SaveChangesAsync();
|
|
|
|
await service.EnrollAsync(1, 1);
|
|
|
|
await scheduler.DidNotReceive().ScheduleAsync(
|
|
Arg.Any<NotificationMessage>(),
|
|
Arg.Any<DateTimeOffset>(),
|
|
"lecture-1-user-1-starts-in-3-hours",
|
|
Arg.Any<CancellationToken>());
|
|
await scheduler.Received(2).ScheduleAsync(
|
|
Arg.Any<NotificationMessage>(),
|
|
Arg.Any<DateTimeOffset>(),
|
|
Arg.Any<string>(),
|
|
Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
[Fact]
|
|
public async Task UnenrollAsync_CancelsLectureReminders()
|
|
{
|
|
await using var db = CreateDbContext();
|
|
var scheduler = Substitute.For<INotificationScheduler>();
|
|
var service = new LectureService(db, Substitute.For<IGamificationService>(), scheduler);
|
|
var startsAt = DateTime.UtcNow.AddHours(4);
|
|
|
|
db.Users.Add(new User { Id = 1, Email = "student@test.local" });
|
|
db.Courses.Add(new Course { Id = 1, Name = "Course" });
|
|
db.Lectures.Add(Lecture(1, startsAt));
|
|
db.LectureEnrollments.Add(new LectureEnrollment { LectureId = 1, UserId = 1 });
|
|
await db.SaveChangesAsync();
|
|
|
|
await service.UnenrollAsync(1, 1);
|
|
|
|
await scheduler.Received(1).CancelAsync("lecture-1-user-1-starts-in-3-hours", Arg.Any<CancellationToken>());
|
|
await scheduler.Received(1).CancelAsync("lecture-1-user-1-starts-in-1-hour", Arg.Any<CancellationToken>());
|
|
await scheduler.Received(1).CancelAsync("lecture-1-user-1-ended", Arg.Any<CancellationToken>());
|
|
}
|
|
|
|
private static AppDbContext CreateDbContext()
|
|
{
|
|
var options = new DbContextOptionsBuilder<AppDbContext>()
|
|
.UseInMemoryDatabase($"LectureServiceTests_{Guid.NewGuid()}")
|
|
.Options;
|
|
return new AppDbContext(options);
|
|
}
|
|
|
|
private static Lecture Lecture(int id, DateTime startsAt) => new()
|
|
{
|
|
Id = id,
|
|
CourseId = 1,
|
|
Title = $"Lecture {id}",
|
|
StartsAt = startsAt,
|
|
EndsAt = startsAt.AddHours(2),
|
|
IsOpen = true,
|
|
MaxEnrollments = 30
|
|
};
|
|
}
|