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
13 changes: 10 additions & 3 deletions Jobs/BotAvatarJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ public BotAvatarJob(DiscordSocketClient client, DB db, LogsService logsService)

public async Task Execute(IJobExecutionContext context)
{
CancellationToken cancellationToken = context.CancellationToken;
try
{

var setting = await _db.BotSettings.FirstOrDefaultAsync(s => s.Key == "BotAvatar");
var setting = await _db.BotSettings.FirstOrDefaultAsync(s => s.Key == "BotAvatar", cancellationToken);
string current = setting?.Value ?? "unknown";

bool isDecember = DateTime.UtcNow.Month == 12;
Expand All @@ -46,7 +47,9 @@ public async Task Execute(IJobExecutionContext context)
return;

await using var fs = File.OpenRead(filePath);
await _client.CurrentUser.ModifyAsync(x => x.Avatar = new Image(fs));
await _client.CurrentUser.ModifyAsync(
x => x.Avatar = new Image(fs),
new RequestOptions { CancelToken = cancellationToken });

if (setting == null)
{
Expand All @@ -60,9 +63,13 @@ public async Task Execute(IJobExecutionContext context)
_db.BotSettings.Update(setting);
}

await _db.SaveChangesAsync();
await _db.SaveChangesAsync(cancellationToken);
_logsService.Log($"Quartz Job - Bot avatar updated to {targetKey}");
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
throw;
}
catch (Exception ex)
{
_logsService.Log($"Quartz Job - Error updating bot avatar: {ex}");
Expand Down
56 changes: 56 additions & 0 deletions Morpheus.Tests/BotAvatarJobTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using Discord.WebSocket;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Morpheus.Database;
using Morpheus.Jobs;
using Morpheus.Services;
using Quartz;
using System.Reflection;

namespace Morpheus.Tests;

public class BotAvatarJobTests
{
[Fact]
public async Task Execute_WhenCanceledBeforeLookup_PropagatesCancellation()
{
await using SqliteConnection connection = new("Data Source=:memory:");
await connection.OpenAsync();
DbContextOptions<DB> options = new DbContextOptionsBuilder<DB>()
.UseSqlite(connection)
.Options;
await using DB db = new(options);
await db.Database.EnsureCreatedAsync();
using DiscordSocketClient discordClient = new();

BotAvatarJob job = new(discordClient, db, new LogsService(new LogQueue()));
using CancellationTokenSource cancellation = new();
await cancellation.CancelAsync();

IJobExecutionContext context = CreateContext(cancellation.Token);

await Assert.ThrowsAnyAsync<OperationCanceledException>(() => job.Execute(context));
}

private static IJobExecutionContext CreateContext(CancellationToken cancellationToken)
{
JobExecutionContextProxy.CurrentCancellationToken = cancellationToken;
return DispatchProxy.Create<IJobExecutionContext, JobExecutionContextProxy>();
}

private class JobExecutionContextProxy : DispatchProxy
{
public static CancellationToken CurrentCancellationToken { get; set; }

protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)
{
if (targetMethod?.ReturnType == typeof(CancellationToken))
return CurrentCancellationToken;

Type returnType = targetMethod?.ReturnType ?? typeof(void);
return returnType == typeof(void) || !returnType.IsValueType
? null
: Activator.CreateInstance(returnType);
}
}
}