package gitutil
import (
"fmt"
"testing"
"time"
)
func (k *keyedMutex) entries() int {
k.mu.Lock()
defer k.mu.Unlock()
return len(k.m)
}
func TestKeyedMutexForgetsKeysNobodyHolds(t *testing.T) {
var k keyedMutex
for i := range 100 {
k.lock(fmt.Sprintf("/repos/did:web:made-up-%d", i))()
}
if got := k.entries(); got != 0 {
t.Fatalf("%d entries left after every lock was released, want 0", got)
}
unlock := k.lock("same")
entered := make(chan struct{})
go func() {
k.lock("same")()
close(entered)
}()
select {
case <-entered:
t.Fatal("a second holder got in while the first still held the key")
case <-time.After(50 * time.Millisecond):
}
if got := k.entries(); got != 1 {
t.Fatalf("%d entries while one holds and one waits, want 1", got)
}
unlock()
select {
case <-entered:
case <-time.After(5 * time.Second):
t.Fatal("the waiter never got the key after the holder let go")
}
// the waiter drops its entry just after signaling, wait for that
deadline := time.Now().Add(5 * time.Second)
for k.entries() != 0 && time.Now().Before(deadline) {
time.Sleep(5 * time.Millisecond)
}
if got := k.entries(); got != 0 {
t.Fatalf("%d entries left after the waiter finished, want 0", got)
}
}