github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/cmd/cli/cli_changefeed_update_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 cli 15 16 import ( 17 "os" 18 "path/filepath" 19 "strings" 20 "testing" 21 22 "github.com/golang/mock/gomock" 23 "github.com/pingcap/errors" 24 "github.com/pingcap/log" 25 v2 "github.com/pingcap/tiflow/cdc/api/v2" 26 "github.com/pingcap/tiflow/pkg/config" 27 putil "github.com/pingcap/tiflow/pkg/util" 28 "github.com/stretchr/testify/require" 29 ) 30 31 func TestApplyChanges(t *testing.T) { 32 t.Parallel() 33 34 cmd := NewCmdCli() 35 commonChangefeedOptions := newChangefeedCommonOptions() 36 o := newUpdateChangefeedOptions(commonChangefeedOptions) 37 o.addFlags(cmd) 38 39 // Test normal update. 40 oldInfo := &v2.ChangeFeedInfo{SinkURI: "blackhole://"} 41 require.Nil(t, cmd.ParseFlags([]string{"--sink-uri=mysql://root@downstream-tidb:4000"})) 42 newInfo, err := o.applyChanges(oldInfo, cmd) 43 require.Nil(t, err) 44 require.Equal(t, "mysql://root@downstream-tidb:4000", newInfo.SinkURI) 45 46 // Test for cli command flags that should be ignored. 47 oldInfo = &v2.ChangeFeedInfo{SinkURI: "blackhole://"} 48 require.Nil(t, cmd.ParseFlags([]string{"--log-level=debug"})) 49 _, err = o.applyChanges(oldInfo, cmd) 50 require.Nil(t, err) 51 52 oldInfo = &v2.ChangeFeedInfo{SinkURI: "blackhole://"} 53 require.Nil(t, cmd.ParseFlags([]string{"--pd=http://127.0.0.1:2379"})) 54 _, err = o.applyChanges(oldInfo, cmd) 55 require.Nil(t, err) 56 57 dir := t.TempDir() 58 filename := filepath.Join(dir, "log.txt") 59 reset, err := initTestLogger(filename) 60 defer reset() 61 require.Nil(t, err) 62 63 // Test for flag that cannot be updated. 64 oldInfo = &v2.ChangeFeedInfo{SinkURI: "blackhole://"} 65 require.Nil(t, cmd.ParseFlags([]string{"--sort-dir=/home"})) 66 _, err = o.applyChanges(oldInfo, cmd) 67 require.Nil(t, err) 68 file, err := os.ReadFile(filename) 69 require.Nil(t, err) 70 require.True(t, strings.Contains(string(file), "this flag cannot be updated and will be ignored")) 71 72 // Test schema registry update 73 oldInfo = &v2.ChangeFeedInfo{Config: v2.ToAPIReplicaConfig(config.GetDefaultReplicaConfig())} 74 require.True(t, oldInfo.Config.Sink.SchemaRegistry == nil) 75 require.Nil(t, cmd.ParseFlags([]string{"--schema-registry=https://username:password@localhost:8081"})) 76 newInfo, err = o.applyChanges(oldInfo, cmd) 77 require.Nil(t, err) 78 require.Equal(t, 79 putil.AddressOf("https://username:password@localhost:8081"), 80 newInfo.Config.Sink.SchemaRegistry) 81 } 82 83 func initTestLogger(filename string) (func(), error) { 84 logConfig := &log.Config{ 85 File: log.FileLogConfig{ 86 Filename: filename, 87 }, 88 } 89 90 logger, props, err := log.InitLogger(logConfig) 91 if err != nil { 92 return nil, err 93 } 94 log.ReplaceGlobals(logger, props) 95 96 return func() { 97 conf := &log.Config{Level: "info", File: log.FileLogConfig{}} 98 logger, props, _ := log.InitLogger(conf) 99 log.ReplaceGlobals(logger, props) 100 }, nil 101 } 102 103 func TestChangefeedUpdateCli(t *testing.T) { 104 ctrl := gomock.NewController(t) 105 defer ctrl.Finish() 106 f := newMockFactory(ctrl) 107 o := newUpdateChangefeedOptions(newChangefeedCommonOptions()) 108 o.complete(f) 109 cmd := newCmdUpdateChangefeed(f) 110 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(nil, errors.New("test")) 111 os.Args = []string{"update", "--no-confirm=true", "--changefeed-id=abc"} 112 o.commonChangefeedOptions.noConfirm = true 113 o.changefeedID = "abc" 114 require.NotNil(t, o.run(cmd)) 115 116 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc"). 117 Return(&v2.ChangeFeedInfo{ 118 ID: "abc", 119 Config: &v2.ReplicaConfig{ 120 Sink: &v2.SinkConfig{}, 121 }, 122 }, nil) 123 f.changefeeds.EXPECT().Update(gomock.Any(), gomock.Any(), "ns", "abc"). 124 Return(&v2.ChangeFeedInfo{}, nil) 125 dir := t.TempDir() 126 configPath := filepath.Join(dir, "cf.toml") 127 err := os.WriteFile(configPath, []byte(""), 0o644) 128 require.Nil(t, err) 129 os.Args = []string{ 130 "update", 131 "--config=" + configPath, 132 "--no-confirm=false", 133 "--target-ts=10", 134 "--sink-uri=abcd", 135 "--schema-registry=a", 136 "--sort-engine=memory", 137 "--changefeed-id=abc", 138 "--namespace=ns", 139 "--sort-dir=a", 140 "--upstream-pd=pd", 141 "--upstream-ca=ca", 142 "--upstream-cert=cer", 143 "--upstream-key=key", 144 } 145 146 path := filepath.Join(dir, "confirm.txt") 147 err = os.WriteFile(path, []byte("y"), 0o644) 148 require.Nil(t, err) 149 file, err := os.Open(path) 150 require.Nil(t, err) 151 stdin := os.Stdin 152 os.Stdin = file 153 defer func() { 154 os.Stdin = stdin 155 }() 156 require.Nil(t, cmd.Execute()) 157 158 // no diff 159 cmd = newCmdUpdateChangefeed(f) 160 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc"). 161 Return(&v2.ChangeFeedInfo{}, nil) 162 os.Args = []string{"update", "--no-confirm=true", "-c", "abc"} 163 require.Nil(t, cmd.Execute()) 164 165 cmd = newCmdUpdateChangefeed(f) 166 f.changefeeds.EXPECT().Get(gomock.Any(), "ns", "abcd"). 167 Return(&v2.ChangeFeedInfo{ID: "abcd"}, errors.New("test")) 168 o.commonChangefeedOptions.noConfirm = true 169 o.commonChangefeedOptions.sortEngine = "unified" 170 o.changefeedID = "abcd" 171 o.namespace = "ns" 172 require.NotNil(t, o.run(cmd)) 173 }