github.com/matrixorigin/matrixone@v0.7.0/pkg/hakeeper/task/task_scheduler_test.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package task 16 17 import ( 18 "context" 19 "testing" 20 21 "github.com/matrixorigin/matrixone/pkg/common/runtime" 22 "github.com/matrixorigin/matrixone/pkg/hakeeper" 23 "github.com/matrixorigin/matrixone/pkg/logutil" 24 pb "github.com/matrixorigin/matrixone/pkg/pb/logservice" 25 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 26 "github.com/matrixorigin/matrixone/pkg/pb/task" 27 "github.com/matrixorigin/matrixone/pkg/taskservice" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 func TestMain(m *testing.M) { 32 logutil.SetupMOLogger(&logutil.LogConfig{ 33 Level: "debug", 34 Format: "console", 35 }) 36 37 runtime.SetupProcessLevelRuntime(runtime.NewRuntime(metadata.ServiceType_LOG, "test", logutil.GetGlobalLogger())) 38 m.Run() 39 } 40 41 func TestGetExpiredTasks(t *testing.T) { 42 cases := []struct { 43 tasks []task.Task 44 expiredCN []string 45 46 expected []task.Task 47 }{ 48 { 49 tasks: nil, 50 expiredCN: nil, 51 52 expected: nil, 53 }, 54 { 55 tasks: []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}}, 56 expiredCN: []string{"a"}, 57 58 expected: []task.Task{{TaskRunner: "a"}}, 59 }, 60 } 61 62 for _, c := range cases { 63 results := getExpiredTasks(c.tasks, c.expiredCN) 64 assert.Equal(t, c.expected, results) 65 } 66 } 67 68 func TestGetCNOrderedMap(t *testing.T) { 69 cases := []struct { 70 tasks []task.Task 71 workingCN []string 72 73 expected *cnMap 74 }{ 75 { 76 tasks: nil, 77 workingCN: nil, 78 79 expected: newOrderedMap(nil), 80 }, 81 { 82 tasks: []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}, {TaskRunner: "b"}}, 83 workingCN: []string{"a", "b"}, 84 85 expected: &cnMap{ 86 m: map[string]uint32{"a": 1, "b": 2}, 87 orderedKeys: []string{"a", "b"}, 88 }, 89 }, 90 { 91 tasks: []task.Task{{TaskRunner: "a"}, {TaskRunner: "b"}, {TaskRunner: "a"}, {TaskRunner: "a"}}, 92 workingCN: []string{"a", "b"}, 93 94 expected: &cnMap{ 95 m: map[string]uint32{"a": 3, "b": 1}, 96 orderedKeys: []string{"b", "a"}, 97 }, 98 }, 99 } 100 101 for _, c := range cases { 102 results := getCNOrdered(c.tasks, c.workingCN) 103 assert.Equal(t, c.expected, results) 104 } 105 } 106 107 func TestScheduleCreatedTasks(t *testing.T) { 108 service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage()) 109 scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{}) 110 cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}} 111 currentTick := uint64(0) 112 113 // Schedule empty task 114 scheduler.Schedule(cnState, currentTick) 115 116 // Create Task 1 117 assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "1"})) 118 query, err := service.QueryTask(context.Background()) 119 assert.NoError(t, err) 120 assert.Equal(t, task.TaskStatus_Created, query[0].Status) 121 122 // Schedule Task 1 123 scheduler.Schedule(cnState, currentTick) 124 125 query, err = service.QueryTask(context.Background()) 126 assert.NoError(t, err) 127 assert.Equal(t, "a", query[0].TaskRunner) 128 assert.Equal(t, task.TaskStatus_Running, query[0].Status) 129 130 // Create Task 2 131 assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "2"})) 132 query, err = service.QueryTask(context.Background(), 133 taskservice.WithTaskStatusCond(taskservice.EQ, task.TaskStatus_Created)) 134 assert.NoError(t, err) 135 assert.Equal(t, 1, len(query)) 136 assert.NotNil(t, query[0].Status) 137 138 // Add CNStore "b" 139 cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}, "b": {}}} 140 141 // Schedule Task 2 142 scheduler.Schedule(cnState, currentTick) 143 144 query, err = service.QueryTask(context.Background(), taskservice.WithTaskRunnerCond(taskservice.EQ, "b")) 145 assert.NoError(t, err) 146 assert.NotNil(t, query) 147 assert.Equal(t, task.TaskStatus_Running, query[0].Status) 148 } 149 150 func TestReallocateExpiredTasks(t *testing.T) { 151 service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage()) 152 scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{}) 153 cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}} 154 currentTick := expiredTick - 1 155 156 // Create Task 1 157 assert.NoError(t, service.Create(context.Background(), task.TaskMetadata{ID: "1"})) 158 query, err := service.QueryTask(context.Background()) 159 assert.NoError(t, err) 160 assert.Equal(t, task.TaskStatus_Created, query[0].Status) 161 162 // Schedule Task 1 on "a" 163 scheduler.Schedule(cnState, currentTick) 164 165 query, err = service.QueryTask(context.Background()) 166 assert.NoError(t, err) 167 assert.Equal(t, 1, len(query)) 168 assert.Equal(t, "a", query[0].TaskRunner) 169 assert.Equal(t, task.TaskStatus_Running, query[0].Status) 170 171 // Make CNStore "a" expired 172 cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}} 173 currentTick = expiredTick + 1 174 175 // Re-schedule Task 1 176 // Since no other CN available, task 1 remains on CN "a" 177 scheduler.Schedule(cnState, currentTick) 178 179 query, err = service.QueryTask(context.Background()) 180 assert.NoError(t, err) 181 assert.Equal(t, 1, len(query)) 182 assert.Equal(t, "a", query[0].TaskRunner) 183 assert.Equal(t, task.TaskStatus_Running, query[0].Status) 184 185 // Add CNStore "b" 186 cnState = pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}, "b": {Tick: expiredTick}}} 187 188 // Re-schedule Task 1 189 // "b" available 190 scheduler.Schedule(cnState, currentTick) 191 192 query, err = service.QueryTask(context.Background()) 193 assert.NoError(t, err) 194 assert.Equal(t, 1, len(query)) 195 assert.Equal(t, "b", query[0].TaskRunner) 196 assert.Equal(t, task.TaskStatus_Running, query[0].Status) 197 } 198 199 func TestSchedulerCreateTasks(t *testing.T) { 200 service := taskservice.NewTaskService(runtime.DefaultRuntime(), taskservice.NewMemTaskStorage()) 201 scheduler := NewScheduler(func() taskservice.TaskService { return service }, hakeeper.Config{}) 202 cnState := pb.CNState{Stores: map[string]pb.CNStoreInfo{"a": {}}} 203 currentTick := uint64(0) 204 205 assert.NoError(t, scheduler.Create(context.Background(), 206 []task.TaskMetadata{{ID: "1"}})) 207 208 // Schedule empty task 209 scheduler.Schedule(cnState, currentTick) 210 }