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