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 }