github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/config/config_test.go (about)

     1  // Copyright 2019 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 config_test
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"flag"
    20  	"fmt"
    21  	"net"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"net/url"
    25  	"path/filepath"
    26  	"regexp"
    27  	"strconv"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/BurntSushi/toml"
    32  	. "github.com/pingcap/check"
    33  	"github.com/pingcap/parser/mysql"
    34  
    35  	"github.com/pingcap/br/pkg/lightning/config"
    36  )
    37  
    38  func Test(t *testing.T) {
    39  	TestingT(t)
    40  }
    41  
    42  var _ = Suite(&configTestSuite{})
    43  
    44  type configTestSuite struct{}
    45  
    46  func startMockServer(c *C, statusCode int, content string) (*httptest.Server, string, int) {
    47  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    48  		w.WriteHeader(statusCode)
    49  		fmt.Fprint(w, content)
    50  	}))
    51  
    52  	url, err := url.Parse(ts.URL)
    53  	c.Assert(err, IsNil)
    54  	host, portString, err := net.SplitHostPort(url.Host)
    55  	c.Assert(err, IsNil)
    56  	port, err := strconv.Atoi(portString)
    57  	c.Assert(err, IsNil)
    58  
    59  	return ts, host, port
    60  }
    61  
    62  func assignMinimalLegalValue(cfg *config.Config) {
    63  	cfg.TiDB.Host = "123.45.67.89"
    64  	cfg.TiDB.Port = 4567
    65  	cfg.TiDB.StatusPort = 8901
    66  	cfg.TiDB.PdAddr = "234.56.78.90:12345"
    67  	cfg.Mydumper.SourceDir = "file://."
    68  	cfg.TikvImporter.Backend = config.BackendLocal
    69  	cfg.TikvImporter.SortedKVDir = "."
    70  	cfg.TikvImporter.DiskQuota = 1
    71  }
    72  
    73  func (s *configTestSuite) TestAdjustPdAddrAndPort(c *C) {
    74  	ts, host, port := startMockServer(c, http.StatusOK,
    75  		`{"port":4444,"advertise-address":"","path":"123.45.67.89:1234,56.78.90.12:3456"}`,
    76  	)
    77  	defer ts.Close()
    78  
    79  	cfg := config.NewConfig()
    80  	cfg.TiDB.Host = host
    81  	cfg.TiDB.StatusPort = port
    82  	cfg.Mydumper.SourceDir = "."
    83  	cfg.TikvImporter.Backend = config.BackendLocal
    84  	cfg.TikvImporter.SortedKVDir = "."
    85  	cfg.TiDB.DistSQLScanConcurrency = 1
    86  
    87  	err := cfg.Adjust(context.Background())
    88  	c.Assert(err, IsNil)
    89  	c.Assert(cfg.TiDB.Port, Equals, 4444)
    90  	c.Assert(cfg.TiDB.PdAddr, Equals, "123.45.67.89:1234")
    91  }
    92  
    93  func (s *configTestSuite) TestAdjustPdAddrAndPortViaAdvertiseAddr(c *C) {
    94  	ts, host, port := startMockServer(c, http.StatusOK,
    95  		`{"port":6666,"advertise-address":"121.212.121.212:5555","path":"34.34.34.34:3434"}`,
    96  	)
    97  	defer ts.Close()
    98  
    99  	cfg := config.NewConfig()
   100  	cfg.TiDB.Host = host
   101  	cfg.TiDB.StatusPort = port
   102  	cfg.Mydumper.SourceDir = "."
   103  	cfg.TikvImporter.Backend = config.BackendLocal
   104  	cfg.TikvImporter.SortedKVDir = "."
   105  	cfg.TiDB.DistSQLScanConcurrency = 1
   106  
   107  	err := cfg.Adjust(context.Background())
   108  	c.Assert(err, IsNil)
   109  	c.Assert(cfg.TiDB.Port, Equals, 6666)
   110  	c.Assert(cfg.TiDB.PdAddr, Equals, "34.34.34.34:3434")
   111  }
   112  
   113  func (s *configTestSuite) TestAdjustPageNotFound(c *C) {
   114  	ts, host, port := startMockServer(c, http.StatusNotFound, "{}")
   115  	defer ts.Close()
   116  
   117  	cfg := config.NewConfig()
   118  	cfg.TiDB.Host = host
   119  	cfg.TiDB.StatusPort = port
   120  	cfg.TikvImporter.Backend = config.BackendLocal
   121  	cfg.TikvImporter.SortedKVDir = "."
   122  	cfg.TiDB.DistSQLScanConcurrency = 1
   123  
   124  	err := cfg.Adjust(context.Background())
   125  	c.Assert(err, ErrorMatches, "cannot fetch settings from TiDB.*")
   126  }
   127  
   128  func (s *configTestSuite) TestAdjustConnectRefused(c *C) {
   129  	ts, host, port := startMockServer(c, http.StatusOK, "{}")
   130  
   131  	cfg := config.NewConfig()
   132  	cfg.TiDB.Host = host
   133  	cfg.TiDB.StatusPort = port
   134  	cfg.TikvImporter.Backend = config.BackendLocal
   135  	cfg.TikvImporter.SortedKVDir = "."
   136  	cfg.TiDB.DistSQLScanConcurrency = 1
   137  
   138  	ts.Close() // immediately close to ensure connection refused.
   139  
   140  	err := cfg.Adjust(context.Background())
   141  	c.Assert(err, ErrorMatches, "cannot fetch settings from TiDB.*")
   142  }
   143  
   144  func (s *configTestSuite) TestAdjustBackendNotSet(c *C) {
   145  	cfg := config.NewConfig()
   146  	cfg.TiDB.DistSQLScanConcurrency = 1
   147  	err := cfg.Adjust(context.Background())
   148  	c.Assert(err, ErrorMatches, "tikv-importer.backend must not be empty!")
   149  }
   150  
   151  func (s *configTestSuite) TestAdjustInvalidBackend(c *C) {
   152  	cfg := config.NewConfig()
   153  	cfg.TikvImporter.Backend = "no_such_backend"
   154  	cfg.TiDB.DistSQLScanConcurrency = 1
   155  	err := cfg.Adjust(context.Background())
   156  	c.Assert(err, ErrorMatches, "invalid config: unsupported `tikv-importer\\.backend` \\(no_such_backend\\)")
   157  }
   158  
   159  func (s *configTestSuite) TestAdjustFileRoutePath(c *C) {
   160  	cfg := config.NewConfig()
   161  	assignMinimalLegalValue(cfg)
   162  
   163  	ctx := context.Background()
   164  	tmpDir := c.MkDir()
   165  	cfg.Mydumper.SourceDir = tmpDir
   166  	invalidPath := filepath.Join(tmpDir, "../test123/1.sql")
   167  	rule := &config.FileRouteRule{Path: invalidPath, Type: "sql", Schema: "test", Table: "tbl"}
   168  	cfg.Mydumper.FileRouters = []*config.FileRouteRule{rule}
   169  	cfg.TiDB.DistSQLScanConcurrency = 1
   170  	err := cfg.Adjust(ctx)
   171  	c.Assert(err, ErrorMatches, fmt.Sprintf("\\Qfile route path '%s' is not in source dir '%s'\\E", invalidPath, tmpDir))
   172  
   173  	relPath := filepath.FromSlash("test_dir/1.sql")
   174  	rule.Path = filepath.Join(tmpDir, relPath)
   175  	err = cfg.Adjust(ctx)
   176  	c.Assert(err, IsNil)
   177  	c.Assert(cfg.Mydumper.FileRouters[0].Path, Equals, relPath)
   178  }
   179  
   180  func (s *configTestSuite) TestDecodeError(c *C) {
   181  	ts, host, port := startMockServer(c, http.StatusOK, "invalid-string")
   182  	defer ts.Close()
   183  
   184  	cfg := config.NewConfig()
   185  	cfg.TiDB.Host = host
   186  	cfg.TiDB.StatusPort = port
   187  	cfg.TikvImporter.Backend = config.BackendLocal
   188  	cfg.TikvImporter.SortedKVDir = "."
   189  	cfg.TiDB.DistSQLScanConcurrency = 1
   190  
   191  	err := cfg.Adjust(context.Background())
   192  	c.Assert(err, ErrorMatches, "cannot fetch settings from TiDB.*")
   193  }
   194  
   195  func (s *configTestSuite) TestInvalidSetting(c *C) {
   196  	ts, host, port := startMockServer(c, http.StatusOK, `{"port": 0}`)
   197  	defer ts.Close()
   198  
   199  	cfg := config.NewConfig()
   200  	cfg.TiDB.Host = host
   201  	cfg.TiDB.StatusPort = port
   202  	cfg.TikvImporter.Backend = config.BackendLocal
   203  	cfg.TikvImporter.SortedKVDir = "."
   204  	cfg.TiDB.DistSQLScanConcurrency = 1
   205  
   206  	err := cfg.Adjust(context.Background())
   207  	c.Assert(err, ErrorMatches, "invalid `tidb.port` setting")
   208  }
   209  
   210  func (s *configTestSuite) TestInvalidPDAddr(c *C) {
   211  	ts, host, port := startMockServer(c, http.StatusOK, `{"port": 1234, "path": ",,"}`)
   212  	defer ts.Close()
   213  
   214  	cfg := config.NewConfig()
   215  	cfg.TiDB.Host = host
   216  	cfg.TiDB.StatusPort = port
   217  	cfg.TikvImporter.Backend = config.BackendLocal
   218  	cfg.TikvImporter.SortedKVDir = "."
   219  	cfg.TiDB.DistSQLScanConcurrency = 1
   220  
   221  	err := cfg.Adjust(context.Background())
   222  	c.Assert(err, ErrorMatches, "invalid `tidb.pd-addr` setting")
   223  }
   224  
   225  func (s *configTestSuite) TestAdjustWillNotContactServerIfEverythingIsDefined(c *C) {
   226  	cfg := config.NewConfig()
   227  	assignMinimalLegalValue(cfg)
   228  	cfg.TiDB.DistSQLScanConcurrency = 1
   229  
   230  	err := cfg.Adjust(context.Background())
   231  	c.Assert(err, IsNil)
   232  	c.Assert(cfg.TiDB.Port, Equals, 4567)
   233  	c.Assert(cfg.TiDB.PdAddr, Equals, "234.56.78.90:12345")
   234  }
   235  
   236  func (s *configTestSuite) TestAdjustWillBatchImportRatioInvalid(c *C) {
   237  	cfg := config.NewConfig()
   238  	assignMinimalLegalValue(cfg)
   239  	cfg.Mydumper.BatchImportRatio = -1
   240  	cfg.TiDB.DistSQLScanConcurrency = 1
   241  	err := cfg.Adjust(context.Background())
   242  	c.Assert(err, IsNil)
   243  	c.Assert(cfg.Mydumper.BatchImportRatio, Equals, 0.75)
   244  }
   245  
   246  func (s *configTestSuite) TestAdjustSecuritySection(c *C) {
   247  	testCases := []struct {
   248  		input       string
   249  		expectedCA  string
   250  		expectedTLS string
   251  	}{
   252  		{
   253  			input:       ``,
   254  			expectedCA:  "",
   255  			expectedTLS: "false",
   256  		},
   257  		{
   258  			input: `
   259  				[security]
   260  			`,
   261  			expectedCA:  "",
   262  			expectedTLS: "false",
   263  		},
   264  		{
   265  			input: `
   266  				[security]
   267  				ca-path = "/path/to/ca.pem"
   268  			`,
   269  			expectedCA:  "/path/to/ca.pem",
   270  			expectedTLS: "cluster",
   271  		},
   272  		{
   273  			input: `
   274  				[security]
   275  				ca-path = "/path/to/ca.pem"
   276  				[tidb.security]
   277  			`,
   278  			expectedCA:  "",
   279  			expectedTLS: "false",
   280  		},
   281  		{
   282  			input: `
   283  				[security]
   284  				ca-path = "/path/to/ca.pem"
   285  				[tidb.security]
   286  				ca-path = "/path/to/ca2.pem"
   287  			`,
   288  			expectedCA:  "/path/to/ca2.pem",
   289  			expectedTLS: "cluster",
   290  		},
   291  		{
   292  			input: `
   293  				[security]
   294  				[tidb.security]
   295  				ca-path = "/path/to/ca2.pem"
   296  			`,
   297  			expectedCA:  "/path/to/ca2.pem",
   298  			expectedTLS: "cluster",
   299  		},
   300  		{
   301  			input: `
   302  				[security]
   303  				[tidb]
   304  				tls = "skip-verify"
   305  				[tidb.security]
   306  			`,
   307  			expectedCA:  "",
   308  			expectedTLS: "skip-verify",
   309  		},
   310  	}
   311  
   312  	for _, tc := range testCases {
   313  		comment := Commentf("input = %s", tc.input)
   314  
   315  		cfg := config.NewConfig()
   316  		assignMinimalLegalValue(cfg)
   317  		cfg.TiDB.DistSQLScanConcurrency = 1
   318  		err := cfg.LoadFromTOML([]byte(tc.input))
   319  		c.Assert(err, IsNil, comment)
   320  
   321  		err = cfg.Adjust(context.Background())
   322  		c.Assert(err, IsNil, comment)
   323  		c.Assert(cfg.TiDB.Security.CAPath, Equals, tc.expectedCA, comment)
   324  		c.Assert(cfg.TiDB.TLS, Equals, tc.expectedTLS, comment)
   325  	}
   326  }
   327  
   328  func (s *configTestSuite) TestInvalidCSV(c *C) {
   329  	testCases := []struct {
   330  		input string
   331  		err   string
   332  	}{
   333  		{
   334  			input: `
   335  				[mydumper.csv]
   336  				separator = ''
   337  			`,
   338  			err: "invalid config: `mydumper.csv.separator` must not be empty",
   339  		},
   340  		{
   341  			input: `
   342  				[mydumper.csv]
   343  				separator = 'hello'
   344  				delimiter = 'hel'
   345  			`,
   346  			err: "invalid config: `mydumper.csv.separator` and `mydumper.csv.delimiter` must not be prefix of each other",
   347  		},
   348  		{
   349  			input: `
   350  				[mydumper.csv]
   351  				separator = 'hel'
   352  				delimiter = 'hello'
   353  			`,
   354  			err: "invalid config: `mydumper.csv.separator` and `mydumper.csv.delimiter` must not be prefix of each other",
   355  		},
   356  		{
   357  			input: `
   358  				[mydumper.csv]
   359  				separator = '\'
   360  				backslash-escape = false
   361  			`,
   362  			err: "",
   363  		},
   364  		{
   365  			input: `
   366  				[mydumper.csv]
   367  				separator = ','
   368  			`,
   369  			err: "",
   370  		},
   371  		{
   372  			input: `
   373  				[mydumper.csv]
   374  				delimiter = ''
   375  			`,
   376  			err: "",
   377  		},
   378  		{
   379  			input: `
   380  				[mydumper.csv]
   381  				delimiter = 'hello'
   382  			`,
   383  			err: "",
   384  		},
   385  		{
   386  			input: `
   387  				[mydumper.csv]
   388  				delimiter = '\'
   389  				backslash-escape = false
   390  			`,
   391  			err: "",
   392  		},
   393  		{
   394  			input: `
   395  				[mydumper.csv]
   396  				separator = '\s'
   397  				delimiter = '\d'
   398  			`,
   399  			err: "",
   400  		},
   401  		{
   402  			input: `
   403  				[mydumper.csv]
   404  				separator = '|'
   405  				delimiter = '|'
   406  			`,
   407  			err: "invalid config: `mydumper.csv.separator` and `mydumper.csv.delimiter` must not be prefix of each other",
   408  		},
   409  		{
   410  			input: `
   411  				[mydumper.csv]
   412  				separator = '\'
   413  				backslash-escape = true
   414  			`,
   415  			err: "invalid config: cannot use '\\' as CSV separator when `mydumper.csv.backslash-escape` is true",
   416  		},
   417  		{
   418  			input: `
   419  				[mydumper.csv]
   420  				delimiter = '\'
   421  				backslash-escape = true
   422  			`,
   423  			err: "invalid config: cannot use '\\' as CSV delimiter when `mydumper.csv.backslash-escape` is true",
   424  		},
   425  		{
   426  			input: `
   427  				[tidb]
   428  				sql-mode = "invalid-sql-mode"
   429  			`,
   430  			err: "invalid config: `mydumper.tidb.sql_mode` must be a valid SQL_MODE: ERROR 1231 (42000): Variable 'sql_mode' can't be set to the value of 'invalid-sql-mode'",
   431  		},
   432  		{
   433  			input: `
   434  				[[routes]]
   435  				schema-pattern = ""
   436  				table-pattern = "shard_table_*"
   437  			`,
   438  			err: "schema pattern of table route rule should not be empty",
   439  		},
   440  		{
   441  			input: `
   442  				[[routes]]
   443  				schema-pattern = "schema_*"
   444  				table-pattern = ""
   445  			`,
   446  			err: "target schema of table route rule should not be empty",
   447  		},
   448  	}
   449  
   450  	for _, tc := range testCases {
   451  		comment := Commentf("input = %s", tc.input)
   452  
   453  		cfg := config.NewConfig()
   454  		cfg.Mydumper.SourceDir = "file://."
   455  		cfg.TiDB.Port = 4000
   456  		cfg.TiDB.PdAddr = "test.invalid:2379"
   457  		cfg.TikvImporter.Backend = config.BackendLocal
   458  		cfg.TikvImporter.SortedKVDir = "."
   459  		cfg.TiDB.DistSQLScanConcurrency = 1
   460  		err := cfg.LoadFromTOML([]byte(tc.input))
   461  		c.Assert(err, IsNil)
   462  
   463  		err = cfg.Adjust(context.Background())
   464  		if tc.err != "" {
   465  			c.Assert(err, ErrorMatches, regexp.QuoteMeta(tc.err), comment)
   466  		} else {
   467  			c.Assert(err, IsNil, comment)
   468  		}
   469  	}
   470  }
   471  
   472  func (s *configTestSuite) TestInvalidTOML(c *C) {
   473  	cfg := &config.Config{}
   474  	err := cfg.LoadFromTOML([]byte(`
   475  		invalid[mydumper.csv]
   476  		delimiter = '\'
   477  		backslash-escape = true
   478  	`))
   479  	c.Assert(err, ErrorMatches, regexp.QuoteMeta("Near line 0 (last key parsed ''): bare keys cannot contain '['"))
   480  }
   481  
   482  func (s *configTestSuite) TestTOMLUnusedKeys(c *C) {
   483  	cfg := &config.Config{}
   484  	err := cfg.LoadFromTOML([]byte(`
   485  		[lightning]
   486  		typo = 123
   487  	`))
   488  	c.Assert(err, ErrorMatches, regexp.QuoteMeta("config file contained unknown configuration options: lightning.typo"))
   489  }
   490  
   491  func (s *configTestSuite) TestDurationUnmarshal(c *C) {
   492  	duration := config.Duration{}
   493  	err := duration.UnmarshalText([]byte("13m20s"))
   494  	c.Assert(err, IsNil)
   495  	c.Assert(duration.Duration.Seconds(), Equals, 13*60+20.0)
   496  	err = duration.UnmarshalText([]byte("13x20s"))
   497  	c.Assert(err, ErrorMatches, "time: unknown unit .?x.? in duration .?13x20s.?")
   498  }
   499  
   500  func (s *configTestSuite) TestDurationMarshalJSON(c *C) {
   501  	duration := config.Duration{}
   502  	err := duration.UnmarshalText([]byte("13m20s"))
   503  	c.Assert(err, IsNil)
   504  	c.Assert(duration.Duration.Seconds(), Equals, 13*60+20.0)
   505  	result, err := duration.MarshalJSON()
   506  	c.Assert(err, IsNil)
   507  	c.Assert(string(result), Equals, `"13m20s"`)
   508  }
   509  
   510  func (s *configTestSuite) TestLoadConfig(c *C) {
   511  	cfg, err := config.LoadGlobalConfig([]string{"-tidb-port", "sss"}, nil)
   512  	c.Assert(err, ErrorMatches, `invalid value "sss" for flag -tidb-port: parse error`)
   513  	c.Assert(cfg, IsNil)
   514  
   515  	cfg, err = config.LoadGlobalConfig([]string{"-V"}, nil)
   516  	c.Assert(err, Equals, flag.ErrHelp)
   517  	c.Assert(cfg, IsNil)
   518  
   519  	cfg, err = config.LoadGlobalConfig([]string{"-config", "not-exists"}, nil)
   520  	c.Assert(err, ErrorMatches, ".*(no such file or directory|The system cannot find the file specified).*")
   521  	c.Assert(cfg, IsNil)
   522  
   523  	cfg, err = config.LoadGlobalConfig([]string{"--server-mode"}, nil)
   524  	c.Assert(err, ErrorMatches, "If server-mode is enabled, the status-addr must be a valid listen address")
   525  	c.Assert(cfg, IsNil)
   526  
   527  	path, _ := filepath.Abs(".")
   528  	cfg, err = config.LoadGlobalConfig([]string{
   529  		"-L", "debug",
   530  		"-log-file", "/path/to/file.log",
   531  		"-tidb-host", "172.16.30.11",
   532  		"-tidb-port", "4001",
   533  		"-tidb-user", "guest",
   534  		"-tidb-password", "12345",
   535  		"-pd-urls", "172.16.30.11:2379,172.16.30.12:2379",
   536  		"-d", path,
   537  		"-backend", config.BackendLocal,
   538  		"-sorted-kv-dir", ".",
   539  		"-checksum=false",
   540  	}, nil)
   541  	c.Assert(err, IsNil)
   542  	c.Assert(cfg.App.Config.Level, Equals, "debug")
   543  	c.Assert(cfg.App.Config.File, Equals, "/path/to/file.log")
   544  	c.Assert(cfg.TiDB.Host, Equals, "172.16.30.11")
   545  	c.Assert(cfg.TiDB.Port, Equals, 4001)
   546  	c.Assert(cfg.TiDB.User, Equals, "guest")
   547  	c.Assert(cfg.TiDB.Psw, Equals, "12345")
   548  	c.Assert(cfg.TiDB.PdAddr, Equals, "172.16.30.11:2379,172.16.30.12:2379")
   549  	c.Assert(cfg.Mydumper.SourceDir, Equals, path)
   550  	c.Assert(cfg.TikvImporter.Backend, Equals, config.BackendLocal)
   551  	c.Assert(cfg.TikvImporter.SortedKVDir, Equals, ".")
   552  	c.Assert(cfg.PostRestore.Checksum, Equals, config.OpLevelOff)
   553  	c.Assert(cfg.PostRestore.Analyze, Equals, config.OpLevelOptional)
   554  
   555  	taskCfg := config.NewConfig()
   556  	err = taskCfg.LoadFromGlobal(cfg)
   557  	c.Assert(err, IsNil)
   558  	c.Assert(taskCfg.PostRestore.Checksum, Equals, config.OpLevelOff)
   559  	c.Assert(taskCfg.PostRestore.Analyze, Equals, config.OpLevelOptional)
   560  
   561  	taskCfg.Checkpoint.DSN = ""
   562  	taskCfg.Checkpoint.Driver = config.CheckpointDriverMySQL
   563  	taskCfg.TiDB.DistSQLScanConcurrency = 1
   564  	err = taskCfg.Adjust(context.Background())
   565  	c.Assert(err, IsNil)
   566  	c.Assert(taskCfg.Checkpoint.DSN, Equals, "guest:12345@tcp(172.16.30.11:4001)/?charset=utf8mb4&sql_mode='"+mysql.DefaultSQLMode+"'&maxAllowedPacket=67108864&tls=false")
   567  
   568  	result := taskCfg.String()
   569  	c.Assert(result, Matches, `.*"pd-addr":"172.16.30.11:2379,172.16.30.12:2379".*`)
   570  }
   571  
   572  func (s *configTestSuite) TestDefaultImporterBackendValue(c *C) {
   573  	cfg := config.NewConfig()
   574  	assignMinimalLegalValue(cfg)
   575  	cfg.TikvImporter.Backend = "importer"
   576  	cfg.TiDB.DistSQLScanConcurrency = 1
   577  	err := cfg.Adjust(context.Background())
   578  	c.Assert(err, IsNil)
   579  	c.Assert(cfg.App.IndexConcurrency, Equals, 2)
   580  	c.Assert(cfg.App.TableConcurrency, Equals, 6)
   581  }
   582  
   583  func (s *configTestSuite) TestDefaultTidbBackendValue(c *C) {
   584  	cfg := config.NewConfig()
   585  	assignMinimalLegalValue(cfg)
   586  	cfg.TikvImporter.Backend = "tidb"
   587  	cfg.App.RegionConcurrency = 123
   588  	cfg.TiDB.DistSQLScanConcurrency = 1
   589  	err := cfg.Adjust(context.Background())
   590  	c.Assert(err, IsNil)
   591  	c.Assert(cfg.App.TableConcurrency, Equals, 123)
   592  }
   593  
   594  func (s *configTestSuite) TestDefaultCouldBeOverwritten(c *C) {
   595  	cfg := config.NewConfig()
   596  	assignMinimalLegalValue(cfg)
   597  	cfg.TikvImporter.Backend = "importer"
   598  	cfg.App.IndexConcurrency = 20
   599  	cfg.App.TableConcurrency = 60
   600  	cfg.TiDB.DistSQLScanConcurrency = 1
   601  	err := cfg.Adjust(context.Background())
   602  	c.Assert(err, IsNil)
   603  	c.Assert(cfg.App.IndexConcurrency, Equals, 20)
   604  	c.Assert(cfg.App.TableConcurrency, Equals, 60)
   605  }
   606  
   607  func (s *configTestSuite) TestLoadFromInvalidConfig(c *C) {
   608  	taskCfg := config.NewConfig()
   609  	err := taskCfg.LoadFromGlobal(&config.GlobalConfig{
   610  		ConfigFileContent: []byte("invalid toml"),
   611  	})
   612  	c.Assert(err, ErrorMatches, "Near line 1.*")
   613  }
   614  
   615  func (s *configTestSuite) TestTomlPostRestore(c *C) {
   616  	cfg := &config.Config{}
   617  	err := cfg.LoadFromTOML([]byte(`
   618  		[post-restore]
   619  		checksum = "req"
   620  	`))
   621  	c.Assert(err, ErrorMatches, regexp.QuoteMeta("invalid op level 'req', please choose valid option between ['off', 'optional', 'required']"))
   622  
   623  	err = cfg.LoadFromTOML([]byte(`
   624  		[post-restore]
   625  		analyze = 123
   626  	`))
   627  	c.Assert(err, ErrorMatches, regexp.QuoteMeta("invalid op level '123', please choose valid option between ['off', 'optional', 'required']"))
   628  
   629  	kvMap := map[string]config.PostOpLevel{
   630  		`"off"`:      config.OpLevelOff,
   631  		`"required"`: config.OpLevelRequired,
   632  		`"optional"`: config.OpLevelOptional,
   633  		"true":       config.OpLevelRequired,
   634  		"false":      config.OpLevelOff,
   635  	}
   636  
   637  	var b bytes.Buffer
   638  	enc := toml.NewEncoder(&b)
   639  
   640  	for k, v := range kvMap {
   641  		cfg := &config.Config{}
   642  		confStr := fmt.Sprintf("[post-restore]\r\nchecksum= %s\r\n", k)
   643  		err := cfg.LoadFromTOML([]byte(confStr))
   644  		c.Assert(err, IsNil)
   645  		c.Assert(cfg.PostRestore.Checksum, Equals, v)
   646  
   647  		b.Reset()
   648  		c.Assert(enc.Encode(cfg.PostRestore), IsNil)
   649  		c.Assert(&b, Matches, fmt.Sprintf(`(?s).*checksum = "\Q%s\E".*`, v))
   650  	}
   651  
   652  	for k, v := range kvMap {
   653  		cfg := &config.Config{}
   654  		confStr := fmt.Sprintf("[post-restore]\r\nanalyze= %s\r\n", k)
   655  		err := cfg.LoadFromTOML([]byte(confStr))
   656  		c.Assert(err, IsNil)
   657  		c.Assert(cfg.PostRestore.Analyze, Equals, v)
   658  
   659  		b.Reset()
   660  		c.Assert(enc.Encode(cfg.PostRestore), IsNil)
   661  		c.Assert(&b, Matches, fmt.Sprintf(`(?s).*analyze = "\Q%s\E".*`, v))
   662  	}
   663  }
   664  
   665  func (s *configTestSuite) TestCronEncodeDecode(c *C) {
   666  	cfg := &config.Config{}
   667  	cfg.Cron.SwitchMode.Duration = 1 * time.Minute
   668  	cfg.Cron.LogProgress.Duration = 2 * time.Minute
   669  	cfg.Cron.CheckDiskQuota.Duration = 3 * time.Second
   670  	var b bytes.Buffer
   671  	c.Assert(toml.NewEncoder(&b).Encode(cfg.Cron), IsNil)
   672  	c.Assert(b.String(), Equals, "switch-mode = \"1m0s\"\nlog-progress = \"2m0s\"\ncheck-disk-quota = \"3s\"\n")
   673  
   674  	confStr := "[cron]\r\n" + b.String()
   675  	cfg2 := &config.Config{}
   676  	c.Assert(cfg2.LoadFromTOML([]byte(confStr)), IsNil)
   677  	c.Assert(cfg2.Cron, DeepEquals, cfg.Cron)
   678  }
   679  
   680  func (s *configTestSuite) TestAdjustWithLegacyBlackWhiteList(c *C) {
   681  	cfg := config.NewConfig()
   682  	assignMinimalLegalValue(cfg)
   683  	c.Assert(cfg.Mydumper.Filter, DeepEquals, config.DefaultFilter)
   684  	c.Assert(cfg.HasLegacyBlackWhiteList(), IsFalse)
   685  
   686  	ctx := context.Background()
   687  	cfg.Mydumper.Filter = []string{"test.*"}
   688  	cfg.TiDB.DistSQLScanConcurrency = 1
   689  	c.Assert(cfg.Adjust(ctx), IsNil)
   690  	c.Assert(cfg.HasLegacyBlackWhiteList(), IsFalse)
   691  
   692  	cfg.BWList.DoDBs = []string{"test"}
   693  	c.Assert(cfg.Adjust(ctx), ErrorMatches, "invalid config: `mydumper\\.filter` and `black-white-list` cannot be simultaneously defined")
   694  
   695  	cfg.Mydumper.Filter = config.DefaultFilter
   696  	c.Assert(cfg.Adjust(ctx), IsNil)
   697  	c.Assert(cfg.HasLegacyBlackWhiteList(), IsTrue)
   698  }
   699  
   700  func (s *configTestSuite) TestAdjustDiskQuota(c *C) {
   701  	cfg := config.NewConfig()
   702  	assignMinimalLegalValue(cfg)
   703  
   704  	base := c.MkDir()
   705  	ctx := context.Background()
   706  	cfg.TikvImporter.Backend = config.BackendLocal
   707  	cfg.TikvImporter.DiskQuota = 0
   708  	cfg.TikvImporter.SortedKVDir = base
   709  	cfg.TiDB.DistSQLScanConcurrency = 1
   710  	c.Assert(cfg.Adjust(ctx), IsNil)
   711  	c.Assert(int64(cfg.TikvImporter.DiskQuota), Equals, int64(0))
   712  }