package atomicheader import ( "errors" "os" "path/filepath" "sync" "testing" "time" ) func NewForTesting(t *testing.T) (*Handler, func()) { tmpDir := t.TempDir() f, err := os.Create(filepath.Join(tmpDir, "h")) if err != nil { t.Fatal(err) } if err := Init(f); err != nil { t.Fatal(err) } h, err := Open(f) if err != nil { t.Fatal(err) } return h, func() { f.Close() os.RemoveAll(tmpDir) } } func TestAtomicHeaderSimple(t *testing.T) { h, cleanup := NewForTesting(t) defer cleanup() err := h.Write(func(page []byte) error { for i := range page[:AvailabePageSize] { page[i] = byte(i) % 11 } return nil }) if err != nil { t.Fatal(err) } err = h.Read(func(page []byte) error { for i := range page[:AvailabePageSize] { if page[i] != byte(i)%11 { t.Fatal(i, page[i], byte(i)%11) } } return nil }) if err != nil { t.Fatal(err) } } func TestAtomicHeaderThreaded(t *testing.T) { h, cleanup := NewForTesting(t) defer cleanup() expectedValue := byte(0) writeErr := make(chan error, 1) stop := make(chan struct{}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() for { select { case <-stop: writeErr <- nil return default: } err := h.Write(func(page []byte) error { if page[0] != expectedValue { return errors.New("Unexpected current value.") } expectedValue++ page[0] = expectedValue return nil }) if err != nil { writeErr <- err return } time.Sleep(time.Millisecond / 13) } }() for i := 0; i < 2000; i++ { time.Sleep(time.Millisecond) err := h.Read(func(page []byte) error { if page[0] != expectedValue { t.Fatal(page[0], expectedValue) } return nil }) if err != nil { t.Fatal(err) } } close(stop) wg.Wait() if err := <-writeErr; err != nil { t.Fatal(err) } }