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

     1  package rosedb
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/stretchr/testify/assert"
     6  	"path/filepath"
     7  	"sort"
     8  	"testing"
     9  )
    10  
    11  func TestRoseDB_SAdd(t *testing.T) {
    12  	t.Run("fileio", func(t *testing.T) {
    13  		testRoseDBSAdd(t, FileIO, KeyValueMemMode)
    14  	})
    15  	t.Run("mmap", func(t *testing.T) {
    16  		testRoseDBSAdd(t, MMap, KeyOnlyMemMode)
    17  	})
    18  }
    19  
    20  func testRoseDBSAdd(t *testing.T, ioType IOType, mode DataIndexMode) {
    21  	path := filepath.Join("/tmp", "rosedb")
    22  	opts := DefaultOptions(path)
    23  	opts.IoType = ioType
    24  	opts.IndexMode = mode
    25  	db, err := Open(opts)
    26  	assert.Nil(t, err)
    27  	defer destroyDB(db)
    28  
    29  	type args struct {
    30  		key     []byte
    31  		members [][]byte
    32  	}
    33  	tests := []struct {
    34  		name    string
    35  		db      *RoseDB
    36  		args    args
    37  		wantErr bool
    38  	}{
    39  		{
    40  			"normal-1", db, args{key: GetKey(1), members: [][]byte{GetValue16B()}}, false,
    41  		},
    42  		{
    43  			"normal-2", db, args{key: GetKey(1), members: [][]byte{GetValue16B()}}, false,
    44  		},
    45  	}
    46  	for _, tt := range tests {
    47  		if err := tt.db.SAdd(tt.args.key, tt.args.members...); (err != nil) != tt.wantErr {
    48  			t.Errorf("SAdd() error = %v, wantErr %v", err, tt.wantErr)
    49  		}
    50  	}
    51  }
    52  
    53  func TestRoseDB_SPop(t *testing.T) {
    54  	t.Run("fileio", func(t *testing.T) {
    55  		testRoseDBSPop(t, FileIO, KeyOnlyMemMode)
    56  	})
    57  	t.Run("mmap", func(t *testing.T) {
    58  		testRoseDBSPop(t, MMap, KeyValueMemMode)
    59  	})
    60  }
    61  
    62  func testRoseDBSPop(t *testing.T, ioType IOType, mode DataIndexMode) {
    63  	path := filepath.Join("/tmp", "rosedb")
    64  	opts := DefaultOptions(path)
    65  	opts.IoType = ioType
    66  	opts.IndexMode = mode
    67  	db, err := Open(opts)
    68  	assert.Nil(t, err)
    69  	defer destroyDB(db)
    70  
    71  	setKey := []byte("my_set")
    72  	err = db.SAdd(setKey, GetKey(1), GetKey(2), GetKey(3))
    73  	assert.Nil(t, err)
    74  
    75  	c1 := db.SCard(setKey)
    76  	assert.Equal(t, 3, c1)
    77  
    78  	p1, err := db.SPop(setKey, 4)
    79  	assert.Nil(t, err)
    80  	assert.Equal(t, 3, len(p1))
    81  	p2, err := db.SPop(setKey, 1)
    82  	assert.Nil(t, err)
    83  	assert.Equal(t, 0, len(p2))
    84  
    85  	c2 := db.SCard(setKey)
    86  	assert.Equal(t, 0, c2)
    87  }
    88  
    89  func TestRoseDB_SRem(t *testing.T) {
    90  	t.Run("fileio", func(t *testing.T) {
    91  		testRoseDBSRem(t, FileIO, KeyOnlyMemMode)
    92  	})
    93  	t.Run("mmap", func(t *testing.T) {
    94  		testRoseDBSRem(t, MMap, KeyValueMemMode)
    95  	})
    96  }
    97  
    98  func testRoseDBSRem(t *testing.T, ioType IOType, mode DataIndexMode) {
    99  	path := filepath.Join("/tmp", "rosedb")
   100  	opts := DefaultOptions(path)
   101  	opts.IoType = ioType
   102  	opts.IndexMode = mode
   103  	db, err := Open(opts)
   104  	assert.Nil(t, err)
   105  	defer destroyDB(db)
   106  
   107  	setKey := []byte("my_set")
   108  	err = db.SAdd(setKey, GetKey(1), GetKey(2), GetKey(3))
   109  	assert.Nil(t, err)
   110  
   111  	err = db.SRem(setKey, GetKey(1))
   112  	assert.Nil(t, err)
   113  
   114  	ok1 := db.SIsMember(setKey, GetKey(1))
   115  	assert.False(t, ok1)
   116  
   117  	ok2 := db.SIsMember(setKey, GetKey(2))
   118  	assert.True(t, ok2)
   119  }
   120  
   121  func TestRoseDB_SIsMember(t *testing.T) {
   122  	t.Run("fileio", func(t *testing.T) {
   123  		testRoseDBSIsMember(t, FileIO, KeyOnlyMemMode)
   124  	})
   125  	t.Run("mmap", func(t *testing.T) {
   126  		testRoseDBSIsMember(t, MMap, KeyValueMemMode)
   127  	})
   128  }
   129  
   130  func testRoseDBSIsMember(t *testing.T, ioType IOType, mode DataIndexMode) {
   131  	path := filepath.Join("/tmp", "rosedb")
   132  	opts := DefaultOptions(path)
   133  	opts.IoType = ioType
   134  	opts.IndexMode = mode
   135  	db, err := Open(opts)
   136  	assert.Nil(t, err)
   137  	defer destroyDB(db)
   138  
   139  	setKey := []byte("my_set")
   140  	ok1 := db.SIsMember(setKey, GetKey(1))
   141  	assert.False(t, ok1)
   142  
   143  	err = db.SAdd(setKey, GetKey(1), GetKey(2), GetKey(3))
   144  	assert.Nil(t, err)
   145  
   146  	ok2 := db.SIsMember(setKey, GetKey(3))
   147  	assert.True(t, ok2)
   148  }
   149  
   150  func TestRoseDB_SMembers(t *testing.T) {
   151  	t.Run("fileio", func(t *testing.T) {
   152  		testRoseDBSMembers(t, FileIO, KeyOnlyMemMode)
   153  	})
   154  	t.Run("mmap", func(t *testing.T) {
   155  		testRoseDBSMembers(t, MMap, KeyValueMemMode)
   156  	})
   157  }
   158  
   159  func testRoseDBSMembers(t *testing.T, ioType IOType, mode DataIndexMode) {
   160  	path := filepath.Join("/tmp", "rosedb")
   161  	opts := DefaultOptions(path)
   162  	opts.IoType = ioType
   163  	opts.IndexMode = mode
   164  	db, err := Open(opts)
   165  	assert.Nil(t, err)
   166  	defer destroyDB(db)
   167  
   168  	setKey := []byte("my_set")
   169  	mems1, err := db.SMembers(setKey)
   170  	assert.Nil(t, err)
   171  	assert.Equal(t, 0, len(mems1))
   172  
   173  	err = db.SAdd(setKey, GetKey(0), GetKey(1), GetKey(2))
   174  	assert.Nil(t, err)
   175  	mems2, err := db.SMembers(setKey)
   176  	assert.Nil(t, err)
   177  	assert.Equal(t, 3, len(mems2))
   178  
   179  	err = db.SRem(setKey, GetKey(2))
   180  	assert.Nil(t, err)
   181  	mems3, err := db.SMembers(setKey)
   182  	assert.Nil(t, err)
   183  	assert.Equal(t, 2, len(mems3))
   184  }
   185  
   186  func TestRoseDB_SCard(t *testing.T) {
   187  	path := filepath.Join("/tmp", "rosedb")
   188  	opts := DefaultOptions(path)
   189  	db, err := Open(opts)
   190  	assert.Nil(t, err)
   191  	defer destroyDB(db)
   192  
   193  	setKey := []byte("my_set")
   194  	c1 := db.SCard(setKey)
   195  	assert.Equal(t, 0, c1)
   196  
   197  	err = db.SAdd(setKey, GetKey(0), GetKey(1), GetKey(2))
   198  	assert.Nil(t, err)
   199  
   200  	c2 := db.SCard(setKey)
   201  	assert.Equal(t, 3, c2)
   202  
   203  	err = db.Close()
   204  	assert.Nil(t, err)
   205  	db2, err := Open(opts)
   206  	assert.Nil(t, err)
   207  	defer func() {
   208  		_ = db2.Close()
   209  	}()
   210  	c3 := db2.SCard(setKey)
   211  	assert.Equal(t, 3, c3)
   212  }
   213  
   214  func TestRoseDB_DiscardStat_Sets(t *testing.T) {
   215  	helper := func(isDelete bool) {
   216  		path := filepath.Join("/tmp", "rosedb")
   217  		opts := DefaultOptions(path)
   218  		opts.LogFileSizeThreshold = 64 << 20
   219  		db, err := Open(opts)
   220  		assert.Nil(t, err)
   221  		defer destroyDB(db)
   222  
   223  		setKey := []byte("my_set")
   224  		writeCount := 500000
   225  		for i := 0; i < writeCount; i++ {
   226  			err := db.SAdd(setKey, GetKey(i))
   227  			assert.Nil(t, err)
   228  		}
   229  
   230  		if isDelete {
   231  			for i := 0; i < writeCount/2; i++ {
   232  				err := db.SRem(setKey, GetKey(i))
   233  				assert.Nil(t, err)
   234  			}
   235  		} else {
   236  			for i := 0; i < writeCount/2; i++ {
   237  				err := db.SAdd(setKey, GetKey(i))
   238  				assert.Nil(t, err)
   239  			}
   240  		}
   241  		_ = db.Sync()
   242  		ccl, err := db.discards[Set].getCCL(10, 0.1)
   243  		assert.Nil(t, err)
   244  		assert.Equal(t, 1, len(ccl))
   245  	}
   246  
   247  	t.Run("rewrite", func(t *testing.T) {
   248  		helper(false)
   249  	})
   250  
   251  	t.Run("delete", func(t *testing.T) {
   252  		helper(true)
   253  	})
   254  }
   255  
   256  func TestRoseDB_SetGC(t *testing.T) {
   257  	path := filepath.Join("/tmp", "rosedb")
   258  	opts := DefaultOptions(path)
   259  	opts.LogFileSizeThreshold = 64 << 20
   260  	db, err := Open(opts)
   261  	assert.Nil(t, err)
   262  	defer destroyDB(db)
   263  
   264  	setKey := []byte("my_set")
   265  	writeCount := 500000
   266  	for i := 0; i < writeCount; i++ {
   267  		err := db.SAdd(setKey, GetValue16B())
   268  		assert.Nil(t, err)
   269  	}
   270  
   271  	_, err = db.SPop(setKey, uint(writeCount/2))
   272  	assert.Nil(t, err)
   273  
   274  	err = db.RunLogFileGC(Set, 0, 0.1)
   275  	assert.Nil(t, err)
   276  
   277  	c1 := db.SCard(setKey)
   278  	assert.Equal(t, writeCount/2, c1)
   279  }
   280  
   281  func TestRoseDB_SDiff(t *testing.T) {
   282  	path := filepath.Join("/tmp", "rosedb")
   283  	opts := DefaultOptions(path)
   284  	db, err := Open(opts)
   285  	assert.Nil(t, err)
   286  	defer destroyDB(db)
   287  
   288  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   289  	_ = db.SAdd([]byte("key-2"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   290  	_ = db.SAdd([]byte("key-3"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9"))
   291  	_ = db.SAdd([]byte("key-4"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   292  	testCases := []struct {
   293  		name       string
   294  		db         *RoseDB
   295  		keys       [][]byte
   296  		expDiffSet [][]byte
   297  		expErr     error
   298  	}{
   299  		{
   300  			name:       "empty key parameters",
   301  			db:         db,
   302  			keys:       [][]byte{},
   303  			expDiffSet: nil,
   304  			expErr:     ErrWrongNumberOfArgs,
   305  		},
   306  		{
   307  			name:       "one key parameter",
   308  			db:         db,
   309  			keys:       [][]byte{[]byte("key-2")},
   310  			expDiffSet: [][]byte{[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7")}, // todo check
   311  			expErr:     nil,
   312  		},
   313  		{
   314  			name:       "two key parameters",
   315  			db:         db,
   316  			keys:       [][]byte{[]byte("key-1"), []byte("key-3")},
   317  			expDiffSet: [][]byte{[]byte("value-3"), []byte("value-1")},
   318  			expErr:     nil,
   319  		},
   320  		{
   321  			name:       "multiple key parameters",
   322  			db:         db,
   323  			keys:       [][]byte{[]byte("key-1"), []byte("key-2"), []byte("key-3")},
   324  			expDiffSet: [][]byte{[]byte("value-3"), []byte("value-1")},
   325  			expErr:     nil,
   326  		},
   327  		{
   328  			name:       "no diff",
   329  			db:         db,
   330  			keys:       [][]byte{[]byte("key-1"), []byte("key-4")},
   331  			expDiffSet: [][]byte{},
   332  			expErr:     nil,
   333  		},
   334  	}
   335  
   336  	for _, tc := range testCases {
   337  		t.Run(tc.name, func(t *testing.T) {
   338  			diffSet, err := db.SDiff(tc.keys...)
   339  			assert.Equal(t, tc.expErr, err)
   340  			assert.Equal(t, tc.expDiffSet, diffSet)
   341  		})
   342  	}
   343  }
   344  
   345  func TestRoseDB_SDiffStore(t *testing.T) {
   346  	path := filepath.Join("/tmp", "rosedb")
   347  	opts := DefaultOptions(path)
   348  	db, err := Open(opts)
   349  	assert.Nil(t, err)
   350  	defer destroyDB(db)
   351  
   352  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   353  	_ = db.SAdd([]byte("key-2"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   354  	_ = db.SAdd([]byte("key-3"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9"))
   355  	_ = db.SAdd([]byte("key-4"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   356  	testCases := []struct {
   357  		name       string
   358  		db         *RoseDB
   359  		keys       [][]byte
   360  		expDiffSet [][]byte
   361  		expErr     error
   362  	}{
   363  		{
   364  			name:       "two key parameter",
   365  			db:         db,
   366  			keys:       [][]byte{[]byte("destination1"), []byte("key-2")},
   367  			expDiffSet: [][]byte{[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7")}, // todo check
   368  			expErr:     nil,
   369  		},
   370  		{
   371  			name:       "three key parameters",
   372  			db:         db,
   373  			keys:       [][]byte{[]byte("destination2"), []byte("key-1"), []byte("key-3")},
   374  			expDiffSet: [][]byte{[]byte("value-3"), []byte("value-1")},
   375  			expErr:     nil,
   376  		},
   377  		{
   378  			name:       "four key parameters",
   379  			db:         db,
   380  			keys:       [][]byte{[]byte("destination3"), []byte("key-1"), []byte("key-2"), []byte("key-3")},
   381  			expDiffSet: [][]byte{[]byte("value-3"), []byte("value-1")},
   382  			expErr:     nil,
   383  		},
   384  		{
   385  			name:       "no diff",
   386  			db:         db,
   387  			keys:       [][]byte{[]byte("destination4"), []byte("key-1"), []byte("key-4")},
   388  			expDiffSet: nil,
   389  			expErr:     nil,
   390  		},
   391  	}
   392  
   393  	for _, tc := range testCases {
   394  		t.Run(tc.name, func(t *testing.T) {
   395  			count, err := db.SDiffStore(tc.keys...)
   396  			assert.Nil(t, err)
   397  			actual, err := db.sMembers(tc.keys[0])
   398  			assert.Equal(t, tc.expErr, err)
   399  			assert.Equal(t, tc.expDiffSet, actual)
   400  			assert.Equal(t, len(actual), count)
   401  		})
   402  	}
   403  }
   404  
   405  func TestRoseDB_SUnion(t *testing.T) {
   406  	path := filepath.Join("/tmp", "rosedb")
   407  	opts := DefaultOptions(path)
   408  	db, err := Open(opts)
   409  	assert.Nil(t, err)
   410  	defer destroyDB(db)
   411  
   412  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   413  	_ = db.SAdd([]byte("key-2"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   414  	_ = db.SAdd([]byte("key-3"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9"))
   415  	testCases := []struct {
   416  		name        string
   417  		db          *RoseDB
   418  		keys        [][]byte
   419  		expUnionSet [][]byte
   420  		expErr      error
   421  	}{
   422  		{
   423  			name:        "empty key parameters",
   424  			db:          db,
   425  			keys:        [][]byte{},
   426  			expUnionSet: nil,
   427  			expErr:      ErrWrongNumberOfArgs,
   428  		},
   429  		{
   430  			name:        "one key parameter",
   431  			db:          db,
   432  			keys:        [][]byte{[]byte("key-1")},
   433  			expUnionSet: [][]byte{[]byte("value-3"), []byte("value-2"), []byte("value-1")},
   434  			expErr:      nil,
   435  		},
   436  		{
   437  			name: "two key parameters",
   438  			db:   db,
   439  			keys: [][]byte{[]byte("key-1"), []byte("key-2")},
   440  			expUnionSet: [][]byte{[]byte("value-3"), []byte("value-2"), []byte("value-1"),
   441  				[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7")},
   442  			expErr: nil,
   443  		},
   444  		{
   445  			name: "multiple key parameters",
   446  			db:   db,
   447  			keys: [][]byte{[]byte("key-1"), []byte("key-2"), []byte("key-3")},
   448  			expUnionSet: [][]byte{[]byte("value-3"), []byte("value-2"), []byte("value-1"),
   449  				[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7"),
   450  				[]byte("value-8"), []byte("value-9")},
   451  			expErr: nil,
   452  		},
   453  		{
   454  			name:        "no union",
   455  			db:          db,
   456  			keys:        [][]byte{[]byte("key-10"), []byte("key-20")},
   457  			expUnionSet: [][]byte{},
   458  			expErr:      nil,
   459  		},
   460  	}
   461  
   462  	for _, tc := range testCases {
   463  		t.Run(tc.name, func(t *testing.T) {
   464  			unionSet, err := db.SUnion(tc.keys...)
   465  			assert.Equal(t, tc.expErr, err)
   466  			assert.Equal(t, tc.expUnionSet, unionSet)
   467  		})
   468  	}
   469  }
   470  
   471  func TestRoseDB_SUnionStore(t *testing.T) {
   472  	path := filepath.Join("/tmp", "rosedb")
   473  	opts := DefaultOptions(path)
   474  	db, err := Open(opts)
   475  	assert.Nil(t, err)
   476  	defer destroyDB(db)
   477  
   478  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   479  	_ = db.SAdd([]byte("key-2"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   480  	_ = db.SAdd([]byte("key-3"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9"))
   481  	_ = db.SAdd([]byte("key-4"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   482  	testCases := []struct {
   483  		name        string
   484  		db          *RoseDB
   485  		keys        [][]byte
   486  		expUnionSet [][]byte
   487  		expErr      error
   488  	}{
   489  		{
   490  			name:        "two key parameter",
   491  			db:          db,
   492  			keys:        [][]byte{[]byte("destination1"), []byte("key-2")},
   493  			expUnionSet: [][]byte{[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7")}, // todo check
   494  			expErr:      nil,
   495  		},
   496  		{
   497  			name:        "three key parameters",
   498  			db:          db,
   499  			keys:        [][]byte{[]byte("destination2"), []byte("key-1"), []byte("key-3")},
   500  			expUnionSet: [][]byte{[]byte("value-3"), []byte("value-1"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9")},
   501  			expErr:      nil,
   502  		},
   503  		{
   504  			name:        "four key parameters",
   505  			db:          db,
   506  			keys:        [][]byte{[]byte("destination3"), []byte("key-1"), []byte("key-2"), []byte("key-3")},
   507  			expUnionSet: [][]byte{[]byte("value-1"), []byte("value-2"), []byte("value-3"), []byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7"), []byte("value-8"), []byte("value-9")},
   508  			expErr:      nil,
   509  		},
   510  		{
   511  			name:        "no union",
   512  			db:          db,
   513  			keys:        [][]byte{[]byte("destination4"), []byte("key-10"), []byte("key-40")},
   514  			expUnionSet: nil,
   515  			expErr:      nil,
   516  		},
   517  	}
   518  
   519  	for _, tc := range testCases {
   520  		t.Run(tc.name, func(t *testing.T) {
   521  			count, err := db.SUnionStore(tc.keys...)
   522  			assert.Nil(t, err)
   523  
   524  			actual, err := db.sMembers(tc.keys[0])
   525  			var expectString []string
   526  			var actualString []string
   527  			for exp := range tc.expUnionSet {
   528  				expectString = append(expectString, fmt.Sprintf("%x", exp))
   529  			}
   530  			for act := range actual {
   531  				actualString = append(actualString, fmt.Sprintf("%x", act))
   532  			}
   533  
   534  			sort.Strings(expectString)
   535  			sort.Strings(actualString)
   536  			assert.Equal(t, tc.expErr, err)
   537  			assert.Equal(t, expectString, actualString)
   538  			assert.Equal(t, len(actual), count)
   539  		})
   540  	}
   541  }
   542  
   543  func TestRoseDB_SInter(t *testing.T) {
   544  	path := filepath.Join("/tmp", "rosedb")
   545  	opts := DefaultOptions(path)
   546  	db, err := Open(opts)
   547  	assert.Nil(t, err)
   548  	defer destroyDB(db)
   549  
   550  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   551  	_ = db.SAdd([]byte("key-2"), []byte("value-1"), []byte("value-2"), []byte("value-3"), []byte("value-4"))
   552  	_ = db.SAdd([]byte("key-3"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   553  	_ = db.SAdd([]byte("key-4"), []byte("value-4"), []byte("value-5"))
   554  	testCases := []struct {
   555  		name        string
   556  		db          *RoseDB
   557  		keys        [][]byte
   558  		expInterSet [][]byte
   559  		expErr      error
   560  	}{
   561  		{
   562  			name:        "empty key parameters",
   563  			db:          db,
   564  			keys:        [][]byte{},
   565  			expInterSet: nil,
   566  			expErr:      ErrWrongNumberOfArgs,
   567  		},
   568  		{
   569  			name:        "one key parameter",
   570  			db:          db,
   571  			keys:        [][]byte{[]byte("key-1")},
   572  			expInterSet: [][]byte{[]byte("value-3"), []byte("value-2"), []byte("value-1")},
   573  			expErr:      nil,
   574  		},
   575  		{
   576  			name:        "two key parameters key-1 key-2",
   577  			db:          db,
   578  			keys:        [][]byte{[]byte("key-1"), []byte("key-2")},
   579  			expInterSet: [][]byte{[]byte("value-3"), []byte("value-2"), []byte("value-1")},
   580  			expErr:      nil,
   581  		},
   582  		{
   583  			name:        "two key parameters key-1 key-3",
   584  			db:          db,
   585  			keys:        [][]byte{[]byte("key-1"), []byte("key-3")},
   586  			expInterSet: [][]byte{},
   587  			expErr:      nil,
   588  		},
   589  		{
   590  			name:        "multiple key parameters key-1 key-2 key-3",
   591  			db:          db,
   592  			keys:        [][]byte{[]byte("key-1"), []byte("key-2"), []byte("key-3")},
   593  			expInterSet: [][]byte{},
   594  			expErr:      nil,
   595  		},
   596  		{
   597  			name:        "multiple key parameters  key-2 key-3 key-4",
   598  			db:          db,
   599  			keys:        [][]byte{[]byte("key-4"), []byte("key-2"), []byte("key-3")},
   600  			expInterSet: [][]byte{[]byte("value-4")},
   601  			expErr:      nil,
   602  		},
   603  		{
   604  			name:        "no Inter",
   605  			db:          db,
   606  			keys:        [][]byte{[]byte("key-10"), []byte("key-20")},
   607  			expInterSet: [][]byte{},
   608  			expErr:      nil,
   609  		},
   610  	}
   611  
   612  	for _, tc := range testCases {
   613  		t.Run(tc.name, func(t *testing.T) {
   614  			unionSet, err := db.SInter(tc.keys...)
   615  			assert.Equal(t, tc.expErr, err)
   616  			assert.Equal(t, tc.expInterSet, unionSet)
   617  		})
   618  	}
   619  }
   620  
   621  func TestRoseDB_SInterStore(t *testing.T) {
   622  	path := filepath.Join("/tmp", "rosedb")
   623  	opts := DefaultOptions(path)
   624  	db, err := Open(opts)
   625  	assert.Nil(t, err)
   626  	defer destroyDB(db)
   627  
   628  	_ = db.SAdd([]byte("key-1"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   629  	_ = db.SAdd([]byte("key-2"), []byte("value-4"), []byte("value-5"), []byte("value-6"), []byte("value-7"))
   630  	_ = db.SAdd([]byte("key-3"), []byte("value-2"), []byte("value-5"), []byte("value-8"), []byte("value-9"))
   631  	_ = db.SAdd([]byte("key-4"), []byte("value-1"), []byte("value-2"), []byte("value-3"))
   632  	testCases := []struct {
   633  		name        string
   634  		db          *RoseDB
   635  		keys        [][]byte
   636  		expInterSet [][]byte
   637  		expErr      error
   638  	}{
   639  		{
   640  			name:        "two key parameter",
   641  			db:          db,
   642  			keys:        [][]byte{[]byte("destination1"), []byte("key-2")},
   643  			expInterSet: [][]byte{[]byte("value-5"), []byte("value-4"), []byte("value-6"), []byte("value-7")}, // todo check
   644  			expErr:      nil,
   645  		},
   646  		{
   647  			name:        "three key parameters",
   648  			db:          db,
   649  			keys:        [][]byte{[]byte("destination2"), []byte("key-1"), []byte("key-3")},
   650  			expInterSet: [][]byte{[]byte("value-2")},
   651  			expErr:      nil,
   652  		},
   653  		{
   654  			name:        "four key parameters",
   655  			db:          db,
   656  			keys:        [][]byte{[]byte("destination3"), []byte("key-1"), []byte("key-3"), []byte("key-4")},
   657  			expInterSet: [][]byte{[]byte("value-2")},
   658  			expErr:      nil,
   659  		},
   660  		{
   661  			name:        "no inter",
   662  			db:          db,
   663  			keys:        [][]byte{[]byte("destination4"), []byte("key-1"), []byte("key-2")},
   664  			expInterSet: nil,
   665  			expErr:      nil,
   666  		},
   667  	}
   668  
   669  	for _, tc := range testCases {
   670  		t.Run(tc.name, func(t *testing.T) {
   671  			count, err := db.SInterStore(tc.keys...)
   672  			assert.Nil(t, err)
   673  
   674  			actual, err := db.sMembers(tc.keys[0])
   675  			var expectString []string
   676  			var actualString []string
   677  			for exp := range tc.expInterSet {
   678  				expectString = append(expectString, fmt.Sprintf("%x", exp))
   679  			}
   680  			for act := range actual {
   681  				actualString = append(actualString, fmt.Sprintf("%x", act))
   682  			}
   683  
   684  			sort.Strings(expectString)
   685  			sort.Strings(actualString)
   686  			assert.Equal(t, tc.expErr, err)
   687  			assert.Equal(t, expectString, actualString)
   688  			assert.Equal(t, len(actual), count)
   689  		})
   690  	}
   691  }