1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
|
// Copyright 2014 Wandoujia Inc. All Rights Reserved.
// Licensed under the MIT (MIT-LICENSE.txt) license.
package rdb
import (
"bytes"
"encoding/hex"
"fmt"
"math"
"strconv"
"strings"
"testing"
)
func AssertNoError(t *testing.T, err error) {
if err == nil {
return
}
t.Fatal(err)
}
func Assert(t *testing.T, b bool) {
if b {
return
}
t.Fatal("assertion failed")
}
func DecodeHexRdb(t *testing.T, s string, n int) map[string]*Entry {
p, err := hex.DecodeString(strings.NewReplacer("\t", "", "\r", "", "\n", "", " ", "").Replace(s))
AssertNoError(t, err)
r := bytes.NewReader(p)
l := NewLoader(r)
AssertNoError(t, l.LoadHeader())
entries := make(map[string]*Entry)
var i int = 0
for {
e, err := l.LoadEntry()
AssertNoError(t, err)
if e == nil {
break
}
Assert(t, e.DB == 0)
entries[string(e.Key)] = e
i++
}
AssertNoError(t, l.LoadChecksum())
Assert(t, r.Len() == 0)
Assert(t, len(entries) == i && i == n)
return entries
}
func getobj(t *testing.T, entries map[string]*Entry, key string) (*Entry, interface{}) {
e := entries[key]
Assert(t, e != nil)
val, err := DecodeDump(e.ValDump)
AssertNoError(t, err)
return e, val
}
/*
#!/bin/bash
./redis-cli flushall
for i in 1 255 256 65535 65536 2147483647 2147483648 4294967295 4294967296 -2147483648; do
./redis-cli set string_${i} ${i}
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadIntString(t *testing.T) {
s := `
524544495330303036fe00000a737472696e675f323535c1ff00000873747269
6e675f31c0010011737472696e675f343239343936373239360a343239343936
373239360011737472696e675f343239343936373239350a3432393439363732
39350012737472696e675f2d32313437343833363438c200000080000c737472
696e675f3635353335c2ffff00000011737472696e675f323134373438333634
380a32313437343833363438000c737472696e675f3635353336c20000010000
0a737472696e675f323536c100010011737472696e675f323134373438333634
37c2ffffff7fffe49d9f131fb5c3b5
`
values := []int{1, 255, 256, 65535, 65536, 2147483647, 2147483648, 4294967295, 4294967296, -2147483648}
entries := DecodeHexRdb(t, s, len(values))
for _, value := range values {
key := fmt.Sprintf("string_%d", value)
_, obj := getobj(t, entries, key)
val := obj.(String)
Assert(t, bytes.Equal([]byte(val), []byte(strconv.Itoa(value))))
}
}
/*
#!/bin/bash
./redis-cli flushall
./redis-cli set string_ttls string_ttls
./redis-cli expireat string_ttls 1500000000
./redis-cli set string_ttlms string_ttlms
./redis-cli pexpireat string_ttlms 1500000000000
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadStringTTL(t *testing.T) {
s := `
524544495330303036fe00fc0098f73e5d010000000c737472696e675f74746c
6d730c737472696e675f74746c6d73fc0098f73e5d010000000b737472696e67
5f74746c730b737472696e675f74746c73ffd15acd935a3fe949
`
expireat := uint64(1500000000000)
entries := DecodeHexRdb(t, s, 2)
keys := []string{"string_ttls", "string_ttlms"}
for _, key := range keys {
e, obj := getobj(t, entries, key)
val := obj.(String)
Assert(t, bytes.Equal([]byte(val), []byte(key)))
Assert(t, e.ExpireAt == expireat)
}
}
/*
#!/bin/bash
s="01"
for ((i=0;i<15;i++)); do
s=$s$s
done
./redis-cli flushall
./redis-cli set string_long $s
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadLongString(t *testing.T) {
s := `
524544495330303036fe00000b737472696e675f6c6f6e67c342f28000010000
02303130e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff
01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0
ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01e0ff01
e0ff01e0ff01e0ff01e0ff01e03201013031ffdfdb02bd6d5da5e6
`
entries := DecodeHexRdb(t, s, 1)
_, obj := getobj(t, entries, "string_long")
val := []byte(obj.(String))
for i := 0; i < (1 << 15); i++ {
var c uint8 = '0'
if i%2 != 0 {
c = '1'
}
Assert(t, val[i] == c)
}
}
/*
#!/bin/bash
./redis-cli flushall
for ((i=0;i<256;i++)); do
./redis-cli rpush list_lzf 0
./redis-cli rpush list_lzf 1
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadListZipmap(t *testing.T) {
s := `
524544495330303036fe000a086c6973745f6c7a66c31f440b040b0400000820
0306000200f102f202e0ff03e1ff07e1ff07e1d90701f2ffff6a1c2d51c02301
16
`
entries := DecodeHexRdb(t, s, 1)
_, obj := getobj(t, entries, "list_lzf")
val := obj.(List)
Assert(t, len(val) == 512)
for i := 0; i < 256; i++ {
var s string = "0"
if i%2 != 0 {
s = "1"
}
Assert(t, string(val[i]) == s)
}
}
/*
#!/bin/bash
./redis-cli flushall
for ((i=0;i<32;i++)); do
./redis-cli rpush list ${i}
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadList(t *testing.T) {
s := `
524544495330303036fe0001046c69737420c000c001c002c003c004c005c006
c007c008c009c00ac00bc00cc00dc00ec00fc010c011c012c013c014c015c016
c017c018c019c01ac01bc01cc01dc01ec01fff756ea1fa90adefe3
`
entries := DecodeHexRdb(t, s, 1)
_, obj := getobj(t, entries, "list")
val := obj.(List)
Assert(t, len(val) == 32)
for i := 0; i < 32; i++ {
Assert(t, string(val[i]) == strconv.Itoa(i))
}
}
/*
#!/bin/bash
./redis-cli flushall
for ((i=0;i<16;i++)); do
./redis-cli sadd set1 ${i}
done
for ((i=0;i<32;i++)); do
./redis-cli sadd set2 ${i}
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadSetAndSetIntset(t *testing.T) {
s := `
524544495330303036fe0002047365743220c016c00dc01bc012c01ac004c014
c002c017c01dc01cc013c019c01ec008c006c000c001c007c00fc009c01fc00e
c003c00ac015c010c00bc018c011c00cc0050b04736574312802000000100000
0000000100020003000400050006000700080009000a000b000c000d000e000f
00ff3a0a9697324d19c3
`
entries := DecodeHexRdb(t, s, 2)
_, obj1 := getobj(t, entries, "set1")
val1 := obj1.(Set)
set1 := make(map[string]bool)
for _, mem := range val1 {
set1[string(mem)] = true
}
Assert(t, len(set1) == 16)
Assert(t, len(set1) == len(val1))
for i := 0; i < 16; i++ {
_, ok := set1[strconv.Itoa(i)]
Assert(t, ok)
}
_, obj2 := getobj(t, entries, "set2")
val2 := obj2.(Set)
set2 := make(map[string]bool)
for _, mem := range val2 {
set2[string(mem)] = true
}
Assert(t, len(set2) == 32)
Assert(t, len(set2) == len(val2))
for i := 0; i < 32; i++ {
_, ok := set2[strconv.Itoa(i)]
Assert(t, ok)
}
}
/*
#!/bin/bash
./redis-cli flushall
for ((i=0;i<16;i++)); do
./redis-cli hset hash1 ${i}
done
for ((i=-16;i<16;i++)); do
./redis-cli hset hash2 ${i}
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadHashAndHashZiplist(t *testing.T) {
s := `
524544495330303036fe000405686173683220c00dc00dc0fcc0fcc0ffc0ffc0
04c004c002c002c0fbc0fbc0f0c0f0c0f9c0f9c008c008c0fac0fac006c006c0
00c000c001c001c0fec0fec007c007c0f6c0f6c00fc00fc009c009c0f7c0f7c0
fdc0fdc0f1c0f1c0f2c0f2c0f3c0f3c00ec00ec003c003c00ac00ac00bc00bc0
f8c0f8c00cc00cc0f5c0f5c0f4c0f4c005c0050d056861736831405151000000
4d000000200000f102f102f202f202f302f302f402f402f502f502f602f602f7
02f702f802f802f902f902fa02fa02fb02fb02fc02fc02fd02fd02fe0d03fe0d
03fe0e03fe0e03fe0f03fe0fffffa423d3036c15e534
`
entries := DecodeHexRdb(t, s, 2)
_, obj1 := getobj(t, entries, "hash1")
val1 := obj1.(Hash)
hash1 := make(map[string]string)
for _, ent := range val1 {
hash1[string(ent.Field)] = string(ent.Value)
}
Assert(t, len(hash1) == 16)
Assert(t, len(hash1) == len(val1))
for i := 0; i < 16; i++ {
s := strconv.Itoa(i)
Assert(t, hash1[s] == s)
}
_, obj2 := getobj(t, entries, "hash2")
val2 := obj2.(Hash)
hash2 := make(map[string]string)
for _, ent := range val2 {
hash2[string(ent.Field)] = string(ent.Value)
}
Assert(t, len(hash2) == 32)
Assert(t, len(hash2) == len(val2))
for i := -16; i < 16; i++ {
s := strconv.Itoa(i)
Assert(t, hash2[s] == s)
}
}
/*
#!/bin/bash
./redis-cli flushall
for ((i=0;i<16;i++)); do
./redis-cli zadd zset1 ${i} ${i}
done
for ((i=0;i<32;i++)); do
./redis-cli zadd zset2 -${i} ${i}
done
./redis-cli save && xxd -p -c 32 dump.rdb
*/
func TestLoadZSetAndZSetZiplist(t *testing.T) {
s := `
524544495330303036fe0003057a7365743220c016032d3232c00d032d3133c0
1b032d3237c012032d3138c01a032d3236c004022d34c014032d3230c002022d
32c017032d3233c01d032d3239c01c032d3238c013032d3139c019032d3235c0
1e032d3330c008022d38c006022d36c000022d30c001022d31c007022d37c009
022d39c00f032d3135c01f032d3331c00e032d3134c003022d33c00a032d3130
c015032d3231c010032d3136c00b032d3131c018032d3234c011032d3137c00c
032d3132c005022d350c057a736574314051510000004d000000200000f102f1
02f202f202f302f302f402f402f502f502f602f602f702f702f802f802f902f9
02fa02fa02fb02fb02fc02fc02fd02fd02fe0d03fe0d03fe0e03fe0e03fe0f03
fe0fffff2addedbf4f5a8f93
`
entries := DecodeHexRdb(t, s, 2)
_, obj1 := getobj(t, entries, "zset1")
val1 := obj1.(ZSet)
zset1 := make(map[string]float64)
for _, ent := range val1 {
zset1[string(ent.Member)] = ent.Score
}
Assert(t, len(zset1) == 16)
Assert(t, len(zset1) == len(val1))
for i := 0; i < 16; i++ {
s := strconv.Itoa(i)
score, ok := zset1[s]
Assert(t, ok)
Assert(t, math.Abs(score-float64(i)) < 1e-10)
}
_, obj2 := getobj(t, entries, "zset2")
val2 := obj2.(ZSet)
zset2 := make(map[string]float64)
for _, ent := range val2 {
zset2[string(ent.Member)] = ent.Score
}
Assert(t, len(zset2) == 32)
Assert(t, len(zset2) == len(val2))
for i := 0; i < 32; i++ {
s := strconv.Itoa(i)
score, ok := zset2[s]
Assert(t, ok)
Assert(t, math.Abs(score+float64(i)) < 1e-10)
}
}
|