github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/tm2/pkg/autofile/group_test.go (about) 1 package autofile 2 3 import ( 4 "io" 5 "os" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 osm "github.com/gnolang/gno/tm2/pkg/os" 12 "github.com/gnolang/gno/tm2/pkg/random" 13 ) 14 15 func createTestGroupWithHeadSizeLimit(t *testing.T, headSizeLimit int64) *Group { 16 t.Helper() 17 18 testID := random.RandStr(12) 19 testDir := "_test_" + testID 20 err := osm.EnsureDir(testDir, 0o700) 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 t.Helper() 33 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 t.Helper() 42 43 assert.Equal(t, minIndex, gInfo.MinIndex) 44 assert.Equal(t, maxIndex, gInfo.MaxIndex) 45 assert.Equal(t, totalSize, gInfo.TotalSize) 46 assert.Equal(t, headSize, gInfo.HeadSize) 47 } 48 49 func TestCheckHeadSizeLimit(t *testing.T) { 50 t.Parallel() 51 52 g := createTestGroupWithHeadSizeLimit(t, 1000*1000) 53 54 // At first, there are no files. 55 assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 0, 0) 56 57 // Write 1000 bytes 999 times. 58 for i := 0; i < 999; i++ { 59 err := g.WriteLine(random.RandStr(999)) 60 require.NoError(t, err, "Error appending to head") 61 } 62 g.FlushAndSync() 63 assertGroupInfo(t, g.ReadGroupInfo(), 0, 0, 999000, 999000) 64 65 // Write 1000 more bytes. 66 err := g.WriteLine(random.RandStr(999)) 67 require.NoError(t, err, "Error appending to head") 68 g.FlushAndSync() 69 assertGroupInfo(t, g.ReadGroupInfo(), 0, 1, 1000000, 0) 70 71 // Write 1000 more bytes. 72 err = g.WriteLine(random.RandStr(999)) 73 require.NoError(t, err, "Error appending to head") 74 g.FlushAndSync() 75 76 // Should not have rotated 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(random.RandStr(999)) 82 require.NoError(t, err, "Error appending to head") 83 } 84 g.FlushAndSync() 85 assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2000000, 0) 86 87 // Write 1000 more bytes. 88 _, err = g.Head.Write([]byte(random.RandStr(999) + "\n")) 89 require.NoError(t, err, "Error appending to head") 90 g.FlushAndSync() 91 assertGroupInfo(t, g.ReadGroupInfo(), 0, 2, 2001000, 1000) 92 93 // Cleanup 94 destroyTestGroup(t, g) 95 } 96 97 func TestRotateFile(t *testing.T) { 98 t.Parallel() 99 100 g := createTestGroupWithHeadSizeLimit(t, 0) 101 g.WriteLine("Line 1") 102 g.WriteLine("Line 2") 103 g.WriteLine("Line 3") 104 g.FlushAndSync() 105 g.RotateFile() 106 g.WriteLine("Line 4") 107 g.WriteLine("Line 5") 108 g.WriteLine("Line 6") 109 g.FlushAndSync() 110 111 // Read g.Head.Path+"000" 112 body1, err := os.ReadFile(g.Head.Path + ".000") 113 assert.NoError(t, err, "Failed to read first rolled file") 114 if string(body1) != "Line 1\nLine 2\nLine 3\n" { 115 t.Errorf("Got unexpected contents: [%v]", string(body1)) 116 } 117 118 // Read g.Head.Path 119 body2, err := os.ReadFile(g.Head.Path) 120 assert.NoError(t, err, "Failed to read first rolled file") 121 if string(body2) != "Line 4\nLine 5\nLine 6\n" { 122 t.Errorf("Got unexpected contents: [%v]", string(body2)) 123 } 124 125 // Cleanup 126 destroyTestGroup(t, g) 127 } 128 129 func TestWrite(t *testing.T) { 130 t.Parallel() 131 132 g := createTestGroupWithHeadSizeLimit(t, 0) 133 134 written := []byte("Medusa") 135 g.Write(written) 136 g.FlushAndSync() 137 138 read := make([]byte, len(written)) 139 gr, err := g.NewReader(0, 0) 140 require.NoError(t, err, "failed to create reader") 141 142 _, err = gr.Read(read) 143 assert.NoError(t, err, "failed to read data") 144 assert.Equal(t, written, read) 145 146 // Cleanup 147 destroyTestGroup(t, g) 148 } 149 150 // test that Read reads the required amount of bytes from all the files in the 151 // group and returns no error if n == size of the given slice. 152 func TestGroupReaderRead(t *testing.T) { 153 t.Parallel() 154 155 g := createTestGroupWithHeadSizeLimit(t, 0) 156 157 professor := []byte("Professor Monster") 158 g.Write(professor) 159 g.FlushAndSync() 160 g.RotateFile() 161 frankenstein := []byte("Frankenstein's Monster") 162 g.Write(frankenstein) 163 g.FlushAndSync() 164 165 totalWrittenLength := len(professor) + len(frankenstein) 166 read := make([]byte, totalWrittenLength) 167 gr, err := g.NewReader(0, 0) 168 require.NoError(t, err, "failed to create reader") 169 170 n, err := gr.Read(read) 171 assert.NoError(t, err, "failed to read data") 172 assert.Equal(t, totalWrittenLength, n, "not enough bytes read") 173 professorPlusFrankenstein := professor 174 professorPlusFrankenstein = append(professorPlusFrankenstein, frankenstein...) 175 assert.Equal(t, professorPlusFrankenstein, read) 176 177 // Cleanup 178 destroyTestGroup(t, g) 179 } 180 181 // test that Read returns an error if number of bytes read < size of 182 // the given slice. Subsequent call should return 0, io.EOF. 183 func TestGroupReaderRead2(t *testing.T) { 184 t.Parallel() 185 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, 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 t.Parallel() 218 219 g := createTestGroupWithHeadSizeLimit(t, 0) 220 221 assert.Zero(t, g.MinIndex(), "MinIndex should be zero at the beginning") 222 223 // Cleanup 224 destroyTestGroup(t, g) 225 } 226 227 func TestMaxIndex(t *testing.T) { 228 t.Parallel() 229 230 g := createTestGroupWithHeadSizeLimit(t, 0) 231 232 assert.Zero(t, g.MaxIndex(), "MaxIndex should be zero at the beginning") 233 234 g.WriteLine("Line 1") 235 g.FlushAndSync() 236 g.RotateFile() 237 238 assert.Equal(t, 1, g.MaxIndex(), "MaxIndex should point to the last file") 239 240 // Cleanup 241 destroyTestGroup(t, g) 242 }