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 }