package index
import (
"testing"
"time"
)
// attachment.head runs on every ticket page that shows a file, and it
// records what it learned in the index. That record must not make the
// page wait for the writer: a mirror fold of a large tracker holds it
// for seconds, and before this the page sat behind the fold once per
// attachment card. The verdict is readable at once, and lands in the
// table when the writer frees up.
func TestAHeadMemoNeverWaitsForTheWriter(t *testing.T) {
ix := openIndex(t)
tx, err := ix.w.Begin()
if err != nil {
t.Fatal(err)
}
const held = 2 * time.Second
released := make(chan struct{})
go func() {
time.Sleep(held)
tx.Rollback()
close(released)
}()
want := AttachmentHead{Size: 9, Kind: "text", Lines: 1, Text: "nine byte"}
start := time.Now()
ix.RememberAttachmentHead("blob1", want)
if el := time.Since(start); el > held/4 {
t.Fatalf("FAIL: remembering a verdict waited %v on a held writer", el.Round(time.Millisecond))
}
got, ok, err := ix.AttachmentHeadFor("blob1")
if err != nil || !ok || got != want {
t.Fatalf("FAIL: a verdict remembered behind a held writer read back ok=%v err=%v %+v", ok, err, got)
}
if el := time.Since(start); el > held/4 {
t.Fatalf("FAIL: reading the verdict back waited %v on a held writer", el.Round(time.Millisecond))
}
<-released
deadline := time.Now().Add(5 * time.Second)
for {
var n int
if err := ix.db.QueryRow(`SELECT count(*) FROM attachment_head WHERE src = 'blob1'`).Scan(&n); err != nil {
t.Fatal(err)
}
if n == 1 {
break
}
if time.Now().After(deadline) {
t.Fatal("FAIL: the verdict never reached the table once the writer was free")
}
time.Sleep(10 * time.Millisecond)
}
t.Log("ok: a head verdict is remembered without waiting on the writer, and written once it is free")
}