github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/cdc/scheduler/internal/v3/compat/compat_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 compat
    15  
    16  import (
    17  	"testing"
    18  
    19  	"github.com/coreos/go-semver/semver"
    20  	"github.com/pingcap/tiflow/cdc/model"
    21  	"github.com/pingcap/tiflow/cdc/processor/tablepb"
    22  	"github.com/pingcap/tiflow/cdc/scheduler/schedulepb"
    23  	"github.com/pingcap/tiflow/pkg/config"
    24  	"github.com/pingcap/tiflow/pkg/spanz"
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func TestCheckSpanReplicationEnabled(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	c := New(&config.SchedulerConfig{
    32  		ChangefeedSettings: &config.ChangefeedSchedulerConfig{
    33  			EnableTableAcrossNodes: true,
    34  			RegionThreshold:        1,
    35  		},
    36  	}, map[string]*model.CaptureInfo{})
    37  
    38  	// Add 1 supported capture.
    39  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    40  		"a": {Version: SpanReplicationMinVersion.String()},
    41  	}))
    42  	require.True(t, c.CheckSpanReplicationEnabled())
    43  
    44  	// Add 1 supported capture again.
    45  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    46  		"a": {Version: SpanReplicationMinVersion.String()},
    47  		"b": {Version: SpanReplicationMinVersion.String()},
    48  	}))
    49  	require.True(t, c.CheckSpanReplicationEnabled())
    50  
    51  	// Rolling upgrade 3 nodes cluster.
    52  	unsupportedVersion := semver.New("4.0.0")
    53  	require.True(t, unsupportedVersion.LessThan(*SpanReplicationMinVersion))
    54  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    55  		"a": {Version: SpanReplicationMinVersion.String()},
    56  		"b": {Version: unsupportedVersion.String()},
    57  		"c": {Version: unsupportedVersion.String()},
    58  	}))
    59  	require.False(t, c.CheckSpanReplicationEnabled())
    60  	// Restart b.
    61  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    62  		"a": {Version: SpanReplicationMinVersion.String()},
    63  		"c": {Version: unsupportedVersion.String()},
    64  	}))
    65  	require.False(t, c.CheckSpanReplicationEnabled())
    66  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    67  		"a": {Version: SpanReplicationMinVersion.String()},
    68  		"b": {Version: SpanReplicationMinVersion.String()},
    69  		"c": {Version: unsupportedVersion.String()},
    70  	}))
    71  	require.False(t, c.CheckSpanReplicationEnabled())
    72  	// Restart c.
    73  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    74  		"a": {Version: SpanReplicationMinVersion.String()},
    75  		"b": {Version: unsupportedVersion.String()},
    76  	}))
    77  	require.False(t, c.CheckSpanReplicationEnabled())
    78  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
    79  		"a": {Version: SpanReplicationMinVersion.String()},
    80  		"b": {Version: SpanReplicationMinVersion.String()},
    81  		"c": {Version: SpanReplicationMinVersion.String()},
    82  	}))
    83  	require.True(t, c.CheckSpanReplicationEnabled())
    84  
    85  	// Disable in config
    86  	c = New(&config.SchedulerConfig{
    87  		ChangefeedSettings: &config.ChangefeedSchedulerConfig{
    88  			RegionThreshold: 0,
    89  		},
    90  	}, map[string]*model.CaptureInfo{
    91  		"a": {Version: SpanReplicationMinVersion.String()},
    92  	})
    93  	require.False(t, c.CheckSpanReplicationEnabled())
    94  }
    95  
    96  func TestBeforeTransportSend(t *testing.T) {
    97  	t.Parallel()
    98  
    99  	c := New(&config.SchedulerConfig{
   100  		ChangefeedSettings: &config.ChangefeedSchedulerConfig{
   101  			RegionThreshold: 0, // Disable span replication.
   102  		},
   103  	}, map[string]*model.CaptureInfo{})
   104  	require.False(t, c.CheckSpanReplicationEnabled())
   105  
   106  	addTableReq := &schedulepb.AddTableRequest{
   107  		Span: spanz.TableIDToComparableSpan(1),
   108  	}
   109  	c.BeforeTransportSend([]*schedulepb.Message{{
   110  		MsgType: schedulepb.MsgDispatchTableRequest,
   111  		DispatchTableRequest: &schedulepb.DispatchTableRequest{
   112  			Request: &schedulepb.DispatchTableRequest_AddTable{
   113  				AddTable: addTableReq,
   114  			},
   115  		},
   116  	}})
   117  	require.EqualValues(t, 1, addTableReq.TableID)
   118  
   119  	removeTableReq := &schedulepb.RemoveTableRequest{
   120  		Span: spanz.TableIDToComparableSpan(1),
   121  	}
   122  	c.BeforeTransportSend([]*schedulepb.Message{{
   123  		MsgType: schedulepb.MsgDispatchTableRequest,
   124  		DispatchTableRequest: &schedulepb.DispatchTableRequest{
   125  			Request: &schedulepb.DispatchTableRequest_RemoveTable{
   126  				RemoveTable: removeTableReq,
   127  			},
   128  		},
   129  	}})
   130  	require.EqualValues(t, 1, removeTableReq.TableID)
   131  
   132  	addTableResp := &schedulepb.AddTableResponse{
   133  		Status: &tablepb.TableStatus{
   134  			Span: spanz.TableIDToComparableSpan(1),
   135  		},
   136  	}
   137  	c.BeforeTransportSend([]*schedulepb.Message{{
   138  		MsgType: schedulepb.MsgDispatchTableResponse,
   139  		DispatchTableResponse: &schedulepb.DispatchTableResponse{
   140  			Response: &schedulepb.DispatchTableResponse_AddTable{
   141  				AddTable: addTableResp,
   142  			},
   143  		},
   144  	}})
   145  	require.EqualValues(t, 1, addTableResp.Status.TableID)
   146  
   147  	removeTableResp := &schedulepb.RemoveTableResponse{
   148  		Status: &tablepb.TableStatus{
   149  			Span: spanz.TableIDToComparableSpan(1),
   150  		},
   151  	}
   152  	c.BeforeTransportSend([]*schedulepb.Message{{
   153  		MsgType: schedulepb.MsgDispatchTableResponse,
   154  		DispatchTableResponse: &schedulepb.DispatchTableResponse{
   155  			Response: &schedulepb.DispatchTableResponse_RemoveTable{
   156  				RemoveTable: removeTableResp,
   157  			},
   158  		},
   159  	}})
   160  	require.EqualValues(t, 1, removeTableResp.Status.TableID)
   161  
   162  	heartbeat := &schedulepb.Heartbeat{
   163  		Spans: []tablepb.Span{spanz.TableIDToComparableSpan(1)},
   164  	}
   165  	c.BeforeTransportSend([]*schedulepb.Message{{
   166  		MsgType:   schedulepb.MsgHeartbeat,
   167  		Heartbeat: heartbeat,
   168  	}})
   169  	require.EqualValues(t, 1, heartbeat.TableIDs[0])
   170  	heartbeatResp := &schedulepb.HeartbeatResponse{
   171  		Tables: []tablepb.TableStatus{{Span: spanz.TableIDToComparableSpan(1)}},
   172  	}
   173  	c.BeforeTransportSend([]*schedulepb.Message{{
   174  		MsgType:           schedulepb.MsgHeartbeatResponse,
   175  		HeartbeatResponse: heartbeatResp,
   176  	}})
   177  	require.EqualValues(t, 1, heartbeatResp.Tables[0].TableID)
   178  }
   179  
   180  func TestAfterTransportReceive(t *testing.T) {
   181  	t.Parallel()
   182  
   183  	c := New(&config.SchedulerConfig{
   184  		ChangefeedSettings: &config.ChangefeedSchedulerConfig{
   185  			RegionThreshold: 0, // Disable span replication.
   186  		},
   187  	}, map[string]*model.CaptureInfo{})
   188  	require.False(t, c.CheckSpanReplicationEnabled())
   189  
   190  	addTableReq := &schedulepb.AddTableRequest{
   191  		TableID: 1,
   192  	}
   193  	c.AfterTransportReceive([]*schedulepb.Message{{
   194  		MsgType: schedulepb.MsgDispatchTableRequest,
   195  		DispatchTableRequest: &schedulepb.DispatchTableRequest{
   196  			Request: &schedulepb.DispatchTableRequest_AddTable{
   197  				AddTable: addTableReq,
   198  			},
   199  		},
   200  	}})
   201  	require.EqualValues(t, spanz.TableIDToComparableSpan(1), addTableReq.Span)
   202  
   203  	addTableReq1 := &schedulepb.AddTableRequest{
   204  		TableID: 1,
   205  		Span:    tablepb.Span{TableID: 1},
   206  	}
   207  	c.AfterTransportReceive([]*schedulepb.Message{{
   208  		MsgType: schedulepb.MsgDispatchTableRequest,
   209  		DispatchTableRequest: &schedulepb.DispatchTableRequest{
   210  			Request: &schedulepb.DispatchTableRequest_AddTable{
   211  				AddTable: addTableReq1,
   212  			},
   213  		},
   214  	}})
   215  	require.EqualValues(t, tablepb.Span{TableID: 1}, addTableReq1.Span)
   216  
   217  	removeTableReq := &schedulepb.RemoveTableRequest{
   218  		TableID: 1,
   219  	}
   220  	c.AfterTransportReceive([]*schedulepb.Message{{
   221  		MsgType: schedulepb.MsgDispatchTableRequest,
   222  		DispatchTableRequest: &schedulepb.DispatchTableRequest{
   223  			Request: &schedulepb.DispatchTableRequest_RemoveTable{
   224  				RemoveTable: removeTableReq,
   225  			},
   226  		},
   227  	}})
   228  	require.EqualValues(t, spanz.TableIDToComparableSpan(1), removeTableReq.Span)
   229  
   230  	addTableResp := &schedulepb.AddTableResponse{
   231  		Status: &tablepb.TableStatus{
   232  			TableID: 1,
   233  		},
   234  	}
   235  	c.AfterTransportReceive([]*schedulepb.Message{{
   236  		MsgType: schedulepb.MsgDispatchTableResponse,
   237  		DispatchTableResponse: &schedulepb.DispatchTableResponse{
   238  			Response: &schedulepb.DispatchTableResponse_AddTable{
   239  				AddTable: addTableResp,
   240  			},
   241  		},
   242  	}})
   243  	require.EqualValues(t, spanz.TableIDToComparableSpan(1), addTableResp.Status.Span)
   244  
   245  	removeTableResp := &schedulepb.RemoveTableResponse{
   246  		Status: &tablepb.TableStatus{
   247  			TableID: 1,
   248  		},
   249  	}
   250  	c.AfterTransportReceive([]*schedulepb.Message{{
   251  		MsgType: schedulepb.MsgDispatchTableResponse,
   252  		DispatchTableResponse: &schedulepb.DispatchTableResponse{
   253  			Response: &schedulepb.DispatchTableResponse_RemoveTable{
   254  				RemoveTable: removeTableResp,
   255  			},
   256  		},
   257  	}})
   258  	require.EqualValues(t, spanz.TableIDToComparableSpan(1), removeTableResp.Status.Span)
   259  
   260  	heartbeat := &schedulepb.Heartbeat{
   261  		TableIDs: []model.TableID{1},
   262  	}
   263  	c.AfterTransportReceive([]*schedulepb.Message{{
   264  		MsgType:   schedulepb.MsgHeartbeat,
   265  		Heartbeat: heartbeat,
   266  	}})
   267  	require.EqualValues(t, 1, heartbeat.TableIDs[0])
   268  	heartbeatResp := &schedulepb.HeartbeatResponse{
   269  		Tables: []tablepb.TableStatus{{TableID: 1}},
   270  	}
   271  	c.AfterTransportReceive([]*schedulepb.Message{{
   272  		MsgType:           schedulepb.MsgHeartbeatResponse,
   273  		HeartbeatResponse: heartbeatResp,
   274  	}})
   275  	require.EqualValues(t, spanz.TableIDToComparableSpan(1), heartbeatResp.Tables[0].Span)
   276  
   277  	heartbeatResp1 := &schedulepb.HeartbeatResponse{
   278  		Tables: []tablepb.TableStatus{{
   279  			TableID: 1,
   280  			Span:    tablepb.Span{TableID: 1},
   281  		}},
   282  	}
   283  	c.AfterTransportReceive([]*schedulepb.Message{{
   284  		MsgType:           schedulepb.MsgHeartbeatResponse,
   285  		HeartbeatResponse: heartbeatResp1,
   286  	}})
   287  	require.EqualValues(t, tablepb.Span{TableID: 1}, heartbeatResp1.Tables[0].Span)
   288  }
   289  
   290  func TestCheckChangefeedEpochEnabled(t *testing.T) {
   291  	t.Parallel()
   292  
   293  	c := New(&config.SchedulerConfig{
   294  		ChangefeedSettings: &config.ChangefeedSchedulerConfig{
   295  			EnableTableAcrossNodes: true,
   296  			RegionThreshold:        1,
   297  		},
   298  	}, map[string]*model.CaptureInfo{})
   299  
   300  	// Unknown capture always return false
   301  	require.False(t, c.CheckChangefeedEpochEnabled("unknown"))
   302  
   303  	// Add 1 supported capture.
   304  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
   305  		"a": {Version: ChangefeedEpochMinVersion.String()},
   306  	}))
   307  	require.True(t, c.CheckChangefeedEpochEnabled("a"))
   308  	// Check again.
   309  	require.True(t, c.CheckChangefeedEpochEnabled("a"))
   310  
   311  	// Add 1 supported capture again.
   312  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
   313  		"a": {Version: ChangefeedEpochMinVersion.String()},
   314  		"b": {Version: ChangefeedEpochMinVersion.String()},
   315  	}))
   316  	require.True(t, c.CheckChangefeedEpochEnabled("a"))
   317  	require.True(t, c.CheckChangefeedEpochEnabled("b"))
   318  
   319  	// Replace 1 unsupported capture.
   320  	unsupported := *ChangefeedEpochMinVersion
   321  	unsupported.Major--
   322  	require.True(t, c.UpdateCaptureInfo(map[string]*model.CaptureInfo{
   323  		"a": {Version: ChangefeedEpochMinVersion.String()},
   324  		"c": {Version: unsupported.String()},
   325  	}))
   326  	require.True(t, c.CheckChangefeedEpochEnabled("a"))
   327  	require.False(t, c.CheckChangefeedEpochEnabled("b"))
   328  	require.False(t, c.CheckChangefeedEpochEnabled("c"))
   329  }