mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-10-06 21:55:39 -04:00
157 lines
6.3 KiB
C#
157 lines
6.3 KiB
C#
using allstarr.Core.Capabilities;
|
|
using allstarr.Core.Matching;
|
|
using allstarr.Core.Storage;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
|
|
namespace allstarr.Tests;
|
|
|
|
public sealed class CanonicalAliasMigrationTests
|
|
{
|
|
[Fact]
|
|
public async Task Migration_ProjectsExistingSignalsAndScopedProviderIdentities()
|
|
{
|
|
await using var database = await PostgresTestDatabase.CreateAsync(useTemplate: false);
|
|
await using (var oldSchema = new AllstarrDbContext(database.Options))
|
|
{
|
|
var migrator = oldSchema.Database.GetService<IMigrator>();
|
|
await migrator.MigrateAsync("20260915000028_ExpandCanonicalCatalog");
|
|
}
|
|
|
|
var now = new DateTimeOffset(2026, 9, 22, 12, 0, 0, TimeSpan.Zero);
|
|
var tenantId = Guid.CreateVersion7();
|
|
var userId = Guid.CreateVersion7();
|
|
var accountId = Guid.CreateVersion7();
|
|
var provisionalRecordingId = Guid.CreateVersion7();
|
|
var musicBrainzRecordingId = Guid.CreateVersion7();
|
|
const string externalId = "same-provider-track";
|
|
const string isrc = "USRC17607839";
|
|
const string mbid = "11111111-2222-3333-4444-555555555555";
|
|
var externalIdHash = CanonicalCatalogKeys.Hash(externalId);
|
|
await using (var seed = new AllstarrDbContext(database.Options))
|
|
{
|
|
seed.AddRange(
|
|
new TenantRecord
|
|
{
|
|
Id = tenantId,
|
|
Slug = "canonical-alias-migration",
|
|
Name = "Canonical alias migration",
|
|
CreatedAt = now
|
|
},
|
|
new PlatformUserRecord
|
|
{
|
|
Id = userId,
|
|
TenantId = tenantId,
|
|
DisplayName = "Catalog owner",
|
|
Status = PlatformUserStatus.Active,
|
|
CreatedAt = now,
|
|
UpdatedAt = now
|
|
},
|
|
new ProviderAccountRecord
|
|
{
|
|
Id = accountId,
|
|
TenantId = tenantId,
|
|
OwnerUserId = userId,
|
|
ProviderId = "fixture",
|
|
DisplayName = "Fixture account",
|
|
Scope = ProviderAccountScope.User,
|
|
Enabled = true,
|
|
CreatedAt = now,
|
|
UpdatedAt = now
|
|
},
|
|
new CanonicalRecordingRecord
|
|
{
|
|
Id = provisionalRecordingId,
|
|
TenantId = tenantId,
|
|
CreatedByUserId = userId,
|
|
Title = "Provider-only recording",
|
|
Isrc = isrc,
|
|
CreatedAt = now,
|
|
UpdatedAt = now
|
|
},
|
|
new CanonicalRecordingRecord
|
|
{
|
|
Id = musicBrainzRecordingId,
|
|
TenantId = tenantId,
|
|
CreatedByUserId = userId,
|
|
Title = "MusicBrainz recording",
|
|
MusicBrainzRecordingId = mbid,
|
|
CreatedAt = now,
|
|
UpdatedAt = now
|
|
},
|
|
Identity(
|
|
provisionalRecordingId,
|
|
providerAccountId: null,
|
|
ProviderIdentityScope.Catalog),
|
|
Identity(
|
|
musicBrainzRecordingId,
|
|
accountId,
|
|
ProviderIdentityScope.Account));
|
|
await seed.SaveChangesAsync();
|
|
}
|
|
|
|
await using (var migrate = new AllstarrDbContext(database.Options))
|
|
{
|
|
await migrate.Database.MigrateAsync();
|
|
}
|
|
|
|
await using var verification = new AllstarrDbContext(database.Options);
|
|
var recordings = await verification.CanonicalRecordings
|
|
.OrderBy(item => item.Id)
|
|
.ToDictionaryAsync(item => item.Id);
|
|
Assert.True(recordings[provisionalRecordingId].IsProvisional);
|
|
Assert.False(recordings[musicBrainzRecordingId].IsProvisional);
|
|
|
|
var aliases = await verification.CanonicalCatalogAliases
|
|
.OrderBy(item => item.Namespace)
|
|
.ToListAsync();
|
|
Assert.Equal(4, aliases.Count);
|
|
Assert.Contains(aliases, alias =>
|
|
alias.Namespace == "isrc" &&
|
|
alias.ExternalId == isrc &&
|
|
alias.CanonicalEntityId == provisionalRecordingId);
|
|
Assert.Contains(aliases, alias =>
|
|
alias.Namespace == "musicbrainz" &&
|
|
alias.ExternalId == mbid &&
|
|
alias.CanonicalEntityId == musicBrainzRecordingId);
|
|
|
|
var catalogNamespace = CanonicalCatalogKeys.ProviderTrackNamespace(
|
|
"fixture", ProviderResourceKind.Track, "default", ProviderIdentityScope.Catalog, null);
|
|
var accountNamespace = CanonicalCatalogKeys.ProviderTrackNamespace(
|
|
"fixture", ProviderResourceKind.Track, "default", ProviderIdentityScope.Account, accountId);
|
|
Assert.NotEqual(catalogNamespace, accountNamespace);
|
|
Assert.Contains(aliases, alias =>
|
|
alias.Namespace == catalogNamespace &&
|
|
alias.ExternalId == externalId &&
|
|
alias.CanonicalEntityId == provisionalRecordingId);
|
|
Assert.Contains(aliases, alias =>
|
|
alias.Namespace == accountNamespace &&
|
|
alias.ExternalId == externalId &&
|
|
alias.CanonicalEntityId == musicBrainzRecordingId);
|
|
|
|
ProviderTrackIdentityRecord Identity(
|
|
Guid canonicalRecordingId,
|
|
Guid? providerAccountId,
|
|
ProviderIdentityScope scope) => new()
|
|
{
|
|
Id = Guid.CreateVersion7(),
|
|
TenantId = tenantId,
|
|
CanonicalRecordingId = canonicalRecordingId,
|
|
ProviderAccountId = providerAccountId,
|
|
ProviderId = "fixture",
|
|
ResourceKind = ProviderResourceKind.Track,
|
|
CatalogNamespace = "default",
|
|
Scope = scope,
|
|
ExternalId = externalId,
|
|
ExternalIdHash = externalIdHash,
|
|
Verification = ProviderIdentityVerification.Verified,
|
|
VerificationMethod = "migration-fixture",
|
|
DecisionVersion = 1,
|
|
VerifiedAt = now,
|
|
CreatedAt = now,
|
|
UpdatedAt = now
|
|
};
|
|
}
|
|
}
|