Files
OpenList/internal/search/build_test.go
ShenLin 8495470e63 fix(search): serialize index updates by parent (#2827)
- Prevent concurrent updates from inserting duplicate index entries
- Preserve parallel indexing across different parent paths
- Add serialization, concurrency, and lock cleanup tests

Signed-off-by: jyxjjj <16695261+jyxjjj@users.noreply.github.com>
Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
Co-authored-by: Pikachu Ren <40362270+PIKACHUIM@users.noreply.github.com>
2026-07-23 19:33:25 +08:00

59 lines
1.2 KiB
Go

package search
import (
"testing"
"time"
)
func TestLockUpdateSerializesSameParent(t *testing.T) {
unlockFirst := lockUpdate("/same-parent")
secondStarted := make(chan struct{})
secondAcquired := make(chan struct{})
secondReleased := make(chan struct{})
go func() {
close(secondStarted)
unlockSecond := lockUpdate("/same-parent")
close(secondAcquired)
unlockSecond()
close(secondReleased)
}()
<-secondStarted
select {
case <-secondAcquired:
t.Fatal("second update acquired the same parent lock")
case <-time.After(20 * time.Millisecond):
}
unlockFirst()
select {
case <-secondReleased:
case <-time.After(time.Second):
t.Fatal("second update did not acquire the released parent lock")
}
updateLocksMu.Lock()
defer updateLocksMu.Unlock()
if len(updateLocks) != 0 {
t.Fatalf("update locks were not cleaned up: %d", len(updateLocks))
}
}
func TestLockUpdateAllowsDifferentParents(t *testing.T) {
unlockFirst := lockUpdate("/first-parent")
defer unlockFirst()
secondAcquired := make(chan struct{})
go func() {
unlockSecond := lockUpdate("/second-parent")
unlockSecond()
close(secondAcquired)
}()
select {
case <-secondAcquired:
case <-time.After(time.Second):
t.Fatal("update for a different parent was blocked")
}
}