github.com/projecteru2/core@v0.0.0-20240321043226-06bcc1c23f58/wal/kv/lithium_test.go (about)

     1  package kv
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestSet(t *testing.T) {
    16  	lit, cancel := newTestLithium(t)
    17  	defer cancel()
    18  	require.NoError(t, lit.Put([]byte("key"), []byte("value")))
    19  }
    20  
    21  func TestGet(t *testing.T) {
    22  	lit, cancel := newTestLithium(t)
    23  	defer cancel()
    24  
    25  	key := []byte("key")
    26  	value := []byte("value")
    27  	require.NoError(t, lit.Put(key, value))
    28  
    29  	act, err := lit.Get(key)
    30  	require.NoError(t, err)
    31  	require.Equal(t, value, act)
    32  }
    33  
    34  func TestDelete(t *testing.T) {
    35  	lit, cancel := newTestLithium(t)
    36  	defer cancel()
    37  
    38  	key := []byte("key")
    39  	value := []byte("value")
    40  	require.NoError(t, lit.Put(key, value))
    41  
    42  	act, err := lit.Get(key)
    43  	require.NoError(t, err)
    44  	require.Equal(t, value, act)
    45  
    46  	// deletes the key
    47  	require.NoError(t, lit.Delete(key))
    48  
    49  	act, err = lit.Get(key)
    50  	require.NoError(t, err)
    51  	require.Equal(t, []byte{}, act)
    52  }
    53  
    54  func TestScan(t *testing.T) {
    55  	lit, cancel := newTestLithium(t)
    56  	defer cancel()
    57  
    58  	key := []byte("/p1/key")
    59  	value := []byte("value")
    60  	require.NoError(t, lit.Put(key, value))
    61  	require.NoError(t, lit.Put([]byte("/p2/key"), value))
    62  
    63  	ch, _ := lit.Scan([]byte("/p1/"))
    64  	require.Equal(t, LithiumScanEntry{key: key, value: value}, <-ch)
    65  	require.Nil(t, <-ch)
    66  }
    67  
    68  func TestScanAbort(t *testing.T) {
    69  	lit, cancel := newTestLithium(t)
    70  	defer cancel()
    71  
    72  	for i := 0; i < 10; i++ {
    73  		key := []byte(fmt.Sprintf("p%d", i))
    74  		require.NoError(t, lit.Put(key, []byte("v")))
    75  	}
    76  
    77  	ch, abort := lit.Scan([]byte("p"))
    78  	abort()
    79  
    80  	// before the above abort() has been finished, the scanned key/value pair
    81  	// had sent to ch already, then the code tries to recv again to make sure the
    82  	// ch had been closed.
    83  	if real := <-ch; real != nil {
    84  		require.Nil(t, <-ch)
    85  	}
    86  }
    87  
    88  func TestNextSequence(t *testing.T) {
    89  	lit, cancel := newTestLithium(t)
    90  	defer cancel()
    91  
    92  	seq0, err := lit.NextSequence()
    93  	require.NoError(t, err)
    94  	require.True(t, seq0 > 0)
    95  
    96  	seq1, err := lit.NextSequence()
    97  	require.NoError(t, err)
    98  	require.True(t, seq1 > seq0)
    99  
   100  	// Closes and Reopens
   101  	require.NoError(t, lit.Reopen())
   102  
   103  	seq2, err := lit.NextSequence()
   104  	require.NoError(t, err)
   105  	require.True(t, seq2 > seq1)
   106  }
   107  
   108  func TestScanOrderedByKeys(t *testing.T) {
   109  	lit, cancel := newTestLithium(t)
   110  	defer cancel()
   111  
   112  	// put by descending order.
   113  	for i := 0xf; i > 0; i-- {
   114  		key := []byte(fmt.Sprintf("/events/%016x", i))
   115  		require.NoError(t, lit.Put(key, []byte("v")))
   116  	}
   117  
   118  	var last uint64
   119  	// asserts read by ascending order.
   120  	ch, _ := lit.Scan([]byte("/events/"))
   121  	for ent := range ch {
   122  		require.NoError(t, ent.Error())
   123  
   124  		key, _ := ent.Pair()
   125  		raw := strings.TrimLeft(strings.TrimPrefix(string(key), "/events/"), "0")
   126  
   127  		id, err := strconv.ParseUint(raw, 16, 64)
   128  		require.NoError(t, err)
   129  		require.True(t, id > last)
   130  
   131  		last = id
   132  	}
   133  }
   134  
   135  func newTestLithium(t *testing.T) (lit *Lithium, cancel func()) {
   136  	path := "/tmp/lithium.unitest.wal"
   137  	os.Remove(path)
   138  
   139  	lit = NewLithium()
   140  	require.NoError(t, lit.Open(path, 0666, time.Second))
   141  
   142  	cancel = func() {
   143  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   144  		defer cancel()
   145  
   146  		closed := make(chan struct{})
   147  		go func() {
   148  			defer close(closed)
   149  			require.NoError(t, lit.Close())
   150  		}()
   151  
   152  		select {
   153  		case <-ctx.Done():
   154  			require.FailNow(t, "close error: %s", ctx.Err())
   155  		case <-closed:
   156  		}
   157  	}
   158  
   159  	return
   160  }