Files
eventbus2/cowmap_test.go

238 lines
4.1 KiB
Go

package eventbus
import (
"strconv"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
func Test_NewCowMap(t *testing.T) {
m := NewCowMap()
assert.NotNil(t, m)
}
func Test_CowMapLoad(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
for i := 0; i < 100; i++ {
val, ok := m.Load(i)
assert.True(t, ok)
assert.Equal(t, strconv.Itoa(i), val.(string))
}
val, ok := m.Load(999999)
assert.False(t, ok)
assert.Equal(t, nil, val)
}
func Test_CowMapStore(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
assert.Equal(t, uint32(100), m.Len())
}
func Test_CowMapDelete(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
for i := 0; i < 50; i++ {
m.Delete(i)
}
for i := 0; i < 50; i++ {
val, ok := m.Load(i)
assert.False(t, ok)
assert.Equal(t, nil, val)
}
for i := 50; i < 100; i++ {
val, ok := m.Load(i)
assert.True(t, ok)
assert.Equal(t, strconv.Itoa(i), val.(string))
}
}
func Test_CowMapClear(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
m.Clear()
assert.Equal(t, uint32(0), m.Len())
}
func Test_CowMapLen(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
assert.Equal(t, uint32(100), m.Len())
}
func Test_CowMapRange(t *testing.T) {
m := NewCowMap()
expert := make([]bool, 100)
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
m.Range(func(key any, value any) bool {
if value.(string) == strconv.Itoa(key.(int)) {
expert[key.(int)] = true
}
return true
})
for _, val := range expert {
assert.True(t, val)
}
}
func Test_CowMapRangeStop(t *testing.T) {
m := NewCowMap()
results := make([]bool, 100)
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
count := 0
m.Range(func(key any, value any) bool {
// only range ten elements and then stop range
if count >= 10 {
return false
}
count++
if value.(string) == strconv.Itoa(key.(int)) {
results[key.(int)] = true
}
return true
})
expert := 0
for _, val := range results {
if val {
expert++
}
}
assert.Equal(t, count, expert)
}
func Test_CowMapConcurrentLoadPanic(t *testing.T) {
m := NewCowMap()
assert.NotPanics(t, func() {
for i := 0; i < 100; i++ {
go func() {
for j := 0; j < 100; j++ {
m.Store(j, strconv.Itoa(j))
}
}()
}
})
}
func Test_CowMapConcurrentStorePanic(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, strconv.Itoa(i))
}
assert.NotPanics(t, func() {
for i := 0; i < 100; i++ {
go func() {
for j := 0; j < 100; j++ {
m.Load(j)
}
}()
}
})
}
func Test_CowMapStoreOrLoadConcurrent(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, i)
}
storewg := sync.WaitGroup{}
storewg.Add(100)
assert.NotPanics(t, func() {
for i := 0; i < 100; i++ {
go func(index int) {
for j := index * 100; j < (index+1)*100; j++ {
m.Store(j, j)
}
storewg.Done()
}(i)
}
})
storewg.Wait()
loadwg := sync.WaitGroup{}
loadwg.Add(100)
assert.NotPanics(t, func() {
for i := 0; i < 100; i++ {
go func(index int) {
for j := index * 100; j < (index+1)*100; j++ {
val, ok := m.Load(j)
assert.True(t, ok)
assert.Equal(t, j, val)
}
loadwg.Done()
}(i)
}
})
loadwg.Wait()
}
func Test_CowMapStoreAndLoadConcurrent(t *testing.T) {
m := NewCowMap()
for i := 0; i < 100; i++ {
m.Store(i, i)
}
assert.NotPanics(t, func() {
loadGoroutineSize := 100
loadWg := sync.WaitGroup{}
loadWg.Add(loadGoroutineSize)
for i := 0; i < loadGoroutineSize; i++ {
go func() {
for j := 0; j < 100; j++ {
val, ok := m.Load(j)
assert.True(t, ok)
assert.Equal(t, j, val)
}
loadWg.Done()
}()
}
storeGoroutineSize := 100
storeWg := sync.WaitGroup{}
storeWg.Add(storeGoroutineSize)
for i := 0; i < storeGoroutineSize; i++ {
go func(index int) {
for j := 0; j < 100; j++ {
m.Store(j, j)
}
storeWg.Done()
}(i)
}
storeWg.Wait()
loadWg.Wait()
})
}