github.com/nutsdb/nutsdb@v1.0.4/tx_list_test.go (about)

     1  // Copyright 2019 The nutsdb Author. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package nutsdb
    16  
    17  import (
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func pushDataByStartEnd(t *testing.T, db *DB, bucket string, key int, start, end int, isLeft bool) {
    25  	for i := start; i <= end; i++ {
    26  		txPush(t, db, bucket, GetTestBytes(key), GetTestBytes(i), isLeft, nil, nil)
    27  	}
    28  }
    29  
    30  func pushDataByValues(t *testing.T, db *DB, bucket string, key int, isLeft bool, values ...int) {
    31  	for _, v := range values {
    32  		txPush(t, db, bucket, GetTestBytes(key), GetTestBytes(v), isLeft, nil, nil)
    33  	}
    34  }
    35  
    36  func TestTx_RPush(t *testing.T) {
    37  	bucket := "bucket"
    38  
    39  	// 1. Insert values for some keys by using RPush
    40  	// 2. Validate values for these keys by using RPop
    41  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
    42  		txCreateBucket(t, db, DataStructureList, bucket, nil)
    43  		pushDataByStartEnd(t, db, bucket, 0, 0, 9, false)
    44  		pushDataByStartEnd(t, db, bucket, 1, 10, 19, false)
    45  		pushDataByStartEnd(t, db, bucket, 2, 20, 29, false)
    46  
    47  		for i := 0; i < 10; i++ {
    48  			txPop(t, db, bucket, GetTestBytes(0), GetTestBytes(9-i), nil, false)
    49  		}
    50  		for i := 10; i < 20; i++ {
    51  			txPop(t, db, bucket, GetTestBytes(1), GetTestBytes(29-i), nil, false)
    52  		}
    53  		for i := 20; i < 30; i++ {
    54  			txPop(t, db, bucket, GetTestBytes(2), GetTestBytes(49-i), nil, false)
    55  		}
    56  	})
    57  }
    58  
    59  func TestTx_MPush(t *testing.T) {
    60  	bucket := "bucket"
    61  	t.Run("Test Multiple LPush ", func(t *testing.T) {
    62  		runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
    63  			bbs := make([][]byte, 0)
    64  			bbs = append(bbs, GetTestBytes(2))
    65  			bbs = append(bbs, GetTestBytes(3))
    66  			bbs = append(bbs, GetTestBytes(4))
    67  
    68  			txCreateBucket(t, db, DataStructureList, bucket, nil)
    69  			txMPush(t, db, bucket, GetTestBytes(1), bbs, true, nil, nil)
    70  
    71  			expect := make([][]byte, 0)
    72  			for i := len(bbs) - 1; i >= 0; i-- {
    73  				expect = append(expect, bbs[i])
    74  			}
    75  
    76  			txLRange(t, db, bucket, GetTestBytes(1), 0, 2, 3, expect, nil)
    77  		})
    78  	})
    79  
    80  	t.Run("Test Error LPush ", func(t *testing.T) {
    81  		runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
    82  			bbs := make([][]byte, 0)
    83  			bbs = append(bbs, GetTestBytes(2))
    84  			bbs = append(bbs, GetTestBytes(3))
    85  			bbs = append(bbs, GetTestBytes(4))
    86  
    87  			txCreateBucket(t, db, DataStructureList, bucket, nil)
    88  			txMPush(t, db, "test1", GetTestBytes(1), bbs, true, ErrorBucketNotExist, nil)
    89  		})
    90  	})
    91  
    92  	t.Run("Test Multiple RPush ", func(t *testing.T) {
    93  		runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
    94  			bbs := make([][]byte, 0)
    95  			bbs = append(bbs, GetTestBytes(2))
    96  			bbs = append(bbs, GetTestBytes(3))
    97  			bbs = append(bbs, GetTestBytes(4))
    98  			txCreateBucket(t, db, DataStructureList, bucket, nil)
    99  			txMPush(t, db, bucket, GetTestBytes(1), bbs, false, nil, nil)
   100  			txLRange(t, db, bucket, GetTestBytes(1), 0, 2, 3, bbs, nil)
   101  		})
   102  	})
   103  
   104  	t.Run("Test Error RPush ", func(t *testing.T) {
   105  		runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   106  			bbs := make([][]byte, 0)
   107  			bbs = append(bbs, GetTestBytes(2))
   108  			bbs = append(bbs, GetTestBytes(3))
   109  			bbs = append(bbs, GetTestBytes(4))
   110  
   111  			txCreateBucket(t, db, DataStructureList, bucket, nil)
   112  			txMPush(t, db, "test1", GetTestBytes(1), bbs, false, ErrorBucketNotExist, nil)
   113  		})
   114  	})
   115  }
   116  
   117  func TestTx_LPush(t *testing.T) {
   118  	bucket := "bucket"
   119  
   120  	// 1. Insert values for some keys by using LPush
   121  	// 2. Validate values for these keys by using LPop
   122  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   123  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   124  
   125  		pushDataByStartEnd(t, db, bucket, 0, 0, 9, true)
   126  		pushDataByStartEnd(t, db, bucket, 1, 10, 19, true)
   127  		pushDataByStartEnd(t, db, bucket, 2, 20, 29, true)
   128  
   129  		txPush(t, db, bucket, []byte("012|sas"), GetTestBytes(0), true, ErrSeparatorForListKey, nil)
   130  
   131  		for i := 0; i < 10; i++ {
   132  			txPop(t, db, bucket, GetTestBytes(0), GetTestBytes(9-i), nil, true)
   133  		}
   134  		for i := 10; i < 20; i++ {
   135  			txPop(t, db, bucket, GetTestBytes(1), GetTestBytes(29-i), nil, true)
   136  		}
   137  		for i := 20; i < 30; i++ {
   138  			txPop(t, db, bucket, GetTestBytes(2), GetTestBytes(49-i), nil, true)
   139  		}
   140  	})
   141  }
   142  
   143  func TestTx_LPushRaw(t *testing.T) {
   144  	bucket := "bucket"
   145  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   146  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   147  
   148  		seq := uint64(100000)
   149  		for i := 0; i <= 100; i++ {
   150  			key := encodeListKey([]byte("0"), seq)
   151  			seq--
   152  			txPushRaw(t, db, bucket, key, GetTestBytes(i), true, nil, nil)
   153  		}
   154  
   155  		for i := 0; i <= 100; i++ {
   156  			v := GetTestBytes(100 - i)
   157  			txPop(t, db, bucket, []byte("0"), v, nil, true)
   158  		}
   159  	})
   160  }
   161  
   162  func TestTx_RPushRaw(t *testing.T) {
   163  	bucket := "bucket"
   164  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   165  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   166  		seq := uint64(100000)
   167  		for i := 0; i <= 100; i++ {
   168  			key := encodeListKey([]byte("0"), seq)
   169  			seq++
   170  			txPushRaw(t, db, bucket, key, GetTestBytes(i), false, nil, nil)
   171  		}
   172  
   173  		txPush(t, db, bucket, []byte("012|sas"), GetTestBytes(0), false, ErrSeparatorForListKey, nil)
   174  
   175  		for i := 0; i <= 100; i++ {
   176  			v := GetTestBytes(100 - i)
   177  			txPop(t, db, bucket, []byte("0"), v, nil, false)
   178  		}
   179  	})
   180  }
   181  
   182  func TestTx_LPop(t *testing.T) {
   183  	bucket := "bucket"
   184  
   185  	// Calling LPop on a non-existent list
   186  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   187  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   188  		txPop(t, db, bucket, GetTestBytes(0), nil, ErrListNotFound, true)
   189  	})
   190  
   191  	// Insert some values for a key and validate them by using LPop
   192  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   193  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   194  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, true)
   195  		for i := 0; i < 3; i++ {
   196  			txPop(t, db, bucket, GetTestBytes(0), GetTestBytes(2-i), nil, true)
   197  		}
   198  	})
   199  }
   200  
   201  func TestTx_RPop(t *testing.T) {
   202  	bucket := "bucket"
   203  
   204  	// Calling RPop on a non-existent list
   205  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   206  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   207  		txPop(t, db, bucket, GetTestBytes(0), nil, ErrListNotFound, false)
   208  	})
   209  
   210  	// Calling RPop on a list with added data
   211  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   212  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   213  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, false)
   214  
   215  		txPop(t, db, "fake_bucket", GetTestBytes(0), nil, ErrBucketNotExist, false)
   216  
   217  		for i := 0; i < 3; i++ {
   218  			txPop(t, db, bucket, GetTestBytes(0), GetTestBytes(2-i), nil, false)
   219  		}
   220  
   221  		txPop(t, db, bucket, GetTestBytes(0), nil, ErrEmptyList, false)
   222  	})
   223  }
   224  
   225  func TestTx_LRange(t *testing.T) {
   226  	bucket := "bucket"
   227  
   228  	// Calling LRange on a non-existent list
   229  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   230  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   231  
   232  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 0, nil, ErrListNotFound)
   233  	})
   234  
   235  	// Calling LRange on a list with added data
   236  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   237  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   238  
   239  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, true)
   240  
   241  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 3, [][]byte{
   242  			GetTestBytes(2), GetTestBytes(1), GetTestBytes(0),
   243  		}, nil)
   244  
   245  		for i := 0; i < 3; i++ {
   246  			txPop(t, db, bucket, GetTestBytes(0), GetTestBytes(2-i), nil, true)
   247  		}
   248  
   249  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 0, nil, nil)
   250  	})
   251  }
   252  
   253  func TestTx_LRem(t *testing.T) {
   254  	bucket := "bucket"
   255  
   256  	// Calling LRem on a non-existent list
   257  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   258  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   259  		txLRem(t, db, bucket, GetTestBytes(0), 1, GetTestBytes(0), ErrListNotFound)
   260  	})
   261  
   262  	// A basic calling for LRem
   263  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   264  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   265  
   266  		pushDataByStartEnd(t, db, bucket, 0, 0, 3, true)
   267  
   268  		txLRem(t, db, bucket, GetTestBytes(0), 1, GetTestBytes(0), nil)
   269  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 3, [][]byte{
   270  			GetTestBytes(3), GetTestBytes(2), GetTestBytes(1),
   271  		}, nil)
   272  		txLRem(t, db, bucket, GetTestBytes(0), 4, GetTestBytes(0), ErrCount)
   273  		txLRem(t, db, bucket, GetTestBytes(0), 1, GetTestBytes(1), nil)
   274  	})
   275  
   276  	// Calling LRem with count > 0
   277  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   278  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   279  
   280  		count := 3
   281  
   282  		pushDataByValues(t, db, bucket, 1, true, 0, 1, 0, 1, 0, 1, 0, 1)
   283  
   284  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 8, [][]byte{
   285  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   286  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   287  		}, nil)
   288  		txLRem(t, db, bucket, GetTestBytes(1), count, GetTestBytes(0), nil)
   289  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 5, [][]byte{
   290  			GetTestBytes(1), GetTestBytes(1), GetTestBytes(1), GetTestBytes(1), GetTestBytes(0),
   291  		}, nil)
   292  	})
   293  
   294  	// Calling LRem with count == 0
   295  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   296  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   297  		count := 0
   298  
   299  		pushDataByValues(t, db, bucket, 1, true, 0, 1, 0, 1, 0, 1, 0, 1)
   300  
   301  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 8, [][]byte{
   302  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   303  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   304  		}, nil)
   305  		txLRem(t, db, bucket, GetTestBytes(1), count, GetTestBytes(0), nil)
   306  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 4, [][]byte{
   307  			GetTestBytes(1), GetTestBytes(1), GetTestBytes(1), GetTestBytes(1),
   308  		}, nil)
   309  	})
   310  
   311  	// Calling LRem with count < 0
   312  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   313  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   314  
   315  		count := -3
   316  
   317  		pushDataByValues(t, db, bucket, 1, true, 0, 1, 0, 1, 0, 1, 0, 1)
   318  
   319  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 8, [][]byte{
   320  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   321  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(0),
   322  		}, nil)
   323  		txLRem(t, db, bucket, GetTestBytes(1), count, GetTestBytes(0), nil)
   324  		txLRange(t, db, bucket, GetTestBytes(1), 0, -1, 5, [][]byte{
   325  			GetTestBytes(1), GetTestBytes(0), GetTestBytes(1), GetTestBytes(1), GetTestBytes(1),
   326  		}, nil)
   327  	})
   328  }
   329  
   330  func TestTx_LTrim(t *testing.T) {
   331  	bucket := "bucket"
   332  
   333  	// Calling LTrim on a non-existent list
   334  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   335  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   336  		txLTrim(t, db, bucket, GetTestBytes(0), 0, 1, ErrListNotFound)
   337  	})
   338  
   339  	// Calling LTrim on a list with added data and use LRange to validate it
   340  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   341  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   342  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, true)
   343  		txLTrim(t, db, bucket, GetTestBytes(0), 0, 1, nil)
   344  
   345  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 2, [][]byte{
   346  			GetTestBytes(2), GetTestBytes(1),
   347  		}, nil)
   348  	})
   349  
   350  	// Calling LTrim with incorrect start and end
   351  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   352  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   353  
   354  		for i := 0; i < 3; i++ {
   355  			txPush(t, db, bucket, GetTestBytes(2), GetTestBytes(i), true, nil, nil)
   356  		}
   357  		txLTrim(t, db, bucket, GetTestBytes(2), 0, -10, ErrStartOrEnd)
   358  	})
   359  }
   360  
   361  func TestTx_LSize(t *testing.T) {
   362  	bucket := "bucket"
   363  
   364  	// Calling LSize on a non-existent list
   365  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   366  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   367  		txLSize(t, db, bucket, GetTestBytes(0), 0, ErrListNotFound)
   368  	})
   369  
   370  	// Calling LSize after adding some values
   371  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   372  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   373  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, false)
   374  		txLSize(t, db, bucket, GetTestBytes(0), 3, nil)
   375  	})
   376  }
   377  
   378  func TestTx_LRemByIndex(t *testing.T) {
   379  	bucket := "bucket"
   380  
   381  	// Calling LRemByIndex on a newly created empty list
   382  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   383  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   384  		txLRemByIndex(t, db, bucket, GetTestBytes(0), nil)
   385  	})
   386  
   387  	// Calling LRemByIndex with len(indexes) == 0
   388  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   389  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   390  		pushDataByValues(t, db, bucket, 0, true, 0)
   391  		txLRemByIndex(t, db, bucket, GetTestBytes(0), nil)
   392  	})
   393  
   394  	// Calling LRemByIndex with a expired bucket name
   395  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   396  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   397  		pushDataByValues(t, db, bucket, 0, true, 0)
   398  		txExpireList(t, db, bucket, GetTestBytes(0), 1, nil)
   399  		time.Sleep(3 * time.Second)
   400  		txLRemByIndex(t, db, bucket, GetTestBytes(0), ErrListNotFound)
   401  	})
   402  
   403  	// Calling LRemByIndex on a list with added data and use LRange to validate it
   404  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   405  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   406  		pushDataByStartEnd(t, db, bucket, 0, 0, 2, false)
   407  		txLRemByIndex(t, db, bucket, GetTestBytes(0), nil, 1, 0, 8, -8, 88, -88)
   408  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 1, [][]byte{
   409  			GetTestBytes(2),
   410  		}, nil)
   411  	})
   412  }
   413  
   414  func TestTx_ExpireList(t *testing.T) {
   415  	bucket := "bucket"
   416  
   417  	// Verify that the list with expiration time expires normally
   418  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   419  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   420  		pushDataByStartEnd(t, db, bucket, 0, 0, 3, false)
   421  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 4, [][]byte{
   422  			GetTestBytes(0), GetTestBytes(1), GetTestBytes(2), GetTestBytes(3),
   423  		}, nil)
   424  
   425  		txExpireList(t, db, bucket, GetTestBytes(0), 1, nil)
   426  		time.Sleep(time.Second)
   427  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 0, nil, ErrListNotFound)
   428  	})
   429  
   430  	// Verify that the list with persistent time
   431  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   432  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   433  		pushDataByStartEnd(t, db, bucket, 0, 0, 3, false)
   434  		txExpireList(t, db, bucket, GetTestBytes(0), Persistent, nil)
   435  		time.Sleep(time.Second)
   436  		txLRange(t, db, bucket, GetTestBytes(0), 0, -1, 4, [][]byte{
   437  			GetTestBytes(0), GetTestBytes(1), GetTestBytes(2), GetTestBytes(3),
   438  		}, nil)
   439  	})
   440  }
   441  
   442  func TestTx_LKeys(t *testing.T) {
   443  	bucket := "bucket"
   444  
   445  	// Calling LKeys after adding some keys
   446  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   447  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   448  		pushDataByValues(t, db, bucket, 10, false, 0)
   449  		pushDataByValues(t, db, bucket, 11, false, 1)
   450  		pushDataByValues(t, db, bucket, 12, false, 2)
   451  		pushDataByValues(t, db, bucket, 23, false, 3)
   452  
   453  		txLKeys(t, db, bucket, "*", 4, nil, func(keys []string) bool {
   454  			return true
   455  		})
   456  
   457  		txLKeys(t, db, bucket, "*", 2, nil, func(keys []string) bool {
   458  			return len(keys) != 2
   459  		})
   460  
   461  		txLKeys(t, db, bucket, "nutsdb-00000001*", 3, nil, func(keys []string) bool {
   462  			return true
   463  		})
   464  	})
   465  }
   466  
   467  func TestTx_GetListTTL(t *testing.T) {
   468  	bucket := "bucket"
   469  
   470  	// Verify TTL of list
   471  	runNutsDBTest(t, nil, func(t *testing.T, db *DB) {
   472  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   473  		pushDataByStartEnd(t, db, bucket, 0, 0, 3, false)
   474  
   475  		txGetListTTL(t, db, bucket, GetTestBytes(0), uint32(0), nil)
   476  		txExpireList(t, db, bucket, GetTestBytes(0), uint32(1), nil)
   477  		txGetListTTL(t, db, bucket, GetTestBytes(0), uint32(1), nil)
   478  
   479  		time.Sleep(3 * time.Second)
   480  		txGetListTTL(t, db, bucket, GetTestBytes(0), uint32(0), ErrListNotFound)
   481  	})
   482  }
   483  
   484  func TestTx_ListEntryIdxMode_HintKeyValAndRAMIdxMode(t *testing.T) {
   485  	bucket := "bucket"
   486  	key := GetTestBytes(0)
   487  
   488  	opts := DefaultOptions
   489  	opts.EntryIdxMode = HintKeyValAndRAMIdxMode
   490  
   491  	// HintKeyValAndRAMIdxMode
   492  	runNutsDBTest(t, &opts, func(t *testing.T, db *DB) {
   493  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   494  		err := db.Update(func(tx *Tx) error {
   495  			err := tx.LPush(bucket, key, []byte("d"), []byte("c"), []byte("b"), []byte("a"))
   496  			require.NoError(t, err)
   497  
   498  			return nil
   499  		})
   500  		require.NoError(t, err)
   501  
   502  		listIdx := db.Index.list.getWithDefault(1)
   503  		item, ok := listIdx.Items[string(key)].PopMin()
   504  		r := item.record
   505  		require.True(t, ok)
   506  		require.NotNil(t, r.Value)
   507  		require.Equal(t, []byte("a"), r.Value)
   508  	})
   509  }
   510  
   511  func TestTx_ListEntryIdxMode_HintKeyAndRAMIdxMode(t *testing.T) {
   512  	bucket := "bucket"
   513  	key := GetTestBytes(0)
   514  
   515  	opts := &DefaultOptions
   516  	opts.EntryIdxMode = HintKeyAndRAMIdxMode
   517  
   518  	// HintKeyAndRAMIdxMode
   519  	runNutsDBTest(t, opts, func(t *testing.T, db *DB) {
   520  		txCreateBucket(t, db, DataStructureList, bucket, nil)
   521  		err := db.Update(func(tx *Tx) error {
   522  			err := tx.LPush(bucket, key, []byte("d"), []byte("c"), []byte("b"), []byte("a"))
   523  			require.NoError(t, err)
   524  
   525  			return nil
   526  		})
   527  		require.NoError(t, err)
   528  
   529  		listIdx := db.Index.list.getWithDefault(1)
   530  		item, ok := listIdx.Items[string(key)].PopMin()
   531  		r := item.record
   532  		require.True(t, ok)
   533  		require.Nil(t, r.Value)
   534  
   535  		val, err := db.getValueByRecord(r)
   536  		require.NoError(t, err)
   537  		require.Equal(t, []byte("a"), val)
   538  	})
   539  }