github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/framework/mock_master_util.go (about) 1 // Copyright 2022 PingCAP, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package framework 15 16 // This file provides helper function to let the implementation of MasterImpl 17 // can finish its unit tests. 18 19 import ( 20 "context" 21 "encoding/json" 22 "testing" 23 24 "github.com/golang/mock/gomock" 25 pb "github.com/pingcap/tiflow/engine/enginepb" 26 "github.com/pingcap/tiflow/engine/framework/metadata" 27 frameModel "github.com/pingcap/tiflow/engine/framework/model" 28 "github.com/pingcap/tiflow/engine/framework/statusutil" 29 "github.com/pingcap/tiflow/engine/model" 30 "github.com/pingcap/tiflow/engine/pkg/client" 31 "github.com/pingcap/tiflow/engine/pkg/clock" 32 dcontext "github.com/pingcap/tiflow/engine/pkg/context" 33 "github.com/pingcap/tiflow/engine/pkg/deps" 34 resModel "github.com/pingcap/tiflow/engine/pkg/externalresource/model" 35 metaMock "github.com/pingcap/tiflow/engine/pkg/meta/mock" 36 pkgOrm "github.com/pingcap/tiflow/engine/pkg/orm" 37 "github.com/pingcap/tiflow/engine/pkg/p2p" 38 "github.com/pingcap/tiflow/engine/pkg/tenant" 39 "github.com/pingcap/tiflow/pkg/errors" 40 "github.com/pingcap/tiflow/pkg/uuid" 41 "github.com/stretchr/testify/require" 42 ) 43 44 // MockBaseMaster returns a mock DefaultBaseMaster 45 func MockBaseMaster(t *testing.T, id frameModel.MasterID, masterImpl MasterImpl) *DefaultBaseMaster { 46 ctx := dcontext.Background() 47 dp := deps.NewDeps() 48 cli, err := pkgOrm.NewMockClient() 49 require.NoError(t, err) 50 err = dp.Provide(func() masterParamListForTest { 51 return masterParamListForTest{ 52 MessageHandlerManager: p2p.NewMockMessageHandlerManager(), 53 MessageSender: p2p.NewMockMessageSender(), 54 FrameMetaClient: cli, 55 BusinessClientConn: metaMock.NewMockClientConn(), 56 ExecutorGroup: client.NewMockExecutorGroup(), 57 ServerMasterClient: client.NewMockServerMasterClient(gomock.NewController(t)), 58 } 59 }) 60 require.NoError(t, err) 61 62 ctx = ctx.WithDeps(dp) 63 ctx.Environ.NodeID = "test-node-id" 64 ctx.Environ.Addr = "127.0.0.1:10000" 65 ctx.ProjectInfo = tenant.TestProjectInfo 66 epoch, err := cli.GenEpoch(ctx) 67 require.NoError(t, err) 68 masterMeta := &frameModel.MasterMeta{ 69 ProjectID: tenant.TestProjectInfo.UniqueID(), 70 Addr: ctx.Environ.Addr, 71 NodeID: ctx.Environ.NodeID, 72 ID: id, 73 Type: frameModel.FakeJobMaster, 74 Epoch: epoch, 75 State: frameModel.MasterStateUninit, 76 } 77 masterMetaBytes, err := masterMeta.Marshal() 78 require.NoError(t, err) 79 ctx.Environ.MasterMetaBytes = masterMetaBytes 80 81 ret := NewBaseMaster( 82 ctx, 83 masterImpl, 84 id, 85 frameModel.FakeTask, 86 ) 87 88 return ret.(*DefaultBaseMaster) 89 } 90 91 // MockMasterPrepareMeta simulates the meta persistence for MockMasterImpl 92 func MockMasterPrepareMeta(ctx context.Context, t *testing.T, master *MockMasterImpl) { 93 err := master.GetFrameMetaClient().UpsertJob( 94 ctx, master.DefaultBaseMaster.MasterMeta()) 95 require.NoError(t, err) 96 } 97 98 // MockBaseMasterCreateWorker mocks to create worker in base master 99 func MockBaseMasterCreateWorker( 100 t *testing.T, 101 master *DefaultBaseMaster, 102 workerType frameModel.WorkerType, 103 config WorkerConfig, 104 masterID frameModel.MasterID, 105 workerID frameModel.WorkerID, 106 executorID model.ExecutorID, 107 resources []resModel.ResourceID, 108 workerEpoch frameModel.Epoch, 109 ) { 110 master.uuidGen = uuid.NewMock() 111 expectedSchedulerReq := &pb.ScheduleTaskRequest{ 112 TaskId: workerID, 113 Resources: resModel.ToResourceRequirement(masterID, resources...), 114 } 115 master.serverMasterClient.(*client.MockServerMasterClient).EXPECT(). 116 ScheduleTask(gomock.Any(), gomock.Eq(expectedSchedulerReq)). 117 Return(&pb.ScheduleTaskResponse{ 118 ExecutorId: string(executorID), 119 }, nil).Times(1) 120 121 mockExecutorClient := client.NewMockExecutorClient(gomock.NewController(t)) 122 master.executorGroup.(*client.MockExecutorGroup).AddClient(executorID, mockExecutorClient) 123 configBytes, err := json.Marshal(config) 124 require.NoError(t, err) 125 126 mockExecutorClient.EXPECT().DispatchTask(gomock.Any(), 127 gomock.Eq(&client.DispatchTaskArgs{ 128 ProjectInfo: tenant.TestProjectInfo, 129 WorkerID: workerID, 130 MasterID: masterID, 131 WorkerType: int64(workerType), 132 WorkerConfig: configBytes, 133 WorkerEpoch: workerEpoch, 134 }), gomock.Any()).Do( 135 func( 136 ctx context.Context, 137 args *client.DispatchTaskArgs, 138 start client.StartWorkerCallback, 139 ) { 140 start() 141 }).Times(1).Return(nil) 142 143 master.uuidGen.(*uuid.MockGenerator).Push(workerID) 144 } 145 146 // MockBaseMasterCreateWorkerMetScheduleTaskError mocks ScheduleTask meets error 147 func MockBaseMasterCreateWorkerMetScheduleTaskError( 148 t *testing.T, 149 master *DefaultBaseMaster, 150 workerType frameModel.WorkerType, 151 config WorkerConfig, 152 masterID frameModel.MasterID, 153 workerID frameModel.WorkerID, 154 executorID model.ExecutorID, 155 ) { 156 master.uuidGen = uuid.NewMock() 157 expectedSchedulerReq := &pb.ScheduleTaskRequest{ 158 TaskId: workerID, 159 } 160 master.serverMasterClient.(*client.MockServerMasterClient).EXPECT(). 161 ScheduleTask(gomock.Any(), gomock.Eq(expectedSchedulerReq)). 162 Return(nil, errors.ErrClusterResourceNotEnough.FastGenByArgs()). 163 Times(1) 164 165 master.uuidGen.(*uuid.MockGenerator).Push(workerID) 166 } 167 168 // MockBaseMasterWorkerHeartbeat sends HeartbeatPingMessage with mock message handler 169 func MockBaseMasterWorkerHeartbeat( 170 t *testing.T, 171 master *DefaultBaseMaster, 172 masterID frameModel.MasterID, 173 workerID frameModel.WorkerID, 174 executorID p2p.NodeID, 175 ) error { 176 worker, ok := master.workerManager.GetWorkers()[workerID] 177 if !ok { 178 return errors.ErrWorkerNotFound.GenWithStackByArgs(workerID) 179 } 180 workerEpoch := worker.Status().Epoch 181 err := master.messageHandlerManager.(*p2p.MockMessageHandlerManager).InvokeHandler( 182 t, 183 frameModel.HeartbeatPingTopic(masterID), 184 executorID, 185 &frameModel.HeartbeatPingMessage{ 186 SendTime: clock.MonoNow(), 187 FromWorkerID: workerID, 188 Epoch: master.currentEpoch.Load(), 189 WorkerEpoch: workerEpoch, 190 }) 191 return err 192 } 193 194 // MockBaseMasterWorkerUpdateStatus mocks to store status in metastore and sends 195 // WorkerStatusMessage. 196 func MockBaseMasterWorkerUpdateStatus( 197 ctx context.Context, 198 t *testing.T, 199 master *DefaultBaseMaster, 200 masterID frameModel.MasterID, 201 workerID frameModel.WorkerID, 202 executorID p2p.NodeID, 203 status *frameModel.WorkerStatus, 204 ) { 205 workerMetaClient := metadata.NewWorkerStatusClient(masterID, master.frameMetaClient) 206 err := workerMetaClient.Store(ctx, status) 207 require.NoError(t, err) 208 209 err = master.messageHandlerManager.(*p2p.MockMessageHandlerManager).InvokeHandler( 210 t, 211 statusutil.WorkerStatusTopic(masterID), 212 executorID, 213 &statusutil.WorkerStatusMessage{ 214 Worker: workerID, 215 MasterEpoch: master.currentEpoch.Load(), 216 Status: status, 217 }) 218 require.NoError(t, err) 219 }