+44
Diff
round #0
+11
internal/firehose/index.go
+11
internal/firehose/index.go
···
1238
1238
_, _ = idx.db.Exec(`DELETE FROM did_by_handle WHERE did = ?`, did)
1239
1239
}
1240
1240
1241
+
// ProfileCachedInMemory reports whether the in-memory profile cache currently
1242
+
// holds an entry for did. Test-only helper for asserting eviction behavior
1243
+
// without going through GetProfile (which would fall through to the public API
1244
+
// on a cache miss).
1245
+
func (idx *FeedIndex) ProfileCachedInMemory(did string) bool {
1246
+
idx.profileCacheMu.RLock()
1247
+
defer idx.profileCacheMu.RUnlock()
1248
+
_, ok := idx.profileCache[did]
1249
+
return ok
1250
+
}
1251
+
1241
1252
// RefreshProfile fetches a profile from the API and stores it in both caches.
1242
1253
// Used by the profile watcher to keep the cache warm on firehose events.
1243
1254
func (idx *FeedIndex) RefreshProfile(ctx context.Context, did string) {
+33
tests/integration/handle_resolution_test.go
+33
tests/integration/handle_resolution_test.go
···
170
170
assert.NotEqual(t, orphanDID, got, "shared handle must not resolve to the evicted prior owner")
171
171
}
172
172
173
+
// The orphan's in-memory profile entry must also be gone. The DB-side
174
+
// assertion above only catches did_by_handle cleanup; this catches the
175
+
// other half of InvalidateProfile.
176
+
assert.False(t, h.FeedIndex.ProfileCachedInMemory(orphanDID),
177
+
"orphan profile must be evicted from the in-memory cache")
178
+
173
179
// Now seed the new DID's profile (as the watcher would, on a working API).
174
180
// The handle must resolve to newDID, never orphanDID.
175
181
seedProfile(t, h, newDID, sharedHandle)
···
178
184
assert.Equal(t, newDID, got, "after reconciliation, shared handle resolves to the new owner")
179
185
}
180
186
187
+
// TestInvalidateProfile_RemovesHandleMapping is a direct unit-level assertion
188
+
// for InvalidateProfile. The eviction paths exercised in other tests
189
+
// (OnIdentityEvent, DeleteAllByDID) reach did_by_handle through different
190
+
// routes; this test pins the contract of InvalidateProfile itself: clear the
191
+
// in-memory cache, the persistent profile row, and the handle mapping.
192
+
func TestInvalidateProfile_RemovesHandleMapping(t *testing.T) {
193
+
h := StartHarness(t, nil)
194
+
ctx := context.Background()
195
+
196
+
const did = "did:plc:invalidatetest"
197
+
const handle = "invalidate.test"
198
+
199
+
seedProfile(t, h, did, handle)
200
+
require.True(t, h.FeedIndex.ProfileCachedInMemory(did),
201
+
"precondition: seed populates the in-memory cache")
202
+
got, ok := h.FeedIndex.GetDIDByHandle(ctx, handle)
203
+
require.True(t, ok)
204
+
require.Equal(t, did, got)
205
+
206
+
h.FeedIndex.InvalidateProfile(did)
207
+
208
+
assert.False(t, h.FeedIndex.ProfileCachedInMemory(did),
209
+
"InvalidateProfile must clear the in-memory cache")
210
+
_, ok = h.FeedIndex.GetDIDByHandle(ctx, handle)
211
+
assert.False(t, ok, "InvalidateProfile must clear the handle mapping")
212
+
}
213
+
181
214
// TestHandleResolution_BackfillFromExistingProfiles verifies that a FeedIndex
182
215
// opened against a database with pre-existing profile rows but no
183
216
// did_by_handle table populates the index on startup, so handle lookups work
History
1 round
0 comments
pdewey.com
submitted
#0
1 commit
expand
collapse
test: handle cache invalidation integration test
merge conflicts detected
expand
collapse
expand
collapse
- internal/handlers/admin.go:842
- internal/routing/routing.go:200