github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/lsmkv/strategies_map_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package lsmkv 13 14 import ( 15 "testing" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestMapEncoderDecoderJourney(t *testing.T) { 22 // this test first encodes the map pairs, then decodes them and replace 23 // duplicates, remove tombstones, etc. 24 type test struct { 25 name string 26 in []MapPair 27 out []MapPair 28 } 29 30 tests := []test{ 31 { 32 name: "single pair", 33 in: []MapPair{ 34 { 35 Key: []byte("foo"), 36 Value: []byte("bar"), 37 }, 38 }, 39 out: []MapPair{ 40 { 41 Key: []byte("foo"), 42 Value: []byte("bar"), 43 }, 44 }, 45 }, 46 { 47 name: "single pair, updated value", 48 in: []MapPair{ 49 { 50 Key: []byte("foo"), 51 Value: []byte("bar"), 52 }, 53 { 54 Key: []byte("foo"), 55 Value: []byte("bar2"), 56 }, 57 }, 58 out: []MapPair{ 59 { 60 Key: []byte("foo"), 61 Value: []byte("bar2"), 62 }, 63 }, 64 }, 65 { 66 name: "single pair, tombstone added", 67 in: []MapPair{ 68 { 69 Key: []byte("foo"), 70 Value: []byte("bar"), 71 }, 72 { 73 Key: []byte("foo"), 74 Tombstone: true, 75 }, 76 }, 77 out: []MapPair{}, 78 }, 79 { 80 name: "single pair, tombstone added, same value added again", 81 in: []MapPair{ 82 { 83 Key: []byte("foo"), 84 Value: []byte("bar"), 85 }, 86 { 87 Key: []byte("foo"), 88 Tombstone: true, 89 }, 90 { 91 Key: []byte("foo"), 92 Value: []byte("bar2"), 93 }, 94 }, 95 out: []MapPair{ 96 { 97 Key: []byte("foo"), 98 Value: []byte("bar2"), 99 }, 100 }, 101 }, 102 { 103 name: "multiple values, combination of updates and tombstones", 104 in: []MapPair{ 105 { 106 Key: []byte("foo"), 107 Value: []byte("never-updated"), 108 }, 109 { 110 Key: []byte("foo1"), 111 Value: []byte("bar1"), 112 }, 113 { 114 Key: []byte("foo2"), 115 Value: []byte("bar2"), 116 }, 117 { 118 Key: []byte("foo2"), 119 Value: []byte("bar2.2"), 120 }, 121 { 122 Key: []byte("foo1"), 123 Tombstone: true, 124 }, 125 { 126 Key: []byte("foo2"), 127 Value: []byte("bar2.3"), 128 }, 129 { 130 Key: []byte("foo1"), 131 Value: []byte("bar1.2"), 132 }, 133 }, 134 out: []MapPair{ 135 { 136 Key: []byte("foo"), 137 Value: []byte("never-updated"), 138 }, 139 { 140 Key: []byte("foo1"), 141 Value: []byte("bar1.2"), 142 }, 143 { 144 Key: []byte("foo2"), 145 Value: []byte("bar2.3"), 146 }, 147 }, 148 }, 149 } 150 151 for _, test := range tests { 152 t.Run(test.name, func(t *testing.T) { 153 encoded := make([]value, len(test.in)) 154 for i, kv := range test.in { 155 enc, err := newMapEncoder().Do(kv) 156 require.Nil(t, err) 157 encoded[i] = enc[0] 158 } 159 res, err := newMapDecoder().Do(encoded, false) 160 require.Nil(t, err) 161 // NOTE: we are accepting that the order can be lost on updates 162 assert.ElementsMatch(t, test.out, res) 163 }) 164 } 165 } 166 167 func TestDecoderRemoveTombstones(t *testing.T) { 168 t.Run("single entry, no tombstones", func(t *testing.T) { 169 m := newMapDecoder() 170 input := mustEncode([]MapPair{ 171 { 172 Key: []byte("hello"), 173 Value: []byte("world"), 174 }, 175 }) 176 177 actual, err := m.doSimplified(input) 178 require.Nil(t, err) 179 180 expected := []MapPair{ 181 { 182 Key: []byte("hello"), 183 Value: []byte("world"), 184 }, 185 } 186 assert.Equal(t, expected, actual) 187 }) 188 189 t.Run("single entry, single tombstone", func(t *testing.T) { 190 m := newMapDecoder() 191 input := mustEncode([]MapPair{ 192 { 193 Key: []byte("hello"), 194 Value: []byte("world"), 195 }, 196 { 197 Key: []byte("hello"), 198 Tombstone: true, 199 }, 200 }) 201 202 actual, err := m.doSimplified(input) 203 require.Nil(t, err) 204 205 expected := []MapPair{} 206 assert.Equal(t, expected, actual) 207 }) 208 209 t.Run("single entry, single tombstone, then read", func(t *testing.T) { 210 m := newMapDecoder() 211 input := mustEncode([]MapPair{ 212 { 213 Key: []byte("hello"), 214 Value: []byte("world"), 215 }, 216 { 217 Key: []byte("hello"), 218 Tombstone: true, 219 }, 220 { 221 Key: []byte("hello"), 222 Value: []byte("world"), 223 }, 224 }) 225 226 actual, err := m.doSimplified(input) 227 require.Nil(t, err) 228 229 expected := []MapPair{ 230 { 231 Key: []byte("hello"), 232 Value: []byte("world"), 233 }, 234 } 235 assert.Equal(t, expected, actual) 236 }) 237 238 t.Run("three entries, two tombstones at the end", func(t *testing.T) { 239 m := newMapDecoder() 240 input := mustEncode([]MapPair{ 241 { 242 Key: []byte("hello"), 243 Value: []byte("world"), 244 }, 245 { 246 Key: []byte("bonjour"), 247 Value: []byte("world"), 248 }, 249 { 250 Key: []byte("guten tag"), 251 Value: []byte("world"), 252 }, 253 { 254 Key: []byte("hello"), 255 Tombstone: true, 256 }, 257 { 258 Key: []byte("bonjour"), 259 Tombstone: true, 260 }, 261 }) 262 263 actual, err := m.doSimplified(input) 264 require.Nil(t, err) 265 266 expected := []MapPair{ 267 { 268 Key: []byte("guten tag"), 269 Value: []byte("world"), 270 }, 271 } 272 assert.Equal(t, expected, actual) 273 }) 274 275 t.Run("three entries, two tombstones at the end, then recreate the first", func(t *testing.T) { 276 m := newMapDecoder() 277 input := mustEncode([]MapPair{ 278 { 279 Key: []byte("hello"), 280 Value: []byte("world"), 281 }, 282 { 283 Key: []byte("bonjour"), 284 Value: []byte("world"), 285 }, 286 { 287 Key: []byte("guten tag"), 288 Value: []byte("world"), 289 }, 290 { 291 Key: []byte("hello"), 292 Tombstone: true, 293 }, 294 { 295 Key: []byte("bonjour"), 296 Tombstone: true, 297 }, 298 { 299 Key: []byte("bonjour"), 300 Value: []byte("world"), 301 }, 302 { 303 Key: []byte("hello"), 304 Value: []byte("world"), 305 }, 306 }) 307 308 actual, err := m.doSimplified(input) 309 require.Nil(t, err) 310 311 expected := []MapPair{ 312 { 313 Key: []byte("guten tag"), 314 Value: []byte("world"), 315 }, 316 { 317 Key: []byte("bonjour"), 318 Value: []byte("world"), 319 }, 320 { 321 Key: []byte("hello"), 322 Value: []byte("world"), 323 }, 324 } 325 assert.Equal(t, expected, actual) 326 }) 327 } 328 329 func mustEncode(kvs []MapPair) []value { 330 res, err := newMapEncoder().DoMulti(kvs) 331 if err != nil { 332 panic(err) 333 } 334 335 return res 336 } 337 338 func Test_MapPair_EncodingBytes(t *testing.T) { 339 kv := MapPair{ 340 Key: []byte("hello-world-key1"), 341 Value: []byte("this is the value ;-)"), 342 } 343 344 control, err := kv.Bytes() 345 assert.Nil(t, err) 346 347 encoded := make([]byte, kv.Size()) 348 err = kv.EncodeBytes(encoded) 349 assert.Nil(t, err) 350 351 assert.Equal(t, control, encoded) 352 }