github.com/vipernet-xyz/tendermint-core@v0.32.0/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 }