github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cmd/cmd_test.go (about) 1 // Copyright 2020 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 cmd 15 16 import ( 17 "context" 18 "io/ioutil" 19 "os" 20 "path/filepath" 21 "testing" 22 23 "github.com/pingcap/check" 24 "github.com/pingcap/parser/model" 25 "github.com/pingcap/ticdc/pkg/config" 26 "github.com/pingcap/ticdc/pkg/util/testleak" 27 "github.com/pingcap/tidb/store/tikv/oracle" 28 "github.com/spf13/cobra" 29 pd "github.com/tikv/pd/client" 30 ) 31 32 func TestSuite(t *testing.T) { check.TestingT(t) } 33 34 type decodeFileSuite struct{} 35 36 var _ = check.Suite(&decodeFileSuite{}) 37 38 func (s *decodeFileSuite) TestCanDecodeTOML(c *check.C) { 39 defer testleak.AfterTest(c)() 40 dir := c.MkDir() 41 path := filepath.Join(dir, "config.toml") 42 content := ` 43 case-sensitive = false 44 45 [filter] 46 ignore-txn-start-ts = [1, 2] 47 ddl-allow-list = [1, 2] 48 rules = ['*.*', '!test.*'] 49 50 [mounter] 51 worker-num = 64 52 53 [sink] 54 dispatchers = [ 55 {matcher = ['test1.*', 'test2.*'], dispatcher = "ts"}, 56 {matcher = ['test3.*', 'test4.*'], dispatcher = "rowid"}, 57 ] 58 protocol = "default" 59 60 [cyclic-replication] 61 enable = true 62 replica-id = 1 63 filter-replica-ids = [2,3] 64 id-buckets = 4 65 sync-ddl = true 66 67 [scheduler] 68 type = "manual" 69 polling-time = 5 70 ` 71 err := ioutil.WriteFile(path, []byte(content), 0o644) 72 c.Assert(err, check.IsNil) 73 74 cfg := config.GetDefaultReplicaConfig() 75 err = strictDecodeFile(path, "cdc", &cfg) 76 c.Assert(err, check.IsNil) 77 78 c.Assert(cfg.CaseSensitive, check.IsFalse) 79 c.Assert(cfg.Filter, check.DeepEquals, &config.FilterConfig{ 80 IgnoreTxnStartTs: []uint64{1, 2}, 81 DDLAllowlist: []model.ActionType{1, 2}, 82 Rules: []string{"*.*", "!test.*"}, 83 }) 84 c.Assert(cfg.Mounter, check.DeepEquals, &config.MounterConfig{ 85 WorkerNum: 64, 86 }) 87 c.Assert(cfg.Sink, check.DeepEquals, &config.SinkConfig{ 88 DispatchRules: []*config.DispatchRule{ 89 {Dispatcher: "ts", Matcher: []string{"test1.*", "test2.*"}}, 90 {Dispatcher: "rowid", Matcher: []string{"test3.*", "test4.*"}}, 91 }, 92 Protocol: "default", 93 }) 94 c.Assert(cfg.Cyclic, check.DeepEquals, &config.CyclicConfig{ 95 Enable: true, 96 ReplicaID: 1, 97 FilterReplicaID: []uint64{2, 3}, 98 IDBuckets: 4, 99 SyncDDL: true, 100 }) 101 c.Assert(cfg.Scheduler, check.DeepEquals, &config.SchedulerConfig{ 102 Tp: "manual", 103 PollingTime: 5, 104 }) 105 } 106 107 func (s *decodeFileSuite) TestAndWriteExampleReplicaTOML(c *check.C) { 108 defer testleak.AfterTest(c)() 109 cfg := config.GetDefaultReplicaConfig() 110 err := strictDecodeFile("changefeed.toml", "cdc", &cfg) 111 c.Assert(err, check.IsNil) 112 113 c.Assert(cfg.CaseSensitive, check.IsTrue) 114 c.Assert(cfg.Filter, check.DeepEquals, &config.FilterConfig{ 115 IgnoreTxnStartTs: []uint64{1, 2}, 116 Rules: []string{"*.*", "!test.*"}, 117 }) 118 c.Assert(cfg.Mounter, check.DeepEquals, &config.MounterConfig{ 119 WorkerNum: 16, 120 }) 121 c.Assert(cfg.Sink, check.DeepEquals, &config.SinkConfig{ 122 DispatchRules: []*config.DispatchRule{ 123 {Dispatcher: "ts", Matcher: []string{"test1.*", "test2.*"}}, 124 {Dispatcher: "rowid", Matcher: []string{"test3.*", "test4.*"}}, 125 }, 126 Protocol: "default", 127 }) 128 c.Assert(cfg.Cyclic, check.DeepEquals, &config.CyclicConfig{ 129 Enable: false, 130 ReplicaID: 1, 131 FilterReplicaID: []uint64{2, 3}, 132 SyncDDL: true, 133 }) 134 } 135 136 func (s *decodeFileSuite) TestAndWriteExampleServerTOML(c *check.C) { 137 defer testleak.AfterTest(c)() 138 cfg := config.GetDefaultServerConfig() 139 err := strictDecodeFile("ticdc.toml", "cdc", &cfg) 140 c.Assert(err, check.IsNil) 141 defcfg := config.GetDefaultServerConfig() 142 defcfg.AdvertiseAddr = "127.0.0.1:8300" 143 defcfg.LogFile = "/tmp/ticdc/ticdc.log" 144 c.Assert(cfg, check.DeepEquals, defcfg) 145 } 146 147 func (s *decodeFileSuite) TestShouldReturnErrForUnknownCfgs(c *check.C) { 148 defer testleak.AfterTest(c)() 149 dir := c.MkDir() 150 path := filepath.Join(dir, "config.toml") 151 content := `filter-case-insensitive = true` 152 err := ioutil.WriteFile(path, []byte(content), 0o644) 153 c.Assert(err, check.IsNil) 154 155 cfg := config.GetDefaultReplicaConfig() 156 err = strictDecodeFile(path, "cdc", &cfg) 157 c.Assert(err, check.NotNil) 158 c.Assert(err, check.ErrorMatches, ".*unknown config.*") 159 } 160 161 func (s *decodeFileSuite) TestVerifyReplicaConfig(c *check.C) { 162 defer testleak.AfterTest(c)() 163 164 dir := c.MkDir() 165 path := filepath.Join(dir, "config.toml") 166 content := ` 167 [filter] 168 rules = ['*.*', '!test.*']` 169 err := ioutil.WriteFile(path, []byte(content), 0o644) 170 c.Assert(err, check.IsNil) 171 172 cfg := config.GetDefaultReplicaConfig() 173 err = verifyReplicaConfig(path, "cdc", cfg) 174 c.Assert(err, check.IsNil) 175 176 path = filepath.Join(dir, "config1.toml") 177 content = ` 178 [filter] 179 rules = ['*.*', '!test.*','rtest1']` 180 err = ioutil.WriteFile(path, []byte(content), 0o644) 181 c.Assert(err, check.IsNil) 182 183 cfg = config.GetDefaultReplicaConfig() 184 err = verifyReplicaConfig(path, "cdc", cfg) 185 c.Assert(err, check.NotNil) 186 c.Assert(err, check.ErrorMatches, ".*CDC:ErrFilterRuleInvalid.*") 187 } 188 189 type mockPDClient struct { 190 pd.Client 191 ts uint64 192 } 193 194 func (m *mockPDClient) GetTS(ctx context.Context) (int64, int64, error) { 195 return oracle.ExtractPhysical(m.ts), 0, nil 196 } 197 198 type commonUtilSuite struct{} 199 200 var _ = check.Suite(&commonUtilSuite{}) 201 202 func (s *commonUtilSuite) TestConfirmLargeDataGap(c *check.C) { 203 defer testleak.AfterTest(c)() 204 ctx := context.Background() 205 currentTs := uint64(423482306736160769) // 2021-03-11 17:59:57.547 206 startTs := uint64(423450030227042420) // 2021-03-10 07:47:52.435 207 pdCli = &mockPDClient{ts: currentTs} 208 cmd := &cobra.Command{} 209 210 // check start ts more than 1 day before current ts, and type N when confirming 211 dir := c.MkDir() 212 path := filepath.Join(dir, "confirm.txt") 213 err := ioutil.WriteFile(path, []byte("n"), 0o644) 214 c.Assert(err, check.IsNil) 215 f, err := os.Open(path) 216 c.Assert(err, check.IsNil) 217 stdin := os.Stdin 218 os.Stdin = f 219 defer func() { 220 os.Stdin = stdin 221 }() 222 err = confirmLargeDataGap(ctx, cmd, startTs) 223 c.Assert(err, check.ErrorMatches, "abort changefeed create or resume") 224 225 // check no confirm works 226 originNoConfirm := noConfirm 227 noConfirm = true 228 defer func() { 229 noConfirm = originNoConfirm 230 }() 231 err = confirmLargeDataGap(ctx, cmd, startTs) 232 c.Assert(err, check.IsNil) 233 noConfirm = false 234 235 // check start ts more than 1 day before current ts, and type Y when confirming 236 err = ioutil.WriteFile(path, []byte("Y"), 0o644) 237 c.Assert(err, check.IsNil) 238 f, err = os.Open(path) 239 c.Assert(err, check.IsNil) 240 os.Stdin = f 241 err = confirmLargeDataGap(ctx, cmd, startTs) 242 c.Assert(err, check.IsNil) 243 244 // check start ts does not exceed threshold 245 pdCli = &mockPDClient{ts: startTs} 246 err = confirmLargeDataGap(ctx, cmd, startTs) 247 c.Assert(err, check.IsNil) 248 }