github.com/adowair/kvdb@v0.0.0-20231101174258-ceca93b03596/kv/ops_test.go (about) 1 package kv_test 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/adowair/kvdb/kv" 10 "github.com/stretchr/testify/assert" 11 ) 12 13 // testcase runs as a subtest of the top-level test in this file. Each 14 // testcase consists of a series of operations to be executed. The returns 15 // from each operation are compared to some expected values. 16 type testcase struct { 17 name string 18 steps []step 19 } 20 21 // step encapsulates the run of a single command, its expected outputs 22 // and the assertion that its outputs match the expectation. 23 type step struct { 24 run func(*testing.T, *expReturns) 25 expReturns 26 } 27 28 // expReturns encapsulates possible returns for any operation. All fields 29 // are optional depending on the operation being tested, except for `expError`. 30 type expReturns struct { 31 err error 32 value string 33 firstSet time.Time 34 lastSet time.Time 35 } 36 37 var ( 38 time0 = time.Unix(0, 0) 39 time1 = time.Unix(1, 0) 40 ) 41 42 func testGet(key string) func(*testing.T, *expReturns) { 43 return func(t *testing.T, r *expReturns) { 44 value, err := kv.Get(key) 45 assert.ErrorIs(t, err, r.err) 46 assert.Equal(t, r.value, value) 47 } 48 } 49 50 func testSet(key, val string, now time.Time) func(*testing.T, *expReturns) { 51 return func(t *testing.T, r *expReturns) { 52 err := kv.Set(key, val, now) 53 assert.ErrorIs(t, err, r.err) 54 } 55 } 56 57 func testTimestamp(key string) func(*testing.T, *expReturns) { 58 return func(t *testing.T, r *expReturns) { 59 firstSet, lastSet, err := kv.Timestamps(key) 60 assert.ErrorIs(t, err, r.err) 61 assert.Equal(t, r.firstSet, firstSet, "firstSet") 62 assert.Equal(t, r.lastSet, lastSet, "lastSet") 63 } 64 } 65 66 func testDelete(key string) func(*testing.T, *expReturns) { 67 return func(t *testing.T, r *expReturns) { 68 err := kv.Delete(key) 69 assert.ErrorIs(t, err, r.err) 70 } 71 } 72 73 func TestKVOps(t *testing.T) { 74 for _, tc := range []testcase{ 75 { 76 name: "TestGetNotExist", 77 steps: []step{ 78 { 79 run: testGet("a"), 80 expReturns: expReturns{err: kv.ErrNotExist}, 81 }, 82 }, 83 }, 84 { 85 name: "TestDoubleGetNotExist", 86 steps: []step{ 87 { 88 run: testGet("a"), 89 expReturns: expReturns{err: kv.ErrNotExist}, 90 }, 91 { 92 run: testGet("b"), 93 expReturns: expReturns{err: kv.ErrNotExist}, 94 }, 95 }, 96 }, 97 { 98 name: "TestSetGet", 99 steps: []step{ 100 { 101 run: testSet("a", "12", time0), 102 expReturns: expReturns{err: nil}, 103 }, 104 { 105 run: testGet("a"), 106 expReturns: expReturns{err: nil, value: "12"}, 107 }, 108 { 109 run: testSet("b", "13", time0), 110 expReturns: expReturns{err: nil}, 111 }, 112 { 113 run: testGet("b"), 114 expReturns: expReturns{err: nil, value: "13"}, 115 }, 116 { 117 run: testSet("a", "14", time1), 118 expReturns: expReturns{err: nil}, 119 }, 120 { 121 run: testGet("a"), 122 expReturns: expReturns{err: nil, value: "14"}, 123 }, 124 }, 125 }, 126 { 127 name: "TestSetTS", 128 steps: []step{ 129 { 130 run: testSet("a", "12", time0), 131 expReturns: expReturns{err: nil}, 132 }, 133 { 134 run: testTimestamp("a"), 135 expReturns: expReturns{err: nil, firstSet: time0, lastSet: time0}, 136 }, 137 { 138 run: testSet("b", "13", time1), 139 expReturns: expReturns{err: nil}, 140 }, 141 { 142 run: testTimestamp("b"), 143 expReturns: expReturns{err: nil, firstSet: time1, lastSet: time1}, 144 }, 145 { 146 run: testSet("a", "13", time1), 147 expReturns: expReturns{err: nil}, 148 }, 149 { 150 run: testTimestamp("a"), 151 expReturns: expReturns{err: nil, firstSet: time0, lastSet: time1}, 152 }, 153 }, 154 }, 155 { 156 name: "TestDeleteTS", 157 steps: []step{ 158 { 159 run: testSet("a", "12", time0), 160 expReturns: expReturns{err: nil}, 161 }, 162 { 163 run: testDelete("a"), 164 expReturns: expReturns{err: nil}, 165 }, 166 { 167 run: testTimestamp("a"), 168 expReturns: expReturns{err: kv.ErrNotExist}, 169 }, 170 }, 171 }, 172 { 173 name: "TestDeleteGet", 174 steps: []step{ 175 { 176 run: testSet("a", "12", time0), 177 expReturns: expReturns{err: nil}, 178 }, 179 { 180 run: testDelete("a"), 181 expReturns: expReturns{err: nil}, 182 }, 183 { 184 run: testGet("a"), 185 expReturns: expReturns{err: kv.ErrNotExist}, 186 }, 187 }, 188 }, 189 } { 190 t.Run(tc.name, func(t *testing.T) { 191 dir := t.TempDir() 192 assert.NoError(t, os.Chdir(dir)) 193 for i, step := range tc.steps { 194 t.Run(fmt.Sprintf("TestStep%d", i), func(t *testing.T) { 195 step.run(t, &step.expReturns) 196 }) 197 } 198 }) 199 } 200 }