github.com/fiagdao/tendermint@v0.32.11-0.20220824195748-2087fcc480c1/libs/autofile/group_test.go (about)

     1  package autofile
     2  
     3  import (
     4  	"io"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	tmos "github.com/tendermint/tendermint/libs/os"
    14  	tmrand "github.com/tendermint/tendermint/libs/rand"
    15  )
    16  
    17  func createTestGroupWithHeadSizeLimit(t *testing.T, headSizeLimit int64) *Group {
    18  	testID := tmrand.Str(12)
    19  	testDir := "_test_" + testID
    20  	err := tmos.EnsureDir(testDir, 0700)
    21  	require.NoError(t, err, "Error creating dir")
    22  
    23  	headPath := testDir + "/myfile"
    24  	g, err := OpenGroup(headPath, GroupHeadSizeLimit(headSizeLimit))
    25  	require.NoError(t, err, "Error opening Group")
    26  	require.NotEqual(t, nil, g, "Failed to create Group")
    27  
    28  	return g
    29  }
    30  
    31  func destroyTestGroup(t *testing.T, g *Group) {
    32  	g.Close()
    33  
    34  	err := os.RemoveAll(g.Dir)
    35  	require.NoError(t, err, "Error removing test Group directory")
    36  }
    37  
    38  func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) {
    39  	assert.Equal(t, minIndex, gInfo.MinIndex)
    40  	assert.Equal(t, maxIndex, gInfo.MaxIndex)
    41  	assert.Equal(t, totalSize, gInfo.TotalSize)
    42  	assert.Equal(t, headSize, gInfo.HeadSize)
    43  }
    44  
    45  func TestCheckHeadSizeLimit(t *testing.T) {
    46  	g := createTestGroupWithHeadSizeLimit(t, 1000*1000)
    47  
    48  	// At first, there are no files.
    49  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0)
    50  
    51  	// Write 1000 bytes 999 times.
    52  	for i := 0; i < 999; i++ {
    53  		err := g.WriteLine(tmrand.Str(999))
    54  		require.NoError(t, err, "Error appending to head")
    55  	}
    56  	g.FlushAndSync()
    57  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    58  
    59  	// Even calling checkHeadSizeLimit manually won't rotate it.
    60  	g.checkHeadSizeLimit()
    61  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    62  
    63  	// Write 1000 more bytes.
    64  	err := g.WriteLine(tmrand.Str(999))
    65  	require.NoError(t, err, "Error appending to head")
    66  	g.FlushAndSync()
    67  
    68  	// Calling checkHeadSizeLimit this time rolls it.
    69  	g.checkHeadSizeLimit()
    70  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0)
    71  
    72  	// Write 1000 more bytes.
    73  	err = g.WriteLine(tmrand.Str(999))
    74  	require.NoError(t, err, "Error appending to head")
    75  	g.FlushAndSync()
    76  
    77  	// Calling checkHeadSizeLimit does nothing.
    78  	g.checkHeadSizeLimit()
    79  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
    80  
    81  	// Write 1000 bytes 999 times.
    82  	for i := 0; i < 999; i++ {
    83  		err = g.WriteLine(tmrand.Str(999))
    84  		require.NoError(t, err, "Error appending to head")
    85  	}
    86  	g.FlushAndSync()
    87  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
    88  
    89  	// Calling checkHeadSizeLimit rolls it again.
    90  	g.checkHeadSizeLimit()
    91  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
    92  
    93  	// Write 1000 more bytes.
    94  	_, err = g.Head.Write([]byte(tmrand.Str(999) + "\n"))
    95  	require.NoError(t, err, "Error appending to head")
    96  	g.FlushAndSync()
    97  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
    98  
    99  	// Calling checkHeadSizeLimit does nothing.
   100  	g.checkHeadSizeLimit()
   101  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
   102  
   103  	// Cleanup
   104  	destroyTestGroup(t, g)
   105  }
   106  
   107  func TestRotateFile(t *testing.T) {
   108  	g := createTestGroupWithHeadSizeLimit(t, 0)
   109  
   110  	// Create a different temporary directory and move into it, to make sure
   111  	// relative paths are resolved at Group creation
   112  	origDir, err := os.Getwd()
   113  	require.NoError(t, err)
   114  	defer os.Chdir(origDir)
   115  
   116  	dir, err := ioutil.TempDir("", "rotate_test")
   117  	require.NoError(t, err)
   118  	defer os.RemoveAll(dir)
   119  	err = os.Chdir(dir)
   120  	require.NoError(t, err)
   121  
   122  	require.True(t, filepath.IsAbs(g.Head.Path))
   123  	require.True(t, filepath.IsAbs(g.Dir))
   124  
   125  	// Create and rotate files
   126  	g.WriteLine("Line 1")
   127  	g.WriteLine("Line 2")
   128  	g.WriteLine("Line 3")
   129  	g.FlushAndSync()
   130  	g.RotateFile()
   131  	g.WriteLine("Line 4")
   132  	g.WriteLine("Line 5")
   133  	g.WriteLine("Line 6")
   134  	g.FlushAndSync()
   135  
   136  	// Read g.Head.Path+"000"
   137  	body1, err := ioutil.ReadFile(g.Head.Path + ".000")
   138  	assert.NoError(t, err, "Failed to read first rolled file")
   139  	if string(body1) != "Line 1\nLine 2\nLine 3\n" {
   140  		t.Errorf("got unexpected contents: [%v]", string(body1))
   141  	}
   142  
   143  	// Read g.Head.Path
   144  	body2, err := ioutil.ReadFile(g.Head.Path)
   145  	assert.NoError(t, err, "Failed to read first rolled file")
   146  	if string(body2) != "Line 4\nLine 5\nLine 6\n" {
   147  		t.Errorf("got unexpected contents: [%v]", string(body2))
   148  	}
   149  
   150  	// Make sure there are no files in the current, temporary directory
   151  	files, err := ioutil.ReadDir(".")
   152  	require.NoError(t, err)
   153  	assert.Empty(t, files)
   154  
   155  	// Cleanup
   156  	destroyTestGroup(t, g)
   157  }
   158  
   159  func TestWrite(t *testing.T) {
   160  	g := createTestGroupWithHeadSizeLimit(t, 0)
   161  
   162  	written := []byte("Medusa")
   163  	g.Write(written)
   164  	g.FlushAndSync()
   165  
   166  	read := make([]byte, len(written))
   167  	gr, err := g.NewReader(0)
   168  	require.NoError(t, err, "failed to create reader")
   169  
   170  	_, err = gr.Read(read)
   171  	assert.NoError(t, err, "failed to read data")
   172  	assert.Equal(t, written, read)
   173  
   174  	// Cleanup
   175  	destroyTestGroup(t, g)
   176  }
   177  
   178  // test that Read reads the required amount of bytes from all the files in the
   179  // group and returns no error if n == size of the given slice.
   180  func TestGroupReaderRead(t *testing.T) {
   181  	g := createTestGroupWithHeadSizeLimit(t, 0)
   182  
   183  	professor := []byte("Professor Monster")
   184  	g.Write(professor)
   185  	g.FlushAndSync()
   186  	g.RotateFile()
   187  	frankenstein := []byte("Frankenstein's Monster")
   188  	g.Write(frankenstein)
   189  	g.FlushAndSync()
   190  
   191  	totalWrittenLength := len(professor) + len(frankenstein)
   192  	read := make([]byte, totalWrittenLength)
   193  	gr, err := g.NewReader(0)
   194  	require.NoError(t, err, "failed to create reader")
   195  
   196  	n, err := gr.Read(read)
   197  	assert.NoError(t, err, "failed to read data")
   198  	assert.Equal(t, totalWrittenLength, n, "not enough bytes read")
   199  	professorPlusFrankenstein := professor
   200  	professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...)
   201  	assert.Equal(t, professorPlusFrankenstein, read)
   202  
   203  	// Cleanup
   204  	destroyTestGroup(t, g)
   205  }
   206  
   207  // test that Read returns an error if number of bytes read < size of
   208  // the given slice. Subsequent call should return 0, io.EOF.
   209  func TestGroupReaderRead2(t *testing.T) {
   210  	g := createTestGroupWithHeadSizeLimit(t, 0)
   211  
   212  	professor := []byte("Professor Monster")
   213  	g.Write(professor)
   214  	g.FlushAndSync()
   215  	g.RotateFile()
   216  	frankenstein := []byte("Frankenstein's Monster")
   217  	frankensteinPart := []byte("Frankenstein")
   218  	g.Write(frankensteinPart) // note writing only a part
   219  	g.FlushAndSync()
   220  
   221  	totalLength := len(professor) + len(frankenstein)
   222  	read := make([]byte, totalLength)
   223  	gr, err := g.NewReader(0)
   224  	require.NoError(t, err, "failed to create reader")
   225  
   226  	// 1) n < (size of the given slice), io.EOF
   227  	n, err := gr.Read(read)
   228  	assert.Equal(t, io.EOF, err)
   229  	assert.Equal(t, len(professor)+len(frankensteinPart), n, "Read more/less bytes than it is in the group")
   230  
   231  	// 2) 0, io.EOF
   232  	n, err = gr.Read([]byte("0"))
   233  	assert.Equal(t, io.EOF, err)
   234  	assert.Equal(t, 0, n)
   235  
   236  	// Cleanup
   237  	destroyTestGroup(t, g)
   238  }
   239  
   240  func TestMinIndex(t *testing.T) {
   241  	g := createTestGroupWithHeadSizeLimit(t, 0)
   242  
   243  	assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning")
   244  
   245  	// Cleanup
   246  	destroyTestGroup(t, g)
   247  }
   248  
   249  func TestMaxIndex(t *testing.T) {
   250  	g := createTestGroupWithHeadSizeLimit(t, 0)
   251  
   252  	assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning")
   253  
   254  	g.WriteLine("Line 1")
   255  	g.FlushAndSync()
   256  	g.RotateFile()
   257  
   258  	assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file")
   259  
   260  	// Cleanup
   261  	destroyTestGroup(t, g)
   262  }