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 }