github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/logfile/log_file_test.go (about)

     1  package logfile
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync/atomic"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  )
    11  
    12  func TestOpenLogFile(t *testing.T) {
    13  	t.Run("fileio", func(t *testing.T) {
    14  		testOpenLogFile(t, FileIO)
    15  	})
    16  
    17  	t.Run("mmap", func(t *testing.T) {
    18  		testOpenLogFile(t, MMap)
    19  	})
    20  }
    21  
    22  func testOpenLogFile(t *testing.T, ioType IOType) {
    23  	type args struct {
    24  		path   string
    25  		fid    uint32
    26  		fsize  int64
    27  		ftype  FileType
    28  		ioType IOType
    29  	}
    30  	tests := []struct {
    31  		name    string
    32  		args    args
    33  		wantErr bool
    34  	}{
    35  		{
    36  			"zero-size", args{"/tmp", 0, 0, List, ioType}, true,
    37  		},
    38  		{
    39  			"normal-size", args{"/tmp", 1, 100, List, ioType}, false,
    40  		},
    41  		{
    42  			"big-size", args{"/tmp", 2, 1024 << 20, List, ioType}, false,
    43  		},
    44  	}
    45  	for _, tt := range tests {
    46  		t.Run(tt.name, func(t *testing.T) {
    47  			gotLf, err := OpenLogFile(tt.args.path, tt.args.fid, tt.args.fsize, tt.args.ftype, tt.args.ioType)
    48  			defer func() {
    49  				if gotLf != nil && gotLf.IoSelector != nil {
    50  					_ = gotLf.Delete()
    51  				}
    52  			}()
    53  
    54  			if (err != nil) != tt.wantErr {
    55  				t.Errorf("OpenLogFile() error = %v, wantErr %v", err, tt.wantErr)
    56  				return
    57  			}
    58  			if !tt.wantErr && gotLf == nil {
    59  				t.Errorf("OpenLogFile() gotLf =nil, want not nil")
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  func TestLogFile_Write(t *testing.T) {
    66  	t.Run("fileio", func(t *testing.T) {
    67  		testLogFileWrite(t, FileIO)
    68  	})
    69  
    70  	t.Run("mmap", func(t *testing.T) {
    71  		testLogFileWrite(t, MMap)
    72  	})
    73  }
    74  
    75  func testLogFileWrite(t *testing.T, ioType IOType) {
    76  	lf, err := OpenLogFile("/tmp", 1, 1<<20, List, ioType)
    77  	assert.Nil(t, err)
    78  	defer func() {
    79  		if lf != nil {
    80  			_ = lf.Delete()
    81  		}
    82  	}()
    83  
    84  	type fields struct {
    85  		lf *LogFile
    86  	}
    87  	type args struct {
    88  		buf []byte
    89  	}
    90  	tests := []struct {
    91  		name    string
    92  		fields  fields
    93  		args    args
    94  		wantErr bool
    95  	}{
    96  		{
    97  			"nil", fields{lf: lf}, args{buf: nil}, false,
    98  		},
    99  		{
   100  			"no-value", fields{lf: lf}, args{buf: []byte{}}, false,
   101  		},
   102  		{
   103  			"normal-1", fields{lf: lf}, args{buf: []byte("lotusdb")}, false,
   104  		},
   105  		{
   106  			"normal-2", fields{lf: lf}, args{buf: []byte("some data")}, false,
   107  		},
   108  	}
   109  	for _, tt := range tests {
   110  		t.Run(tt.name, func(t *testing.T) {
   111  			if err := tt.fields.lf.Write(tt.args.buf); (err != nil) != tt.wantErr {
   112  				t.Errorf("Write() error = %v, wantErr %v", err, tt.wantErr)
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestLogFile_Read(t *testing.T) {
   119  	t.Run("fileio", func(t *testing.T) {
   120  		testLogFileRead(t, FileIO)
   121  	})
   122  
   123  	t.Run("mmap", func(t *testing.T) {
   124  		testLogFileRead(t, MMap)
   125  	})
   126  }
   127  
   128  func testLogFileRead(t *testing.T, ioType IOType) {
   129  	lf, err := OpenLogFile("/tmp", 1, 1<<20, List, ioType)
   130  	assert.Nil(t, err)
   131  	defer func() {
   132  		if lf != nil {
   133  			_ = lf.Delete()
   134  		}
   135  	}()
   136  
   137  	data := [][]byte{
   138  		[]byte("0"),
   139  		[]byte("some data"),
   140  		[]byte("some data 1"),
   141  		[]byte("some data 2"),
   142  		[]byte("some data 3"),
   143  		[]byte("lotusdb"),
   144  	}
   145  	offset := writeSomeData(lf, data)
   146  
   147  	type fields struct {
   148  		lf *LogFile
   149  	}
   150  	type args struct {
   151  		offset int64
   152  		size   uint32
   153  	}
   154  	tests := []struct {
   155  		name    string
   156  		fields  fields
   157  		args    args
   158  		want    []byte
   159  		wantErr bool
   160  	}{
   161  		{
   162  			"read-0", fields{lf: lf}, args{offset[0], uint32(len(data[0]))}, data[0], false,
   163  		},
   164  		{
   165  			"read-1", fields{lf: lf}, args{offset[1], uint32(len(data[1]))}, data[1], false,
   166  		},
   167  		{
   168  			"read-2", fields{lf: lf}, args{offset[2], uint32(len(data[2]))}, data[2], false,
   169  		},
   170  		{
   171  			"read-3", fields{lf: lf}, args{offset[3], uint32(len(data[3]))}, data[3], false,
   172  		},
   173  		{
   174  			"read-4", fields{lf: lf}, args{offset[4], uint32(len(data[4]))}, data[4], false,
   175  		},
   176  		{
   177  			"read-5", fields{lf: lf}, args{offset[5], uint32(len(data[5]))}, data[5], false,
   178  		},
   179  	}
   180  
   181  	for _, tt := range tests {
   182  		t.Run(tt.name, func(t *testing.T) {
   183  			got, err := tt.fields.lf.Read(tt.args.offset, tt.args.size)
   184  			if (err != nil) != tt.wantErr {
   185  				t.Errorf("Read() error = %v, wantErr %v", err, tt.wantErr)
   186  				return
   187  			}
   188  			if !reflect.DeepEqual(got, tt.want) {
   189  				t.Errorf("Read() got = %v, want %v", got, tt.want)
   190  			}
   191  		})
   192  	}
   193  }
   194  
   195  func writeSomeData(lf *LogFile, data [][]byte) []int64 {
   196  	var offset []int64
   197  	for _, v := range data {
   198  		off := atomic.LoadInt64(&lf.WriteAt)
   199  		offset = append(offset, off)
   200  		if err := lf.Write(v); err != nil {
   201  			panic(fmt.Sprintf("write data err.%+v", err))
   202  		}
   203  	}
   204  	return offset
   205  }
   206  
   207  func TestLogFile_ReadLogEntry(t *testing.T) {
   208  	t.Run("fileio", func(t *testing.T) {
   209  		testLogFileReadLogEntry(t, FileIO)
   210  	})
   211  
   212  	t.Run("mmap", func(t *testing.T) {
   213  		testLogFileReadLogEntry(t, MMap)
   214  	})
   215  }
   216  
   217  func testLogFileReadLogEntry(t *testing.T, ioType IOType) {
   218  	lf, err := OpenLogFile("/tmp", 1, 1<<20, Strs, ioType)
   219  	assert.Nil(t, err)
   220  	defer func() {
   221  		if lf != nil {
   222  			_ = lf.Delete()
   223  		}
   224  	}()
   225  
   226  	// write some entries.
   227  	entries := []*LogEntry{
   228  		{ExpiredAt: 123332, Type: 0},
   229  		{ExpiredAt: 123332, Type: TypeDelete},
   230  		{Key: []byte(""), Value: []byte(""), ExpiredAt: 994332343, Type: TypeDelete},
   231  		{Key: []byte("k1"), Value: nil, ExpiredAt: 7844332343},
   232  		{Key: nil, Value: []byte("lotusdb"), ExpiredAt: 99400542343},
   233  		{Key: []byte("k2"), Value: []byte("lotusdb"), ExpiredAt: 8847333912},
   234  		{Key: []byte("k3"), Value: []byte("some data"), ExpiredAt: 8847333912, Type: TypeDelete},
   235  	}
   236  	var vals [][]byte
   237  	for _, e := range entries {
   238  		v, _ := EncodeEntry(e)
   239  		vals = append(vals, v)
   240  	}
   241  	offsets := writeSomeData(lf, vals)
   242  
   243  	type fields struct {
   244  		lf *LogFile
   245  	}
   246  	type args struct {
   247  		offset int64
   248  	}
   249  	tests := []struct {
   250  		name    string
   251  		fields  fields
   252  		args    args
   253  		want    *LogEntry
   254  		want1   int64
   255  		wantErr bool
   256  	}{
   257  		{
   258  			"read-entry-0", fields{lf: lf}, args{offset: offsets[0]}, entries[0], int64(len(vals[0])), false,
   259  		},
   260  		{
   261  			"read-entry-1", fields{lf: lf}, args{offset: offsets[1]}, entries[1], int64(len(vals[1])), false,
   262  		},
   263  		{
   264  			"read-entry-2", fields{lf: lf}, args{offset: offsets[2]}, &LogEntry{ExpiredAt: 994332343, Type: TypeDelete}, int64(len(vals[2])), false,
   265  		},
   266  		{
   267  			"read-entry-3", fields{lf: lf}, args{offset: offsets[3]}, &LogEntry{Key: []byte("k1"), Value: []byte{}, ExpiredAt: 7844332343}, int64(len(vals[3])), false,
   268  		},
   269  		{
   270  			"read-entry-4", fields{lf: lf}, args{offset: offsets[4]}, &LogEntry{Key: []byte{}, Value: []byte("lotusdb"), ExpiredAt: 99400542343}, int64(len(vals[4])), false,
   271  		},
   272  		{
   273  			"read-entry-5", fields{lf: lf}, args{offset: offsets[5]}, entries[5], int64(len(vals[5])), false,
   274  		},
   275  		{
   276  			"read-entry-6", fields{lf: lf}, args{offset: offsets[6]}, entries[6], int64(len(vals[6])), false,
   277  		},
   278  	}
   279  	for _, tt := range tests {
   280  		t.Run(tt.name, func(t *testing.T) {
   281  			got, got1, err := tt.fields.lf.ReadLogEntry(tt.args.offset)
   282  			if (err != nil) != tt.wantErr {
   283  				t.Errorf("ReadLogEntry() error = %v, wantErr %v", err, tt.wantErr)
   284  				return
   285  			}
   286  			if !reflect.DeepEqual(got, tt.want) {
   287  				t.Errorf("ReadLogEntry() got = %v, want %v", got, tt.want)
   288  			}
   289  			if got1 != tt.want1 {
   290  				t.Errorf("ReadLogEntry() got1 = %v, want %v", got1, tt.want1)
   291  			}
   292  		})
   293  	}
   294  }
   295  
   296  func TestLogFile_Sync(t *testing.T) {
   297  	sync := func(ioType IOType) {
   298  		file, err := OpenLogFile("/tmp", 0, 100, Hash, ioType)
   299  		assert.Nil(t, err)
   300  		defer func() {
   301  			if file != nil {
   302  				_ = file.Delete()
   303  			}
   304  		}()
   305  		err = file.Sync()
   306  		assert.Nil(t, err)
   307  	}
   308  
   309  	t.Run("fileio", func(t *testing.T) {
   310  		sync(FileIO)
   311  	})
   312  
   313  	t.Run("mmap", func(t *testing.T) {
   314  		sync(MMap)
   315  	})
   316  }
   317  
   318  func TestLogFile_Close(t *testing.T) {
   319  	var fid uint32 = 0
   320  
   321  	closeLf := func(ioType IOType) {
   322  		file, err := OpenLogFile("/tmp", fid, 100, Sets, ioType)
   323  		assert.Nil(t, err)
   324  
   325  		err = file.Delete()
   326  		assert.Nil(t, err)
   327  	}
   328  
   329  	t.Run("fileio", func(t *testing.T) {
   330  		closeLf(FileIO)
   331  	})
   332  
   333  	t.Run("mmap", func(t *testing.T) {
   334  		closeLf(MMap)
   335  	})
   336  }
   337  
   338  func TestLogFile_Delete(t *testing.T) {
   339  	deleteLf := func(ioType IOType) {
   340  		file, err := OpenLogFile("/tmp", 0, 100, ZSet, ioType)
   341  		assert.Nil(t, err)
   342  		err = file.Delete()
   343  		assert.Nil(t, err)
   344  	}
   345  
   346  	t.Run("fileio", func(t *testing.T) {
   347  		deleteLf(FileIO)
   348  	})
   349  
   350  	t.Run("mmap", func(t *testing.T) {
   351  		deleteLf(MMap)
   352  	})
   353  }