Let a row show the metadata it was handed

This commit is contained in:
Arkadiusz Fal
2026-09-07 07:30:00 +02:00
parent 69aed50012
commit dca8e2fbe4
12 changed files with 223 additions and 79 deletions

View File

@@ -277,7 +277,7 @@ private final class AccountServiceHarness {
var credentialSwapOnNextRead: String?
init(type: InstanceType = .invidious, isEnabled: Bool = true) {
instances = InstancesManager()
instances = makeTestInstancesManager()
instance = Instance(
type: type,
url: URL(string: "https://accounts-\(UUID().uuidString).example.com")!,

View File

@@ -691,7 +691,7 @@ struct AccountSyncTests {
@Test("A repair made mid-batch is never uploaded over the server's older context")
func repairIsNotPublishedForAStaleServerContext() async {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = Instance(type: .invidious, url: URL(string: "https://inv-\(UUID().uuidString).example.com")!)
instances.add(instance)
defer { instances.remove(instance) }
@@ -732,7 +732,7 @@ struct AccountSyncTests {
@Test("An account discarded for its tombstone still repairs the context")
func discardedAccountKeepsItsInstance() async {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = Instance(type: .invidious, url: URL(string: "https://inv-\(UUID().uuidString).example.com")!)
instances.add(instance)
defer { instances.remove(instance) }
@@ -765,7 +765,7 @@ struct AccountSyncTests {
@Test("A context fetched ahead of the records it depends on is still applied last")
func stagedContextIsAppliedAfterTheAccountRecords() async {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = Instance(type: .invidious, url: URL(string: "https://inv-\(UUID().uuidString).example.com")!)
instances.add(instance)
defer { instances.remove(instance) }

View File

@@ -406,7 +406,7 @@ struct AccountsManagerTests {
@Test("An unresolved identity never migrates a legacy login")
func unresolvedIdentityDoesNotMigrate() {
let defaults = makeDefaults()
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeLegacyInstance()
instances.add(instance)
defer { instances.remove(instance) }
@@ -438,7 +438,7 @@ struct AccountsManagerTests {
@Test("A scope that dips to unresolved and returns writes nothing in between")
func scopeRoundTripLeavesTheUnresolvedNamespaceEmpty() async throws {
let defaults = makeDefaults()
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeLegacyInstance()
instances.add(instance)
defer { instances.remove(instance) }
@@ -570,7 +570,7 @@ struct DataContextValidatorTests {
@Test("A switched-off instance makes its context unavailable, not removed")
func disabledInstanceIsUnavailable() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
var instance = Instance(type: .invidious, url: URL(string: "https://inv.example.com")!)
instances.add(instance)
@@ -598,7 +598,7 @@ struct DataContextValidatorTests {
@Test("Only a deletion the app can point at moves the context")
func correctionRequiresATombstone() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
var instance = Instance(type: .invidious, url: URL(string: "https://inv-correct.example.com")!)
instances.add(instance)
defer { instances.remove(instance) }
@@ -639,7 +639,7 @@ struct DataContextValidatorTests {
@Test("A tombstoned selection is repaired without being published")
func correctionFollowsTheTombstone() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = Instance(type: .invidious, url: URL(string: "https://inv-tombstone.example.com")!)
instances.add(instance)
defer { instances.remove(instance) }
@@ -668,7 +668,7 @@ struct DataContextValidatorTests {
@Test("Nothing is repaired while the namespace is reloading")
func correctionIsFencedToTheLoadedNamespace() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = Instance(type: .invidious, url: URL(string: "https://inv-reload.example.com")!)
instances.add(instance)
defer { instances.remove(instance) }
@@ -715,7 +715,7 @@ struct DataContextValidatorTests {
@Test("Only accounts the app can actually resolve are offered")
func availableContextsAreFiltered() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let enabled = Instance(type: .invidious, url: URL(string: "https://inv-a.example.com")!)
let disabled = Instance(type: .invidious, url: URL(string: "https://inv-b.example.com")!, isEnabled: false)
// No account concept on PeerTube, so a context there could never be
@@ -756,7 +756,7 @@ struct DataContextRepairTests {
@Test("Deleting the selected account falls back to a signed-in sibling")
func deletionPrefersSignedInSibling() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -779,7 +779,7 @@ struct DataContextRepairTests {
@Test("Without a signed-in sibling the repair lands on local")
func deletionWithoutSiblingFallsBackToLocal() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -800,7 +800,7 @@ struct DataContextRepairTests {
@Test("A repair made while a sibling was still being checked never comes back")
func repairIsNotReconsideredWhenStatusesSettle() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -829,7 +829,7 @@ struct DataContextRepairTests {
@Test("A signed-in account on another server is never the repair")
func repairNeverCrossesInstances() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let first = makeInstance("inv-first")
let second = makeInstance("inv-second")
instances.add(first)
@@ -852,7 +852,7 @@ struct DataContextRepairTests {
@Test("A synced context naming a deleted account repairs to its sibling")
func syncedTombstoneRepairPrefersSibling() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -878,7 +878,7 @@ struct DataContextRepairTests {
@Test("A synced context for a deleted account with no sibling lands on local")
func syncedTombstoneRepairFallsBackToLocal() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -900,7 +900,7 @@ struct DataContextRepairTests {
@Test("Adopting a repaired synced context drops what the replaced choice owed")
func syncedTombstoneRepairIsNeverPublished() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -929,7 +929,7 @@ struct DataContextRepairTests {
@Test("A local choice that outranks a repair keeps its upload")
func repairThatLosesLeavesTheChoiceDirty() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -956,7 +956,7 @@ struct DataContextRepairTests {
@Test("A repair is never pushed back over the server's older context")
func repairIsNeverPushedBackOverAnOlderContext() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1002,7 +1002,7 @@ struct DataContextRepairTests {
@Test("A repair read back from disk still yields rather than publishing")
func reloadedRepairStillYieldsToTheServersContext() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1035,7 +1035,7 @@ struct DataContextRepairTests {
@Test("A repair yields to an explicit context it ties with")
func repairYieldsToAnExplicitContextOnATie() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1064,7 +1064,7 @@ struct DataContextRepairTests {
@Test("A repair yields to an older context naming an account that is still there")
func repairYieldsToAnOlderContextNamingALiveAccount() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1096,7 +1096,7 @@ struct DataContextRepairTests {
@Test("An older context naming the deleted account repairs again rather than landing on it")
func repairYieldsToAnOlderContextNamingTheDeletedAccount() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1130,7 +1130,7 @@ struct DataContextRepairTests {
@Test("A repair recomputes statuses before it picks a sibling")
func repairRefreshesStatusesBeforeChoosing() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }
@@ -1160,7 +1160,7 @@ struct DataContextRepairTests {
@Test("An account dominated by a tombstone still says where it lived")
func discardedAccountKeepsItsInstanceForRepair() {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance("inv")
instances.add(instance)
defer { instances.remove(instance) }

View File

@@ -30,7 +30,7 @@ struct OrphanedAccountRemovalTests {
@Test("An account outlives its source, and knows nothing about it")
func orphanHasNothingToResolveThrough() {
let scope = makeScope()
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.invidious)
instances.add(instance)
@@ -59,7 +59,7 @@ struct OrphanedAccountRemovalTests {
let invidious = InvidiousCredentialsManager(identityScope: scope)
let piped = PipedCredentialsManager(identityScope: scope)
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.invidious)
instances.add(instance)
@@ -96,7 +96,7 @@ struct OrphanedAccountRemovalTests {
let invidious = InvidiousCredentialsManager(identityScope: scope)
let piped = PipedCredentialsManager(identityScope: scope)
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.piped)
instances.add(instance)
@@ -126,7 +126,7 @@ struct OrphanedAccountRemovalTests {
@Test("A deletion queued for the server survives the removal")
func removalQueuesTheTombstone() {
let scope = makeScope()
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.invidious)
instances.add(instance)
@@ -155,7 +155,7 @@ struct OrphanedAccountRemovalTests {
@Test("The deletion is durable before the secret is destroyed")
func removalRecordsTheTombstoneFirst() {
let scope = makeScope()
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.invidious)
instances.add(instance)
@@ -186,7 +186,7 @@ struct OrphanedAccountRemovalTests {
let scope = makeScope()
let invidious = InvidiousCredentialsManager(identityScope: scope)
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let instance = makeInstance(.invidious)
instances.add(instance)

View File

@@ -47,7 +47,7 @@ private final class ProbeHarness {
cooldown: TimeInterval = 0,
unreachableRetryInterval: TimeInterval = 60
) {
instances = InstancesManager()
instances = makeTestInstancesManager()
instance = Instance(
type: type,
url: URL(string: "https://probe-\(UUID().uuidString).example.com")!,

View File

@@ -147,3 +147,15 @@ struct InstanceIdentityTests {
#expect(instance.id == originalID)
}
}
// MARK: - Test Support
/// An instances manager with defaults of its own.
///
/// `InstancesManager()` reads and writes `UserDefaults.standard`, which under a
/// test host is the app's own container: an instance a fixture adds becomes one
/// the app on that device is configured with, and it stays there after the run.
@MainActor
func makeTestInstancesManager() -> InstancesManager {
InstancesManager(defaults: UserDefaults(suiteName: "yattee.tests.instances.\(UUID().uuidString)")!)
}

View File

@@ -117,7 +117,7 @@ struct SubscriptionDestinationRoutingTests {
}
private func makeFixture() throws -> Fixture {
let instances = InstancesManager()
let instances = makeTestInstancesManager()
let made = (0 ..< 2).map { index in
Instance(
type: .invidious,

View File

@@ -35,7 +35,7 @@ private final class WatchHistorySyncHarness {
var credentials: [UUID: String] = [:]
init(type: InstanceType = .invidious) {
instances = InstancesManager()
instances = makeTestInstancesManager()
instance = Instance(
type: type,
url: URL(string: "https://history-\(UUID().uuidString).example.com")!,