github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/cmd/server/server_test.go (about)

     1  // Copyright 2020 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 server
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"os"
    20  	"path/filepath"
    21  	"testing"
    22  	"time"
    23  
    24  	ticonfig "github.com/pingcap/tidb/pkg/config"
    25  	"github.com/pingcap/tiflow/pkg/config"
    26  	"github.com/pingcap/tiflow/pkg/security"
    27  	"github.com/spf13/cobra"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  func TestPatchTiDBConf(t *testing.T) {
    32  	t.TempDir()
    33  	patchTiDBConf()
    34  	cfg := ticonfig.GetGlobalConfig()
    35  	require.Equal(t, uint(0), cfg.TiKVClient.MaxBatchSize)
    36  }
    37  
    38  func TestValidateWithEmptyPdAddress(t *testing.T) {
    39  	cmd := new(cobra.Command)
    40  	o := newOptions()
    41  	o.addFlags(cmd)
    42  
    43  	require.Nil(t, cmd.ParseFlags([]string{"--pd="}))
    44  	err := o.complete(cmd)
    45  	require.Nil(t, err)
    46  	err = o.validate()
    47  	require.Regexp(t, ".*empty PD address.*", err.Error())
    48  }
    49  
    50  func TestValidateWithInvalidPdAddress(t *testing.T) {
    51  	cmd := new(cobra.Command)
    52  	o := newOptions()
    53  	o.addFlags(cmd)
    54  
    55  	require.Nil(t, cmd.ParseFlags([]string{"--pd=aa"}))
    56  	err := o.complete(cmd)
    57  	require.Nil(t, err)
    58  	err = o.validate()
    59  	require.Regexp(t, ".*PD endpoint should be a valid http or https URL.*", err.Error())
    60  }
    61  
    62  func TestValidateWithInvalidPdAddressWithoutHost(t *testing.T) {
    63  	cmd := new(cobra.Command)
    64  	o := newOptions()
    65  	o.addFlags(cmd)
    66  
    67  	require.Nil(t, cmd.ParseFlags([]string{"--pd=http://"}))
    68  	err := o.complete(cmd)
    69  	require.Nil(t, err)
    70  	err = o.validate()
    71  	require.Regexp(t, ".*PD endpoint should be a valid http or https URL.*", err.Error())
    72  }
    73  
    74  func TestValidateWithHttpsPdAddressWithoutCertificate(t *testing.T) {
    75  	cmd := new(cobra.Command)
    76  	o := newOptions()
    77  	o.addFlags(cmd)
    78  
    79  	require.Nil(t, cmd.ParseFlags([]string{"--pd=https://aa"}))
    80  	err := o.complete(cmd)
    81  	require.Nil(t, err)
    82  	err = o.validate()
    83  	require.Regexp(t, ".*PD endpoint scheme is https, please provide certificate.*", err.Error())
    84  }
    85  
    86  func TestAddUnknownFlag(t *testing.T) {
    87  	cmd := new(cobra.Command)
    88  	o := newOptions()
    89  	o.addFlags(cmd)
    90  
    91  	require.Regexp(t, ".*unknown flag: --PD.*", cmd.ParseFlags([]string{"--PD="}).Error())
    92  }
    93  
    94  func TestDefaultCfg(t *testing.T) {
    95  	cmd := new(cobra.Command)
    96  	o := newOptions()
    97  	o.addFlags(cmd)
    98  
    99  	require.Nil(t, cmd.ParseFlags([]string{}))
   100  	err := o.complete(cmd)
   101  	require.Nil(t, err)
   102  
   103  	defaultCfg := config.GetDefaultServerConfig()
   104  	require.Nil(t, defaultCfg.ValidateAndAdjust())
   105  	require.Equal(t, defaultCfg, o.serverConfig)
   106  	require.Equal(t, "http://127.0.0.1:2379", o.serverPdAddr)
   107  }
   108  
   109  func TestParseCfg(t *testing.T) {
   110  	dataDir := t.TempDir()
   111  	cmd := new(cobra.Command)
   112  	o := newOptions()
   113  	o.addFlags(cmd)
   114  
   115  	require.Nil(t, cmd.ParseFlags([]string{
   116  		"--addr", "127.5.5.1:8833",
   117  		"--advertise-addr", "127.5.5.1:7777",
   118  		"--log-file", "/root/cdc.log",
   119  		"--log-level", "debug",
   120  		"--data-dir", dataDir,
   121  		"--gc-ttl", "10",
   122  		"--tz", "UTC",
   123  		"--owner-flush-interval", "150ms",
   124  		"--processor-flush-interval", "150ms",
   125  		"--cert", "bb",
   126  		"--key", "cc",
   127  		"--cert-allowed-cn", "dd,ee",
   128  		"--sort-dir", "/tmp/just_a_test",
   129  	}))
   130  
   131  	err := o.complete(cmd)
   132  	require.Nil(t, err)
   133  	err = o.validate()
   134  	require.Nil(t, err)
   135  	require.Equal(t, &config.ServerConfig{
   136  		Addr:          "127.5.5.1:8833",
   137  		AdvertiseAddr: "127.5.5.1:7777",
   138  		LogFile:       "/root/cdc.log",
   139  		LogLevel:      "debug",
   140  		Log: &config.LogConfig{
   141  			File: &config.LogFileConfig{
   142  				MaxSize:    300,
   143  				MaxDays:    0,
   144  				MaxBackups: 0,
   145  			},
   146  			InternalErrOutput: "stderr",
   147  		},
   148  		DataDir:                dataDir,
   149  		GcTTL:                  10,
   150  		TZ:                     "UTC",
   151  		CaptureSessionTTL:      10,
   152  		OwnerFlushInterval:     config.TomlDuration(150 * time.Millisecond),
   153  		ProcessorFlushInterval: config.TomlDuration(150 * time.Millisecond),
   154  		Sorter: &config.SorterConfig{
   155  			SortDir:       config.DefaultSortDir,
   156  			CacheSizeInMB: 128,
   157  		},
   158  		Security: &security.Credential{
   159  			CertPath:      "bb",
   160  			KeyPath:       "cc",
   161  			CertAllowedCN: []string{"dd", "ee"},
   162  		},
   163  		KVClient: &config.KVClientConfig{
   164  			EnableMultiplexing:   true,
   165  			WorkerConcurrent:     8,
   166  			GrpcStreamConcurrent: 1,
   167  			AdvanceIntervalInMs:  300,
   168  			FrontierConcurrent:   8,
   169  			WorkerPoolSize:       0,
   170  			RegionScanLimit:      40,
   171  			RegionRetryDuration:  config.TomlDuration(time.Minute),
   172  		},
   173  		Debug: &config.DebugConfig{
   174  			DB: &config.DBConfig{
   175  				Count:               8,
   176  				MaxOpenFiles:        10000,
   177  				BlockSize:           65536,
   178  				WriterBufferSize:    8388608,
   179  				Compression:         "snappy",
   180  				WriteL0PauseTrigger: math.MaxInt32,
   181  				CompactionL0Trigger: 16,
   182  			},
   183  			// We expect the default configuration here.
   184  			Messages: &config.MessagesConfig{
   185  				ClientMaxBatchInterval:       config.TomlDuration(time.Millisecond * 10),
   186  				ClientMaxBatchSize:           8 * 1024 * 1024,
   187  				ClientMaxBatchCount:          128,
   188  				ClientRetryRateLimit:         1.0,
   189  				ServerMaxPendingMessageCount: 102400,
   190  				ServerAckInterval:            config.TomlDuration(time.Millisecond * 100),
   191  				ServerWorkerPoolSize:         4,
   192  				MaxRecvMsgSize:               256 * 1024 * 1024,
   193  				KeepAliveTimeout:             config.TomlDuration(time.Second * 10),
   194  				KeepAliveTime:                config.TomlDuration(time.Second * 30),
   195  			},
   196  			Scheduler: &config.SchedulerConfig{
   197  				HeartbeatTick:        2,
   198  				CollectStatsTick:     200,
   199  				MaxTaskConcurrency:   10,
   200  				CheckBalanceInterval: 60000000000,
   201  				AddTableBatchSize:    50,
   202  			},
   203  			CDCV2: &config.CDCV2{
   204  				Enable:          false,
   205  				MetaStoreConfig: config.MetaStoreConfiguration{},
   206  			},
   207  			Puller: &config.PullerConfig{
   208  				EnableResolvedTsStuckDetection: false,
   209  				ResolvedTsStuckInterval:        config.TomlDuration(5 * time.Minute),
   210  			},
   211  		},
   212  		ClusterID: "default",
   213  	}, o.serverConfig)
   214  }
   215  
   216  func TestDecodeCfg(t *testing.T) {
   217  	dataDir := t.TempDir()
   218  	tmpDir := t.TempDir()
   219  	configPath := filepath.Join(tmpDir, "ticdc.toml")
   220  	configContent := fmt.Sprintf(`
   221  addr = "128.0.0.1:1234"
   222  advertise-addr = "127.0.0.1:1111"
   223  
   224  log-file = "/root/cdc1.log"
   225  log-level = "warn"
   226  
   227  data-dir = "%+v"
   228  gc-ttl = 500
   229  tz = "US"
   230  capture-session-ttl = 10
   231  
   232  owner-flush-interval = "600ms"
   233  processor-flush-interval = "600ms"
   234  
   235  [log.file]
   236  max-size = 200
   237  max-days = 1
   238  max-backups = 1
   239  
   240  [sorter]
   241  sort-dir = "/tmp/just_a_test"
   242  cache-size-in-mb = 8
   243  
   244  [kv-client]
   245  region-retry-duration = "3s"
   246  
   247  [debug]
   248  [debug.db]
   249  count = 5
   250  max-open-files = 7
   251  block-size = 32768 # 32 KB
   252  block-cache-size = 8
   253  writer-buffer-size = 9
   254  compression = "none"
   255  target-file-size-base = 10
   256  compaction-l0-trigger = 11
   257  write-l0-pause-trigger = 13
   258  
   259  [debug.messages]
   260  client-max-batch-interval = "500ms"
   261  client-max-batch-size = 999
   262  client-max-batch-count = 888
   263  client-retry-rate-limit = 100.0
   264  server-max-pending-message-count = 1024
   265  server-ack-interval = "1s"
   266  server-worker-pool-size = 16
   267  max-recv-msg-size = 4
   268  [debug.scheduler]
   269  heartbeat-tick = 3
   270  collect-stats-tick = 201
   271  max-task-concurrency = 11
   272  check-balance-interval = "10s"
   273  `, dataDir)
   274  	err := os.WriteFile(configPath, []byte(configContent), 0o644)
   275  	require.Nil(t, err)
   276  
   277  	cmd := new(cobra.Command)
   278  	o := newOptions()
   279  	o.addFlags(cmd)
   280  
   281  	require.Nil(t, cmd.ParseFlags([]string{"--config", configPath}))
   282  
   283  	err = o.complete(cmd)
   284  	require.Nil(t, err)
   285  	err = o.validate()
   286  	require.Nil(t, err)
   287  	require.Equal(t, &config.ServerConfig{
   288  		Addr:          "128.0.0.1:1234",
   289  		AdvertiseAddr: "127.0.0.1:1111",
   290  		LogFile:       "/root/cdc1.log",
   291  		LogLevel:      "warn",
   292  		Log: &config.LogConfig{
   293  			File: &config.LogFileConfig{
   294  				MaxSize:    200,
   295  				MaxDays:    1,
   296  				MaxBackups: 1,
   297  			},
   298  			InternalErrOutput: "stderr",
   299  		},
   300  		DataDir:                dataDir,
   301  		GcTTL:                  500,
   302  		TZ:                     "US",
   303  		CaptureSessionTTL:      10,
   304  		OwnerFlushInterval:     config.TomlDuration(600 * time.Millisecond),
   305  		ProcessorFlushInterval: config.TomlDuration(600 * time.Millisecond),
   306  		Sorter: &config.SorterConfig{
   307  			SortDir:       config.DefaultSortDir,
   308  			CacheSizeInMB: 8,
   309  		},
   310  		Security: &security.Credential{},
   311  		KVClient: &config.KVClientConfig{
   312  			EnableMultiplexing:   true,
   313  			WorkerConcurrent:     8,
   314  			GrpcStreamConcurrent: 1,
   315  			AdvanceIntervalInMs:  300,
   316  			FrontierConcurrent:   8,
   317  			WorkerPoolSize:       0,
   318  			RegionScanLimit:      40,
   319  			RegionRetryDuration:  config.TomlDuration(3 * time.Second),
   320  		},
   321  		Debug: &config.DebugConfig{
   322  			DB: &config.DBConfig{
   323  				Count:               5,
   324  				MaxOpenFiles:        7,
   325  				BlockSize:           32768,
   326  				WriterBufferSize:    9,
   327  				Compression:         "none",
   328  				CompactionL0Trigger: 11,
   329  				WriteL0PauseTrigger: 13,
   330  			},
   331  			Messages: &config.MessagesConfig{
   332  				ClientMaxBatchInterval:       config.TomlDuration(500 * time.Millisecond),
   333  				ClientMaxBatchSize:           999,
   334  				ClientMaxBatchCount:          888,
   335  				ClientRetryRateLimit:         100.0,
   336  				ServerMaxPendingMessageCount: 1024,
   337  				ServerAckInterval:            config.TomlDuration(1 * time.Second),
   338  				ServerWorkerPoolSize:         16,
   339  				MaxRecvMsgSize:               4,
   340  				KeepAliveTimeout:             config.TomlDuration(time.Second * 10),
   341  				KeepAliveTime:                config.TomlDuration(time.Second * 30),
   342  			},
   343  			Scheduler: &config.SchedulerConfig{
   344  				HeartbeatTick:        3,
   345  				CollectStatsTick:     201,
   346  				MaxTaskConcurrency:   11,
   347  				CheckBalanceInterval: config.TomlDuration(10 * time.Second),
   348  				AddTableBatchSize:    50,
   349  			},
   350  			CDCV2: &config.CDCV2{
   351  				Enable:          false,
   352  				MetaStoreConfig: config.MetaStoreConfiguration{},
   353  			},
   354  			Puller: &config.PullerConfig{
   355  				EnableResolvedTsStuckDetection: false,
   356  				ResolvedTsStuckInterval:        config.TomlDuration(5 * time.Minute),
   357  			},
   358  		},
   359  		ClusterID: "default",
   360  	}, o.serverConfig)
   361  }
   362  
   363  func TestDecodeCfgWithFlags(t *testing.T) {
   364  	dataDir := t.TempDir()
   365  	tmpDir := t.TempDir()
   366  	configPath := filepath.Join(tmpDir, "ticdc.toml")
   367  	configContent := fmt.Sprintf(`
   368  addr = "128.0.0.1:1234"
   369  advertise-addr = "127.0.0.1:1111"
   370  
   371  log-file = "/root/cdc1.log"
   372  log-level = "warn"
   373  
   374  data-dir = "%+v"
   375  gc-ttl = 500
   376  tz = "US"
   377  capture-session-ttl = 10
   378  
   379  owner-flush-interval = "600ms"
   380  processor-flush-interval = "600ms"
   381  
   382  [log.file]
   383  max-size = 200
   384  max-days = 1
   385  max-backups = 1
   386  
   387  [sorter]
   388  sort-dir = "/tmp/just_a_test"
   389  cache-size-in-mb = 8
   390  
   391  [security]
   392  ca-path = "aa"
   393  cert-path = "bb"
   394  key-path = "cc"
   395  cert-allowed-cn = ["dd","ee"]
   396  `, dataDir)
   397  	err := os.WriteFile(configPath, []byte(configContent), 0o644)
   398  	require.Nil(t, err)
   399  
   400  	cmd := new(cobra.Command)
   401  	o := newOptions()
   402  	o.addFlags(cmd)
   403  
   404  	require.Nil(t, cmd.ParseFlags([]string{
   405  		"--addr", "127.5.5.1:8833",
   406  		"--log-file", "/root/cdc.log",
   407  		"--log-level", "debug",
   408  		"--data-dir", dataDir,
   409  		"--gc-ttl", "10",
   410  		"--tz", "UTC",
   411  		"--owner-flush-interval", "150ms",
   412  		"--processor-flush-interval", "150ms",
   413  		"--ca", "",
   414  		"--config", configPath,
   415  	}))
   416  
   417  	err = o.complete(cmd)
   418  	require.Nil(t, err)
   419  	err = o.validate()
   420  	require.Nil(t, err)
   421  	require.Equal(t, &config.ServerConfig{
   422  		Addr:          "127.5.5.1:8833",
   423  		AdvertiseAddr: "127.0.0.1:1111",
   424  		LogFile:       "/root/cdc.log",
   425  		LogLevel:      "debug",
   426  		Log: &config.LogConfig{
   427  			File: &config.LogFileConfig{
   428  				MaxSize:    200,
   429  				MaxDays:    1,
   430  				MaxBackups: 1,
   431  			},
   432  			InternalErrOutput: "stderr",
   433  		},
   434  		DataDir:                dataDir,
   435  		GcTTL:                  10,
   436  		TZ:                     "UTC",
   437  		CaptureSessionTTL:      10,
   438  		OwnerFlushInterval:     config.TomlDuration(150 * time.Millisecond),
   439  		ProcessorFlushInterval: config.TomlDuration(150 * time.Millisecond),
   440  		Sorter: &config.SorterConfig{
   441  			SortDir:       config.DefaultSortDir,
   442  			CacheSizeInMB: 8,
   443  		},
   444  		Security: &security.Credential{
   445  			CertPath:      "bb",
   446  			KeyPath:       "cc",
   447  			CertAllowedCN: []string{"dd", "ee"},
   448  		},
   449  		KVClient: &config.KVClientConfig{
   450  			EnableMultiplexing:   true,
   451  			WorkerConcurrent:     8,
   452  			GrpcStreamConcurrent: 1,
   453  			AdvanceIntervalInMs:  300,
   454  			FrontierConcurrent:   8,
   455  			WorkerPoolSize:       0,
   456  			RegionScanLimit:      40,
   457  			RegionRetryDuration:  config.TomlDuration(time.Minute),
   458  		},
   459  		Debug: &config.DebugConfig{
   460  			DB: &config.DBConfig{
   461  				Count:               8,
   462  				MaxOpenFiles:        10000,
   463  				BlockSize:           65536,
   464  				WriterBufferSize:    8388608,
   465  				Compression:         "snappy",
   466  				WriteL0PauseTrigger: math.MaxInt32,
   467  				CompactionL0Trigger: 16,
   468  			},
   469  			// We expect the default configuration here.
   470  			Messages: &config.MessagesConfig{
   471  				ClientMaxBatchInterval:       config.TomlDuration(time.Millisecond * 10),
   472  				ClientMaxBatchSize:           8 * 1024 * 1024,
   473  				ClientMaxBatchCount:          128,
   474  				ClientRetryRateLimit:         1.0,
   475  				ServerMaxPendingMessageCount: 102400,
   476  				ServerAckInterval:            config.TomlDuration(time.Millisecond * 100),
   477  				ServerWorkerPoolSize:         4,
   478  				MaxRecvMsgSize:               256 * 1024 * 1024,
   479  				KeepAliveTimeout:             config.TomlDuration(time.Second * 10),
   480  				KeepAliveTime:                config.TomlDuration(time.Second * 30),
   481  			},
   482  			Scheduler: &config.SchedulerConfig{
   483  				HeartbeatTick:        2,
   484  				CollectStatsTick:     200,
   485  				MaxTaskConcurrency:   10,
   486  				CheckBalanceInterval: 60000000000,
   487  				AddTableBatchSize:    50,
   488  			},
   489  			CDCV2: &config.CDCV2{
   490  				Enable:          false,
   491  				MetaStoreConfig: config.MetaStoreConfiguration{},
   492  			},
   493  			Puller: &config.PullerConfig{
   494  				EnableResolvedTsStuckDetection: false,
   495  				ResolvedTsStuckInterval:        config.TomlDuration(5 * time.Minute),
   496  			},
   497  		},
   498  		ClusterID: "default",
   499  	}, o.serverConfig)
   500  }
   501  
   502  func TestDecodeUnknownDebugCfg(t *testing.T) {
   503  	tmpDir := t.TempDir()
   504  	configPath := filepath.Join(tmpDir, "ticdc.toml")
   505  	configContent := `
   506  [debug]
   507  unknown1 = 1
   508  [debug.unknown2]
   509  unknown3 = 3
   510  `
   511  	err := os.WriteFile(configPath, []byte(configContent), 0o644)
   512  	require.Nil(t, err)
   513  
   514  	cmd := new(cobra.Command)
   515  	o := newOptions()
   516  	o.addFlags(cmd)
   517  
   518  	require.Nil(t, cmd.ParseFlags([]string{"--config", configPath}))
   519  
   520  	err = o.complete(cmd)
   521  	require.Nil(t, err)
   522  	err = o.validate()
   523  	require.Nil(t, err)
   524  	require.Equal(t, &config.DebugConfig{
   525  		DB: &config.DBConfig{
   526  			Count:               8,
   527  			MaxOpenFiles:        10000,
   528  			BlockSize:           65536,
   529  			WriterBufferSize:    8388608,
   530  			Compression:         "snappy",
   531  			WriteL0PauseTrigger: math.MaxInt32,
   532  			CompactionL0Trigger: 16,
   533  		},
   534  		// We expect the default configuration here.
   535  		Messages: &config.MessagesConfig{
   536  			ClientMaxBatchInterval:       config.TomlDuration(time.Millisecond * 10),
   537  			ClientMaxBatchSize:           8 * 1024 * 1024,
   538  			ClientMaxBatchCount:          128,
   539  			ClientRetryRateLimit:         1.0,
   540  			ServerMaxPendingMessageCount: 102400,
   541  			ServerAckInterval:            config.TomlDuration(time.Millisecond * 100),
   542  			ServerWorkerPoolSize:         4,
   543  			MaxRecvMsgSize:               256 * 1024 * 1024,
   544  			KeepAliveTimeout:             config.TomlDuration(time.Second * 10),
   545  			KeepAliveTime:                config.TomlDuration(time.Second * 30),
   546  		},
   547  		Scheduler: &config.SchedulerConfig{
   548  			HeartbeatTick:        2,
   549  			CollectStatsTick:     200,
   550  			MaxTaskConcurrency:   10,
   551  			CheckBalanceInterval: 60000000000,
   552  			AddTableBatchSize:    50,
   553  		},
   554  		CDCV2: &config.CDCV2{
   555  			Enable:          false,
   556  			MetaStoreConfig: config.MetaStoreConfiguration{},
   557  		},
   558  		Puller: &config.PullerConfig{
   559  			EnableResolvedTsStuckDetection: false,
   560  			ResolvedTsStuckInterval:        config.TomlDuration(5 * time.Minute),
   561  		},
   562  	}, o.serverConfig.Debug)
   563  }