github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/config/task_converters_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  package config
    14  
    15  import (
    16  	"fmt"
    17  	"testing"
    18  
    19  	"github.com/pingcap/check"
    20  	"github.com/pingcap/tidb/pkg/util/filter"
    21  	"github.com/pingcap/tiflow/dm/config/dbconfig"
    22  	"github.com/pingcap/tiflow/dm/openapi"
    23  	"github.com/pingcap/tiflow/dm/openapi/fixtures"
    24  	"github.com/pingcap/tiflow/dm/pkg/terror"
    25  	bf "github.com/pingcap/tiflow/pkg/binlog-filter"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func (t *testConfig) TestTaskGetTargetDBCfg(c *check.C) {
    30  	certAllowedCn := []string{"test"}
    31  	task := &openapi.Task{
    32  		TargetConfig: openapi.TaskTargetDataBase{
    33  			Host:     "root",
    34  			Password: "123456",
    35  			Port:     4000,
    36  			User:     "root",
    37  			Security: &openapi.Security{CertAllowedCn: &certAllowedCn},
    38  		},
    39  	}
    40  	dbCfg := GetTargetDBCfgFromOpenAPITask(task)
    41  	c.Assert(dbCfg.Host, check.Equals, task.TargetConfig.Host)
    42  	c.Assert(dbCfg.Password, check.Equals, task.TargetConfig.Password)
    43  	c.Assert(dbCfg.Port, check.Equals, task.TargetConfig.Port)
    44  	c.Assert(dbCfg.User, check.Equals, task.TargetConfig.User)
    45  	c.Assert(dbCfg.Security, check.NotNil)
    46  	c.Assert([]string{dbCfg.Security.CertAllowedCN[0]}, check.DeepEquals, certAllowedCn)
    47  }
    48  
    49  func (t *testConfig) TestOpenAPITaskToSubTaskConfigs(c *check.C) {
    50  	testNoShardTaskToSubTaskConfigs(c)
    51  	testShardAndFilterTaskToSubTaskConfigs(c)
    52  }
    53  
    54  func testNoShardTaskToSubTaskConfigs(c *check.C) {
    55  	task, err := fixtures.GenNoShardOpenAPITaskForTest()
    56  	c.Assert(err, check.IsNil)
    57  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
    58  	c.Assert(err, check.IsNil)
    59  	source1Name := task.SourceConfig.SourceConf[0].SourceName
    60  	sourceCfg1.SourceID = task.SourceConfig.SourceConf[0].SourceName
    61  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1}
    62  	toDBCfg := &dbconfig.DBConfig{
    63  		Host:     task.TargetConfig.Host,
    64  		Port:     task.TargetConfig.Port,
    65  		User:     task.TargetConfig.User,
    66  		Password: task.TargetConfig.Password,
    67  	}
    68  	// change meta
    69  	newMeta := "new_dm_meta"
    70  	task.MetaSchema = &newMeta
    71  	subTaskConfigList, err := OpenAPITaskToSubTaskConfigs(&task, toDBCfg, sourceCfgMap)
    72  	c.Assert(err, check.IsNil)
    73  	c.Assert(subTaskConfigList, check.HasLen, 1)
    74  	subTaskConfig := subTaskConfigList[0]
    75  	// check task name and mode
    76  	c.Assert(subTaskConfig.Name, check.Equals, task.Name)
    77  	// check task meta
    78  	c.Assert(subTaskConfig.MetaSchema, check.Equals, *task.MetaSchema)
    79  	c.Assert(subTaskConfig.Meta, check.IsNil)
    80  	// check shard config
    81  	c.Assert(subTaskConfig.ShardMode, check.Equals, "")
    82  	// check online schema change
    83  	c.Assert(subTaskConfig.OnlineDDL, check.Equals, true)
    84  	// check case sensitive
    85  	c.Assert(subTaskConfig.CaseSensitive, check.Equals, sourceCfg1.CaseSensitive)
    86  	// check from
    87  	c.Assert(subTaskConfig.From.Host, check.Equals, sourceCfg1.From.Host)
    88  	// check to
    89  	c.Assert(subTaskConfig.To.Host, check.Equals, toDBCfg.Host)
    90  	// check dumpling loader syncer config
    91  	c.Assert(subTaskConfig.MydumperConfig.Threads, check.Equals, *task.SourceConfig.FullMigrateConf.ExportThreads)
    92  	c.Assert(subTaskConfig.LoaderConfig.Dir, check.Equals, fmt.Sprintf(
    93  		"%s.%s", *task.SourceConfig.FullMigrateConf.DataDir, task.Name))
    94  	c.Assert(subTaskConfig.LoaderConfig.PoolSize, check.Equals, *task.SourceConfig.FullMigrateConf.ImportThreads)
    95  	c.Assert(subTaskConfig.SyncerConfig.WorkerCount, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplThreads)
    96  	c.Assert(subTaskConfig.SyncerConfig.Batch, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplBatch)
    97  	// check route
    98  	c.Assert(subTaskConfig.RouteRules, check.HasLen, 1)
    99  	rule := subTaskConfig.RouteRules[0]
   100  
   101  	sourceSchema := task.TableMigrateRule[0].Source.Schema
   102  	sourceTable := task.TableMigrateRule[0].Source.Table
   103  	tartgetSchema := task.TableMigrateRule[0].Target.Schema
   104  	tartgetTable := task.TableMigrateRule[0].Target.Table
   105  
   106  	c.Assert(rule.SchemaPattern, check.Equals, sourceSchema)
   107  	c.Assert(rule.TablePattern, check.Equals, sourceTable)
   108  	c.Assert(rule.TargetSchema, check.Equals, *tartgetSchema)
   109  	c.Assert(rule.TargetTable, check.Equals, *tartgetTable)
   110  	// check filter
   111  	c.Assert(subTaskConfig.FilterRules, check.HasLen, 0)
   112  	// check balist
   113  	c.Assert(subTaskConfig.BAList, check.NotNil)
   114  	bAListFromOpenAPITask := &filter.Rules{
   115  		DoTables: []*filter.Table{{Schema: sourceSchema, Name: sourceTable}},
   116  	}
   117  	c.Assert(subTaskConfig.BAList, check.DeepEquals, bAListFromOpenAPITask)
   118  	// check ignore check items
   119  	c.Assert(subTaskConfig.IgnoreCheckingItems, check.IsNil)
   120  }
   121  
   122  func testShardAndFilterTaskToSubTaskConfigs(c *check.C) {
   123  	task, err := fixtures.GenShardAndFilterOpenAPITaskForTest()
   124  	c.Assert(err, check.IsNil)
   125  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   126  	c.Assert(err, check.IsNil)
   127  	source1Name := task.SourceConfig.SourceConf[0].SourceName
   128  	sourceCfg1.SourceID = source1Name
   129  	sourceCfg2, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   130  	c.Assert(err, check.IsNil)
   131  	source2Name := task.SourceConfig.SourceConf[1].SourceName
   132  	sourceCfg2.SourceID = source2Name
   133  
   134  	toDBCfg := &dbconfig.DBConfig{
   135  		Host:     task.TargetConfig.Host,
   136  		Port:     task.TargetConfig.Port,
   137  		User:     task.TargetConfig.User,
   138  		Password: task.TargetConfig.Password,
   139  	}
   140  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1, source2Name: sourceCfg2}
   141  	subTaskConfigList, err := OpenAPITaskToSubTaskConfigs(&task, toDBCfg, sourceCfgMap)
   142  	c.Assert(err, check.IsNil)
   143  	c.Assert(subTaskConfigList, check.HasLen, 2)
   144  
   145  	// check sub task 1
   146  	subTask1Config := subTaskConfigList[0]
   147  	// check task name and mode
   148  	c.Assert(subTask1Config.Name, check.Equals, task.Name)
   149  	// check task meta
   150  	c.Assert(subTask1Config.MetaSchema, check.Equals, *task.MetaSchema)
   151  	c.Assert(subTask1Config.Meta, check.NotNil)
   152  	c.Assert(subTask1Config.Meta.BinLogGTID, check.Equals, *task.SourceConfig.SourceConf[0].BinlogGtid)
   153  	c.Assert(subTask1Config.Meta.BinLogName, check.Equals, *task.SourceConfig.SourceConf[0].BinlogName)
   154  	c.Assert(subTask1Config.Meta.BinLogPos, check.Equals, uint32(*task.SourceConfig.SourceConf[0].BinlogPos))
   155  
   156  	// check shard config
   157  	c.Assert(subTask1Config.ShardMode, check.Equals, string(openapi.TaskShardModeOptimistic))
   158  	c.Assert(subTask1Config.StrictOptimisticShardMode, check.IsTrue)
   159  	// check online schema change
   160  	c.Assert(subTask1Config.OnlineDDL, check.Equals, true)
   161  	// check case sensitive
   162  	c.Assert(subTask1Config.CaseSensitive, check.Equals, sourceCfg1.CaseSensitive)
   163  	// check from
   164  	c.Assert(subTask1Config.From.Host, check.Equals, sourceCfg1.From.Host)
   165  	// check to
   166  	c.Assert(subTask1Config.To.Host, check.Equals, toDBCfg.Host)
   167  	// check dumpling loader syncer config
   168  	c.Assert(subTask1Config.MydumperConfig.Threads, check.Equals, *task.SourceConfig.FullMigrateConf.ExportThreads)
   169  	c.Assert(subTask1Config.LoaderConfig.Dir, check.Equals, fmt.Sprintf(
   170  		"%s.%s", *task.SourceConfig.FullMigrateConf.DataDir, task.Name))
   171  	c.Assert(subTask1Config.LoaderConfig.PoolSize, check.Equals, *task.SourceConfig.FullMigrateConf.ImportThreads)
   172  	c.Assert(subTask1Config.SyncerConfig.WorkerCount, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplThreads)
   173  	c.Assert(subTask1Config.SyncerConfig.Batch, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplBatch)
   174  	// check route
   175  	c.Assert(subTask1Config.RouteRules, check.HasLen, 1)
   176  	rule := subTask1Config.RouteRules[0]
   177  	source1Schema := task.TableMigrateRule[0].Source.Schema
   178  	source1Table := task.TableMigrateRule[0].Source.Table
   179  	tartgetSchema := task.TableMigrateRule[0].Target.Schema
   180  	tartgetTable := task.TableMigrateRule[0].Target.Table
   181  	c.Assert(rule.SchemaPattern, check.Equals, source1Schema)
   182  	c.Assert(rule.TablePattern, check.Equals, source1Table)
   183  	c.Assert(rule.TargetSchema, check.Equals, *tartgetSchema)
   184  	c.Assert(rule.TargetTable, check.Equals, *tartgetTable)
   185  	// check filter
   186  	filterARule, ok := task.BinlogFilterRule.Get("filterA")
   187  	c.Assert(ok, check.IsTrue)
   188  	filterIgnoreEvents := *filterARule.IgnoreEvent
   189  	c.Assert(filterIgnoreEvents, check.HasLen, 1)
   190  	filterEvents := []bf.EventType{bf.EventType(filterIgnoreEvents[0])}
   191  	filterRulesFromOpenAPITask := &bf.BinlogEventRule{
   192  		Action:        bf.Ignore,
   193  		Events:        filterEvents,
   194  		SQLPattern:    *filterARule.IgnoreSql,
   195  		SchemaPattern: source1Schema,
   196  		TablePattern:  source1Table,
   197  	}
   198  	c.Assert(filterRulesFromOpenAPITask.Valid(), check.IsNil)
   199  	c.Assert(subTask1Config.FilterRules, check.HasLen, 1)
   200  	c.Assert(subTask1Config.FilterRules[0], check.DeepEquals, filterRulesFromOpenAPITask)
   201  
   202  	// check balist
   203  	c.Assert(subTask1Config.BAList, check.NotNil)
   204  	bAListFromOpenAPITask := &filter.Rules{
   205  		DoTables: []*filter.Table{{Schema: source1Schema, Name: source1Table}},
   206  	}
   207  	c.Assert(subTask1Config.BAList, check.DeepEquals, bAListFromOpenAPITask)
   208  	// check ignore check items
   209  	c.Assert(subTask1Config.IgnoreCheckingItems, check.IsNil)
   210  
   211  	// check sub task 2
   212  	subTask2Config := subTaskConfigList[1]
   213  	// check task name and mode
   214  	c.Assert(subTask2Config.Name, check.Equals, task.Name)
   215  	// check task meta
   216  	c.Assert(subTask2Config.MetaSchema, check.Equals, *task.MetaSchema)
   217  	c.Assert(subTask2Config.Meta, check.NotNil)
   218  	c.Assert(subTask2Config.Meta.BinLogGTID, check.Equals, *task.SourceConfig.SourceConf[1].BinlogGtid)
   219  	c.Assert(subTask2Config.Meta.BinLogName, check.Equals, *task.SourceConfig.SourceConf[1].BinlogName)
   220  	c.Assert(subTask2Config.Meta.BinLogPos, check.Equals, uint32(*task.SourceConfig.SourceConf[1].BinlogPos))
   221  	// check shard config
   222  	c.Assert(subTask2Config.ShardMode, check.Equals, string(openapi.TaskShardModeOptimistic))
   223  	// check online schema change
   224  	c.Assert(subTask2Config.OnlineDDL, check.Equals, true)
   225  	// check case sensitive
   226  	c.Assert(subTask2Config.CaseSensitive, check.Equals, sourceCfg2.CaseSensitive)
   227  	// check from
   228  	c.Assert(subTask2Config.From.Host, check.Equals, sourceCfg2.From.Host)
   229  	// check to
   230  	c.Assert(subTask2Config.To.Host, check.Equals, toDBCfg.Host)
   231  	// check dumpling loader syncer config
   232  	c.Assert(subTask2Config.MydumperConfig.Threads, check.Equals, *task.SourceConfig.FullMigrateConf.ExportThreads)
   233  	c.Assert(subTask2Config.LoaderConfig.Dir, check.Equals, fmt.Sprintf(
   234  		"%s.%s", *task.SourceConfig.FullMigrateConf.DataDir, task.Name))
   235  	c.Assert(subTask2Config.LoaderConfig.PoolSize, check.Equals, *task.SourceConfig.FullMigrateConf.ImportThreads)
   236  	c.Assert(subTask2Config.SyncerConfig.WorkerCount, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplThreads)
   237  	c.Assert(subTask2Config.SyncerConfig.Batch, check.Equals, *task.SourceConfig.IncrMigrateConf.ReplBatch)
   238  	// check route
   239  	c.Assert(subTask2Config.RouteRules, check.HasLen, 1)
   240  	rule = subTask2Config.RouteRules[0]
   241  	source2Schema := task.TableMigrateRule[1].Source.Schema
   242  	source2Table := task.TableMigrateRule[1].Source.Table
   243  	c.Assert(rule.SchemaPattern, check.Equals, source2Schema)
   244  	c.Assert(rule.TablePattern, check.Equals, source2Table)
   245  	c.Assert(rule.TargetSchema, check.Equals, *tartgetSchema)
   246  	c.Assert(rule.TargetTable, check.Equals, *tartgetTable)
   247  	// check filter
   248  	_, ok = task.BinlogFilterRule.Get("filterB")
   249  	c.Assert(ok, check.IsFalse)
   250  	c.Assert(subTask2Config.FilterRules, check.HasLen, 0)
   251  	// check balist
   252  	c.Assert(subTask2Config.BAList, check.NotNil)
   253  	bAListFromOpenAPITask = &filter.Rules{
   254  		DoTables: []*filter.Table{{Schema: source2Schema, Name: source2Table}},
   255  	}
   256  	c.Assert(subTask2Config.BAList, check.DeepEquals, bAListFromOpenAPITask)
   257  	// check ignore check items
   258  	c.Assert(subTask2Config.IgnoreCheckingItems, check.IsNil)
   259  }
   260  
   261  func (t *testConfig) TestSubTaskConfigsToOpenAPITask(c *check.C) {
   262  	testNoShardSubTaskConfigsToOpenAPITask(c)
   263  	testShardAndFilterSubTaskConfigsToOpenAPITask(c)
   264  }
   265  
   266  func testNoShardSubTaskConfigsToOpenAPITask(c *check.C) {
   267  	task, err := fixtures.GenNoShardOpenAPITaskForTest()
   268  	c.Assert(err, check.IsNil)
   269  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   270  	c.Assert(err, check.IsNil)
   271  	source1Name := task.SourceConfig.SourceConf[0].SourceName
   272  	sourceCfg1.SourceID = task.SourceConfig.SourceConf[0].SourceName
   273  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1}
   274  	toDBCfg := &dbconfig.DBConfig{
   275  		Host:     task.TargetConfig.Host,
   276  		Port:     task.TargetConfig.Port,
   277  		User:     task.TargetConfig.User,
   278  		Password: task.TargetConfig.Password,
   279  	}
   280  	subTaskConfigList, err := OpenAPITaskToSubTaskConfigs(&task, toDBCfg, sourceCfgMap)
   281  	c.Assert(err, check.IsNil)
   282  	c.Assert(subTaskConfigList, check.HasLen, 1)
   283  
   284  	// prepare sub task config
   285  	subTaskConfigMap := make(map[string]map[string]*SubTaskConfig)
   286  	subTaskConfigMap[task.Name] = make(map[string]*SubTaskConfig)
   287  	subTaskConfigMap[task.Name][source1Name] = subTaskConfigList[0]
   288  
   289  	taskList := SubTaskConfigsToOpenAPITaskList(subTaskConfigMap)
   290  	c.Assert(taskList, check.HasLen, 1)
   291  	newTask := taskList[0]
   292  	c.Assert(&task, check.DeepEquals, newTask)
   293  }
   294  
   295  func testShardAndFilterSubTaskConfigsToOpenAPITask(c *check.C) {
   296  	task, err := fixtures.GenShardAndFilterOpenAPITaskForTest()
   297  	c.Assert(err, check.IsNil)
   298  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   299  	c.Assert(err, check.IsNil)
   300  	source1Name := task.SourceConfig.SourceConf[0].SourceName
   301  	sourceCfg1.SourceID = source1Name
   302  	sourceCfg2, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   303  	c.Assert(err, check.IsNil)
   304  	source2Name := task.SourceConfig.SourceConf[1].SourceName
   305  	sourceCfg2.SourceID = source2Name
   306  
   307  	toDBCfg := &dbconfig.DBConfig{
   308  		Host:     task.TargetConfig.Host,
   309  		Port:     task.TargetConfig.Port,
   310  		User:     task.TargetConfig.User,
   311  		Password: task.TargetConfig.Password,
   312  	}
   313  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1, source2Name: sourceCfg2}
   314  	subTaskConfigList, err := OpenAPITaskToSubTaskConfigs(&task, toDBCfg, sourceCfgMap)
   315  	c.Assert(err, check.IsNil)
   316  	c.Assert(subTaskConfigList, check.HasLen, 2)
   317  
   318  	// prepare sub task config
   319  	subTaskConfigMap := make(map[string]map[string]*SubTaskConfig)
   320  	subTaskConfigMap[task.Name] = make(map[string]*SubTaskConfig)
   321  	subTaskConfigMap[task.Name][source1Name] = subTaskConfigList[0]
   322  	subTaskConfigMap[task.Name][source2Name] = subTaskConfigList[1]
   323  
   324  	taskList := SubTaskConfigsToOpenAPITaskList(subTaskConfigMap)
   325  	c.Assert(taskList, check.HasLen, 1)
   326  	newTask := taskList[0]
   327  
   328  	// because subtask config not have filter-rule-name, so we need to add it manually
   329  	oldRuleName := "filterA"
   330  	newRuleName := genFilterRuleName(source1Name, 0)
   331  	oldRule, ok := task.BinlogFilterRule.Get(oldRuleName)
   332  	c.Assert(ok, check.IsTrue)
   333  	newRule := openapi.Task_BinlogFilterRule{}
   334  	newRule.Set(newRuleName, oldRule)
   335  	task.BinlogFilterRule = &newRule
   336  	task.TableMigrateRule[0].BinlogFilterRule = &[]string{newRuleName}
   337  
   338  	// because map key is not sorted, so generated array (source_conf and table_migrate_rule) order may not same with old one.
   339  	// so we need to fix it manually.
   340  	if task.SourceConfig.SourceConf[0].SourceName != newTask.SourceConfig.SourceConf[0].SourceName {
   341  		task.SourceConfig.SourceConf[0], task.SourceConfig.SourceConf[1] = task.SourceConfig.SourceConf[1], task.SourceConfig.SourceConf[0]
   342  	}
   343  	if task.TableMigrateRule[0].Source.SourceName != newTask.TableMigrateRule[0].Source.SourceName {
   344  		task.TableMigrateRule[0], task.TableMigrateRule[1] = task.TableMigrateRule[1], task.TableMigrateRule[0]
   345  	}
   346  
   347  	c.Assert(&task, check.DeepEquals, newTask)
   348  }
   349  
   350  func TestConvertWithIgnoreCheckItems(t *testing.T) {
   351  	task, err := fixtures.GenNoShardOpenAPITaskForTest()
   352  	require.NoError(t, err)
   353  	ignoreCheckingItems := []string{DumpPrivilegeChecking, VersionChecking}
   354  	task.IgnoreCheckingItems = &ignoreCheckingItems
   355  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   356  	require.NoError(t, err)
   357  	source1Name := task.SourceConfig.SourceConf[0].SourceName
   358  	sourceCfg1.SourceID = task.SourceConfig.SourceConf[0].SourceName
   359  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1}
   360  	toDBCfg := &dbconfig.DBConfig{
   361  		Host:     task.TargetConfig.Host,
   362  		Port:     task.TargetConfig.Port,
   363  		User:     task.TargetConfig.User,
   364  		Password: task.TargetConfig.Password,
   365  	}
   366  	subTaskConfigList, err := OpenAPITaskToSubTaskConfigs(&task, toDBCfg, sourceCfgMap)
   367  	require.NoError(t, err)
   368  	require.Equal(t, 1, len(subTaskConfigList))
   369  
   370  	// prepare sub task config
   371  	subTaskConfigMap := make(map[string]map[string]*SubTaskConfig)
   372  	subTaskConfigMap[task.Name] = make(map[string]*SubTaskConfig)
   373  	subTaskConfigMap[task.Name][source1Name] = subTaskConfigList[0]
   374  
   375  	taskList := SubTaskConfigsToOpenAPITaskList(subTaskConfigMap)
   376  	require.Equal(t, 1, len(taskList))
   377  	newTask := taskList[0]
   378  	require.Equal(t, *newTask.IgnoreCheckingItems, ignoreCheckingItems)
   379  	require.Equal(t, *newTask, task)
   380  }
   381  
   382  func TestConvertBetweenOpenAPITaskAndTaskConfig(t *testing.T) {
   383  	// one source task
   384  	task, err := fixtures.GenNoShardOpenAPITaskForTest()
   385  	require.NoError(t, err)
   386  
   387  	sourceCfg1, err := SourceCfgFromYamlAndVerify(SampleSourceConfig)
   388  	require.NoError(t, err)
   389  	source1Name := task.SourceConfig.SourceConf[0].SourceName
   390  	sourceCfg1.SourceID = source1Name
   391  	sourceCfgMap := map[string]*SourceConfig{source1Name: sourceCfg1}
   392  
   393  	taskCfg, err := OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   394  	require.NoError(t, err)
   395  	require.NotNil(t, taskCfg)
   396  	task1, err := TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   397  	require.NoError(t, err)
   398  	require.NotNil(t, task1)
   399  	require.EqualValues(t, task1, &task)
   400  
   401  	// test update some fields in task
   402  	{
   403  		batch := 1000
   404  		task.SourceConfig.IncrMigrateConf.ReplBatch = &batch
   405  		taskCfg2, err2 := OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   406  		require.NoError(t, err2)
   407  		require.Equal(t, batch, taskCfg2.MySQLInstances[0].Syncer.Batch)
   408  		for _, cfg := range taskCfg2.Syncers {
   409  			require.Equal(t, batch, cfg.Batch)
   410  		}
   411  
   412  		// test update some fields in taskConfig
   413  		batch = 1
   414  		for _, cfg := range taskCfg2.Syncers {
   415  			cfg.Batch = batch
   416  		}
   417  		task2, err3 := TaskConfigToOpenAPITask(taskCfg2, sourceCfgMap)
   418  		require.NoError(t, err3)
   419  		require.Equal(t, batch, *task2.SourceConfig.IncrMigrateConf.ReplBatch)
   420  	}
   421  
   422  	// test update route
   423  	{
   424  		require.Len(t, task.TableMigrateRule, 1)
   425  		sourceSchema := task.TableMigrateRule[0].Source.Schema
   426  		targetSchema := *task.TableMigrateRule[0].Target.Schema
   427  		// only route schema
   428  		task.TableMigrateRule[0].Source = struct {
   429  			Schema     string `json:"schema"`
   430  			SourceName string `json:"source_name"`
   431  			Table      string `json:"table"`
   432  		}{
   433  			SourceName: source1Name,
   434  			Schema:     sourceSchema,
   435  		}
   436  		task.TableMigrateRule[0].Target = &struct {
   437  			Schema *string `json:"schema,omitempty"`
   438  			Table  *string `json:"table,omitempty"`
   439  		}{
   440  			Schema: &targetSchema,
   441  		}
   442  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   443  		require.NoError(t, err)
   444  		require.Len(t, taskCfg.Routes, 1)
   445  		var routeKey string
   446  		for k := range taskCfg.Routes {
   447  			routeKey = k
   448  		}
   449  
   450  		// validate route rule in taskCfg
   451  		require.Equal(t, sourceSchema, taskCfg.Routes[routeKey].SchemaPattern)
   452  		require.Equal(t, "", taskCfg.Routes[routeKey].TablePattern)
   453  		require.Equal(t, targetSchema, taskCfg.Routes[routeKey].TargetSchema)
   454  		require.Equal(t, "", taskCfg.Routes[routeKey].TargetTable)
   455  
   456  		// validate baList in taskCfg, just do DBs because there is no table route rule
   457  		require.Len(t, taskCfg.BAList, 1)
   458  		require.Len(t, taskCfg.MySQLInstances, 1)
   459  		baListName := taskCfg.MySQLInstances[0].BAListName
   460  		require.Len(t, taskCfg.BAList[baListName].DoTables, 0)
   461  		require.Len(t, taskCfg.BAList[baListName].DoDBs, 1)
   462  		require.Equal(t, sourceSchema, taskCfg.BAList[baListName].DoDBs[0])
   463  
   464  		// convert back to openapi.Task
   465  		taskAfterConvert, err2 := TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   466  		require.NoError(t, err2)
   467  		require.NotNil(t, taskAfterConvert)
   468  		require.EqualValues(t, taskAfterConvert, &task)
   469  
   470  		// only route table will meet error
   471  		sourceTable := "tb"
   472  		targetTable := "tb1"
   473  		task.TableMigrateRule[0].Source = struct {
   474  			Schema     string `json:"schema"`
   475  			SourceName string `json:"source_name"`
   476  			Table      string `json:"table"`
   477  		}{
   478  			SourceName: source1Name,
   479  			Schema:     sourceSchema,
   480  			Table:      sourceTable,
   481  		}
   482  		task.TableMigrateRule[0].Target = &struct {
   483  			Schema *string `json:"schema,omitempty"`
   484  			Table  *string `json:"table,omitempty"`
   485  		}{
   486  			Table: &targetTable,
   487  		}
   488  		_, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   489  		require.True(t, terror.ErrConfigGenTableRouter.Equal(err))
   490  
   491  		// route both
   492  		task.TableMigrateRule[0].Source = struct {
   493  			Schema     string `json:"schema"`
   494  			SourceName string `json:"source_name"`
   495  			Table      string `json:"table"`
   496  		}{
   497  			SourceName: source1Name,
   498  			Schema:     sourceSchema,
   499  			Table:      sourceTable,
   500  		}
   501  		task.TableMigrateRule[0].Target = &struct {
   502  			Schema *string `json:"schema,omitempty"`
   503  			Table  *string `json:"table,omitempty"`
   504  		}{
   505  			Schema: &targetSchema,
   506  			Table:  &targetTable,
   507  		}
   508  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   509  		require.NoError(t, err)
   510  
   511  		// validate route rule in taskCfg
   512  		require.Equal(t, sourceSchema, taskCfg.Routes[routeKey].SchemaPattern)
   513  		require.Equal(t, sourceTable, taskCfg.Routes[routeKey].TablePattern)
   514  		require.Equal(t, targetSchema, taskCfg.Routes[routeKey].TargetSchema)
   515  		require.Equal(t, targetTable, taskCfg.Routes[routeKey].TargetTable)
   516  
   517  		// validate baList in taskCfg, just do Tables because there is a table route rule
   518  		require.Len(t, taskCfg.BAList[baListName].DoDBs, 0)
   519  		require.Len(t, taskCfg.BAList[baListName].DoTables, 1)
   520  		require.Equal(t, sourceSchema, taskCfg.BAList[baListName].DoTables[0].Schema)
   521  		require.Equal(t, sourceTable, taskCfg.BAList[baListName].DoTables[0].Name)
   522  
   523  		// convert back to openapi.Task
   524  		taskAfterConvert, err = TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   525  		require.NoError(t, err)
   526  		require.NotNil(t, taskAfterConvert)
   527  		require.EqualValues(t, taskAfterConvert, &task)
   528  
   529  		// no route and only sync one table
   530  		task.TableMigrateRule[0].Target = nil
   531  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   532  		require.NoError(t, err)
   533  		require.Len(t, taskCfg.Routes, 0)
   534  
   535  		// validate baList in taskCfg, just do Tables because there is a table route rule
   536  		require.Len(t, taskCfg.BAList[baListName].DoDBs, 0)
   537  		require.Len(t, taskCfg.BAList[baListName].DoTables, 1)
   538  		require.Equal(t, sourceSchema, taskCfg.BAList[baListName].DoTables[0].Schema)
   539  		require.Equal(t, sourceTable, taskCfg.BAList[baListName].DoTables[0].Name)
   540  
   541  		taskAfterConvert, err = TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   542  		require.NoError(t, err)
   543  		require.NotNil(t, taskAfterConvert)
   544  		require.EqualValues(t, taskAfterConvert, &task)
   545  
   546  		// no route and sync one schema
   547  		task.TableMigrateRule[0].Source = struct {
   548  			Schema     string `json:"schema"`
   549  			SourceName string `json:"source_name"`
   550  			Table      string `json:"table"`
   551  		}{
   552  			SourceName: source1Name,
   553  			Schema:     sourceSchema,
   554  			Table:      "",
   555  		}
   556  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   557  		require.NoError(t, err)
   558  		require.Len(t, taskCfg.Routes, 0)
   559  
   560  		// validate baList in taskCfg, just do DBs because there is no table route rule
   561  		require.Len(t, taskCfg.BAList[baListName].DoTables, 0)
   562  		require.Len(t, taskCfg.BAList[baListName].DoDBs, 1)
   563  		require.Equal(t, sourceSchema, taskCfg.BAList[baListName].DoDBs[0])
   564  
   565  		taskAfterConvert, err = TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   566  		require.NoError(t, err)
   567  		require.NotNil(t, taskAfterConvert)
   568  		require.EqualValues(t, taskAfterConvert, &task)
   569  	}
   570  
   571  	// test update filter
   572  	{
   573  		// no filter no change
   574  		require.Nil(t, task.BinlogFilterRule)
   575  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   576  		require.NoError(t, err)
   577  		taskAfterConvert, err := TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   578  		require.NoError(t, err)
   579  		require.NotNil(t, taskAfterConvert)
   580  		require.EqualValues(t, taskAfterConvert, &task)
   581  
   582  		// filter both
   583  		sourceSchema := task.TableMigrateRule[0].Source.Schema
   584  		sourceTable := task.TableMigrateRule[0].Source.Table
   585  		ignoreEvent := []string{"drop database"}
   586  		ignoreSQL := []string{"^Drop"}
   587  		ruleName := genFilterRuleName(source1Name, 0)
   588  		ruleNameList := []string{ruleName}
   589  		rule := openapi.TaskBinLogFilterRule{IgnoreEvent: &ignoreEvent, IgnoreSql: &ignoreSQL}
   590  		ruleM := &openapi.Task_BinlogFilterRule{}
   591  		ruleM.Set(ruleName, rule)
   592  		task.BinlogFilterRule = ruleM
   593  		task.TableMigrateRule[0].BinlogFilterRule = &ruleNameList
   594  
   595  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   596  		require.NoError(t, err)
   597  		require.Len(t, taskCfg.Filters, 1)
   598  		require.Len(t, taskCfg.MySQLInstances[0].FilterRules, 1)
   599  		filterName := taskCfg.MySQLInstances[0].FilterRules[0]
   600  		require.Equal(t, bf.Ignore, taskCfg.Filters[filterName].Action)
   601  		require.Equal(t, sourceSchema, taskCfg.Filters[filterName].SchemaPattern)
   602  		require.Equal(t, sourceTable, taskCfg.Filters[filterName].TablePattern)
   603  		require.Len(t, taskCfg.Filters[filterName].SQLPattern, 1)
   604  		require.Equal(t, ignoreSQL[0], taskCfg.Filters[filterName].SQLPattern[0])
   605  		require.Len(t, taskCfg.Filters[filterName].Events, 1)
   606  		require.Equal(t, ignoreEvent[0], string(taskCfg.Filters[filterName].Events[0]))
   607  
   608  		// convert back to openapi.Task
   609  		taskAfterConvert, err = TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   610  		require.NoError(t, err)
   611  		require.NotNil(t, taskAfterConvert)
   612  		require.EqualValues(t, taskAfterConvert, &task)
   613  
   614  		// only filter events
   615  		rule = openapi.TaskBinLogFilterRule{IgnoreEvent: &ignoreEvent}
   616  		ruleM.Set(ruleName, rule)
   617  		taskCfg, err = OpenAPITaskToTaskConfig(&task, sourceCfgMap)
   618  		require.NoError(t, err)
   619  		require.Len(t, taskCfg.Filters[filterName].SQLPattern, 0)
   620  
   621  		taskAfterConvert, err = TaskConfigToOpenAPITask(taskCfg, sourceCfgMap)
   622  		ruleMAfterConvert := taskAfterConvert.BinlogFilterRule
   623  		ruleAfterConvert, ok := ruleMAfterConvert.Get(ruleName)
   624  		require.True(t, ok)
   625  		require.Nil(t, ruleAfterConvert.IgnoreSql)
   626  		require.NoError(t, err)
   627  		require.NotNil(t, taskAfterConvert)
   628  		require.EqualValues(t, taskAfterConvert, &task)
   629  	}
   630  }