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  }