Skip to content
Snippets Groups Projects
log_test.go 2.48 KiB
Newer Older
  • Learn to ignore specific revisions
  • ale's avatar
    ale committed
    package memlog
    
    ale's avatar
    ale committed
    
    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: int64(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)
    	}
    
    	// 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)
    	value, ok := m.m[testPath]
    	if !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...")
    	l.Write(&pb.Node{
    		Path:    testPath,
    		Version: int64(time.Now().Unix()),
    		Data:    []byte("new data"),
    	})
    
    	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()
    }