github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/owner/owner_test.go (about) 1 // Copyright 2021 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 owner 15 16 import ( 17 "bytes" 18 "context" 19 "time" 20 21 "github.com/pingcap/check" 22 "github.com/pingcap/ticdc/cdc/model" 23 "github.com/pingcap/ticdc/pkg/config" 24 cdcContext "github.com/pingcap/ticdc/pkg/context" 25 cerror "github.com/pingcap/ticdc/pkg/errors" 26 "github.com/pingcap/ticdc/pkg/etcd" 27 "github.com/pingcap/ticdc/pkg/orchestrator" 28 "github.com/pingcap/ticdc/pkg/util/testleak" 29 "github.com/pingcap/tidb/store/tikv/oracle" 30 ) 31 32 var _ = check.Suite(&ownerSuite{}) 33 34 type ownerSuite struct { 35 } 36 37 type mockGcManager struct { 38 GcManager 39 } 40 41 func (m *mockGcManager) checkStaleCheckpointTs(ctx cdcContext.Context, checkpointTs model.Ts) error { 42 return cerror.ErrGCTTLExceeded.GenWithStackByArgs() 43 } 44 45 var _ GcManager = &mockGcManager{} 46 47 func createOwner4Test(ctx cdcContext.Context, c *check.C) (*Owner, *model.GlobalReactorState, *orchestrator.ReactorStateTester) { 48 ctx.GlobalVars().PDClient = &mockPDClient{updateServiceGCSafePointFunc: func(ctx context.Context, serviceID string, ttl int64, safePoint uint64) (uint64, error) { 49 return safePoint, nil 50 }} 51 cf := NewOwner4Test(func(ctx cdcContext.Context, startTs uint64) (DDLPuller, error) { 52 return &mockDDLPuller{resolvedTs: startTs - 1}, nil 53 }, func(ctx cdcContext.Context) (AsyncSink, error) { 54 return &mockAsyncSink{}, nil 55 }) 56 state := model.NewGlobalState().(*model.GlobalReactorState) 57 tester := orchestrator.NewReactorStateTester(c, state, nil) 58 59 // set captures 60 cdcKey := etcd.CDCKey{ 61 Tp: etcd.CDCKeyTypeCapture, 62 CaptureID: ctx.GlobalVars().CaptureInfo.ID, 63 } 64 captureBytes, err := ctx.GlobalVars().CaptureInfo.Marshal() 65 c.Assert(err, check.IsNil) 66 tester.MustUpdate(cdcKey.String(), captureBytes) 67 return cf, state, tester 68 } 69 70 func (s *ownerSuite) TestCreateRemoveChangefeed(c *check.C) { 71 defer testleak.AfterTest(c)() 72 ctx := cdcContext.NewBackendContext4Test(false) 73 owner, state, tester := createOwner4Test(ctx, c) 74 changefeedID := "test-changefeed" 75 changefeedInfo := &model.ChangeFeedInfo{ 76 StartTs: oracle.GoTimeToTS(time.Now()), 77 Config: config.GetDefaultReplicaConfig(), 78 } 79 changefeedStr, err := changefeedInfo.Marshal() 80 c.Assert(err, check.IsNil) 81 cdcKey := etcd.CDCKey{ 82 Tp: etcd.CDCKeyTypeChangefeedInfo, 83 ChangefeedID: changefeedID, 84 } 85 tester.MustUpdate(cdcKey.String(), []byte(changefeedStr)) 86 _, err = owner.Tick(ctx, state) 87 tester.MustApplyPatches() 88 c.Assert(err, check.IsNil) 89 c.Assert(owner.changefeeds, check.HasKey, changefeedID) 90 91 // delete changefeed info key to remove changefeed 92 tester.MustUpdate(cdcKey.String(), nil) 93 // this tick to clean the leak info fo the removed changefeed 94 _, err = owner.Tick(ctx, state) 95 c.Assert(err, check.IsNil) 96 // this tick to remove the changefeed state in memory 97 tester.MustApplyPatches() 98 _, err = owner.Tick(ctx, state) 99 c.Assert(err, check.IsNil) 100 tester.MustApplyPatches() 101 c.Assert(err, check.IsNil) 102 c.Assert(owner.changefeeds, check.Not(check.HasKey), changefeedID) 103 c.Assert(state.Changefeeds, check.Not(check.HasKey), changefeedID) 104 105 tester.MustUpdate(cdcKey.String(), []byte(changefeedStr)) 106 _, err = owner.Tick(ctx, state) 107 tester.MustApplyPatches() 108 c.Assert(err, check.IsNil) 109 c.Assert(owner.changefeeds, check.HasKey, changefeedID) 110 111 removeJob := model.AdminJob{ 112 CfID: changefeedID, 113 Type: model.AdminRemove, 114 Opts: &model.AdminJobOption{ForceRemove: true}, 115 Error: nil, 116 } 117 118 // this will make changefeed always meet ErrGCTTLExceeded 119 mockedGcManager := &mockGcManager{GcManager: owner.gcManager} 120 owner.gcManager = mockedGcManager 121 122 // this tick create remove changefeed patches 123 owner.EnqueueJob(removeJob) 124 _, err = owner.Tick(ctx, state) 125 c.Assert(err, check.IsNil) 126 127 // apply patches and update owner's in memory changefeed states 128 tester.MustApplyPatches() 129 _, err = owner.Tick(ctx, state) 130 c.Assert(err, check.IsNil) 131 c.Assert(owner.changefeeds, check.Not(check.HasKey), changefeedID) 132 } 133 134 func (s *ownerSuite) TestStopChangefeed(c *check.C) { 135 defer testleak.AfterTest(c)() 136 ctx := cdcContext.NewBackendContext4Test(false) 137 owner, state, tester := createOwner4Test(ctx, c) 138 changefeedID := "test-changefeed" 139 changefeedInfo := &model.ChangeFeedInfo{ 140 StartTs: oracle.GoTimeToTS(time.Now()), 141 Config: config.GetDefaultReplicaConfig(), 142 } 143 changefeedStr, err := changefeedInfo.Marshal() 144 c.Assert(err, check.IsNil) 145 cdcKey := etcd.CDCKey{ 146 Tp: etcd.CDCKeyTypeChangefeedInfo, 147 ChangefeedID: changefeedID, 148 } 149 tester.MustUpdate(cdcKey.String(), []byte(changefeedStr)) 150 _, err = owner.Tick(ctx, state) 151 tester.MustApplyPatches() 152 c.Assert(err, check.IsNil) 153 c.Assert(owner.changefeeds, check.HasKey, changefeedID) 154 155 // remove changefeed forcibly 156 owner.EnqueueJob(model.AdminJob{ 157 CfID: changefeedID, 158 Type: model.AdminRemove, 159 Opts: &model.AdminJobOption{ 160 ForceRemove: true, 161 }, 162 }) 163 164 // this tick to clean the leak info fo the removed changefeed 165 _, err = owner.Tick(ctx, state) 166 c.Assert(err, check.IsNil) 167 c.Assert(err, check.IsNil) 168 // this tick to remove the changefeed state in memory 169 tester.MustApplyPatches() 170 _, err = owner.Tick(ctx, state) 171 c.Assert(err, check.IsNil) 172 c.Assert(err, check.IsNil) 173 tester.MustApplyPatches() 174 c.Assert(err, check.IsNil) 175 c.Assert(owner.changefeeds, check.Not(check.HasKey), changefeedID) 176 c.Assert(state.Changefeeds, check.Not(check.HasKey), changefeedID) 177 } 178 179 func (s *ownerSuite) TestCheckClusterVersion(c *check.C) { 180 defer testleak.AfterTest(c)() 181 ctx := cdcContext.NewBackendContext4Test(false) 182 owner, state, tester := createOwner4Test(ctx, c) 183 tester.MustUpdate("/tidb/cdc/capture/6bbc01c8-0605-4f86-a0f9-b3119109b225", []byte(`{"id":"6bbc01c8-0605-4f86-a0f9-b3119109b225","address":"127.0.0.1:8300","version":"v6.0.0"}`)) 184 185 changefeedID := "test-changefeed" 186 changefeedInfo := &model.ChangeFeedInfo{ 187 StartTs: oracle.GoTimeToTS(time.Now()), 188 Config: config.GetDefaultReplicaConfig(), 189 } 190 changefeedStr, err := changefeedInfo.Marshal() 191 c.Assert(err, check.IsNil) 192 cdcKey := etcd.CDCKey{ 193 Tp: etcd.CDCKeyTypeChangefeedInfo, 194 ChangefeedID: changefeedID, 195 } 196 tester.MustUpdate(cdcKey.String(), []byte(changefeedStr)) 197 198 // check the tick is skipped and the changefeed will not be handled 199 _, err = owner.Tick(ctx, state) 200 tester.MustApplyPatches() 201 c.Assert(err, check.IsNil) 202 c.Assert(owner.changefeeds, check.Not(check.HasKey), changefeedID) 203 204 tester.MustUpdate("/tidb/cdc/capture/6bbc01c8-0605-4f86-a0f9-b3119109b225", 205 []byte(`{"id":"6bbc01c8-0605-4f86-a0f9-b3119109b225","address":"127.0.0.1:8300","version":"`+ctx.GlobalVars().CaptureInfo.Version+`"}`)) 206 207 // check the tick is not skipped and the changefeed will be handled normally 208 _, err = owner.Tick(ctx, state) 209 tester.MustApplyPatches() 210 c.Assert(err, check.IsNil) 211 c.Assert(owner.changefeeds, check.HasKey, changefeedID) 212 } 213 214 func (s *ownerSuite) TestAdminJob(c *check.C) { 215 defer testleak.AfterTest(c)() 216 ctx := cdcContext.NewBackendContext4Test(false) 217 owner, _, _ := createOwner4Test(ctx, c) 218 owner.EnqueueJob(model.AdminJob{ 219 CfID: "test-changefeed1", 220 Type: model.AdminResume, 221 }) 222 owner.TriggerRebalance("test-changefeed2") 223 owner.ManualSchedule("test-changefeed3", "test-caputre1", 10) 224 var buf bytes.Buffer 225 owner.WriteDebugInfo(&buf) 226 227 // remove job.done, it's hard to check deep equals 228 jobs := owner.takeOwnerJobs() 229 for _, job := range jobs { 230 c.Assert(job.done, check.NotNil) 231 close(job.done) 232 job.done = nil 233 } 234 c.Assert(jobs, check.DeepEquals, []*ownerJob{ 235 { 236 tp: ownerJobTypeAdminJob, 237 adminJob: &model.AdminJob{ 238 CfID: "test-changefeed1", 239 Type: model.AdminResume, 240 }, 241 changefeedID: "test-changefeed1", 242 }, { 243 tp: ownerJobTypeRebalance, 244 changefeedID: "test-changefeed2", 245 }, { 246 tp: ownerJobTypeManualSchedule, 247 changefeedID: "test-changefeed3", 248 targetCaptureID: "test-caputre1", 249 tableID: 10, 250 }, { 251 tp: ownerJobTypeDebugInfo, 252 debugInfoWriter: &buf, 253 }, 254 }) 255 c.Assert(owner.takeOwnerJobs(), check.HasLen, 0) 256 }