Files
redis-go/datastruct/dict/concurrent_test.go
finley bf7f628810 raft cluster
wip: raft does not care about migrating

wip: optimize code

wip: raft election

wip

wip: fix raft leader missing log entries

wip

fix a dead lock

batch set slot route

wip: raft persist

wip

refactor cluster suite

remove relay

rename relay2

refactor: allow customizing client factory

test raft

refactor re-balance

avoid errors caused by inconsistent status on follower nodes during raft commits

test raft election
2023-06-10 22:48:24 +08:00

291 lines
7.1 KiB
Go

package dict
import (
"github.com/hdt3213/godis/lib/utils"
"strconv"
"sync"
"testing"
)
func TestConcurrentPut(t *testing.T) {
d := MakeConcurrent(0)
count := 100
var wg sync.WaitGroup
wg.Add(count)
for i := 0; i < count; i++ {
go func(i int) {
// insert
key := "k" + strconv.Itoa(i)
ret := d.Put(key, i)
if ret != 1 { // insert 1
t.Error("put test failed: expected result 1, actual: " + strconv.Itoa(ret) + ", key: " + key)
}
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal) + ", key: " + key)
}
} else {
_, ok := d.Get(key)
t.Error("put test failed: expected true, actual: false, key: " + key + ", retry: " + strconv.FormatBool(ok))
}
wg.Done()
}(i)
}
wg.Wait()
}
func TestConcurrentPutIfAbsent(t *testing.T) {
d := MakeConcurrent(0)
count := 100
var wg sync.WaitGroup
wg.Add(count)
for i := 0; i < count; i++ {
go func(i int) {
// insert
key := "k" + strconv.Itoa(i)
ret := d.PutIfAbsent(key, i)
if ret != 1 { // insert 1
t.Error("put test failed: expected result 1, actual: " + strconv.Itoa(ret) + ", key: " + key)
}
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal) +
", key: " + key)
}
} else {
_, ok := d.Get(key)
t.Error("put test failed: expected true, actual: false, key: " + key + ", retry: " + strconv.FormatBool(ok))
}
// update
ret = d.PutIfAbsent(key, i*10)
if ret != 0 { // no update
t.Error("put test failed: expected result 0, actual: " + strconv.Itoa(ret))
}
val, ok = d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal) + ", key: " + key)
}
} else {
t.Error("put test failed: expected true, actual: false, key: " + key)
}
wg.Done()
}(i)
}
wg.Wait()
}
func TestConcurrentPutIfExists(t *testing.T) {
d := MakeConcurrent(0)
count := 100
var wg sync.WaitGroup
wg.Add(count)
for i := 0; i < count; i++ {
go func(i int) {
// insert
key := "k" + strconv.Itoa(i)
// insert
ret := d.PutIfExists(key, i)
if ret != 0 { // insert
t.Error("put test failed: expected result 0, actual: " + strconv.Itoa(ret))
}
d.Put(key, i)
d.PutIfExists(key, 10*i)
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != 10*i {
t.Error("put test failed: expected " + strconv.Itoa(10*i) + ", actual: " + strconv.Itoa(intVal))
}
} else {
_, ok := d.Get(key)
t.Error("put test failed: expected true, actual: false, key: " + key + ", retry: " + strconv.FormatBool(ok))
}
wg.Done()
}(i)
}
wg.Wait()
}
func TestConcurrentRemove(t *testing.T) {
d := MakeConcurrent(0)
totalCount := 100
// remove head node
for i := 0; i < totalCount; i++ {
// insert
key := "k" + strconv.Itoa(i)
d.Put(key, i)
}
if d.Len() != totalCount {
t.Error("put test failed: expected len is 100, actual: " + strconv.Itoa(d.Len()))
}
for i := 0; i < totalCount; i++ {
key := "k" + strconv.Itoa(i)
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal))
}
} else {
t.Error("put test failed: expected true, actual: false")
}
_, ret := d.Remove(key)
if ret != 1 {
t.Error("remove test failed: expected result 1, actual: " + strconv.Itoa(ret) + ", key:" + key)
}
if d.Len() != totalCount-i-1 {
t.Error("put test failed: expected len is 99, actual: " + strconv.Itoa(d.Len()))
}
_, ok = d.Get(key)
if ok {
t.Error("remove test failed: expected true, actual false")
}
_, ret = d.Remove(key)
if ret != 0 {
t.Error("remove test failed: expected result 0 actual: " + strconv.Itoa(ret))
}
if d.Len() != totalCount-i-1 {
t.Error("put test failed: expected len is 99, actual: " + strconv.Itoa(d.Len()))
}
}
// remove tail node
d = MakeConcurrent(0)
for i := 0; i < 100; i++ {
// insert
key := "k" + strconv.Itoa(i)
d.Put(key, i)
}
for i := 9; i >= 0; i-- {
key := "k" + strconv.Itoa(i)
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal))
}
} else {
t.Error("put test failed: expected true, actual: false")
}
_, ret := d.Remove(key)
if ret != 1 {
t.Error("remove test failed: expected result 1, actual: " + strconv.Itoa(ret))
}
_, ok = d.Get(key)
if ok {
t.Error("remove test failed: expected true, actual false")
}
_, ret = d.Remove(key)
if ret != 0 {
t.Error("remove test failed: expected result 0 actual: " + strconv.Itoa(ret))
}
}
// remove middle node
d = MakeConcurrent(0)
d.Put("head", 0)
for i := 0; i < 10; i++ {
// insert
key := "k" + strconv.Itoa(i)
d.Put(key, i)
}
d.Put("tail", 0)
for i := 9; i >= 0; i-- {
key := "k" + strconv.Itoa(i)
val, ok := d.Get(key)
if ok {
intVal, _ := val.(int)
if intVal != i {
t.Error("put test failed: expected " + strconv.Itoa(i) + ", actual: " + strconv.Itoa(intVal))
}
} else {
t.Error("put test failed: expected true, actual: false")
}
_, ret := d.Remove(key)
if ret != 1 {
t.Error("remove test failed: expected result 1, actual: " + strconv.Itoa(ret))
}
_, ok = d.Get(key)
if ok {
t.Error("remove test failed: expected true, actual false")
}
_, ret = d.Remove(key)
if ret != 0 {
t.Error("remove test failed: expected result 0 actual: " + strconv.Itoa(ret))
}
}
}
func TestConcurrentForEach(t *testing.T) {
d := MakeConcurrent(0)
size := 100
for i := 0; i < size; i++ {
// insert
key := "k" + strconv.Itoa(i)
d.Put(key, i)
}
i := 0
d.ForEach(func(key string, value interface{}) bool {
intVal, _ := value.(int)
expectedKey := "k" + strconv.Itoa(intVal)
if key != expectedKey {
t.Error("remove test failed: expected " + expectedKey + ", actual: " + key)
}
i++
return true
})
if i != size {
t.Error("remove test failed: expected " + strconv.Itoa(size) + ", actual: " + strconv.Itoa(i))
}
}
func TestConcurrentRandomKey(t *testing.T) {
d := MakeConcurrent(0)
count := 100
for i := 0; i < count; i++ {
key := "k" + strconv.Itoa(i)
d.Put(key, i)
}
fetchSize := 10
result := d.RandomKeys(fetchSize)
if len(result) != fetchSize {
t.Errorf("expect %d random keys acturally %d", fetchSize, len(result))
}
result = d.RandomDistinctKeys(fetchSize)
distinct := make(map[string]struct{})
for _, key := range result {
distinct[key] = struct{}{}
}
if len(result) != fetchSize {
t.Errorf("expect %d random keys acturally %d", fetchSize, len(result))
}
if len(result) > len(distinct) {
t.Errorf("get duplicated keys in result")
}
}
func TestConcurrentDict_Keys(t *testing.T) {
d := MakeConcurrent(0)
size := 10
for i := 0; i < size; i++ {
d.Put(utils.RandString(5), utils.RandString(5))
}
if len(d.Keys()) != size {
t.Errorf("expect %d keys, actual: %d", size, len(d.Keys()))
}
}