2022-09-05 13:29:11 +08:00
|
|
|
package rootcoord
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2022-09-21 15:46:51 +08:00
|
|
|
"fmt"
|
2022-09-05 13:29:11 +08:00
|
|
|
"math/rand"
|
|
|
|
"testing"
|
2022-09-21 15:46:51 +08:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"go.uber.org/atomic"
|
2022-09-05 13:29:11 +08:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mockFailTask struct {
|
|
|
|
baseTaskV2
|
|
|
|
prepareErr error
|
|
|
|
executeErr error
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockFailTask() *mockFailTask {
|
|
|
|
task := &mockFailTask{
|
|
|
|
baseTaskV2: baseTaskV2{
|
|
|
|
ctx: context.Background(),
|
|
|
|
done: make(chan error, 1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
task.SetCtx(context.Background())
|
|
|
|
return task
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockPrepareFailTask() *mockFailTask {
|
|
|
|
task := newMockFailTask()
|
|
|
|
task.prepareErr = errors.New("error mock Prepare")
|
|
|
|
return task
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockExecuteFailTask() *mockFailTask {
|
|
|
|
task := newMockFailTask()
|
|
|
|
task.prepareErr = errors.New("error mock Execute")
|
|
|
|
return task
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m mockFailTask) Prepare(context.Context) error {
|
|
|
|
return m.prepareErr
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m mockFailTask) Execute(context.Context) error {
|
|
|
|
return m.executeErr
|
|
|
|
}
|
|
|
|
|
|
|
|
type mockNormalTask struct {
|
|
|
|
baseTaskV2
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockNormalTask() *mockNormalTask {
|
|
|
|
task := &mockNormalTask{
|
|
|
|
baseTaskV2: baseTaskV2{
|
|
|
|
ctx: context.Background(),
|
|
|
|
done: make(chan error, 1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
task.SetCtx(context.Background())
|
|
|
|
return task
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_scheduler_Start_Stop(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
s.Start()
|
|
|
|
s.Stop()
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_scheduler_failed_to_set_id(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 0, errors.New("error mock AllocOne")
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
task := newMockNormalTask()
|
|
|
|
err := s.AddTask(task)
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_scheduler_failed_to_set_ts(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 100, nil
|
|
|
|
}
|
|
|
|
tsoAlloc.GenerateTSOF = func(count uint32) (uint64, error) {
|
|
|
|
return 0, errors.New("error mock GenerateTSO")
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
task := newMockNormalTask()
|
|
|
|
err := s.AddTask(task)
|
|
|
|
assert.Error(t, err)
|
|
|
|
}
|
|
|
|
|
2022-09-21 15:46:51 +08:00
|
|
|
func Test_scheduler_enqueue_normal_case(t *testing.T) {
|
2022-09-05 13:29:11 +08:00
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 100, nil
|
|
|
|
}
|
|
|
|
tsoAlloc.GenerateTSOF = func(count uint32) (uint64, error) {
|
|
|
|
return 101, nil
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
s.Start()
|
|
|
|
defer s.Stop()
|
|
|
|
task := newMockNormalTask()
|
|
|
|
err := s.AddTask(task)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, UniqueID(100), task.GetID())
|
|
|
|
assert.Equal(t, Timestamp(101), task.GetTs())
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_scheduler_bg(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 100, nil
|
|
|
|
}
|
|
|
|
tsoAlloc.GenerateTSOF = func(count uint32) (uint64, error) {
|
|
|
|
return 101, nil
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
s.Start()
|
|
|
|
|
|
|
|
n := 10
|
|
|
|
tasks := make([]taskV2, 0, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
which := rand.Int() % 3
|
|
|
|
switch which {
|
|
|
|
case 0:
|
|
|
|
tasks = append(tasks, newMockPrepareFailTask())
|
|
|
|
case 1:
|
|
|
|
tasks = append(tasks, newMockExecuteFailTask())
|
|
|
|
default:
|
|
|
|
tasks = append(tasks, newMockNormalTask())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, task := range tasks {
|
|
|
|
s.AddTask(task)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, task := range tasks {
|
|
|
|
err := task.WaitToFinish()
|
|
|
|
switch task.(type) {
|
|
|
|
case *mockFailTask:
|
|
|
|
assert.Error(t, err)
|
|
|
|
case *mockNormalTask:
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Stop()
|
|
|
|
}
|
2022-09-21 15:46:51 +08:00
|
|
|
|
|
|
|
func Test_scheduler_updateDdlMinTsLoop(t *testing.T) {
|
|
|
|
t.Run("normal case", func(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
tso := atomic.NewUint64(100)
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 100, nil
|
|
|
|
}
|
|
|
|
tsoAlloc.GenerateTSOF = func(count uint32) (uint64, error) {
|
|
|
|
got := tso.Inc()
|
|
|
|
return got, nil
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
Params.InitOnce()
|
|
|
|
Params.ProxyCfg.TimeTickInterval = time.Millisecond
|
|
|
|
s.Start()
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 4)
|
|
|
|
|
|
|
|
// add task to queue.
|
|
|
|
n := 10
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
task := newMockNormalTask()
|
|
|
|
err := s.AddTask(task)
|
|
|
|
assert.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 4)
|
|
|
|
s.Stop()
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("invalid tso", func(t *testing.T) {
|
|
|
|
idAlloc := newMockIDAllocator()
|
|
|
|
tsoAlloc := newMockTsoAllocator()
|
|
|
|
idAlloc.AllocOneF = func() (UniqueID, error) {
|
|
|
|
return 100, nil
|
|
|
|
}
|
|
|
|
tsoAlloc.GenerateTSOF = func(count uint32) (uint64, error) {
|
|
|
|
return 0, fmt.Errorf("error mock GenerateTSO")
|
|
|
|
}
|
|
|
|
ctx := context.Background()
|
|
|
|
s := newScheduler(ctx, idAlloc, tsoAlloc)
|
|
|
|
Params.InitOnce()
|
|
|
|
Params.ProxyCfg.TimeTickInterval = time.Millisecond
|
|
|
|
s.Start()
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 4)
|
|
|
|
s.Stop()
|
|
|
|
})
|
|
|
|
}
|