github.com/MagHErmit/tendermint@v0.282.1/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/MagHErmit/tendermint/libs/os"
    14  	tmrand "github.com/MagHErmit/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  	err := g.FlushAndSync()
    57  	require.NoError(t, err)
    58  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    59  
    60  	// Even calling checkHeadSizeLimit manually won't rotate it.
    61  	g.checkHeadSizeLimit()
    62  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    63  
    64  	// Write 1000 more bytes.
    65  	err = g.WriteLine(tmrand.Str(999))
    66  	require.NoError(t, err, "Error appending to head")
    67  	err = g.FlushAndSync()
    68  	require.NoError(t, err)
    69  
    70  	// Calling checkHeadSizeLimit this time rolls it.
    71  	g.checkHeadSizeLimit()
    72  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0)
    73  
    74  	// Write 1000 more bytes.
    75  	err = g.WriteLine(tmrand.Str(999))
    76  	require.NoError(t, err, "Error appending to head")
    77  	err = g.FlushAndSync()
    78  	require.NoError(t, err)
    79  
    80  	// Calling checkHeadSizeLimit does nothing.
    81  	g.checkHeadSizeLimit()
    82  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
    83  
    84  	// Write 1000 bytes 999 times.
    85  	for i := 0; i < 999; i++ {
    86  		err = g.WriteLine(tmrand.Str(999))
    87  		require.NoError(t, err, "Error appending to head")
    88  	}
    89  	err = g.FlushAndSync()
    90  	require.NoError(t, err)
    91  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
    92  
    93  	// Calling checkHeadSizeLimit rolls it again.
    94  	g.checkHeadSizeLimit()
    95  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
    96  
    97  	// Write 1000 more bytes.
    98  	_, err = g.Head.Write([]byte(tmrand.Str(999) + "\n"))
    99  	require.NoError(t, err, "Error appending to head")
   100  	err = g.FlushAndSync()
   101  	require.NoError(t, err)
   102  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
   103  
   104  	// Calling checkHeadSizeLimit does nothing.
   105  	g.checkHeadSizeLimit()
   106  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
   107  
   108  	// Cleanup
   109  	destroyTestGroup(t, g)
   110  }
   111  
   112  func TestRotateFile(t *testing.T) {
   113  	g := createTestGroupWithHeadSizeLimit(t, 0)
   114  
   115  	// Create a different temporary directory and move into it, to make sure
   116  	// relative paths are resolved at Group creation
   117  	origDir, err := os.Getwd()
   118  	require.NoError(t, err)
   119  	defer func() {
   120  		if err := os.Chdir(origDir); err != nil {
   121  			t.Error(err)
   122  		}
   123  	}()
   124  
   125  	dir, err := ioutil.TempDir("", "rotate_test")
   126  	require.NoError(t, err)
   127  	defer os.RemoveAll(dir)
   128  	err = os.Chdir(dir)
   129  	require.NoError(t, err)
   130  
   131  	require.True(t, filepath.IsAbs(g.Head.Path))
   132  	require.True(t, filepath.IsAbs(g.Dir))
   133  
   134  	// Create and rotate files
   135  	err = g.WriteLine("Line 1")
   136  	require.NoError(t, err)
   137  	err = g.WriteLine("Line 2")
   138  	require.NoError(t, err)
   139  	err = g.WriteLine("Line 3")
   140  	require.NoError(t, err)
   141  	err = g.FlushAndSync()
   142  	require.NoError(t, err)
   143  	g.RotateFile()
   144  	err = g.WriteLine("Line 4")
   145  	require.NoError(t, err)
   146  	err = g.WriteLine("Line 5")
   147  	require.NoError(t, err)
   148  	err = g.WriteLine("Line 6")
   149  	require.NoError(t, err)
   150  	err = g.FlushAndSync()
   151  	require.NoError(t, err)
   152  
   153  	// Read g.Head.Path+"000"
   154  	body1, err := ioutil.ReadFile(g.Head.Path + ".000")
   155  	assert.NoError(t, err, "Failed to read first rolled file")
   156  	if string(body1) != "Line 1\nLine 2\nLine 3\n" {
   157  		t.Errorf("got unexpected contents: [%v]", string(body1))
   158  	}
   159  
   160  	// Read g.Head.Path
   161  	body2, err := ioutil.ReadFile(g.Head.Path)
   162  	assert.NoError(t, err, "Failed to read first rolled file")
   163  	if string(body2) != "Line 4\nLine 5\nLine 6\n" {
   164  		t.Errorf("got unexpected contents: [%v]", string(body2))
   165  	}
   166  
   167  	// Make sure there are no files in the current, temporary directory
   168  	files, err := ioutil.ReadDir(".")
   169  	require.NoError(t, err)
   170  	assert.Empty(t, files)
   171  
   172  	// Cleanup
   173  	destroyTestGroup(t, g)
   174  }
   175  
   176  func TestWrite(t *testing.T) {
   177  	g := createTestGroupWithHeadSizeLimit(t, 0)
   178  
   179  	written := []byte("Medusa")
   180  	_, err := g.Write(written)
   181  	require.NoError(t, err)
   182  	err = g.FlushAndSync()
   183  	require.NoError(t, err)
   184  
   185  	read := make([]byte, len(written))
   186  	gr, err := g.NewReader(0)
   187  	require.NoError(t, err, "failed to create reader")
   188  
   189  	_, err = gr.Read(read)
   190  	assert.NoError(t, err, "failed to read data")
   191  	assert.Equal(t, written, read)
   192  
   193  	// Cleanup
   194  	destroyTestGroup(t, g)
   195  }
   196  
   197  // test that Read reads the required amount of bytes from all the files in the
   198  // group and returns no error if n == size of the given slice.
   199  func TestGroupReaderRead(t *testing.T) {
   200  	g := createTestGroupWithHeadSizeLimit(t, 0)
   201  
   202  	professor := []byte("Professor Monster")
   203  	_, err := g.Write(professor)
   204  	require.NoError(t, err)
   205  	err = g.FlushAndSync()
   206  	require.NoError(t, err)
   207  	g.RotateFile()
   208  	frankenstein := []byte("Frankenstein's Monster")
   209  	_, err = g.Write(frankenstein)
   210  	require.NoError(t, err)
   211  	err = g.FlushAndSync()
   212  	require.NoError(t, err)
   213  
   214  	totalWrittenLength := len(professor) + len(frankenstein)
   215  	read := make([]byte, totalWrittenLength)
   216  	gr, err := g.NewReader(0)
   217  	require.NoError(t, err, "failed to create reader")
   218  
   219  	n, err := gr.Read(read)
   220  	assert.NoError(t, err, "failed to read data")
   221  	assert.Equal(t, totalWrittenLength, n, "not enough bytes read")
   222  	professorPlusFrankenstein := professor
   223  	professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...)
   224  	assert.Equal(t, professorPlusFrankenstein, read)
   225  
   226  	// Cleanup
   227  	destroyTestGroup(t, g)
   228  }
   229  
   230  // test that Read returns an error if number of bytes read < size of
   231  // the given slice. Subsequent call should return 0, io.EOF.
   232  func TestGroupReaderRead2(t *testing.T) {
   233  	g := createTestGroupWithHeadSizeLimit(t, 0)
   234  
   235  	professor := []byte("Professor Monster")
   236  	_, err := g.Write(professor)
   237  	require.NoError(t, err)
   238  	err = g.FlushAndSync()
   239  	require.NoError(t, err)
   240  	g.RotateFile()
   241  	frankenstein := []byte("Frankenstein's Monster")
   242  	frankensteinPart := []byte("Frankenstein")
   243  	_, err = g.Write(frankensteinPart) // note writing only a part
   244  	require.NoError(t, err)
   245  	err = g.FlushAndSync()
   246  	require.NoError(t, err)
   247  
   248  	totalLength := len(professor) + len(frankenstein)
   249  	read := make([]byte, totalLength)
   250  	gr, err := g.NewReader(0)
   251  	require.NoError(t, err, "failed to create reader")
   252  
   253  	// 1) n < (size of the given slice), io.EOF
   254  	n, err := gr.Read(read)
   255  	assert.Equal(t, io.EOF, err)
   256  	assert.Equal(t, len(professor)+len(frankensteinPart), n, "Read more/less bytes than it is in the group")
   257  
   258  	// 2) 0, io.EOF
   259  	n, err = gr.Read([]byte("0"))
   260  	assert.Equal(t, io.EOF, err)
   261  	assert.Equal(t, 0, n)
   262  
   263  	// Cleanup
   264  	destroyTestGroup(t, g)
   265  }
   266  
   267  func TestMinIndex(t *testing.T) {
   268  	g := createTestGroupWithHeadSizeLimit(t, 0)
   269  
   270  	assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning")
   271  
   272  	// Cleanup
   273  	destroyTestGroup(t, g)
   274  }
   275  
   276  func TestMaxIndex(t *testing.T) {
   277  	g := createTestGroupWithHeadSizeLimit(t, 0)
   278  
   279  	assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning")
   280  
   281  	err := g.WriteLine("Line 1")
   282  	require.NoError(t, err)
   283  	err = g.FlushAndSync()
   284  	require.NoError(t, err)
   285  	g.RotateFile()
   286  
   287  	assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file")
   288  
   289  	// Cleanup
   290  	destroyTestGroup(t, g)
   291  }