Fixed voice work updater bug. Added integration tests for voice work search updates (Japanese).
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
using JSMR.Application.Enums;
|
||||||
|
|
||||||
|
namespace JSMR.Application.Scanning.Ports;
|
||||||
|
public interface IVoiceWorkScannerRepository
|
||||||
|
{
|
||||||
|
public IVoiceWorksScanner? GetScanner(Locale locale);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using JSMR.Application.Enums;
|
||||||
|
|
||||||
|
namespace JSMR.Application.Scanning.Ports;
|
||||||
|
|
||||||
|
public interface IVoiceWorkUpdaterRepository
|
||||||
|
{
|
||||||
|
public IVoiceWorkUpdater? GetUpdater(Locale locale);
|
||||||
|
}
|
||||||
@@ -3,20 +3,20 @@ using JSMR.Application.Integrations.DLSite.Models;
|
|||||||
using JSMR.Application.Integrations.Ports;
|
using JSMR.Application.Integrations.Ports;
|
||||||
using JSMR.Application.Scanning.Contracts;
|
using JSMR.Application.Scanning.Contracts;
|
||||||
using JSMR.Application.Scanning.Ports;
|
using JSMR.Application.Scanning.Ports;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace JSMR.Application.Scanning;
|
namespace JSMR.Application.Scanning;
|
||||||
|
|
||||||
public sealed class ScanVoiceWorksHandler(
|
public sealed class ScanVoiceWorksHandler(
|
||||||
IServiceProvider serviceProvider,
|
IVoiceWorkScannerRepository scannerRepository,
|
||||||
|
IVoiceWorkUpdaterRepository updaterRepository,
|
||||||
IDLSiteClient dlsiteClient,
|
IDLSiteClient dlsiteClient,
|
||||||
ISpamCircleCache spamCircleCache,
|
ISpamCircleCache spamCircleCache,
|
||||||
IVoiceWorkSearchUpdater searchUpdater)
|
IVoiceWorkSearchUpdater searchUpdater)
|
||||||
{
|
{
|
||||||
public async Task<ScanVoiceWorksResponse> HandleAsync(ScanVoiceWorksRequest request, CancellationToken cancellationToken)
|
public async Task<ScanVoiceWorksResponse> HandleAsync(ScanVoiceWorksRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
IVoiceWorksScanner? scanner = serviceProvider.GetKeyedService<IVoiceWorksScanner>(request.Locale);
|
IVoiceWorksScanner? scanner = scannerRepository.GetScanner(request.Locale);
|
||||||
IVoiceWorkUpdater? updater = serviceProvider.GetKeyedService<IVoiceWorkUpdater>(request.Locale);
|
IVoiceWorkUpdater? updater = updaterRepository.GetUpdater(request.Locale);
|
||||||
|
|
||||||
if (scanner is null || updater is null)
|
if (scanner is null || updater is null)
|
||||||
return new();
|
return new();
|
||||||
|
|||||||
@@ -47,9 +47,12 @@ public static class InfrastructureServiceCollectionExtensions
|
|||||||
|
|
||||||
services.AddKeyedScoped<IVoiceWorksScanner, JapaneseVoiceWorksScanner>(Locale.Japanese);
|
services.AddKeyedScoped<IVoiceWorksScanner, JapaneseVoiceWorksScanner>(Locale.Japanese);
|
||||||
services.AddKeyedScoped<IVoiceWorksScanner, EnglishVoiceWorksScanner>(Locale.English);
|
services.AddKeyedScoped<IVoiceWorksScanner, EnglishVoiceWorksScanner>(Locale.English);
|
||||||
|
services.AddSingleton<IVoiceWorkScannerRepository, VoiceWorkScannerRepository>();
|
||||||
|
|
||||||
services.AddKeyedScoped<IVoiceWorkUpdater, VoiceWorkUpdater>(Locale.Japanese);
|
services.AddKeyedScoped<IVoiceWorkUpdater, VoiceWorkUpdater>(Locale.Japanese);
|
||||||
services.AddKeyedScoped<IVoiceWorkUpdater, EnglishVoiceWorkUpdater>(Locale.English);
|
services.AddKeyedScoped<IVoiceWorkUpdater, EnglishVoiceWorkUpdater>(Locale.English);
|
||||||
|
services.AddSingleton<IVoiceWorkUpdaterRepository, VoiceWorkUpdaterRepository>();
|
||||||
|
|
||||||
services.AddScoped<IVoiceWorkSearchUpdater, VoiceWorkSearchUpdater>();
|
services.AddScoped<IVoiceWorkSearchUpdater, VoiceWorkSearchUpdater>();
|
||||||
|
|
||||||
//services.AddKeyedScoped<ISupportedLanguage, JapaneseLanguage>(Locale.Japanese);
|
//services.AddKeyedScoped<ISupportedLanguage, JapaneseLanguage>(Locale.Japanese);
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ public class VoiceWorkUpdater(AppDbContext dbContext, ITimeProvider timeProvider
|
|||||||
|
|
||||||
await dbContext.SaveChangesAsync(cancellationToken);
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
foreach (VoiceWorkIngest ingest in ingests)
|
||||||
|
{
|
||||||
|
VoiceWorkUpsertResult result = upsertContext.Results[ingest.ProductId];
|
||||||
|
|
||||||
|
if (result.Status is VoiceWorkUpsertStatus.Skipped)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
VoiceWork voiceWork = upsertContext.VoiceWorks[ingest.ProductId];
|
||||||
|
|
||||||
|
result.VoiceWorkId = voiceWork.VoiceWorkId;
|
||||||
|
}
|
||||||
|
|
||||||
return [.. upsertContext.Results.Select(x => x.Value)];
|
return [.. upsertContext.Results.Select(x => x.Value)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
JSMR.Infrastructure/Ingestion/VoiceWorkUpdaterRepository.cs
Normal file
13
JSMR.Infrastructure/Ingestion/VoiceWorkUpdaterRepository.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using JSMR.Application.Enums;
|
||||||
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace JSMR.Infrastructure.Ingestion;
|
||||||
|
|
||||||
|
public class VoiceWorkUpdaterRepository(IServiceProvider serviceProvider) : IVoiceWorkUpdaterRepository
|
||||||
|
{
|
||||||
|
public IVoiceWorkUpdater? GetUpdater(Locale locale)
|
||||||
|
{
|
||||||
|
return serviceProvider.GetKeyedService<IVoiceWorkUpdater>(locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
JSMR.Infrastructure/Scanning/VoiceWorkScannerRepository.cs
Normal file
13
JSMR.Infrastructure/Scanning/VoiceWorkScannerRepository.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using JSMR.Application.Enums;
|
||||||
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace JSMR.Infrastructure.Scanning;
|
||||||
|
|
||||||
|
public class VoiceWorkScannerRepository(IServiceProvider serviceProvider) : IVoiceWorkScannerRepository
|
||||||
|
{
|
||||||
|
public IVoiceWorksScanner? GetScanner(Locale locale)
|
||||||
|
{
|
||||||
|
return serviceProvider.GetKeyedService<IVoiceWorksScanner>(locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
JSMR.Tests/Ingestion/IngestTestFactory.cs
Normal file
32
JSMR.Tests/Ingestion/IngestTestFactory.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
|
using JSMR.Domain.Enums;
|
||||||
|
using JSMR.Domain.ValueObjects;
|
||||||
|
using JSMR.Tests.Ingestion.Search;
|
||||||
|
|
||||||
|
namespace JSMR.Tests.Ingestion;
|
||||||
|
|
||||||
|
internal class IngestTestFactory
|
||||||
|
{
|
||||||
|
public static VoiceWorkIngest Create(SearchRelatedParameters searchRelatedParameters)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
MakerId = searchRelatedParameters.MakerId,
|
||||||
|
MakerName = searchRelatedParameters.MakerName,
|
||||||
|
ProductId = searchRelatedParameters.ProductId,
|
||||||
|
Title = searchRelatedParameters.Title,
|
||||||
|
Description = searchRelatedParameters.Description,
|
||||||
|
Tags = searchRelatedParameters.Tags,
|
||||||
|
Creators = searchRelatedParameters.Creators,
|
||||||
|
WishlistCount = 100,
|
||||||
|
Downloads = 0,
|
||||||
|
HasTrial = false,
|
||||||
|
HasDLPlay = false,
|
||||||
|
AgeRating = AgeRating.AllAges,
|
||||||
|
HasImage = false,
|
||||||
|
SupportedLanguages = [SupportedLanguage.Japanese],
|
||||||
|
SalesDate = null,
|
||||||
|
ExpectedDate = new DateOnly(2025, 1, 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
using JSMR.Application.Scanning.Contracts;
|
using JSMR.Application.Enums;
|
||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
using JSMR.Application.Scanning.Ports;
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using JSMR.Domain.Entities;
|
||||||
using JSMR.Infrastructure.Common.Time;
|
using JSMR.Infrastructure.Common.Time;
|
||||||
using JSMR.Infrastructure.Data;
|
using JSMR.Infrastructure.Data;
|
||||||
using JSMR.Infrastructure.Ingestion;
|
using JSMR.Infrastructure.Ingestion;
|
||||||
@@ -25,6 +27,13 @@ public abstract class JapaneseIngestionTestsBase(MariaDbContainerFixture contain
|
|||||||
return await updater.UpsertAsync(ingests, TestContext.Current.CancellationToken);
|
return await updater.UpsertAsync(ingests, TestContext.Current.CancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static async Task UpdateSearchAsync(AppDbContext dbContext, int[] voiceWorkIds)
|
||||||
|
{
|
||||||
|
VoiceWorkSearchUpdater updater = new(dbContext);
|
||||||
|
|
||||||
|
await updater.UpdateAsync(voiceWorkIds, TestContext.Current.CancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
protected static DateTime TokyoLocalToUtc(int year, int month, int day, int hour, int minute, int second)
|
protected static DateTime TokyoLocalToUtc(int year, int month, int day, int hour, int minute, int second)
|
||||||
{
|
{
|
||||||
var tokyo = TimeZoneInfo.FindSystemTimeZoneById(
|
var tokyo = TimeZoneInfo.FindSystemTimeZoneById(
|
||||||
|
|||||||
69
JSMR.Tests/Ingestion/Search/Insert_Into_Search_Tests.cs
Normal file
69
JSMR.Tests/Ingestion/Search/Insert_Into_Search_Tests.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
|
using JSMR.Domain.Entities;
|
||||||
|
using JSMR.Infrastructure.Data;
|
||||||
|
using JSMR.Tests.Fixtures;
|
||||||
|
using JSMR.Tests.Ingestion.Japanese;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace JSMR.Tests.Ingestion.Search;
|
||||||
|
|
||||||
|
internal record SearchRelatedParameters(
|
||||||
|
string ProductId,
|
||||||
|
string MakerId,
|
||||||
|
string Title,
|
||||||
|
string Description,
|
||||||
|
string MakerName,
|
||||||
|
string[] Tags,
|
||||||
|
string[] Creators
|
||||||
|
);
|
||||||
|
|
||||||
|
public class Insert_Into_Search_Tests(MariaDbContainerFixture container) : JapaneseIngestionTestsBase(container)
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task Insert_Into_Search_And_Update()
|
||||||
|
{
|
||||||
|
await using AppDbContext dbContext = await GetAppDbContextAsync();
|
||||||
|
|
||||||
|
// PART 1 - Insert
|
||||||
|
SearchRelatedParameters parameters = new(
|
||||||
|
ProductId: "RJ1",
|
||||||
|
MakerId: "RG1",
|
||||||
|
Title: "Title",
|
||||||
|
Description: "Description",
|
||||||
|
MakerName: "Maker",
|
||||||
|
Tags: ["Tag 1", "Tag 2"],
|
||||||
|
Creators: ["Creator 1"]
|
||||||
|
);
|
||||||
|
|
||||||
|
VoiceWorkIngest ingest = IngestTestFactory.Create(parameters);
|
||||||
|
|
||||||
|
await UpsertAndVerify(dbContext, ingest, "RJ1 RG1 Title Description Maker Tag 1 Tag 2 Creator 1");
|
||||||
|
|
||||||
|
// PART 2 - Update
|
||||||
|
SearchRelatedParameters updateParameters = parameters with
|
||||||
|
{
|
||||||
|
Title = "Updated Title",
|
||||||
|
Tags = ["Tag 1", "Tag 2", "Tag 3"]
|
||||||
|
};
|
||||||
|
|
||||||
|
VoiceWorkIngest updatedIngest = IngestTestFactory.Create(updateParameters);
|
||||||
|
|
||||||
|
await UpsertAndVerify(dbContext, updatedIngest, "RJ1 RG1 Updated Title Description Maker Tag 1 Tag 2 Tag 3 Creator 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task UpsertAndVerify(AppDbContext dbContext, VoiceWorkIngest ingest, string searchText)
|
||||||
|
{
|
||||||
|
await UpsertAsync(dbContext, TokyoLocalToUtc(2025, 01, 15, 00, 00, 00), [ingest]);
|
||||||
|
|
||||||
|
VoiceWork? voiceWork = await dbContext.VoiceWorks.SingleAsync(v => v.ProductId == ingest.ProductId, TestContext.Current.CancellationToken);
|
||||||
|
voiceWork.ShouldNotBeNull();
|
||||||
|
|
||||||
|
await UpdateSearchAsync(dbContext, [voiceWork.VoiceWorkId]);
|
||||||
|
|
||||||
|
VoiceWorkSearch voiceWorkSearch = await dbContext.VoiceWorkSearches.SingleAsync(v => v.VoiceWorkId == voiceWork.VoiceWorkId, TestContext.Current.CancellationToken);
|
||||||
|
voiceWorkSearch.ShouldNotBeNull();
|
||||||
|
|
||||||
|
voiceWorkSearch.SearchText.ShouldBe(searchText);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user