github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/ioselector/io_selector_test.go (about) 1 package ioselector 2 3 import ( 4 "fmt" 5 "github.com/stretchr/testify/assert" 6 "os" 7 "path/filepath" 8 "testing" 9 ) 10 11 func TestNewFileIOSelector(t *testing.T) { 12 testNewIOSelector(t, 0) 13 } 14 15 func TestNewMMapSelector(t *testing.T) { 16 testNewIOSelector(t, 1) 17 } 18 19 func TestFileIOSelector_Write(t *testing.T) { 20 testIOSelectorWrite(t, 0) 21 } 22 23 func TestMMapSelector_Write(t *testing.T) { 24 testIOSelectorWrite(t, 1) 25 } 26 27 func TestFileIOSelector_Read(t *testing.T) { 28 testIOSelectorRead(t, 0) 29 } 30 31 func TestMMapSelector_Read(t *testing.T) { 32 testIOSelectorRead(t, 1) 33 } 34 35 func TestFileIOSelector_Sync(t *testing.T) { 36 testIOSelectorSync(t, 0) 37 } 38 39 func TestMMapSelector_Sync(t *testing.T) { 40 testIOSelectorSync(t, 1) 41 } 42 43 func TestFileIOSelector_Close(t *testing.T) { 44 testIOSelectorClose(t, 0) 45 } 46 47 func TestMMapSelector_Close(t *testing.T) { 48 testIOSelectorClose(t, 1) 49 } 50 51 func TestFileIOSelector_Delete(t *testing.T) { 52 testIOSelectorDelete(t, 0) 53 } 54 55 func TestMMapSelector_Delete(t *testing.T) { 56 testIOSelectorDelete(t, 1) 57 } 58 59 func testNewIOSelector(t *testing.T, ioType uint8) { 60 type args struct { 61 fName string 62 fsize int64 63 } 64 tests := []struct { 65 name string 66 args args 67 }{ 68 { 69 "size-zero", args{fName: "000000001.wal", fsize: 0}, 70 }, 71 { 72 "size-negative", args{fName: "000000002.wal", fsize: -1}, 73 }, 74 { 75 "size-big", args{fName: "000000003.wal", fsize: 1024 << 20}, 76 }, 77 } 78 for _, tt := range tests { 79 t.Run(tt.name, func(t *testing.T) { 80 absPath, err := filepath.Abs(filepath.Join("/tmp", tt.args.fName)) 81 assert.Nil(t, err) 82 83 var got IOSelector 84 if ioType == 0 { 85 got, err = NewFileIOSelector(absPath, tt.args.fsize) 86 } 87 if ioType == 1 { 88 got, err = NewMMapSelector(absPath, tt.args.fsize) 89 } 90 defer func() { 91 if got != nil { 92 err = got.Delete() 93 assert.Nil(t, err) 94 } 95 }() 96 if tt.args.fsize > 0 { 97 assert.Nil(t, err) 98 assert.NotNil(t, got) 99 } else { 100 assert.Equal(t, err, ErrInvalidFsize) 101 } 102 }) 103 } 104 } 105 106 func testIOSelectorWrite(t *testing.T, ioType uint8) { 107 absPath, err := filepath.Abs(filepath.Join("/tmp", "00000001.vlog")) 108 assert.Nil(t, err) 109 var size int64 = 1048576 110 111 var selector IOSelector 112 if ioType == 0 { 113 selector, err = NewFileIOSelector(absPath, size) 114 } 115 if ioType == 1 { 116 selector, err = NewMMapSelector(absPath, size) 117 } 118 assert.Nil(t, err) 119 defer func() { 120 if selector != nil { 121 _ = selector.Delete() 122 } 123 }() 124 125 type fields struct { 126 selector IOSelector 127 } 128 type args struct { 129 b []byte 130 offset int64 131 } 132 tests := []struct { 133 name string 134 fields fields 135 args args 136 want int 137 wantErr bool 138 }{ 139 { 140 "nil-byte", fields{selector: selector}, args{b: nil, offset: 0}, 0, false, 141 }, 142 { 143 "one-byte", fields{selector: selector}, args{b: []byte("0"), offset: 0}, 1, false, 144 }, 145 { 146 "many-bytes", fields{selector: selector}, args{b: []byte("lotusdb"), offset: 0}, 7, false, 147 }, 148 { 149 "bigvalue-byte", fields{selector: selector}, args{b: []byte(fmt.Sprintf("%01048576d", 123)), offset: 0}, 1048576, false, 150 }, 151 { 152 "exceed-size", fields{selector: selector}, args{b: []byte(fmt.Sprintf("%01048577d", 123)), offset: 0}, 1048577, false, 153 }, 154 { 155 "EOF-error", fields{selector: selector}, args{b: []byte("lotusdb"), offset: -1}, 0, true, 156 }, 157 } 158 159 for _, tt := range tests { 160 t.Run(tt.name, func(t *testing.T) { 161 got, err := tt.fields.selector.Write(tt.args.b, tt.args.offset) 162 // io.EOF err in mmmap. 163 if tt.want == 1048577 && ioType == 1 { 164 tt.wantErr = true 165 tt.want = 0 166 } 167 if (err != nil) != tt.wantErr { 168 t.Errorf("Write() error = %v, wantErr %v", err, tt.wantErr) 169 return 170 } 171 if got != tt.want { 172 t.Errorf("Write() got = %v, want %v", got, tt.want) 173 } 174 }) 175 } 176 } 177 178 func testIOSelectorRead(t *testing.T, ioType uint8) { 179 absPath, err := filepath.Abs(filepath.Join("/tmp", "00000001.wal")) 180 var selector IOSelector 181 if ioType == 0 { 182 selector, err = NewFileIOSelector(absPath, 100) 183 } 184 if ioType == 1 { 185 selector, err = NewMMapSelector(absPath, 100) 186 } 187 assert.Nil(t, err) 188 defer func() { 189 if selector != nil { 190 _ = selector.Delete() 191 } 192 }() 193 offsets := writeSomeData(selector, t) 194 results := [][]byte{ 195 []byte(""), 196 []byte("1"), 197 []byte("lotusdb"), 198 } 199 200 type fields struct { 201 selector IOSelector 202 } 203 type args struct { 204 b []byte 205 offset int64 206 } 207 tests := []struct { 208 name string 209 fields fields 210 args args 211 want int 212 wantErr bool 213 }{ 214 { 215 "nil", fields{selector: selector}, args{b: make([]byte, 0), offset: offsets[0]}, 0, false, 216 }, 217 { 218 "one-byte", fields{selector: selector}, args{b: make([]byte, 1), offset: offsets[1]}, 1, false, 219 }, 220 { 221 "many-bytes", fields{selector: selector}, args{b: make([]byte, 7), offset: offsets[2]}, 7, false, 222 }, 223 { 224 "EOF-1", fields{selector: selector}, args{b: make([]byte, 100), offset: -1}, 0, true, 225 }, 226 { 227 "EOF-2", fields{selector: selector}, args{b: make([]byte, 100), offset: 1024}, 0, true, 228 }, 229 } 230 for i, tt := range tests { 231 t.Run(tt.name, func(t *testing.T) { 232 got, err := tt.fields.selector.Read(tt.args.b, tt.args.offset) 233 if (err != nil) != tt.wantErr { 234 t.Errorf("Read() error = %v, wantErr %v", err, tt.wantErr) 235 return 236 } 237 if got != tt.want { 238 t.Errorf("Read() got = %v, want %v", got, tt.want) 239 } 240 if !tt.wantErr { 241 assert.Equal(t, tt.args.b, results[i]) 242 } 243 }) 244 } 245 } 246 247 func writeSomeData(selector IOSelector, t *testing.T) []int64 { 248 tests := [][]byte{ 249 []byte(""), 250 []byte("1"), 251 []byte("lotusdb"), 252 } 253 254 var offsets []int64 255 var offset int64 256 for _, tt := range tests { 257 offsets = append(offsets, offset) 258 n, err := selector.Write(tt, offset) 259 assert.Nil(t, err) 260 offset += int64(n) 261 } 262 return offsets 263 } 264 265 func testIOSelectorSync(t *testing.T, ioType uint8) { 266 sync := func(id int, fsize int64) { 267 absPath, err := filepath.Abs(filepath.Join("/tmp", fmt.Sprintf("0000000%d.wal", id))) 268 assert.Nil(t, err) 269 var selector IOSelector 270 if ioType == 0 { 271 selector, err = NewFileIOSelector(absPath, fsize) 272 } 273 if ioType == 1 { 274 selector, err = NewMMapSelector(absPath, fsize) 275 } 276 assert.Nil(t, err) 277 defer func() { 278 if selector != nil { 279 _ = selector.Delete() 280 } 281 }() 282 writeSomeData(selector, t) 283 err = selector.Sync() 284 assert.Nil(t, err) 285 } 286 287 for i := 1; i < 4; i++ { 288 sync(i, int64(i*100)) 289 } 290 } 291 292 func testIOSelectorClose(t *testing.T, ioType uint8) { 293 sync := func(id int, fsize int64) { 294 absPath, err := filepath.Abs(filepath.Join("/tmp", fmt.Sprintf("0000000%d.wal", id))) 295 defer func() { 296 _ = os.Remove(absPath) 297 }() 298 assert.Nil(t, err) 299 var selector IOSelector 300 if ioType == 0 { 301 selector, err = NewFileIOSelector(absPath, fsize) 302 } 303 if ioType == 1 { 304 selector, err = NewMMapSelector(absPath, fsize) 305 } 306 assert.Nil(t, err) 307 defer func() { 308 if selector != nil { 309 err := selector.Close() 310 assert.Nil(t, err) 311 } 312 }() 313 writeSomeData(selector, t) 314 assert.Nil(t, err) 315 } 316 317 for i := 1; i < 4; i++ { 318 sync(i, int64(i*100)) 319 } 320 } 321 322 func testIOSelectorDelete(t *testing.T, ioType uint8) { 323 tests := []struct { 324 name string 325 wantErr bool 326 }{ 327 {"1", false}, 328 {"2", false}, 329 {"3", false}, 330 {"4", false}, 331 } 332 for i, tt := range tests { 333 t.Run(tt.name, func(t *testing.T) { 334 absPath, err := filepath.Abs(filepath.Join("/tmp", fmt.Sprintf("0000000%d.wal", i))) 335 assert.Nil(t, err) 336 var selector IOSelector 337 if ioType == 0 { 338 selector, err = NewFileIOSelector(absPath, int64((i+1)*100)) 339 } 340 if ioType == 1 { 341 selector, err = NewFileIOSelector(absPath, int64((i+1)*100)) 342 } 343 assert.Nil(t, err) 344 345 if err := selector.Delete(); (err != nil) != tt.wantErr { 346 t.Errorf("Delete() error = %v, wantErr %v", err, tt.wantErr) 347 } 348 }) 349 } 350 }