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  }