Added English localization integration tests.
This commit is contained in:
@@ -4,5 +4,32 @@ namespace JSMR.Application.Scanning.Ports;
|
|||||||
|
|
||||||
public interface IVoiceWorkUpdater
|
public interface IVoiceWorkUpdater
|
||||||
{
|
{
|
||||||
Task<int[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken);
|
Task<VoiceWorkUpsertResult[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VoiceWorkUpsertResult
|
||||||
|
{
|
||||||
|
public int? VoiceWorkId { get; set; }
|
||||||
|
public ICollection<VoiceWorkUpsertIssue> Issues { get; } = [];
|
||||||
|
public VoiceWorkUpsertStatus Status { get; set; } = VoiceWorkUpsertStatus.Unchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record VoiceWorkUpsertIssue(
|
||||||
|
string Message,
|
||||||
|
VoiceWorkUpsertIssueSeverity Severity
|
||||||
|
);
|
||||||
|
|
||||||
|
public enum VoiceWorkUpsertIssueSeverity
|
||||||
|
{
|
||||||
|
Information,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum VoiceWorkUpsertStatus
|
||||||
|
{
|
||||||
|
Unchanged,
|
||||||
|
Inserted,
|
||||||
|
Updated,
|
||||||
|
Skipped
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,9 @@ public sealed class ScanVoiceWorksHandler(
|
|||||||
return VoiceWorkIngest.From(work, value);
|
return VoiceWorkIngest.From(work, value);
|
||||||
})];
|
})];
|
||||||
|
|
||||||
int[] voiceWorkIds = await updater.UpsertAsync(ingests, cancellationToken);
|
VoiceWorkUpsertResult[] upsertResults = await updater.UpsertAsync(ingests, cancellationToken);
|
||||||
|
int[] voiceWorkIds = [.. upsertResults.Where(x => x.VoiceWorkId.HasValue).Select(x => x.VoiceWorkId!.Value)];
|
||||||
|
|
||||||
await searchUpdater.UpdateAsync(voiceWorkIds, cancellationToken);
|
await searchUpdater.UpdateAsync(voiceWorkIds, cancellationToken);
|
||||||
|
|
||||||
return new();
|
return new();
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class LanguageIdentifier : ILanguageIdentifier
|
|||||||
{
|
{
|
||||||
RankedLanguageIdentifierFactory factory = new();
|
RankedLanguageIdentifierFactory factory = new();
|
||||||
|
|
||||||
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("JSMR.Infrastructure.Languages.Language.xml");
|
using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("JSMR.Infrastructure.Common.Languages.Language.xml");
|
||||||
_identifier = factory.Load(stream);
|
_identifier = factory.Load(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ using JSMR.Infrastructure.Data.Repositories.Creators;
|
|||||||
using JSMR.Infrastructure.Data.Repositories.Tags;
|
using JSMR.Infrastructure.Data.Repositories.Tags;
|
||||||
using JSMR.Infrastructure.Data.Repositories.VoiceWorks;
|
using JSMR.Infrastructure.Data.Repositories.VoiceWorks;
|
||||||
using JSMR.Infrastructure.Http;
|
using JSMR.Infrastructure.Http;
|
||||||
using JSMR.Infrastructure.Ingest;
|
using JSMR.Infrastructure.Ingestion;
|
||||||
using JSMR.Infrastructure.Ingestions;
|
|
||||||
using JSMR.Infrastructure.Scanning;
|
using JSMR.Infrastructure.Scanning;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace JSMR.Infrastructure.Ingestion;
|
|||||||
|
|
||||||
public class EnglishVoiceWorkUpdater(AppDbContext dbContext, ILanguageIdentifier languageIdentifier) : IVoiceWorkUpdater
|
public class EnglishVoiceWorkUpdater(AppDbContext dbContext, ILanguageIdentifier languageIdentifier) : IVoiceWorkUpdater
|
||||||
{
|
{
|
||||||
public async Task<int[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
public async Task<VoiceWorkUpsertResult[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
EnglishVoiceWorkUpsertContext upsertContext = await CreateUpsertContextAsync(ingests, cancellationToken);
|
EnglishVoiceWorkUpsertContext upsertContext = await CreateUpsertContextAsync(ingests, cancellationToken);
|
||||||
|
|
||||||
@@ -20,20 +20,23 @@ public class EnglishVoiceWorkUpdater(AppDbContext dbContext, ILanguageIdentifier
|
|||||||
|
|
||||||
VoiceWorkUpsertResult result = upsertContext.Results[ingest.ProductId];
|
VoiceWorkUpsertResult result = upsertContext.Results[ingest.ProductId];
|
||||||
|
|
||||||
|
if (upsertContext.VoiceWorks.TryGetValue(ingest.ProductId, out VoiceWork? voiceWork))
|
||||||
|
{
|
||||||
|
result.VoiceWorkId = upsertContext.VoiceWorks[ingest.ProductId].VoiceWorkId;
|
||||||
|
}
|
||||||
|
|
||||||
if (result.Issues.Count > 0)
|
if (result.Issues.Count > 0)
|
||||||
{
|
{
|
||||||
result.Status = VoiceWorkUpsertStatus.Skipped;
|
result.Status = VoiceWorkUpsertStatus.Skipped;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpsertEnglishVoiceWork(ingest, upsertContext);
|
result.Status = UpsertEnglishVoiceWork(ingest, upsertContext);
|
||||||
|
|
||||||
result.Status = VoiceWorkUpsertStatus.Updated;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await dbContext.SaveChangesAsync(cancellationToken);
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
return [.. upsertContext.VoiceWorks.Select(x => x.Value.VoiceWorkId)];
|
return [.. upsertContext.Results.Select(x => x.Value)];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<EnglishVoiceWorkUpsertContext> CreateUpsertContextAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
private async Task<EnglishVoiceWorkUpsertContext> CreateUpsertContextAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
||||||
@@ -68,31 +71,41 @@ public class EnglishVoiceWorkUpdater(AppDbContext dbContext, ILanguageIdentifier
|
|||||||
|
|
||||||
if (!isTitleEnglish && !isDescriptionEnglish)
|
if (!isTitleEnglish && !isDescriptionEnglish)
|
||||||
{
|
{
|
||||||
string message = $"Prouct title and/or description is not in English";
|
string message = $"Product title and/or description is not in English";
|
||||||
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Information));
|
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Information));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upsertContext.Circles.TryGetValue(ingest.MakerId, out Circle? circle) == false)
|
if (upsertContext.Circles.ContainsKey(ingest.MakerId) == false)
|
||||||
{
|
{
|
||||||
string message = $"Unable to find circle for maker id: {ingest.MakerId}";
|
string message = $"Unable to find circle for maker id: {ingest.MakerId}";
|
||||||
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Error));
|
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upsertContext.VoiceWorks.TryGetValue(ingest.ProductId, out VoiceWork? voiceWork) == false)
|
if (upsertContext.VoiceWorks.ContainsKey(ingest.ProductId) == false)
|
||||||
{
|
{
|
||||||
string message = $"Unable to find voice work for product id: {ingest.ProductId}";
|
string message = $"Unable to find voice work for product id: {ingest.ProductId}";
|
||||||
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Error));
|
result.Issues.Add(new(message, VoiceWorkUpsertIssueSeverity.Error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpsertEnglishVoiceWork(VoiceWorkIngest ingest, EnglishVoiceWorkUpsertContext upsertContext)
|
private VoiceWorkUpsertStatus UpsertEnglishVoiceWork(VoiceWorkIngest ingest, EnglishVoiceWorkUpsertContext upsertContext)
|
||||||
{
|
{
|
||||||
EnglishVoiceWork englishVoiceWork = GetOrAddEnglishVoiceWork(ingest, upsertContext);
|
EnglishVoiceWork englishVoiceWork = GetOrAddEnglishVoiceWork(ingest, upsertContext);
|
||||||
englishVoiceWork.ProductName = ingest.Title;
|
englishVoiceWork.ProductName = ingest.Title;
|
||||||
englishVoiceWork.Description = ingest.Description;
|
englishVoiceWork.Description = ingest.Description;
|
||||||
englishVoiceWork.IsValid = true;
|
englishVoiceWork.IsValid = true;
|
||||||
|
|
||||||
|
switch (dbContext.Entry(englishVoiceWork).State)
|
||||||
|
{
|
||||||
|
case EntityState.Added:
|
||||||
|
return VoiceWorkUpsertStatus.Inserted;
|
||||||
|
case EntityState.Modified:
|
||||||
|
return VoiceWorkUpsertStatus.Updated;
|
||||||
|
default:
|
||||||
|
return VoiceWorkUpsertStatus.Unchanged;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EnglishVoiceWork GetOrAddEnglishVoiceWork(VoiceWorkIngest ingest, EnglishVoiceWorkUpsertContext upsertContext)
|
private EnglishVoiceWork GetOrAddEnglishVoiceWork(VoiceWorkIngest ingest, EnglishVoiceWorkUpsertContext upsertContext)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using JSMR.Domain.Entities;
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using JSMR.Domain.Entities;
|
||||||
|
|
||||||
namespace JSMR.Infrastructure.Ingestion;
|
namespace JSMR.Infrastructure.Ingestion;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace JSMR.Infrastructure.Ingestion;
|
|||||||
|
|
||||||
public class VoiceWorkUpdater(AppDbContext dbContext, ITimeProvider timeProvider) : IVoiceWorkUpdater
|
public class VoiceWorkUpdater(AppDbContext dbContext, ITimeProvider timeProvider) : IVoiceWorkUpdater
|
||||||
{
|
{
|
||||||
public async Task<int[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
public async Task<VoiceWorkUpsertResult[]> UpsertAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
VoiceWorkUpsertContext upsertContext = await CreateUpsertContextAsync(ingests, cancellationToken);
|
VoiceWorkUpsertContext upsertContext = await CreateUpsertContextAsync(ingests, cancellationToken);
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ public class VoiceWorkUpdater(AppDbContext dbContext, ITimeProvider timeProvider
|
|||||||
|
|
||||||
await dbContext.SaveChangesAsync(cancellationToken);
|
await dbContext.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
return [.. upsertContext.VoiceWorks.Select(x => x.Value.VoiceWorkId)];
|
return [.. upsertContext.Results.Select(x => x.Value)];
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<VoiceWorkUpsertContext> CreateUpsertContextAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
private async Task<VoiceWorkUpsertContext> CreateUpsertContextAsync(IReadOnlyCollection<VoiceWorkIngest> ingests, CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using JSMR.Domain.Entities;
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using JSMR.Domain.Entities;
|
||||||
|
|
||||||
namespace JSMR.Infrastructure.Ingestion;
|
namespace JSMR.Infrastructure.Ingestion;
|
||||||
|
|
||||||
@@ -12,29 +13,29 @@ public record VoiceWorkUpsertContext(
|
|||||||
Dictionary<string, VoiceWorkUpsertResult> Results
|
Dictionary<string, VoiceWorkUpsertResult> Results
|
||||||
);
|
);
|
||||||
|
|
||||||
public class VoiceWorkUpsertResult
|
//public class VoiceWorkUpsertResult
|
||||||
{
|
//{
|
||||||
public int? VoiceWorkId { get; set; }
|
// public int? VoiceWorkId { get; set; }
|
||||||
public ICollection<VoiceWorkUpsertIssue> Issues { get; } = [];
|
// public ICollection<VoiceWorkUpsertIssue> Issues { get; } = [];
|
||||||
public VoiceWorkUpsertStatus Status { get; set; } = VoiceWorkUpsertStatus.Unchanged;
|
// public VoiceWorkUpsertStatus Status { get; set; } = VoiceWorkUpsertStatus.Unchanged;
|
||||||
}
|
//}
|
||||||
|
|
||||||
public record VoiceWorkUpsertIssue(
|
//public record VoiceWorkUpsertIssue(
|
||||||
string Message,
|
// string Message,
|
||||||
VoiceWorkUpsertIssueSeverity Severity
|
// VoiceWorkUpsertIssueSeverity Severity
|
||||||
);
|
//);
|
||||||
|
|
||||||
public enum VoiceWorkUpsertIssueSeverity
|
//public enum VoiceWorkUpsertIssueSeverity
|
||||||
{
|
//{
|
||||||
Information,
|
// Information,
|
||||||
Warning,
|
// Warning,
|
||||||
Error
|
// Error
|
||||||
}
|
//}
|
||||||
|
|
||||||
public enum VoiceWorkUpsertStatus
|
//public enum VoiceWorkUpsertStatus
|
||||||
{
|
//{
|
||||||
Unchanged,
|
// Unchanged,
|
||||||
Inserted,
|
// Inserted,
|
||||||
Updated,
|
// Updated,
|
||||||
Skipped
|
// Skipped
|
||||||
}
|
//}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
using JSMR.Infrastructure.Data;
|
using DotNet.Testcontainers.Builders;
|
||||||
|
using DotNet.Testcontainers.Containers;
|
||||||
|
using JSMR.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using MySqlConnector;
|
||||||
using Testcontainers.MariaDb;
|
using Testcontainers.MariaDb;
|
||||||
|
using Testcontainers.Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace JSMR.Tests.Fixtures;
|
namespace JSMR.Tests.Fixtures;
|
||||||
|
|
||||||
@@ -65,3 +70,112 @@ public class MariaDbFixture : IAsyncLifetime
|
|||||||
await context.Database.EnsureCreatedAsync();
|
await context.Database.EnsureCreatedAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CollectionDefinition("db")]
|
||||||
|
public sealed class MariaDbCollection : ICollectionFixture<MariaDbContainerFixture> { }
|
||||||
|
|
||||||
|
//[UsedImplicitly]
|
||||||
|
public sealed class MariaDbContainerFixture2(IMessageSink messageSink)
|
||||||
|
: ContainerFixture<MariaDbBuilder, MariaDbContainer>(messageSink)
|
||||||
|
{
|
||||||
|
const int MajorVersion = 10;
|
||||||
|
const int MinorVersion = 11;
|
||||||
|
const int Build = 6;
|
||||||
|
|
||||||
|
public string RootConnectionString => $"Server={Container.IpAddress};Port=3306;User=root;Password=rootpw;SslMode=none;";
|
||||||
|
|
||||||
|
protected override MariaDbBuilder Configure(MariaDbBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.WithImage($"mariadb:{MajorVersion}.{MinorVersion}.{Build}")
|
||||||
|
.WithEnvironment("MARIADB_ROOT_PASSWORD", "rootpw")
|
||||||
|
.WithPortBinding(3307, 3306)
|
||||||
|
//.WithPortBinding(3306, assignRandomHostPort: true)
|
||||||
|
.WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(3306));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class MariaDbContainerFixture : IAsyncLifetime
|
||||||
|
{
|
||||||
|
const int MajorVersion = 10;
|
||||||
|
const int MinorVersion = 11;
|
||||||
|
const int Build = 6;
|
||||||
|
|
||||||
|
private IContainer _container = default!;
|
||||||
|
public string RootConnectionString { get; private set; } = default!;
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
//_container = new ContainerBuilder()
|
||||||
|
// .WithImage("mariadb:11")
|
||||||
|
// .WithEnvironment("MARIADB_ROOT_PASSWORD", "rootpw")
|
||||||
|
// .WithPortBinding(3307, 3306)
|
||||||
|
// .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(3306))
|
||||||
|
// .Build();
|
||||||
|
|
||||||
|
_container = new ContainerBuilder()
|
||||||
|
.WithImage($"mariadb:{MajorVersion}.{MinorVersion}.{Build}")
|
||||||
|
.WithEnvironment("MARIADB_ROOT_PASSWORD", "rootpw")
|
||||||
|
.WithPortBinding(3307, 3306)
|
||||||
|
//.WithPortBinding(3306, assignRandomHostPort: true)
|
||||||
|
.WithWaitStrategy(Wait.ForUnixContainer().UntilInternalTcpPortIsAvailable(3306))
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
await _container.StartAsync();
|
||||||
|
|
||||||
|
// No database specified: we’ll create per-test DBs
|
||||||
|
//RootConnectionString = "Server=127.0.0.1;Port=3307;User=root;Password=rootpw;SslMode=none;";
|
||||||
|
|
||||||
|
//RootConnectionString = _container.GetConnectionString();
|
||||||
|
var port = _container.GetMappedPublicPort(3306);
|
||||||
|
RootConnectionString = $"Server=127.0.0.1;Port={port};User=root;Password=rootpw;SslMode=none;";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeAsync() => await _container.DisposeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MariaTestDb
|
||||||
|
{
|
||||||
|
public static async Task<AppDbContext> CreateIsolatedAsync(string rootConnectionString, Func<AppDbContext, Task>? seed = null)
|
||||||
|
{
|
||||||
|
string databaseName = $"t_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}";
|
||||||
|
|
||||||
|
await CreateDatabaseAsync(rootConnectionString, databaseName);
|
||||||
|
|
||||||
|
MySqlConnectionStringBuilder connectionStringBuilder = new(rootConnectionString)
|
||||||
|
{
|
||||||
|
Database = databaseName
|
||||||
|
};
|
||||||
|
|
||||||
|
AppDbContext dbContext = CreateDbContext(connectionStringBuilder.ConnectionString);
|
||||||
|
await dbContext.Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
if (seed != null)
|
||||||
|
await seed(dbContext);
|
||||||
|
|
||||||
|
return dbContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task CreateDatabaseAsync(string rootConnectionString, string databaseName)
|
||||||
|
{
|
||||||
|
await using MySqlConnection connection = new(rootConnectionString);
|
||||||
|
|
||||||
|
await connection.OpenAsync();
|
||||||
|
|
||||||
|
await using MySqlCommand command = connection.CreateCommand();
|
||||||
|
command.CommandText = $"CREATE DATABASE `{databaseName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;";
|
||||||
|
|
||||||
|
await command.ExecuteNonQueryAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AppDbContext CreateDbContext(string connectionString)
|
||||||
|
{
|
||||||
|
DbContextOptions<AppDbContext> options = new DbContextOptionsBuilder<AppDbContext>()
|
||||||
|
.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString),
|
||||||
|
o => o.EnableRetryOnFailure())
|
||||||
|
.EnableSensitiveDataLogging()
|
||||||
|
.Options;
|
||||||
|
|
||||||
|
return new AppDbContext(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
using JSMR.Infrastructure.Data;
|
using JSMR.Infrastructure.Data;
|
||||||
|
using JSMR.Tests.Ingestion;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using MySqlConnector;
|
||||||
|
using Testcontainers.MariaDb;
|
||||||
|
|
||||||
namespace JSMR.Tests.Fixtures;
|
namespace JSMR.Tests.Fixtures;
|
||||||
|
|
||||||
@@ -30,3 +33,43 @@ public class TagSearchProviderFixture : MariaDbFixture
|
|||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class TagSearchProviderFixture2(MariaDbContainerFixture container) : IAsyncLifetime
|
||||||
|
{
|
||||||
|
public AppDbContext? DbContext { get; private set; }
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
DbContext = await MariaTestDb.CreateIsolatedAsync(
|
||||||
|
container.RootConnectionString,
|
||||||
|
seed: SeedAsync);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SeedAsync(AppDbContext context)
|
||||||
|
{
|
||||||
|
if (await context.Tags.AnyAsync())
|
||||||
|
return;
|
||||||
|
|
||||||
|
context.Tags.AddRange(
|
||||||
|
new() { TagId = 1, Name = "OL" },
|
||||||
|
new() { TagId = 2, Name = "ほのぼの", Favorite = true },
|
||||||
|
new() { TagId = 3, Name = "ツンデレ", Blacklisted = true }
|
||||||
|
);
|
||||||
|
|
||||||
|
context.EnglishTags.AddRange(
|
||||||
|
new() { EnglishTagId = 1, TagId = 1, Name = "Office Lady" },
|
||||||
|
new() { EnglishTagId = 2, TagId = 2, Name = "Heartwarming" },
|
||||||
|
new() { EnglishTagId = 3, TagId = 3, Name = "Tsundere" }
|
||||||
|
);
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DisposeAsync()
|
||||||
|
{
|
||||||
|
if (DbContext is not null)
|
||||||
|
{
|
||||||
|
await DbContext.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
189
JSMR.Tests/Ingestion/EnglishLocalizationTests.cs
Normal file
189
JSMR.Tests/Ingestion/EnglishLocalizationTests.cs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
|
using JSMR.Application.Scanning.Ports;
|
||||||
|
using JSMR.Domain.Entities;
|
||||||
|
using JSMR.Infrastructure.Common.Languages;
|
||||||
|
using JSMR.Infrastructure.Data;
|
||||||
|
using JSMR.Infrastructure.Ingestion;
|
||||||
|
using JSMR.Tests.Fixtures;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace JSMR.Tests.Ingestion;
|
||||||
|
|
||||||
|
public class EnglishLocalizationTests(MariaDbContainerFixture container) : IClassFixture<MariaDbContainerFixture>
|
||||||
|
{
|
||||||
|
private readonly LanguageIdentifier languageIdentifier = new();
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Insert_Then_Update()
|
||||||
|
{
|
||||||
|
await using AppDbContext dbContext = await MariaTestDb.CreateIsolatedAsync(
|
||||||
|
container.RootConnectionString,
|
||||||
|
seed: VoiceWorkIngestionSeedData.SeedAsync);
|
||||||
|
|
||||||
|
// Part 1 -- Insert
|
||||||
|
VoiceWorkIngest ingest = new()
|
||||||
|
{
|
||||||
|
MakerId = "RG00001",
|
||||||
|
MakerName = "Good Dreams",
|
||||||
|
ProductId = "RJ0000001",
|
||||||
|
Title = "Today Sounds (EN)",
|
||||||
|
Description = "An average product. (EN)"
|
||||||
|
};
|
||||||
|
|
||||||
|
EnglishVoiceWorkUpdater updater = new(dbContext, languageIdentifier);
|
||||||
|
VoiceWorkUpsertResult[] results = await updater.UpsertAsync([ingest], CancellationToken.None);
|
||||||
|
|
||||||
|
VoiceWork voiceWork = await dbContext.VoiceWorks.SingleAsync(v => v.ProductId == "RJ0000001");
|
||||||
|
EnglishVoiceWork? englishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId);
|
||||||
|
|
||||||
|
englishVoiceWork.ShouldNotBeNull();
|
||||||
|
englishVoiceWork.ProductName.ShouldBe("Today Sounds (EN)");
|
||||||
|
englishVoiceWork.Description.ShouldBe("An average product. (EN)");
|
||||||
|
englishVoiceWork.IsValid?.ShouldBeTrue();
|
||||||
|
|
||||||
|
results.Length.ShouldBe(1);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(1);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(0);
|
||||||
|
results.Sum(r => r.Issues.Count).ShouldBe(0);
|
||||||
|
|
||||||
|
// Part 2 -- Update
|
||||||
|
VoiceWorkIngest ingestUpdate = ingest with
|
||||||
|
{
|
||||||
|
Title = "Today Sounds (EN v2)",
|
||||||
|
Description = "Updated English description."
|
||||||
|
};
|
||||||
|
|
||||||
|
VoiceWorkUpsertResult[] updatedResults = await updater.UpsertAsync([ingestUpdate], CancellationToken.None);
|
||||||
|
|
||||||
|
EnglishVoiceWork? updatedEnglishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId);
|
||||||
|
updatedEnglishVoiceWork.ShouldNotBeNull();
|
||||||
|
updatedEnglishVoiceWork.ProductName.ShouldBe("Today Sounds (EN v2)");
|
||||||
|
updatedEnglishVoiceWork.Description.ShouldBe("Updated English description.");
|
||||||
|
updatedEnglishVoiceWork.IsValid?.ShouldBeTrue();
|
||||||
|
|
||||||
|
updatedResults.Length.ShouldBe(1);
|
||||||
|
updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
|
||||||
|
updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(1);
|
||||||
|
updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
|
||||||
|
updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(0);
|
||||||
|
updatedResults.Sum(r => r.Issues.Count).ShouldBe(0);
|
||||||
|
|
||||||
|
// Part 3 -- Update Again (No Change)
|
||||||
|
VoiceWorkUpsertResult[] updatedAgainResults = await updater.UpsertAsync([ingestUpdate], CancellationToken.None);
|
||||||
|
|
||||||
|
EnglishVoiceWork? updatedAgainEnglishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId);
|
||||||
|
updatedAgainEnglishVoiceWork.ShouldNotBeNull();
|
||||||
|
updatedAgainEnglishVoiceWork.ProductName.ShouldBe("Today Sounds (EN v2)");
|
||||||
|
updatedAgainEnglishVoiceWork.Description.ShouldBe("Updated English description.");
|
||||||
|
updatedAgainEnglishVoiceWork.IsValid?.ShouldBeTrue();
|
||||||
|
|
||||||
|
updatedAgainResults.Length.ShouldBe(1);
|
||||||
|
updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
|
||||||
|
updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
|
||||||
|
updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
|
||||||
|
updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(1);
|
||||||
|
updatedAgainResults.Sum(r => r.Issues.Count).ShouldBe(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Fail_Attempted_Insert_With_Missing_Circle()
|
||||||
|
{
|
||||||
|
await using AppDbContext dbContext = await MariaTestDb.CreateIsolatedAsync(
|
||||||
|
container.RootConnectionString,
|
||||||
|
seed: VoiceWorkIngestionSeedData.SeedAsync);
|
||||||
|
|
||||||
|
VoiceWorkIngest ingest = new()
|
||||||
|
{
|
||||||
|
MakerId = "RG99999",
|
||||||
|
MakerName = "Missing Maker",
|
||||||
|
ProductId = "RJ9999999",
|
||||||
|
Title = "EN Title",
|
||||||
|
Description = "EN Desc"
|
||||||
|
};
|
||||||
|
|
||||||
|
EnglishVoiceWorkUpdater updater = new(dbContext, languageIdentifier);
|
||||||
|
VoiceWorkUpsertResult[] results = await updater.UpsertAsync([ingest], CancellationToken.None);
|
||||||
|
|
||||||
|
int englishVoiceWorkCount = await dbContext.EnglishVoiceWorks.CountAsync(CancellationToken.None);
|
||||||
|
englishVoiceWorkCount.ShouldBe(0);
|
||||||
|
|
||||||
|
results.Length.ShouldBe(1);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(1);
|
||||||
|
results.Sum(r => r.Issues.Count).ShouldBe(1);
|
||||||
|
|
||||||
|
VoiceWorkUpsertIssue issue = results[0].Issues.ElementAt(0);
|
||||||
|
issue.Severity.ShouldBe(VoiceWorkUpsertIssueSeverity.Error);
|
||||||
|
issue.Message.ShouldBe($"Unable to find circle for maker id: {ingest.MakerId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Fail_Attempted_Insert_With_Missing_Product()
|
||||||
|
{
|
||||||
|
await using AppDbContext dbContext = await MariaTestDb.CreateIsolatedAsync(
|
||||||
|
container.RootConnectionString,
|
||||||
|
seed: VoiceWorkIngestionSeedData.SeedAsync);
|
||||||
|
|
||||||
|
VoiceWorkIngest ingest = new()
|
||||||
|
{
|
||||||
|
MakerId = "RG00001",
|
||||||
|
MakerName = "Good Dreams",
|
||||||
|
ProductId = "RJ9999999",
|
||||||
|
Title = "EN Title",
|
||||||
|
Description = "EN Desc"
|
||||||
|
};
|
||||||
|
|
||||||
|
EnglishVoiceWorkUpdater updater = new(dbContext, languageIdentifier);
|
||||||
|
VoiceWorkUpsertResult[] results = await updater.UpsertAsync([ingest], CancellationToken.None);
|
||||||
|
|
||||||
|
int englishVoiceWorkCount = await dbContext.EnglishVoiceWorks.CountAsync(CancellationToken.None);
|
||||||
|
englishVoiceWorkCount.ShouldBe(0);
|
||||||
|
|
||||||
|
results.Length.ShouldBe(1);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(1);
|
||||||
|
results.Sum(r => r.Issues.Count).ShouldBe(1);
|
||||||
|
|
||||||
|
VoiceWorkUpsertIssue issue = results[0].Issues.ElementAt(0);
|
||||||
|
issue.Severity.ShouldBe(VoiceWorkUpsertIssueSeverity.Error);
|
||||||
|
issue.Message.ShouldBe($"Unable to find voice work for product id: {ingest.ProductId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Fail_Attempted_Insert_When_Not_English()
|
||||||
|
{
|
||||||
|
await using AppDbContext dbContext = await MariaTestDb.CreateIsolatedAsync(
|
||||||
|
container.RootConnectionString,
|
||||||
|
seed: VoiceWorkIngestionSeedData.SeedAsync);
|
||||||
|
|
||||||
|
VoiceWorkIngest ingest = new()
|
||||||
|
{
|
||||||
|
MakerId = "RG00001",
|
||||||
|
MakerName = "Good Dreams",
|
||||||
|
ProductId = "RJ0000001",
|
||||||
|
Title = "すごく快適なASMR",
|
||||||
|
Description = "最高の製品です!"
|
||||||
|
};
|
||||||
|
|
||||||
|
EnglishVoiceWorkUpdater updater = new(dbContext, languageIdentifier);
|
||||||
|
VoiceWorkUpsertResult[] results = await updater.UpsertAsync([ingest], CancellationToken.None);
|
||||||
|
|
||||||
|
int englishVoiceWorkCount = await dbContext.EnglishVoiceWorks.CountAsync(CancellationToken.None);
|
||||||
|
englishVoiceWorkCount.ShouldBe(0);
|
||||||
|
|
||||||
|
results.Length.ShouldBe(1);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
|
||||||
|
results.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(1);
|
||||||
|
results.Sum(r => r.Issues.Count).ShouldBe(1);
|
||||||
|
|
||||||
|
VoiceWorkUpsertIssue issue = results[0].Issues.ElementAt(0);
|
||||||
|
issue.Severity.ShouldBe(VoiceWorkUpsertIssueSeverity.Information);
|
||||||
|
issue.Message.ShouldBe("Product title and/or description is not in English");
|
||||||
|
}
|
||||||
|
}
|
||||||
49
JSMR.Tests/Ingestion/VoiceWorkIngestionTests.cs
Normal file
49
JSMR.Tests/Ingestion/VoiceWorkIngestionTests.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using JSMR.Application.Scanning.Contracts;
|
||||||
|
using JSMR.Infrastructure.Common.Time;
|
||||||
|
using JSMR.Infrastructure.Data;
|
||||||
|
using JSMR.Infrastructure.Ingestion;
|
||||||
|
using NSubstitute;
|
||||||
|
using Shouldly;
|
||||||
|
|
||||||
|
namespace JSMR.Tests.Ingestion;
|
||||||
|
|
||||||
|
//public class VoiceWorkIngestionTests(VoiceWorkIngestionFixture fixture)
|
||||||
|
//{
|
||||||
|
// [Fact]
|
||||||
|
// public async Task Simple_Upsert()
|
||||||
|
// {
|
||||||
|
// await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
|
||||||
|
// VoiceWorkIngest[] ingests =
|
||||||
|
// [
|
||||||
|
// // TODO
|
||||||
|
// //new()
|
||||||
|
// //{
|
||||||
|
// // MakerId = "RG00001",
|
||||||
|
// // MakerName = "Good Dreams",
|
||||||
|
// // ProductId = "A Newly Announced Work",
|
||||||
|
// // Title = "",
|
||||||
|
// // Description = ""
|
||||||
|
// //},
|
||||||
|
// //new()
|
||||||
|
// //{
|
||||||
|
// // MakerId = "RG00002",
|
||||||
|
// // MakerName = "Sweet Dreams",
|
||||||
|
// // ProductId = "",
|
||||||
|
// // Title = "",
|
||||||
|
// // Description = ""
|
||||||
|
// //}
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// IClock clock = Substitute.For<IClock>();
|
||||||
|
// clock.UtcNow.Returns(new DateTimeOffset(2025, 1, 3, 0, 0, 0, 0, TimeSpan.FromSeconds(0)));
|
||||||
|
|
||||||
|
// TokyoTimeProvider timeProvider = new(clock);
|
||||||
|
|
||||||
|
// VoiceWorkUpdater updater = new(context, timeProvider);
|
||||||
|
// await updater.UpsertAsync(ingests, CancellationToken.None);
|
||||||
|
|
||||||
|
// // TODO
|
||||||
|
// //context.VoiceWorks.Count().ShouldBe(2);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -1,19 +1,12 @@
|
|||||||
using JSMR.Application.Common;
|
using JSMR.Application.Common;
|
||||||
using JSMR.Application.Integrations.DLSite.Models;
|
|
||||||
using JSMR.Application.Scanning.Contracts;
|
|
||||||
using JSMR.Infrastructure.Data;
|
using JSMR.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace JSMR.Tests.Fixtures;
|
namespace JSMR.Tests.Ingestion;
|
||||||
|
|
||||||
public class VoiceWorkUpsertFixture : MariaDbFixture
|
public static class VoiceWorkIngestionSeedData
|
||||||
{
|
{
|
||||||
protected override async Task OnInitializedAsync(AppDbContext context)
|
public static async Task SeedAsync(AppDbContext context)
|
||||||
{
|
|
||||||
await SeedAsync(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task SeedAsync(AppDbContext context)
|
|
||||||
{
|
{
|
||||||
if (await context.VoiceWorks.AnyAsync())
|
if (await context.VoiceWorks.AnyAsync())
|
||||||
return;
|
return;
|
||||||
@@ -126,61 +119,4 @@ public class VoiceWorkUpsertFixture : MariaDbFixture
|
|||||||
|
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public VoiceWorkIngest[] GetFirstRoundIngests()
|
|
||||||
{
|
|
||||||
VoiceWorkIngest[] ingests =
|
|
||||||
[
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
MakerId = "RG00001",
|
|
||||||
MakerName = "Good Dreams",
|
|
||||||
ProductId = "RJ0000001",
|
|
||||||
Title = "Today Sounds",
|
|
||||||
Description = "An average product.",
|
|
||||||
Tags = ["ASMR", "Office Lady"],
|
|
||||||
AgeRating = AgeRating.R15,
|
|
||||||
SalesDate = new DateOnly(2025, 1, 1),
|
|
||||||
ExpectedDate = null,
|
|
||||||
WishlistCount = 750,
|
|
||||||
Downloads = 500,
|
|
||||||
HasTrial = true,
|
|
||||||
HasDLPlay = true
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
MakerId = "RG00002",
|
|
||||||
MakerName = "Sweet Dreams",
|
|
||||||
ProductId = "RJ0000002",
|
|
||||||
Title = "Super Comfy ASMR",
|
|
||||||
Description = "An amazing product!",
|
|
||||||
AgeRating = AgeRating.AllAges,
|
|
||||||
Tags = ["ASMR", "Heartwarming", "Elf / Fairy", "Tsundere", "All Happy", "Gal", "Maid"],
|
|
||||||
SalesDate = new DateOnly(2025, 3, 1),
|
|
||||||
ExpectedDate = null,
|
|
||||||
WishlistCount = 12000,
|
|
||||||
Downloads = 5000,
|
|
||||||
HasTrial = true,
|
|
||||||
HasDLPlay = true
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
MakerId = "RG00003",
|
|
||||||
MakerName = "Nightmare Fuel",
|
|
||||||
ProductId = "RJ0000003",
|
|
||||||
Title = "Low Effort",
|
|
||||||
Description = "A bad product.",
|
|
||||||
Tags = ["Tsundere", "Non-Fiction / Narrative"],
|
|
||||||
AgeRating = AgeRating.R18,
|
|
||||||
SalesDate = new DateOnly(2025, 1, 1),
|
|
||||||
ExpectedDate = null,
|
|
||||||
WishlistCount = 100,
|
|
||||||
Downloads = 50,
|
|
||||||
HasTrial = true,
|
|
||||||
HasDLPlay = false
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
return ingests;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,16 +3,20 @@ using JSMR.Application.Tags.Queries.Search.Contracts;
|
|||||||
using JSMR.Infrastructure.Data;
|
using JSMR.Infrastructure.Data;
|
||||||
using JSMR.Infrastructure.Data.Repositories.Tags;
|
using JSMR.Infrastructure.Data.Repositories.Tags;
|
||||||
using JSMR.Tests.Fixtures;
|
using JSMR.Tests.Fixtures;
|
||||||
|
using JSMR.Tests.Ingestion;
|
||||||
using Shouldly;
|
using Shouldly;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace JSMR.Tests.Integration;
|
namespace JSMR.Tests.Integration;
|
||||||
|
|
||||||
|
//[Collection("db")]
|
||||||
public class TagSearchProviderTests(TagSearchProviderFixture fixture) : IClassFixture<TagSearchProviderFixture>
|
public class TagSearchProviderTests(TagSearchProviderFixture fixture) : IClassFixture<TagSearchProviderFixture>
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Filter_None_Sort_Name()
|
public async Task Filter_None_Sort_Name()
|
||||||
{
|
{
|
||||||
await using AppDbContext context = fixture.CreateDbContext();
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
//AppDbContext context = fixture.DbContext!;
|
||||||
TagSearchProvider provider = new(context);
|
TagSearchProvider provider = new(context);
|
||||||
|
|
||||||
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
||||||
@@ -32,6 +36,7 @@ public class TagSearchProviderTests(TagSearchProviderFixture fixture) : IClassFi
|
|||||||
public async Task Filter_None_Sort_EnglishName()
|
public async Task Filter_None_Sort_EnglishName()
|
||||||
{
|
{
|
||||||
await using AppDbContext context = fixture.CreateDbContext();
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
//AppDbContext context = fixture.DbContext!;
|
||||||
TagSearchProvider provider = new(context);
|
TagSearchProvider provider = new(context);
|
||||||
|
|
||||||
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
||||||
@@ -51,6 +56,7 @@ public class TagSearchProviderTests(TagSearchProviderFixture fixture) : IClassFi
|
|||||||
public async Task Filter_By_Name_Tag_Name()
|
public async Task Filter_By_Name_Tag_Name()
|
||||||
{
|
{
|
||||||
await using AppDbContext context = fixture.CreateDbContext();
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
//await using AppDbContext context = fixture.CreateDbContext();
|
||||||
TagSearchProvider provider = new(context);
|
TagSearchProvider provider = new(context);
|
||||||
|
|
||||||
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
||||||
@@ -72,6 +78,7 @@ public class TagSearchProviderTests(TagSearchProviderFixture fixture) : IClassFi
|
|||||||
public async Task Filter_By_Name_English_Tag_Name()
|
public async Task Filter_By_Name_English_Tag_Name()
|
||||||
{
|
{
|
||||||
await using AppDbContext context = fixture.CreateDbContext();
|
await using AppDbContext context = fixture.CreateDbContext();
|
||||||
|
//AppDbContext context = fixture.DbContext!;
|
||||||
TagSearchProvider provider = new(context);
|
TagSearchProvider provider = new(context);
|
||||||
|
|
||||||
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
var options = new SearchOptions<TagSearchCriteria, TagSortField>()
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
using JSMR.Application.Scanning.Contracts;
|
|
||||||
using JSMR.Infrastructure.Common.Time;
|
|
||||||
using JSMR.Infrastructure.Data;
|
|
||||||
using JSMR.Infrastructure.Ingestion;
|
|
||||||
using JSMR.Tests.Fixtures;
|
|
||||||
using NSubstitute;
|
|
||||||
using Shouldly;
|
|
||||||
|
|
||||||
namespace JSMR.Tests.Integration;
|
|
||||||
|
|
||||||
public class VoiceWorkUpsertTests(VoiceWorkUpsertFixture fixture) : IClassFixture<VoiceWorkUpsertFixture>
|
|
||||||
{
|
|
||||||
[Fact]
|
|
||||||
public async Task Simple_Upsert()
|
|
||||||
{
|
|
||||||
await using AppDbContext context = fixture.CreateDbContext();
|
|
||||||
|
|
||||||
VoiceWorkIngest[] ingests =
|
|
||||||
[
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
MakerId = "RG00001",
|
|
||||||
MakerName = "Good Dreams",
|
|
||||||
ProductId = "A Newly Announced Work",
|
|
||||||
Title = "",
|
|
||||||
Description = ""
|
|
||||||
},
|
|
||||||
new()
|
|
||||||
{
|
|
||||||
MakerId = "RG00001",
|
|
||||||
MakerName = "Sweet Dreams",
|
|
||||||
ProductId = "",
|
|
||||||
Title = "",
|
|
||||||
Description = ""
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
IClock clock = Substitute.For<IClock>();
|
|
||||||
clock.UtcNow.Returns(new DateTimeOffset(2025, 10, 1, 0, 0, 0, 0, TimeSpan.FromSeconds(0)));
|
|
||||||
|
|
||||||
TokyoTimeProvider timeProvider = new(clock);
|
|
||||||
|
|
||||||
VoiceWorkUpdater updater = new(context, timeProvider);
|
|
||||||
await updater.UpsertAsync(ingests, CancellationToken.None);
|
|
||||||
|
|
||||||
context.VoiceWorks.Count().ShouldBe(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
<PackageReference Include="Shouldly" Version="4.3.0" />
|
<PackageReference Include="Shouldly" Version="4.3.0" />
|
||||||
<PackageReference Include="Testcontainers" Version="4.8.1" />
|
<PackageReference Include="Testcontainers" Version="4.8.1" />
|
||||||
<PackageReference Include="Testcontainers.MariaDb" Version="4.8.1" />
|
<PackageReference Include="Testcontainers.MariaDb" Version="4.8.1" />
|
||||||
|
<PackageReference Include="Testcontainers.Xunit" Version="4.8.1" />
|
||||||
<PackageReference Include="xunit" Version="2.9.3" />
|
<PackageReference Include="xunit" Version="2.9.3" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
|||||||
Reference in New Issue
Block a user