github.com/supragya/TendermintConnector@v0.0.0-20210619045051-113e32b84fb1/_deprecated_chains/irisnet/libs/autofile/group_test.go (about)

     1  package autofile
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	cmn "github.com/tendermint/tendermint/libs/common"
    17  )
    18  
    19  func createTestGroupWithHeadSizeLimit(t *testing.T, headSizeLimit int64) *Group {
    20  	testID := cmn.RandStr(12)
    21  	testDir := "_test_" + testID
    22  	err := cmn.EnsureDir(testDir, 0700)
    23  	require.NoError(t, err, "Error creating dir")
    24  
    25  	headPath := testDir + "/myfile"
    26  	g, err := OpenGroup(headPath, GroupHeadSizeLimit(headSizeLimit))
    27  	require.NoError(t, err, "Error opening Group")
    28  	require.NotEqual(t, nil, g, "Failed to create Group")
    29  
    30  	return g
    31  }
    32  
    33  func destroyTestGroup(t *testing.T, g *Group) {
    34  	g.Close()
    35  
    36  	err := os.RemoveAll(g.Dir)
    37  	require.NoError(t, err, "Error removing test Group directory")
    38  }
    39  
    40  func assertGroupInfo(t *testing.T, gInfo GroupInfo, minIndex, maxIndex int, totalSize, headSize int64) {
    41  	assert.Equal(t, minIndex, gInfo.MinIndex)
    42  	assert.Equal(t, maxIndex, gInfo.MaxIndex)
    43  	assert.Equal(t, totalSize, gInfo.TotalSize)
    44  	assert.Equal(t, headSize, gInfo.HeadSize)
    45  }
    46  
    47  func TestCheckHeadSizeLimit(t *testing.T) {
    48  	g := createTestGroupWithHeadSizeLimit(t, 1000*1000)
    49  
    50  	// At first, there are no files.
    51  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0)
    52  
    53  	// Write 1000 bytes 999 times.
    54  	for i := 0; i < 999; i++ {
    55  		err := g.WriteLine(cmn.RandStr(999))
    56  		require.NoError(t, err, "Error appending to head")
    57  	}
    58  	g.Flush()
    59  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    60  
    61  	// Even calling checkHeadSizeLimit manually won't rotate it.
    62  	g.checkHeadSizeLimit()
    63  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000)
    64  
    65  	// Write 1000 more bytes.
    66  	err := g.WriteLine(cmn.RandStr(999))
    67  	require.NoError(t, err, "Error appending to head")
    68  	g.Flush()
    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(cmn.RandStr(999))
    76  	require.NoError(t, err, "Error appending to head")
    77  	g.Flush()
    78  
    79  	// Calling checkHeadSizeLimit does nothing.
    80  	g.checkHeadSizeLimit()
    81  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1001000, 1000)
    82  
    83  	// Write 1000 bytes 999 times.
    84  	for i := 0; i < 999; i++ {
    85  		err = g.WriteLine(cmn.RandStr(999))
    86  		require.NoError(t, err, "Error appending to head")
    87  	}
    88  	g.Flush()
    89  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 2000000, 1000000)
    90  
    91  	// Calling checkHeadSizeLimit rolls it again.
    92  	g.checkHeadSizeLimit()
    93  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0)
    94  
    95  	// Write 1000 more bytes.
    96  	_, err = g.Head.Write([]byte(cmn.RandStr(999) + "\n"))
    97  	require.NoError(t, err, "Error appending to head")
    98  	g.Flush()
    99  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
   100  
   101  	// Calling checkHeadSizeLimit does nothing.
   102  	g.checkHeadSizeLimit()
   103  	assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000)
   104  
   105  	// Cleanup
   106  	destroyTestGroup(t, g)
   107  }
   108  
   109  func TestSearch(t *testing.T) {
   110  	g := createTestGroupWithHeadSizeLimit(t, 10*1000)
   111  
   112  	// Create some files in the group that have several INFO lines in them.
   113  	// Try to put the INFO lines in various spots.
   114  	for i := 0; i < 100; i++ {
   115  		// The random junk at the end ensures that this INFO linen
   116  		// is equally likely to show up at the end.
   117  		_, err := g.Head.Write([]byte(fmt.Sprintf("INFO %v %v\n", i, cmn.RandStr(123))))
   118  		require.NoError(t, err, "Failed to write to head")
   119  		g.checkHeadSizeLimit()
   120  		for j := 0; j < 10; j++ {
   121  			_, err1 := g.Head.Write([]byte(cmn.RandStr(123) + "\n"))
   122  			require.NoError(t, err1, "Failed to write to head")
   123  			g.checkHeadSizeLimit()
   124  		}
   125  	}
   126  
   127  	// Create a search func that searches for line
   128  	makeSearchFunc := func(target int) SearchFunc {
   129  		return func(line string) (int, error) {
   130  			parts := strings.Split(line, " ")
   131  			if len(parts) != 3 {
   132  				return -1, errors.New("Line did not have 3 parts")
   133  			}
   134  			i, err := strconv.Atoi(parts[1])
   135  			if err != nil {
   136  				return -1, errors.New("Failed to parse INFO: " + err.Error())
   137  			}
   138  			if target < i {
   139  				return 1, nil
   140  			} else if target == i {
   141  				return 0, nil
   142  			} else {
   143  				return -1, nil
   144  			}
   145  		}
   146  	}
   147  
   148  	// Now search for each number
   149  	for i := 0; i < 100; i++ {
   150  		gr, match, err := g.Search("INFO", makeSearchFunc(i))
   151  		require.NoError(t, err, "Failed to search for line, tc #%d", i)
   152  		assert.True(t, match, "Expected Search to return exact match, tc #%d", i)
   153  		line, err := gr.ReadLine()
   154  		require.NoError(t, err, "Failed to read line after search, tc #%d", i)
   155  		if !strings.HasPrefix(line, fmt.Sprintf("INFO %v ", i)) {
   156  			t.Fatalf("Failed to get correct line, tc #%d", i)
   157  		}
   158  		// Make sure we can continue to read from there.
   159  		cur := i + 1
   160  		for {
   161  			line, err := gr.ReadLine()
   162  			if err == io.EOF {
   163  				if cur == 99+1 {
   164  					// OK!
   165  					break
   166  				} else {
   167  					t.Fatalf("Got EOF after the wrong INFO #, tc #%d", i)
   168  				}
   169  			} else if err != nil {
   170  				t.Fatalf("Error reading line, tc #%d, err:\n%s", i, err)
   171  			}
   172  			if !strings.HasPrefix(line, "INFO ") {
   173  				continue
   174  			}
   175  			if !strings.HasPrefix(line, fmt.Sprintf("INFO %v ", cur)) {
   176  				t.Fatalf("Unexpected INFO #. Expected %v got:\n%v, tc #%d", cur, line, i)
   177  			}
   178  			cur++
   179  		}
   180  		gr.Close()
   181  	}
   182  
   183  	// Now search for something that is too small.
   184  	// We should get the first available line.
   185  	{
   186  		gr, match, err := g.Search("INFO", makeSearchFunc(-999))
   187  		require.NoError(t, err, "Failed to search for line")
   188  		assert.False(t, match, "Expected Search to not return exact match")
   189  		line, err := gr.ReadLine()
   190  		require.NoError(t, err, "Failed to read line after search")
   191  		if !strings.HasPrefix(line, "INFO 0 ") {
   192  			t.Error("Failed to fetch correct line, which is the earliest INFO")
   193  		}
   194  		err = gr.Close()
   195  		require.NoError(t, err, "Failed to close GroupReader")
   196  	}
   197  
   198  	// Now search for something that is too large.
   199  	// We should get an EOF error.
   200  	{
   201  		gr, _, err := g.Search("INFO", makeSearchFunc(999))
   202  		assert.Equal(t, io.EOF, err)
   203  		assert.Nil(t, gr)
   204  	}
   205  
   206  	// Cleanup
   207  	destroyTestGroup(t, g)
   208  }
   209  
   210  func TestRotateFile(t *testing.T) {
   211  	g := createTestGroupWithHeadSizeLimit(t, 0)
   212  	g.WriteLine("Line 1")
   213  	g.WriteLine("Line 2")
   214  	g.WriteLine("Line 3")
   215  	g.Flush()
   216  	g.RotateFile()
   217  	g.WriteLine("Line 4")
   218  	g.WriteLine("Line 5")
   219  	g.WriteLine("Line 6")
   220  	g.Flush()
   221  
   222  	// Read g.Head.Path+"000"
   223  	body1, err := ioutil.ReadFile(g.Head.Path + ".000")
   224  	assert.NoError(t, err, "Failed to read first rolled file")
   225  	if string(body1) != "Line 1\nLine 2\nLine 3\n" {
   226  		t.Errorf("Got unexpected contents: [%v]", string(body1))
   227  	}
   228  
   229  	// Read g.Head.Path
   230  	body2, err := ioutil.ReadFile(g.Head.Path)
   231  	assert.NoError(t, err, "Failed to read first rolled file")
   232  	if string(body2) != "Line 4\nLine 5\nLine 6\n" {
   233  		t.Errorf("Got unexpected contents: [%v]", string(body2))
   234  	}
   235  
   236  	// Cleanup
   237  	destroyTestGroup(t, g)
   238  }
   239  
   240  func TestFindLast1(t *testing.T) {
   241  	g := createTestGroupWithHeadSizeLimit(t, 0)
   242  
   243  	g.WriteLine("Line 1")
   244  	g.WriteLine("Line 2")
   245  	g.WriteLine("# a")
   246  	g.WriteLine("Line 3")
   247  	g.Flush()
   248  	g.RotateFile()
   249  	g.WriteLine("Line 4")
   250  	g.WriteLine("Line 5")
   251  	g.WriteLine("Line 6")
   252  	g.WriteLine("# b")
   253  	g.Flush()
   254  
   255  	match, found, err := g.FindLast("#")
   256  	assert.NoError(t, err)
   257  	assert.True(t, found)
   258  	assert.Equal(t, "# b", match)
   259  
   260  	// Cleanup
   261  	destroyTestGroup(t, g)
   262  }
   263  
   264  func TestFindLast2(t *testing.T) {
   265  	g := createTestGroupWithHeadSizeLimit(t, 0)
   266  
   267  	g.WriteLine("Line 1")
   268  	g.WriteLine("Line 2")
   269  	g.WriteLine("Line 3")
   270  	g.Flush()
   271  	g.RotateFile()
   272  	g.WriteLine("# a")
   273  	g.WriteLine("Line 4")
   274  	g.WriteLine("Line 5")
   275  	g.WriteLine("# b")
   276  	g.WriteLine("Line 6")
   277  	g.Flush()
   278  
   279  	match, found, err := g.FindLast("#")
   280  	assert.NoError(t, err)
   281  	assert.True(t, found)
   282  	assert.Equal(t, "# b", match)
   283  
   284  	// Cleanup
   285  	destroyTestGroup(t, g)
   286  }
   287  
   288  func TestFindLast3(t *testing.T) {
   289  	g := createTestGroupWithHeadSizeLimit(t, 0)
   290  
   291  	g.WriteLine("Line 1")
   292  	g.WriteLine("# a")
   293  	g.WriteLine("Line 2")
   294  	g.WriteLine("# b")
   295  	g.WriteLine("Line 3")
   296  	g.Flush()
   297  	g.RotateFile()
   298  	g.WriteLine("Line 4")
   299  	g.WriteLine("Line 5")
   300  	g.WriteLine("Line 6")
   301  	g.Flush()
   302  
   303  	match, found, err := g.FindLast("#")
   304  	assert.NoError(t, err)
   305  	assert.True(t, found)
   306  	assert.Equal(t, "# b", match)
   307  
   308  	// Cleanup
   309  	destroyTestGroup(t, g)
   310  }
   311  
   312  func TestFindLast4(t *testing.T) {
   313  	g := createTestGroupWithHeadSizeLimit(t, 0)
   314  
   315  	g.WriteLine("Line 1")
   316  	g.WriteLine("Line 2")
   317  	g.WriteLine("Line 3")
   318  	g.Flush()
   319  	g.RotateFile()
   320  	g.WriteLine("Line 4")
   321  	g.WriteLine("Line 5")
   322  	g.WriteLine("Line 6")
   323  	g.Flush()
   324  
   325  	match, found, err := g.FindLast("#")
   326  	assert.NoError(t, err)
   327  	assert.False(t, found)
   328  	assert.Empty(t, match)
   329  
   330  	// Cleanup
   331  	destroyTestGroup(t, g)
   332  }
   333  
   334  func TestWrite(t *testing.T) {
   335  	g := createTestGroupWithHeadSizeLimit(t, 0)
   336  
   337  	written := []byte("Medusa")
   338  	g.Write(written)
   339  	g.Flush()
   340  
   341  	read := make([]byte, len(written))
   342  	gr, err := g.NewReader(0)
   343  	require.NoError(t, err, "failed to create reader")
   344  
   345  	_, err = gr.Read(read)
   346  	assert.NoError(t, err, "failed to read data")
   347  	assert.Equal(t, written, read)
   348  
   349  	// Cleanup
   350  	destroyTestGroup(t, g)
   351  }
   352  
   353  // test that Read reads the required amount of bytes from all the files in the
   354  // group and returns no error if n == size of the given slice.
   355  func TestGroupReaderRead(t *testing.T) {
   356  	g := createTestGroupWithHeadSizeLimit(t, 0)
   357  
   358  	professor := []byte("Professor Monster")
   359  	g.Write(professor)
   360  	g.Flush()
   361  	g.RotateFile()
   362  	frankenstein := []byte("Frankenstein's Monster")
   363  	g.Write(frankenstein)
   364  	g.Flush()
   365  
   366  	totalWrittenLength := len(professor) + len(frankenstein)
   367  	read := make([]byte, totalWrittenLength)
   368  	gr, err := g.NewReader(0)
   369  	require.NoError(t, err, "failed to create reader")
   370  
   371  	n, err := gr.Read(read)
   372  	assert.NoError(t, err, "failed to read data")
   373  	assert.Equal(t, totalWrittenLength, n, "not enough bytes read")
   374  	professorPlusFrankenstein := professor
   375  	professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...)
   376  	assert.Equal(t, professorPlusFrankenstein, read)
   377  
   378  	// Cleanup
   379  	destroyTestGroup(t, g)
   380  }
   381  
   382  // test that Read returns an error if number of bytes read < size of
   383  // the given slice. Subsequent call should return 0, io.EOF.
   384  func TestGroupReaderRead2(t *testing.T) {
   385  	g := createTestGroupWithHeadSizeLimit(t, 0)
   386  
   387  	professor := []byte("Professor Monster")
   388  	g.Write(professor)
   389  	g.Flush()
   390  	g.RotateFile()
   391  	frankenstein := []byte("Frankenstein's Monster")
   392  	frankensteinPart := []byte("Frankenstein")
   393  	g.Write(frankensteinPart) // note writing only a part
   394  	g.Flush()
   395  
   396  	totalLength := len(professor) + len(frankenstein)
   397  	read := make([]byte, totalLength)
   398  	gr, err := g.NewReader(0)
   399  	require.NoError(t, err, "failed to create reader")
   400  
   401  	// 1) n < (size of the given slice), io.EOF
   402  	n, err := gr.Read(read)
   403  	assert.Equal(t, io.EOF, err)
   404  	assert.Equal(t, len(professor)+len(frankensteinPart), n, "Read more/less bytes than it is in the group")
   405  
   406  	// 2) 0, io.EOF
   407  	n, err = gr.Read([]byte("0"))
   408  	assert.Equal(t, io.EOF, err)
   409  	assert.Equal(t, 0, n)
   410  
   411  	// Cleanup
   412  	destroyTestGroup(t, g)
   413  }
   414  
   415  func TestMinIndex(t *testing.T) {
   416  	g := createTestGroupWithHeadSizeLimit(t, 0)
   417  
   418  	assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning")
   419  
   420  	// Cleanup
   421  	destroyTestGroup(t, g)
   422  }
   423  
   424  func TestMaxIndex(t *testing.T) {
   425  	g := createTestGroupWithHeadSizeLimit(t, 0)
   426  
   427  	assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning")
   428  
   429  	g.WriteLine("Line 1")
   430  	g.Flush()
   431  	g.RotateFile()
   432  
   433  	assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file")
   434  
   435  	// Cleanup
   436  	destroyTestGroup(t, g)
   437  }