package oltp
import (
"fmt"
"path/filepath"
"sync"
"testing"
)
// One sequence per repository, apart from the tickets'; the order given
// is the order numbered; a numbered landing keeps its number.
func TestLandingNumbersAreTheirOwnSequence(t *testing.T) {
d := openTest(t)
if err := d.TicketNumbersAssign("q", []string{"t1", "t2"}); err != nil {
t.Fatal(err)
}
if err := d.LandingNumbersAssign("q", []string{"aa", "bb"}); err != nil {
t.Fatal(err)
}
if err := d.LandingNumbersAssign("q", []string{"bb", "cc"}); err != nil {
t.Fatal(err)
}
if err := d.LandingNumbersAssign("other", []string{"zz"}); err != nil {
t.Fatal(err)
}
got, err := d.LandingNumbers("q")
if err != nil {
t.Fatal(err)
}
if got["aa"] != 1 || got["bb"] != 2 || got["cc"] != 3 || len(got) != 3 {
t.Fatalf("FAIL: %v", got)
}
if o, _ := d.LandingNumbers("other"); o["zz"] != 1 {
t.Fatalf("FAIL: another repository shares the sequence: %v", o)
}
if id, ok, _ := d.LandingNumbered("q", 3); !ok || id != "cc" {
t.Fatalf("FAIL: !3 names %q", id)
}
if _, ok, _ := d.LandingNumbered("q", 9); ok {
t.Fatal("FAIL: an unassigned number names a landing")
}
t.Log("ok: 1 2 3 in order beside tickets 1 2, bb kept its number, another repository starts at 1")
}
// Two handles on one database — two nodes on one file — numbering the
// same landings and their own at once: no number twice, no landing twice.
func TestLandingNumbersConcurrentAssignIsUnique(t *testing.T) {
path := filepath.Join(t.TempDir(), "oltp.db")
a, err := Open(path)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { a.Close() })
b, err := Open(path)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { b.Close() })
var wg sync.WaitGroup
errs := make(chan error, 40)
for i := 0; i < 20; i++ {
for _, db := range []*DB{a, b} {
wg.Add(1)
go func(db *DB, i int) {
defer wg.Done()
errs <- db.LandingNumbersAssign("q", []string{"shared", fmt.Sprintf("own%d", i)})
}(db, i)
}
}
wg.Wait()
close(errs)
for err := range errs {
if err != nil {
t.Fatal(err)
}
}
got, _ := a.LandingNumbers("q")
if len(got) != 21 {
t.Fatalf("FAIL: %d landings numbered, want 21: %v", len(got), got)
}
seen := map[int]bool{}
for _, n := range got {
if seen[n] || n < 1 || n > 21 {
t.Fatalf("FAIL: numbers are not 1..21 once each: %v", got)
}
seen[n] = true
}
t.Log("ok: 21 landings, numbers 1..21 once each")
}