Skip to content

Commit 482b9a2

Browse files
committed
Add safeguards for corrupted jobs
Closes #904
1 parent f602c34 commit 482b9a2

4 files changed

Lines changed: 72 additions & 16 deletions

File tree

OpenBullet2.Core.Tests/Services/DataPoolFactoryServiceTests.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.Extensions.DependencyInjection;
2+
using Newtonsoft.Json;
23
using OpenBullet2.Core.Entities;
34
using OpenBullet2.Core.Models.Data;
45
using OpenBullet2.Core.Repositories;
@@ -56,6 +57,24 @@ public async Task FromOptionsAsync_FileOptions_ReturnsFileDataPool()
5657
Assert.Equal(["one", "two"], filePool.DataList.ToArray());
5758
}
5859

60+
[Fact]
61+
public async Task FromOptionsAsync_FileOptions_WithNullFileName_FallsBackToInfiniteDataPool()
62+
{
63+
var options = JsonConvert.DeserializeObject<FileDataPoolOptions>(
64+
"""
65+
{
66+
"FileName": null,
67+
"WordlistType": "Default"
68+
}
69+
""")!;
70+
71+
var service = CreateService();
72+
var pool = await service.FromOptionsAsync(options);
73+
74+
Assert.IsType<InfiniteDataPool>(pool);
75+
Assert.Equal(string.Empty, options.FileName);
76+
}
77+
5978
[Fact]
6079
public async Task FromOptionsAsync_WordlistOptions_ReturnsWordlistDataPool()
6180
{

OpenBullet2.Core.Tests/Services/JobManagerServiceTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ public async Task SaveMultiRunJobOptionsAsync_WhenJobCompleted_ResetsPersistedSk
6161
Assert.Equal(0, options.Skip);
6262
}
6363

64+
[Fact]
65+
public async Task Constructor_WhenPersistedJobOptionsAreMalformed_DoesNotThrow()
66+
{
67+
using var database = new TestDatabase();
68+
await database.AddRawJobEntityAsync("{ this is not valid json }");
69+
70+
var exception = Record.Exception(() => new JobManagerService(
71+
database.Services.GetRequiredService<IServiceScopeFactory>(),
72+
(JobFactoryService)RuntimeHelpers.GetUninitializedObject(typeof(JobFactoryService))));
73+
74+
Assert.Null(exception);
75+
}
76+
6477
private static RuriLibSettingsService CreateSettingsService()
6578
=> new(Path.Combine(Path.GetTempPath(), $"ob2-jobmanager-settings-{Guid.NewGuid():N}"));
6679

@@ -103,6 +116,21 @@ public async Task<JobEntity> AddJobEntityAsync(MultiRunJobOptions options)
103116
return entity;
104117
}
105118

119+
public async Task<JobEntity> AddRawJobEntityAsync(string jobOptions)
120+
{
121+
using var scope = Services.CreateScope();
122+
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
123+
var entity = new JobEntity
124+
{
125+
JobType = JobType.MultiRun,
126+
JobOptions = jobOptions
127+
};
128+
129+
context.Jobs.Add(entity);
130+
await context.SaveChangesAsync(TestContext.Current.CancellationToken);
131+
return entity;
132+
}
133+
106134
public async Task<JobEntity> GetJobEntityAsync(int id)
107135
{
108136
using var scope = Services.CreateScope();

OpenBullet2.Core/Models/Data/FileDataPoolOptions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,19 @@ public string FileName
1818
get => fileName;
1919
set
2020
{
21+
var safeValue = value ?? string.Empty;
22+
2123
// Double quotes in file names are not allowed in Windows, but they are included
2224
// at the start and end of the file path if you copy/paste it from some programs,
2325
// so we need to remove them, otherwise it will not find the file.
2426
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
2527
{
2628
// Remove the double quotes from the file
27-
fileName = value.Replace("\"", "");
29+
fileName = safeValue.Replace("\"", "");
2830
}
2931
else
3032
{
31-
fileName = value;
33+
fileName = safeValue;
3234
}
3335
}
3436
}

OpenBullet2.Core/Services/JobManagerService.cs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,32 @@ public JobManagerService(IServiceScopeFactory scopeFactory, JobFactoryService jo
4646
continue;
4747
}
4848

49-
// Convert old namespaces to support old databases
50-
if (entity.JobOptions.Contains("OpenBullet2.Models") || entity.JobOptions.Contains(", OpenBullet2\""))
49+
try
5150
{
52-
entity.JobOptions = entity.JobOptions
53-
.Replace("OpenBullet2.Models", "OpenBullet2.Core.Models")
54-
.Replace(", OpenBullet2\"", ", OpenBullet2.Core\"");
51+
// Convert old namespaces to support old databases
52+
if (entity.JobOptions.Contains("OpenBullet2.Models") || entity.JobOptions.Contains(", OpenBullet2\""))
53+
{
54+
entity.JobOptions = entity.JobOptions
55+
.Replace("OpenBullet2.Models", "OpenBullet2.Core.Models")
56+
.Replace(", OpenBullet2\"", ", OpenBullet2.Core\"");
5557

56-
jobRepo.UpdateAsync(entity).Wait();
57-
}
58+
jobRepo.UpdateAsync(entity).Wait();
59+
}
60+
61+
var wrapper = JsonConvert.DeserializeObject<JobOptionsWrapper>(entity.JobOptions, jsonSettings);
62+
if (wrapper?.Options is null)
63+
{
64+
continue;
65+
}
5866

59-
var wrapper = JsonConvert.DeserializeObject<JobOptionsWrapper>(entity.JobOptions, jsonSettings);
60-
if (wrapper?.Options is null)
67+
var options = wrapper.Options;
68+
var job = jobFactory.FromOptions(entity.Id, entity.Owner == null ? 0 : entity.Owner.Id, options);
69+
AddJob(job);
70+
}
71+
catch (Exception ex)
6172
{
62-
continue;
73+
Console.WriteLine($"Skipped restoring job {entity.Id}: {ex.Message}");
6374
}
64-
65-
var options = wrapper.Options;
66-
var job = jobFactory.FromOptions(entity.Id, entity.Owner == null ? 0 : entity.Owner.Id, options);
67-
AddJob(job);
6875
}
6976

7077
_scopeFactory = scopeFactory;

0 commit comments

Comments
 (0)