2023-02-22 11:37:45 +08:00
|
|
|
// Licensed to the LF AI & Data foundation under one
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
// distributed with this work for additional information
|
|
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
|
|
// to you under the Apache License, Version 2.0 (the
|
|
|
|
// "License"); you may not use this file except in compliance
|
|
|
|
// with the License. You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2022-09-05 13:29:11 +08:00
|
|
|
package rootcoord
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
2023-02-26 11:31:49 +08:00
|
|
|
"github.com/cockroachdb/errors"
|
2022-09-05 13:29:11 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mockFailStep struct {
|
2022-09-21 15:46:51 +08:00
|
|
|
baseStep
|
2022-09-05 13:29:11 +08:00
|
|
|
calledChan chan struct{}
|
|
|
|
called bool
|
2022-09-21 15:46:51 +08:00
|
|
|
err error
|
2022-09-05 13:29:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func newMockFailStep() *mockFailStep {
|
|
|
|
return &mockFailStep{calledChan: make(chan struct{}, 1), called: false}
|
|
|
|
}
|
|
|
|
|
2022-09-21 15:46:51 +08:00
|
|
|
func (m *mockFailStep) Execute(ctx context.Context) ([]nestedStep, error) {
|
2022-09-05 13:29:11 +08:00
|
|
|
m.called = true
|
|
|
|
m.calledChan <- struct{}{}
|
2022-09-21 15:46:51 +08:00
|
|
|
if m.err != nil {
|
|
|
|
return nil, m.err
|
|
|
|
}
|
|
|
|
return nil, errors.New("error mock Execute")
|
2022-09-05 13:29:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
type mockNormalStep struct {
|
2022-09-21 15:46:51 +08:00
|
|
|
nestedStep
|
2022-09-05 13:29:11 +08:00
|
|
|
calledChan chan struct{}
|
|
|
|
called bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newMockNormalStep() *mockNormalStep {
|
|
|
|
return &mockNormalStep{calledChan: make(chan struct{}, 1), called: false}
|
|
|
|
}
|
|
|
|
|
2022-09-21 15:46:51 +08:00
|
|
|
func (m *mockNormalStep) Execute(ctx context.Context) ([]nestedStep, error) {
|
2022-09-05 13:29:11 +08:00
|
|
|
m.called = true
|
|
|
|
m.calledChan <- struct{}{}
|
2022-09-21 15:46:51 +08:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func newTestRedoTask() *baseRedoTask {
|
|
|
|
stepExecutor := newMockStepExecutor()
|
|
|
|
stepExecutor.AddStepsFunc = func(s *stepStack) {
|
|
|
|
// no schedule, execute directly.
|
|
|
|
s.Execute(context.Background())
|
|
|
|
}
|
|
|
|
redo := newBaseRedoTask(stepExecutor)
|
|
|
|
return redo
|
2022-09-05 13:29:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func Test_baseRedoTask_redoAsyncSteps(t *testing.T) {
|
|
|
|
t.Run("partial error", func(t *testing.T) {
|
2022-09-21 15:46:51 +08:00
|
|
|
redo := newTestRedoTask()
|
|
|
|
steps := []nestedStep{newMockNormalStep(), newMockFailStep(), newMockNormalStep()}
|
2022-09-05 13:29:11 +08:00
|
|
|
for _, step := range steps {
|
|
|
|
redo.AddAsyncStep(step)
|
|
|
|
}
|
|
|
|
redo.redoAsyncSteps()
|
|
|
|
assert.True(t, steps[0].(*mockNormalStep).called)
|
|
|
|
assert.False(t, steps[2].(*mockNormalStep).called)
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("normal case", func(t *testing.T) {
|
2022-09-21 15:46:51 +08:00
|
|
|
redo := newTestRedoTask()
|
2022-09-05 13:29:11 +08:00
|
|
|
n := 10
|
2022-09-21 15:46:51 +08:00
|
|
|
steps := make([]nestedStep, 0, n)
|
2022-09-05 13:29:11 +08:00
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
steps = append(steps, newMockNormalStep())
|
|
|
|
}
|
|
|
|
for _, step := range steps {
|
|
|
|
redo.AddAsyncStep(step)
|
|
|
|
}
|
|
|
|
redo.redoAsyncSteps()
|
|
|
|
for _, step := range steps {
|
|
|
|
assert.True(t, step.(*mockNormalStep).called)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_baseRedoTask_Execute(t *testing.T) {
|
|
|
|
t.Run("sync not finished, no async task", func(t *testing.T) {
|
2022-09-21 15:46:51 +08:00
|
|
|
redo := newTestRedoTask()
|
|
|
|
syncSteps := []nestedStep{newMockFailStep()}
|
2022-09-05 13:29:11 +08:00
|
|
|
asyncNum := 10
|
2022-09-21 15:46:51 +08:00
|
|
|
asyncSteps := make([]nestedStep, 0, asyncNum)
|
2022-09-05 13:29:11 +08:00
|
|
|
for i := 0; i < asyncNum; i++ {
|
|
|
|
asyncSteps = append(asyncSteps, newMockNormalStep())
|
|
|
|
}
|
|
|
|
for _, step := range asyncSteps {
|
|
|
|
redo.AddAsyncStep(step)
|
|
|
|
}
|
|
|
|
for _, step := range syncSteps {
|
|
|
|
redo.AddSyncStep(step)
|
|
|
|
}
|
|
|
|
err := redo.Execute(context.Background())
|
|
|
|
assert.Error(t, err)
|
|
|
|
for _, step := range asyncSteps {
|
|
|
|
assert.False(t, step.(*mockNormalStep).called)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// TODO: sync finished, but some async fail.
|
|
|
|
|
|
|
|
t.Run("normal case", func(t *testing.T) {
|
2022-09-21 15:46:51 +08:00
|
|
|
redo := newTestRedoTask()
|
2022-09-05 13:29:11 +08:00
|
|
|
syncNum := 10
|
2022-09-21 15:46:51 +08:00
|
|
|
syncSteps := make([]nestedStep, 0, syncNum)
|
2022-09-05 13:29:11 +08:00
|
|
|
asyncNum := 10
|
2022-09-21 15:46:51 +08:00
|
|
|
asyncSteps := make([]nestedStep, 0, asyncNum)
|
2022-09-05 13:29:11 +08:00
|
|
|
for i := 0; i < syncNum; i++ {
|
|
|
|
syncSteps = append(syncSteps, newMockNormalStep())
|
|
|
|
}
|
|
|
|
for i := 0; i < asyncNum; i++ {
|
|
|
|
asyncSteps = append(asyncSteps, newMockNormalStep())
|
|
|
|
}
|
|
|
|
for _, step := range asyncSteps {
|
|
|
|
redo.AddAsyncStep(step)
|
|
|
|
}
|
|
|
|
for _, step := range syncSteps {
|
|
|
|
redo.AddSyncStep(step)
|
|
|
|
}
|
|
|
|
err := redo.Execute(context.Background())
|
|
|
|
assert.NoError(t, err)
|
|
|
|
for _, step := range asyncSteps {
|
|
|
|
<-step.(*mockNormalStep).calledChan
|
|
|
|
assert.True(t, step.(*mockNormalStep).called)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|