github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/orm/util_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 orm 15 16 import ( 17 "context" 18 "regexp" 19 "testing" 20 "time" 21 22 "github.com/DATA-DOG/go-sqlmock" 23 "github.com/go-sql-driver/mysql" 24 tmysql "github.com/pingcap/tidb/pkg/parser/mysql" 25 metaMock "github.com/pingcap/tiflow/engine/pkg/meta/mock" 26 "github.com/pingcap/tiflow/pkg/errors" 27 "github.com/stretchr/testify/require" 28 ) 29 30 func TestIsNotFoundError(t *testing.T) { 31 b := IsNotFoundError(errors.ErrMetaEntryNotFound.GenWithStackByArgs("error")) 32 require.True(t, b) 33 34 b = IsNotFoundError(errors.ErrMetaEntryNotFound.GenWithStack("err:%s", "error")) 35 require.True(t, b) 36 37 b = IsNotFoundError(errors.ErrMetaEntryNotFound.Wrap(errors.New("error"))) 38 require.True(t, b) 39 40 b = IsNotFoundError(errors.ErrMetaNewClientFail.Wrap(errors.New("error"))) 41 require.False(t, b) 42 43 b = IsNotFoundError(errors.New("error")) 44 require.False(t, b) 45 } 46 47 func TestInitialize(t *testing.T) { 48 db, mock, err := sqlmock.New() 49 require.Nil(t, err) 50 defer db.Close() 51 defer mock.ExpectClose() 52 53 // common execution for orm 54 mock.ExpectQuery("SELECT VERSION()"). 55 WillReturnRows(sqlmock.NewRows([]string{"VERSION()"}).AddRow("5.7.35-log")) 56 57 mock.ExpectExec(regexp.QuoteMeta("CREATE TABLE `project_infos` (`seq_id` bigint unsigned AUTO_INCREMENT," + 58 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL," + 59 "`id` varchar(128) not null,`name` varchar(128) not null,PRIMARY KEY (`seq_id`)," + 60 "UNIQUE INDEX `uidx_id` (`id`))")).WillReturnResult(sqlmock.NewResult(1, 1)) 61 62 mock.ExpectExec(regexp.QuoteMeta("CREATE TABLE `project_operations` (`seq_id` bigint unsigned AUTO_INCREMENT," + 63 "`project_id` varchar(128) not null,`operation` varchar(16) not null,`job_id` varchar(128) not null," + 64 "`created_at` datetime(3) NULL,PRIMARY KEY (`seq_id`),INDEX `idx_op` (`project_id`,`created_at`))")).WillReturnResult(sqlmock.NewResult(1, 1)) 65 66 mock.ExpectExec(regexp.QuoteMeta( 67 "CREATE TABLE `master_meta` (`seq_id` bigint unsigned AUTO_INCREMENT,"+ 68 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,"+ 69 "`project_id` varchar(128) not null,`id` varchar(128) not null,"+ 70 "`type` smallint not null COMMENT "+ 71 "'JobManager(1),CvsJobMaster(2),FakeJobMaster(3),DMJobMaster(4),CDCJobMaster(5)',"+ 72 "`state` tinyint not null COMMENT "+ 73 "'Uninit(1),Init(2),Finished(3),Stopped(4),Failed(5)',"+ 74 "`node_id` varchar(128) not null,`address` varchar(256) not null,"+ 75 "`epoch` bigint not null,`config` blob,`error_message` text,"+ 76 "`detail` blob,`ext` JSON,`deleted` datetime(3) NULL,"+ 77 "PRIMARY KEY (`seq_id`)") + 78 ".*", // sequence of indexes are nondeterministic 79 ).WillReturnResult(sqlmock.NewResult(1, 1)) 80 81 mock.ExpectExec(regexp.QuoteMeta( 82 "CREATE TABLE `worker_statuses` (`seq_id` bigint unsigned AUTO_INCREMENT,"+ 83 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,"+ 84 "`project_id` varchar(128) not null,`job_id` varchar(128) not null,"+ 85 "`id` varchar(128) not null,`type` smallint not null COMMENT "+ 86 "'JobManager(1),CvsJobMaster(2),FakeJobMaster(3),DMJobMaster(4),"+ 87 "CDCJobMaster(5),CvsTask(6),FakeTask(7),DMTask(8),CDCTask(9),"+ 88 "WorkerDMDump(10),WorkerDMLoad(11),WorkerDMSync(12)',"+ 89 "`state` tinyint not null COMMENT "+ 90 "'Normal(1),Created(2),Init(3),Error(4),Finished(5),Stopped(6)',"+ 91 "`epoch` bigint not null,`error_message` text,`extend_bytes` blob,"+ 92 "PRIMARY KEY (`seq_id`)") + 93 ".*", // sequence of indexes are nondeterministic 94 ).WillReturnResult(sqlmock.NewResult(1, 1)) 95 96 mock.ExpectExec(regexp.QuoteMeta( 97 "CREATE TABLE `resource_meta` (`seq_id` bigint unsigned AUTO_INCREMENT,"+ 98 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,"+ 99 "`project_id` varchar(128) not null,`tenant_id` varchar(128) not null,"+ 100 "`id` varchar(128) not null,`job_id` varchar(128) not null,"+ 101 "`worker_id` varchar(128) not null,`executor_id` varchar(128) not null,"+ 102 "`gc_pending` BOOLEAN,`deleted` BOOLEAN,PRIMARY KEY (`seq_id`),") + 103 ".*", // sequence of indexes are nondeterministic 104 ).WillReturnResult(sqlmock.NewResult(1, 1)) 105 106 mock.ExpectExec(regexp.QuoteMeta("CREATE TABLE `logic_epoches` (`seq_id` bigint unsigned AUTO_INCREMENT,`created_at` datetime(3) NULL," + 107 "`updated_at` datetime(3) NULL,`job_id` varchar(128) not null,`epoch` bigint not null default 1,PRIMARY KEY (`seq_id`),UNIQUE INDEX `uidx_jk` (`job_id`))")). 108 WillReturnResult(sqlmock.NewResult(1, 1)) 109 110 mock.ExpectExec(regexp.QuoteMeta( 111 "CREATE TABLE `job_ops` (`seq_id` bigint unsigned AUTO_INCREMENT,"+ 112 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,"+ 113 "`op` tinyint not null COMMENT 'Canceling(1),Canceled(2)',"+ 114 "`job_id` varchar(128) not null,PRIMARY KEY (`seq_id`),") + 115 ".*", // sequence of indexes are nondeterministic 116 ).WillReturnResult(sqlmock.NewResult(1, 1)) 117 118 mock.ExpectExec(regexp.QuoteMeta( 119 "CREATE TABLE `executors` (`seq_id` bigint unsigned AUTO_INCREMENT," + 120 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL," + 121 "`id` varchar(256) not null,`name` varchar(256) not null," + 122 "`address` varchar(256) not null,`labels` json,PRIMARY KEY (`seq_id`)," + 123 "UNIQUE INDEX `uni_id` (`id`))"), 124 ).WillReturnResult(sqlmock.NewResult(1, 1)) 125 126 mock.ExpectExec(regexp.QuoteMeta("CREATE TABLE `logic_epoches` (`seq_id` bigint unsigned AUTO_INCREMENT," + 127 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,`job_id` varchar(128) not null,`epoch` bigint not null default 1," + 128 "PRIMARY KEY (`seq_id`),UNIQUE INDEX `uidx_jk` (`job_id`))")). 129 WillReturnResult(sqlmock.NewResult(1, 1)) 130 131 conn := metaMock.NewClientConnWithDB(db) 132 require.NotNil(t, conn) 133 defer conn.Close() 134 135 err = InitAllFrameworkModels(context.TODO(), conn) 136 require.Nil(t, err) 137 } 138 139 func TestInitEpochModel(t *testing.T) { 140 t.Parallel() 141 142 db, mock, err := sqlmock.New() 143 require.Nil(t, err) 144 defer db.Close() 145 defer mock.ExpectClose() 146 147 ctx, cancel := context.WithTimeout(context.TODO(), 1*time.Second) 148 defer cancel() 149 150 err = InitEpochModel(ctx, nil) 151 require.Regexp(t, regexp.QuoteMeta("input client conn is nil"), err.Error()) 152 153 mock.ExpectQuery("SELECT VERSION()"). 154 WillReturnRows(sqlmock.NewRows([]string{"VERSION()"}).AddRow("5.7.35-log")) 155 mock.ExpectExec(regexp.QuoteMeta("CREATE TABLE `logic_epoches` (`seq_id` bigint unsigned AUTO_INCREMENT," + 156 "`created_at` datetime(3) NULL,`updated_at` datetime(3) NULL,`job_id` varchar(128) not null,`epoch` bigint not null default 1," + 157 "PRIMARY KEY (`seq_id`),UNIQUE INDEX `uidx_jk` (`job_id`))")). 158 WillReturnResult(sqlmock.NewResult(1, 1)) 159 160 conn := metaMock.NewClientConnWithDB(db) 161 require.NotNil(t, conn) 162 defer conn.Close() 163 164 err = InitEpochModel(ctx, conn) 165 require.NoError(t, err) 166 } 167 168 func TestIsDuplicateEntryError(t *testing.T) { 169 t.Parallel() 170 testCases := []struct { 171 err error 172 expected bool 173 }{ 174 { 175 nil, false, 176 }, 177 { 178 errors.New("invalid connection"), false, 179 }, 180 { 181 &mysql.MySQLError{ 182 Number: tmysql.ErrDupEntry, 183 Message: "Duplicate entry '123456' for key 'index'", 184 }, true, 185 }, 186 { 187 errors.New("constraint failed: UNIQUE constraint failed: master_meta.id (2067)"), 188 true, 189 }, 190 } 191 for _, tc := range testCases { 192 require.Equal(t, tc.expected, IsDuplicateEntryError(tc.err)) 193 } 194 }