github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/servermaster/job_fsm_test.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 servermaster
    15  
    16  import (
    17  	"testing"
    18  
    19  	"github.com/pingcap/tiflow/engine/framework"
    20  	frameModel "github.com/pingcap/tiflow/engine/framework/model"
    21  	"github.com/stretchr/testify/require"
    22  )
    23  
    24  func TestJobFsmStateTrans(t *testing.T) {
    25  	t.Parallel()
    26  
    27  	fsm := NewJobFsm()
    28  
    29  	id := "fsm-test-job-master-1"
    30  	job := &frameModel.MasterMeta{
    31  		ID:     id,
    32  		Config: []byte("simple config"),
    33  	}
    34  
    35  	createWorkerCount := 0
    36  
    37  	// Failover, job fsm loads tombstone job master
    38  	fsm.JobDispatched(job, true)
    39  	err := fsm.IterWaitAckJobs(func(job *frameModel.MasterMeta) (string, error) {
    40  		createWorkerCount++
    41  		return id, nil
    42  	})
    43  	require.NoError(t, err)
    44  	require.Equal(t, 1, createWorkerCount)
    45  	require.Len(t, fsm.waitAckJobs, 1)
    46  
    47  	// job that is not added from failover won't be processed
    48  	err = fsm.IterWaitAckJobs(func(job *frameModel.MasterMeta) (string, error) {
    49  		createWorkerCount++
    50  		return id, nil
    51  	})
    52  	require.NoError(t, err)
    53  	require.Equal(t, 1, createWorkerCount)
    54  
    55  	// OnWorkerOnline, WaitAck -> Online
    56  	err = fsm.JobOnline(&framework.MockHandle{
    57  		WorkerID:     id,
    58  		WorkerStatus: &frameModel.WorkerStatus{State: frameModel.WorkerStateNormal},
    59  		ExecutorID:   "executor-1",
    60  	})
    61  	require.NoError(t, err)
    62  	require.Empty(t, fsm.waitAckJobs)
    63  	require.Len(t, fsm.onlineJobs, 1)
    64  
    65  	// OnWorkerOffline, Online -> Pending
    66  	fsm.JobOffline(&framework.MockHandle{
    67  		WorkerID:     id,
    68  		WorkerStatus: &frameModel.WorkerStatus{State: frameModel.WorkerStateNormal},
    69  		IsTombstone:  true,
    70  	}, true /* needFailover */)
    71  	require.Empty(t, fsm.onlineJobs)
    72  	require.Len(t, fsm.pendingJobs, 1)
    73  
    74  	// Tick, process pending jobs, Pending -> WaitAck
    75  	dispatchedJobs := make([]*frameModel.MasterMeta, 0)
    76  	err = fsm.IterPendingJobs(func(job *frameModel.MasterMeta) (string, error) {
    77  		dispatchedJobs = append(dispatchedJobs, job)
    78  		return id, nil
    79  	})
    80  	require.NoError(t, err)
    81  	require.Empty(t, fsm.pendingJobs)
    82  	require.Len(t, fsm.waitAckJobs, 1)
    83  
    84  	// Dispatch job meets error, WaitAck -> Pending
    85  	err = fsm.JobDispatchFailed(&framework.MockHandle{
    86  		WorkerID:     id,
    87  		WorkerStatus: &frameModel.WorkerStatus{State: frameModel.WorkerStateNormal},
    88  		IsTombstone:  true,
    89  	})
    90  	require.NoError(t, err)
    91  	require.Len(t, fsm.pendingJobs, 1)
    92  	require.Empty(t, fsm.waitAckJobs)
    93  
    94  	// Tick, Pending -> WaitAck
    95  	err = fsm.IterPendingJobs(func(job *frameModel.MasterMeta) (string, error) {
    96  		return id, nil
    97  	})
    98  	require.NoError(t, err)
    99  	require.Len(t, fsm.waitAckJobs, 1)
   100  	// job finished
   101  	fsm.JobOffline(&framework.MockHandle{
   102  		WorkerID:     id,
   103  		WorkerStatus: &frameModel.WorkerStatus{State: frameModel.WorkerStateNormal},
   104  		IsTombstone:  true,
   105  	}, false /*needFailover*/)
   106  	require.Empty(t, fsm.waitAckJobs)
   107  
   108  	// offline invalid job, will do nothing
   109  	invalidWorker := &framework.MockHandle{
   110  		WorkerID:     id + "invalid",
   111  		WorkerStatus: &frameModel.WorkerStatus{State: frameModel.WorkerStateNormal},
   112  		ExecutorID:   "executor-1",
   113  	}
   114  
   115  	fsm.JobOffline(invalidWorker, true)
   116  }