2020-02-14 23:01:42 +00:00
|
|
|
package batcher
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2020-02-16 13:24:43 +00:00
|
|
|
"go.uber.org/goleak"
|
2020-02-14 23:01:42 +00:00
|
|
|
|
2024-06-05 17:36:34 +00:00
|
|
|
"gitlab.com/slon/shad-go/batcher/slow"
|
2020-02-14 23:01:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestSimple(t *testing.T) {
|
2020-02-16 13:24:43 +00:00
|
|
|
defer goleak.VerifyNone(t)
|
|
|
|
|
2020-02-14 23:01:42 +00:00
|
|
|
var value slow.Value
|
|
|
|
b := NewBatcher(&value)
|
|
|
|
|
|
|
|
value.Store(1)
|
|
|
|
require.Equal(t, 1, b.Load())
|
|
|
|
require.Equal(t, 1, value.Load())
|
|
|
|
|
|
|
|
value.Store(2)
|
|
|
|
require.Equal(t, 2, b.Load())
|
|
|
|
require.Equal(t, 2, value.Load())
|
|
|
|
}
|
|
|
|
|
2020-04-03 00:15:41 +00:00
|
|
|
func TestTwoParallelLoads(t *testing.T) {
|
|
|
|
defer goleak.VerifyNone(t)
|
|
|
|
var value slow.Value
|
|
|
|
b := NewBatcher(&value)
|
|
|
|
|
|
|
|
value.Store(1)
|
|
|
|
go func() {
|
|
|
|
require.Equal(t, 1, b.Load())
|
|
|
|
}()
|
|
|
|
require.Equal(t, 1, b.Load())
|
|
|
|
}
|
|
|
|
|
2020-02-14 23:01:42 +00:00
|
|
|
func TestStaleRead(t *testing.T) {
|
2020-02-16 13:24:43 +00:00
|
|
|
defer goleak.VerifyNone(t)
|
|
|
|
|
2020-02-14 23:01:42 +00:00
|
|
|
const (
|
|
|
|
N = 100
|
|
|
|
K = 100
|
|
|
|
M = 10
|
|
|
|
)
|
|
|
|
|
|
|
|
var value slow.Value
|
|
|
|
b := NewBatcher(&value)
|
|
|
|
|
|
|
|
var counter int32
|
|
|
|
value.Store(counter)
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
go func(i int) {
|
|
|
|
defer wg.Done()
|
|
|
|
|
2020-04-03 08:53:06 +00:00
|
|
|
time.Sleep(time.Duration(i) * time.Millisecond / time.Duration(N))
|
2020-02-14 23:01:42 +00:00
|
|
|
for j := 0; j < K; j++ {
|
|
|
|
counterValue := atomic.LoadInt32(&counter)
|
|
|
|
batcherValue := b.Load().(int32)
|
|
|
|
|
|
|
|
if batcherValue < counterValue {
|
|
|
|
t.Errorf("load returned old value: counter=%d, batcher=%d", counterValue, batcherValue)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(i)
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < M*K; i++ {
|
|
|
|
// value is always greater than counter
|
|
|
|
value.Store(int32(i))
|
|
|
|
atomic.StoreInt32(&counter, int32(i))
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond / M)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2021-03-05 11:54:34 +00:00
|
|
|
var race = false
|
|
|
|
|
2020-02-14 23:01:42 +00:00
|
|
|
func TestSpeed(t *testing.T) {
|
2021-03-05 11:54:34 +00:00
|
|
|
if race {
|
|
|
|
t.Skip("this test fails under race detector because of timing issues")
|
|
|
|
}
|
|
|
|
|
2020-02-16 13:24:43 +00:00
|
|
|
defer goleak.VerifyNone(t)
|
|
|
|
|
2020-02-14 23:01:42 +00:00
|
|
|
const (
|
|
|
|
N = 100
|
|
|
|
K = 200
|
|
|
|
)
|
|
|
|
|
|
|
|
var value slow.Value
|
|
|
|
b := NewBatcher(&value)
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < N; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
for i := 0; i < K; i++ {
|
|
|
|
b.Load()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
require.Truef(t, time.Since(start) < time.Second, "batching it too slow")
|
|
|
|
}
|