mirror of
https://github.com/truewhile/MeBox.git
synced 2026-11-12 19:34:24 +08:00
80 lines
1.9 KiB
Go
80 lines
1.9 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestSQLiteWriteGateRejectsCancelledContext(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
cancel()
|
|
gate := newSQLiteWriteGate()
|
|
holder, err := gate.Lock(ctx)
|
|
defer gate.Unlock(holder)
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("Lock error=%v, want context.Canceled", err)
|
|
}
|
|
}
|
|
|
|
func TestSQLiteWriteGateWakesForExpiredHolder(t *testing.T) {
|
|
gate := newSQLiteWriteGate()
|
|
holder, err := gate.Lock(t.Context())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer gate.Unlock(holder)
|
|
// Make the lease expire shortly, without waiting a full minute.
|
|
gate.mu.Lock()
|
|
holder.acquired = time.Now().Add(-sqliteGateHoldLimit + 20*time.Millisecond)
|
|
gate.mu.Unlock()
|
|
done := make(chan *sqliteGateHolder, 1)
|
|
go func() {
|
|
next, _ := gate.Lock(t.Context())
|
|
done <- next
|
|
}()
|
|
select {
|
|
case next := <-done:
|
|
gate.Unlock(holder) // A stale holder must not unlock its successor.
|
|
gate.mu.Lock()
|
|
owner := gate.owner
|
|
gate.mu.Unlock()
|
|
gate.Unlock(next)
|
|
if next == nil || owner != next {
|
|
t.Fatal("expired holder released the new owner's lock")
|
|
}
|
|
case <-time.After(time.Second):
|
|
gate.Unlock(holder)
|
|
gate.Unlock(<-done)
|
|
t.Fatal("waiter was not woken when the holder expired")
|
|
}
|
|
}
|
|
|
|
func TestSQLiteWriteGateWakesForCancellation(t *testing.T) {
|
|
gate := newSQLiteWriteGate()
|
|
holder, err := gate.Lock(t.Context())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer gate.Unlock(holder)
|
|
ctx, cancel := context.WithCancel(t.Context())
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
next, err := gate.Lock(ctx)
|
|
gate.Unlock(next)
|
|
done <- err
|
|
}()
|
|
cancel()
|
|
select {
|
|
case err := <-done:
|
|
if !errors.Is(err, context.Canceled) {
|
|
t.Fatalf("Lock error=%v, want context.Canceled", err)
|
|
}
|
|
case <-time.After(time.Second):
|
|
gate.Unlock(holder)
|
|
<-done
|
|
t.Fatal("waiter was not woken for cancellation")
|
|
}
|
|
}
|