|
|
- package autofile
-
- import (
- "errors"
- "io"
- "io/ioutil"
- "os"
- "strconv"
- "strings"
- "testing"
-
- . "github.com/tendermint/tmlibs/common"
- )
-
- // NOTE: Returned group has ticker stopped
- func createTestGroup(t *testing.T, headSizeLimit int64) *Group {
- testID := RandStr(12)
- testDir := "_test_" + testID
- err := EnsureDir(testDir, 0700)
- if err != nil {
- t.Fatal("Error creating dir", err)
- }
- headPath := testDir + "/myfile"
- g, err := OpenGroup(headPath)
- if err != nil {
- t.Fatal("Error opening Group", err)
- }
- g.SetHeadSizeLimit(headSizeLimit)
- g.stopTicker()
-
- if g == nil {
- t.Fatal("Failed to create Group")
- }
- return g
- }
-
- func destroyTestGroup(t *testing.T, g *Group) {
- err := os.RemoveAll(g.Dir)
- if err != nil {
- t.Fatal("Error removing test Group directory", err)
- }
- }
-
- func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) {
- if gInfo.MinIndex != minIndex {
- t.Errorf("GroupInfo MinIndex expected %v, got %v", minIndex, gInfo.MinIndex)
- }
- if gInfo.MaxIndex != maxIndex {
- t.Errorf("GroupInfo MaxIndex expected %v, got %v", maxIndex, gInfo.MaxIndex)
- }
- if gInfo.TotalSize != totalSize {
- t.Errorf("GroupInfo TotalSize expected %v, got %v", totalSize, gInfo.TotalSize)
- }
- if gInfo.HeadSize != headSize {
- t.Errorf("GroupInfo HeadSize expected %v, got %v", headSize, gInfo.HeadSize)
- }
- }
-
- func TestCheckHeadSizeLimit(t *testing.T) {
- g := createTestGroup(t, 1000*1000)
-
- // At first, there are no files.
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0)
-
- // Write 1000 bytes 999 times.
- for i := 0; i < 999; i++ {
- err := g.WriteLine(RandStr(999))
- if err != nil {
- t.Fatal("Error appending to head", err)
- }
- }
- g.Flush()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
-
- // Even calling checkHeadSizeLimit manually won't rotate it.
- g.checkHeadSizeLimit()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
-
- // Write 1000 more bytes.
- if err := g.WriteLine(RandStr(999)); err != nil {
- t.Fatal("Error appending to head", err)
- }
- g.Flush()
-
- // Calling checkHeadSizeLimit this time rolls it.
- g.checkHeadSizeLimit()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0)
-
- // Write 1000 more bytes.
- if err := g.WriteLine(RandStr(999)); err != nil {
- t.Fatal("Error appending to head", err)
- }
- g.Flush()
-
- // Calling checkHeadSizeLimit does nothing.
- g.checkHeadSizeLimit()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
-
- // Write 1000 bytes 999 times.
- for i := 0; i < 999; i++ {
- if err := g.WriteLine(RandStr(999)); err != nil {
- t.Fatal("Error appending to head", err)
- }
- }
- g.Flush()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
-
- // Calling checkHeadSizeLimit rolls it again.
- g.checkHeadSizeLimit()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
-
- // Write 1000 more bytes.
- _, err := g.Head.Write([]byte(RandStr(999) + "\n"))
- if err != nil {
- t.Fatal("Error appending to head", err)
- }
- g.Flush()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
-
- // Calling checkHeadSizeLimit does nothing.
- g.checkHeadSizeLimit()
- assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestSearch(t *testing.T) {
- g := createTestGroup(t, 10*1000)
-
- // Create some files in the group that have several INFO lines in them.
- // Try to put the INFO lines in various spots.
- for i := 0; i < 100; i++ {
- // The random junk at the end ensures that this INFO linen
- // is equally likely to show up at the end.
- _, err := g.Head.Write([]byte(Fmt("INFO %v %v\n", i, RandStr(123))))
- if err != nil {
- t.Error("Failed to write to head")
- }
- g.checkHeadSizeLimit()
- for j := 0; j < 10; j++ {
- _, err := g.Head.Write([]byte(RandStr(123) + "\n"))
- if err != nil {
- t.Error("Failed to write to head")
- }
- g.checkHeadSizeLimit()
- }
- }
-
- // Create a search func that searches for line
- makeSearchFunc := func(target int) SearchFunc {
- return func(line string) (int, error) {
- parts := strings.Split(line, " ")
- if len(parts) != 3 {
- return -1, errors.New("Line did not have 3 parts")
- }
- i, err := strconv.Atoi(parts[1])
- if err != nil {
- return -1, errors.New("Failed to parse INFO: " + err.Error())
- }
- if target < i {
- return 1, nil
- } else if target == i {
- return 0, nil
- } else {
- return -1, nil
- }
- }
- }
-
- // Now search for each number
- for i := 0; i < 100; i++ {
- t.Log("Testing for i", i)
- gr, match, err := g.Search("INFO", makeSearchFunc(i))
- if err != nil {
- t.Fatal("Failed to search for line:", err)
- }
- if !match {
- t.Error("Expected Search to return exact match")
- }
- line, err := gr.ReadLine()
- if err != nil {
- t.Fatal("Failed to read line after search", err)
- }
- if !strings.HasPrefix(line, Fmt("INFO %v ", i)) {
- t.Fatal("Failed to get correct line")
- }
- // Make sure we can continue to read from there.
- cur := i + 1
- for {
- line, err := gr.ReadLine()
- if err == io.EOF {
- if cur == 99+1 {
- // OK!
- break
- } else {
- t.Fatal("Got EOF after the wrong INFO #")
- }
- } else if err != nil {
- t.Fatal("Error reading line", err)
- }
- if !strings.HasPrefix(line, "INFO ") {
- continue
- }
- if !strings.HasPrefix(line, Fmt("INFO %v ", cur)) {
- t.Fatalf("Unexpected INFO #. Expected %v got:\n%v", cur, line)
- }
- cur += 1
- }
- gr.Close()
- }
-
- // Now search for something that is too small.
- // We should get the first available line.
- {
- gr, match, err := g.Search("INFO", makeSearchFunc(-999))
- if err != nil {
- t.Fatal("Failed to search for line:", err)
- }
- if match {
- t.Error("Expected Search to not return exact match")
- }
- line, err := gr.ReadLine()
- if err != nil {
- t.Fatal("Failed to read line after search", err)
- }
- if !strings.HasPrefix(line, "INFO 0 ") {
- t.Error("Failed to fetch correct line, which is the earliest INFO")
- }
- err = gr.Close()
- if err != nil {
- t.Error("Failed to close GroupReader", err)
- }
- }
-
- // Now search for something that is too large.
- // We should get an EOF error.
- {
- gr, _, err := g.Search("INFO", makeSearchFunc(999))
- if err != io.EOF {
- t.Error("Expected to get an EOF error")
- }
- if gr != nil {
- t.Error("Expected to get nil GroupReader")
- }
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestRotateFile(t *testing.T) {
- g := createTestGroup(t, 0)
- g.WriteLine("Line 1")
- g.WriteLine("Line 2")
- g.WriteLine("Line 3")
- g.Flush()
- g.RotateFile()
- g.WriteLine("Line 4")
- g.WriteLine("Line 5")
- g.WriteLine("Line 6")
- g.Flush()
-
- // Read g.Head.Path+"000"
- body1, err := ioutil.ReadFile(g.Head.Path + ".000")
- if err != nil {
- t.Error("Failed to read first rolled file")
- }
- if string(body1) != "Line 1\nLine 2\nLine 3\n" {
- t.Errorf("Got unexpected contents: [%v]", string(body1))
- }
-
- // Read g.Head.Path
- body2, err := ioutil.ReadFile(g.Head.Path)
- if err != nil {
- t.Error("Failed to read first rolled file")
- }
- if string(body2) != "Line 4\nLine 5\nLine 6\n" {
- t.Errorf("Got unexpected contents: [%v]", string(body2))
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestFindLast1(t *testing.T) {
- g := createTestGroup(t, 0)
-
- g.WriteLine("Line 1")
- g.WriteLine("Line 2")
- g.WriteLine("# a")
- g.WriteLine("Line 3")
- g.Flush()
- g.RotateFile()
- g.WriteLine("Line 4")
- g.WriteLine("Line 5")
- g.WriteLine("Line 6")
- g.WriteLine("# b")
- g.Flush()
-
- match, found, err := g.FindLast("#")
- if err != nil {
- t.Error("Unexpected error", err)
- }
- if !found {
- t.Error("Expected found=True")
- }
- if match != "# b" {
- t.Errorf("Unexpected match: [%v]", match)
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestFindLast2(t *testing.T) {
- g := createTestGroup(t, 0)
-
- g.WriteLine("Line 1")
- g.WriteLine("Line 2")
- g.WriteLine("Line 3")
- g.Flush()
- g.RotateFile()
- g.WriteLine("# a")
- g.WriteLine("Line 4")
- g.WriteLine("Line 5")
- g.WriteLine("# b")
- g.WriteLine("Line 6")
- g.Flush()
-
- match, found, err := g.FindLast("#")
- if err != nil {
- t.Error("Unexpected error", err)
- }
- if !found {
- t.Error("Expected found=True")
- }
- if match != "# b" {
- t.Errorf("Unexpected match: [%v]", match)
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestFindLast3(t *testing.T) {
- g := createTestGroup(t, 0)
-
- g.WriteLine("Line 1")
- g.WriteLine("# a")
- g.WriteLine("Line 2")
- g.WriteLine("# b")
- g.WriteLine("Line 3")
- g.Flush()
- g.RotateFile()
- g.WriteLine("Line 4")
- g.WriteLine("Line 5")
- g.WriteLine("Line 6")
- g.Flush()
-
- match, found, err := g.FindLast("#")
- if err != nil {
- t.Error("Unexpected error", err)
- }
- if !found {
- t.Error("Expected found=True")
- }
- if match != "# b" {
- t.Errorf("Unexpected match: [%v]", match)
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
-
- func TestFindLast4(t *testing.T) {
- g := createTestGroup(t, 0)
-
- g.WriteLine("Line 1")
- g.WriteLine("Line 2")
- g.WriteLine("Line 3")
- g.Flush()
- g.RotateFile()
- g.WriteLine("Line 4")
- g.WriteLine("Line 5")
- g.WriteLine("Line 6")
- g.Flush()
-
- match, found, err := g.FindLast("#")
- if err != nil {
- t.Error("Unexpected error", err)
- }
- if found {
- t.Error("Expected found=False")
- }
- if match != "" {
- t.Errorf("Unexpected match: [%v]", match)
- }
-
- // Cleanup
- destroyTestGroup(t, g)
- }
|