package memlog import ( "fmt" "io/ioutil" "log" "os" "testing" "time" pb "git.autistici.org/ai3/tools/replds2/proto" ) type testMap struct { m map[string]*pb.Node } func (m *testMap) set(node *pb.Node) error { m.m[node.Path] = node return nil } func (m *testMap) dump(f func(*pb.Node) error) error { for _, node := range m.m { if err := f(node); err != nil { return err } } return nil } func TestLog(t *testing.T) { // Make smaller log files maxLogSize = 1024 * 1024 dir, err := ioutil.TempDir("", "") if err != nil { t.Fatal(err) } defer os.RemoveAll(dir) m := &testMap{m: make(map[string]*pb.Node)} l, err := openLog(dir, m.set, m.dump) if err != nil { t.Fatal(err) } // Create a bunch of entries, with repeated updates. log.Printf(">>> writing test entries...") numEntries := 100000 maxSz := 5000 for i := 0; i < numEntries; i++ { node := &pb.Node{ Path: fmt.Sprintf("/path/to/%08d", (i % maxSz)), Version: time.Now().Unix(), Data: []byte("just some random data, blah blah, blah blah!"), } if err := l.Write(node); err != nil { t.Fatal(err) } m.set(node) // nolint: errcheck } // We should be now on log #8. if l.curIdx != 8 { t.Fatalf("expected to be on log #9, actually #%d", l.curIdx) } log.Printf(">>> forcing a checkpoint...") if err := l.Rotate(true, m.dump); err != nil { t.Fatal(err) } // Ensure that there is a single log file post checkpoint. if n := len(listLogfiles(l.path)); n != 1 { t.Fatalf("expected just a single log after checkpoint, found %d", n) } // Now we close the log, and re-open it. log.Printf(">>> closing and re-opening log...") l.Close() m = &testMap{m: make(map[string]*pb.Node)} l, err = openLog(dir, m.set, m.dump) if err != nil { t.Fatal(err) } testPath := fmt.Sprintf("/path/to/%08d", 10) if _, ok := m.m[testPath]; !ok { t.Fatalf("expected value not found post reload") } // Modify the log, close it and reopen it, expecting it to be // dirty, and re-checkpointing on open. log.Printf(">>> writing new data, closing and re-opening log...") err = l.Write(&pb.Node{ Path: testPath, Version: time.Now().Unix(), Data: []byte("new data"), }) if err != nil { t.Fatal(err) } l.Close() m = &testMap{m: make(map[string]*pb.Node)} l, err = openLog(dir, m.set, m.dump) if err != nil { t.Fatal(err) } value, ok := m.m[testPath] if !ok { t.Fatal("expected value not found post reload") } if s := string(value.Data); s != "new data" { t.Fatalf("data of %s is wrong post-reload: %s", testPath, s) } l.Close() }