github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/cmd/cli/cli_changefeed_resume_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 "testing" 20 "time" 21 22 "github.com/golang/mock/gomock" 23 "github.com/pingcap/errors" 24 v2 "github.com/pingcap/tiflow/cdc/api/v2" 25 "github.com/pingcap/tiflow/cdc/model" 26 cerror "github.com/pingcap/tiflow/pkg/errors" 27 "github.com/stretchr/testify/require" 28 "github.com/tikv/client-go/v2/oracle" 29 ) 30 31 func TestChangefeedResumeCli(t *testing.T) { 32 ctrl := gomock.NewController(t) 33 defer ctrl.Finish() 34 f := newMockFactory(ctrl) 35 o := newResumeChangefeedOptions() 36 o.complete(f) 37 cmd := newCmdResumeChangefeed(f) 38 39 // 1. test changefeed resume with non-nil changefeed get result, non-nil tso get result 40 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 41 UpstreamID: 1, 42 Namespace: "default", 43 ID: "abc", 44 CheckpointTime: model.JSONTime{}, 45 Error: nil, 46 }, nil) 47 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(&v2.Tso{ 48 Timestamp: time.Now().Unix() * 1000, 49 }, nil).AnyTimes() 50 f.changefeeds.EXPECT().Resume(gomock.Any(), &v2.ResumeChangefeedConfig{ 51 OverwriteCheckpointTs: 0, 52 }, "ns", "abc").Return(nil) 53 os.Args = []string{"resume", "--no-confirm=true", "--changefeed-id=abc", "--namespace=ns"} 54 require.Nil(t, cmd.Execute()) 55 56 // 2. test changefeed resume with nil changfeed get result 57 f.changefeeds.EXPECT().Get(gomock.Any(), "ns", "abc").Return(&v2.ChangeFeedInfo{}, nil) 58 os.Args = []string{"resume", "--no-confirm=false", "--changefeed-id=abc", "--namespace=ns"} 59 o.noConfirm = false 60 o.changefeedID = "abc" 61 o.namespace = "ns" 62 require.NotNil(t, o.run(cmd)) 63 64 // 3. test changefeed resume with nil tso get result 65 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 66 UpstreamID: 1, 67 Namespace: "default", 68 ID: "abc", 69 CheckpointTime: model.JSONTime{}, 70 CheckpointTs: 2, 71 }, nil) 72 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(nil, errors.New("test")).AnyTimes() 73 require.NotNil(t, o.run(cmd)) 74 75 // 4. test changefeed resume with non-nil changefeed result, non-nil tso get result, 76 // and confirmation checking 77 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 78 UpstreamID: 1, 79 Namespace: "default", 80 ID: "abc", 81 CheckpointTime: model.JSONTime{}, 82 CheckpointTs: 2, 83 }, nil) 84 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(&v2.Tso{ 85 Timestamp: time.Now().Unix() * 1000, 86 }, nil).AnyTimes() 87 dir := t.TempDir() 88 path := filepath.Join(dir, "confirm.txt") 89 err := os.WriteFile(path, []byte("n"), 0o644) 90 require.Nil(t, err) 91 file, err := os.Open(path) 92 require.Nil(t, err) 93 stdin := os.Stdin 94 os.Stdin = file 95 defer func() { 96 os.Stdin = stdin 97 }() 98 err = o.run(cmd) 99 require.NotNil(t, err) 100 require.Regexp(t, "cli changefeed resume", err) 101 } 102 103 func TestChangefeedResumeWithNewCheckpointTs(t *testing.T) { 104 ctrl := gomock.NewController(t) 105 defer ctrl.Finish() 106 f := newMockFactory(ctrl) 107 o := newResumeChangefeedOptions() 108 o.complete(f) 109 cmd := newCmdResumeChangefeed(f) 110 111 // 1. test changefeed resume with valid overwritten checkpointTs 112 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 113 UpstreamID: 1, 114 Namespace: "default", 115 ID: "abc", 116 CheckpointTime: model.JSONTime{}, 117 Error: nil, 118 }, nil) 119 tso := &v2.Tso{ 120 Timestamp: time.Now().Unix() * 1000, 121 } 122 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(tso, nil).AnyTimes() 123 f.changefeeds.EXPECT().Resume(gomock.Any(), &v2.ResumeChangefeedConfig{ 124 OverwriteCheckpointTs: oracle.ComposeTS(tso.Timestamp, tso.LogicTime), 125 }, gomock.Any(), "abc").Return(nil) 126 os.Args = []string{ 127 "resume", "--no-confirm=true", "--changefeed-id=abc", 128 "--overwrite-checkpoint-ts=now", 129 } 130 require.Nil(t, cmd.Execute()) 131 132 // 2. test changefeed resume with invalid overwritten checkpointTs 133 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 134 UpstreamID: 1, 135 Namespace: "default", 136 ID: "abc", 137 CheckpointTime: model.JSONTime{}, 138 Error: nil, 139 }, nil) 140 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(tso, nil).AnyTimes() 141 o.noConfirm = true 142 o.changefeedID = "abc" 143 o.overwriteCheckpointTs = "Hello" 144 require.NotNil(t, o.run(cmd)) 145 146 // 3. test changefeed resume with checkpointTs larger than current tso 147 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 148 UpstreamID: 1, 149 Namespace: "default", 150 ID: "abc", 151 CheckpointTime: model.JSONTime{}, 152 Error: nil, 153 }, nil) 154 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(tso, nil).AnyTimes() 155 o.overwriteCheckpointTs = "18446744073709551615" 156 require.NotNil(t, o.run(cmd)) 157 158 // 4. test changefeed resume with checkpointTs smaller than gcSafePoint 159 f.changefeeds.EXPECT().Get(gomock.Any(), gomock.Any(), "abc").Return(&v2.ChangeFeedInfo{ 160 UpstreamID: 1, 161 Namespace: "default", 162 ID: "abc", 163 CheckpointTime: model.JSONTime{}, 164 Error: nil, 165 }, nil) 166 tso = &v2.Tso{ 167 Timestamp: 1, 168 } 169 f.tso.EXPECT().Query(gomock.Any(), gomock.Any()).Return(tso, nil).AnyTimes() 170 f.changefeeds.EXPECT().Resume(gomock.Any(), &v2.ResumeChangefeedConfig{ 171 OverwriteCheckpointTs: 262144, 172 }, gomock.Any(), "abc"). 173 Return(cerror.ErrStartTsBeforeGC) 174 o.overwriteCheckpointTs = "262144" 175 require.NotNil(t, o.run(cmd)) 176 }