github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/lightning/mydump/loader_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 mydump_test
    15  
    16  import (
    17  	"context"
    18  	"os"
    19  	"path/filepath"
    20  	"testing"
    21  
    22  	. "github.com/pingcap/check"
    23  	filter "github.com/pingcap/tidb-tools/pkg/table-filter"
    24  	router "github.com/pingcap/tidb-tools/pkg/table-router"
    25  
    26  	"github.com/pingcap/br/pkg/lightning/config"
    27  	md "github.com/pingcap/br/pkg/lightning/mydump"
    28  	"github.com/pingcap/br/pkg/storage"
    29  )
    30  
    31  var _ = Suite(&testMydumpLoaderSuite{})
    32  
    33  func TestMydumps(t *testing.T) {
    34  	TestingT(t)
    35  }
    36  
    37  type testMydumpLoaderSuite struct {
    38  	cfg       *config.Config
    39  	sourceDir string
    40  }
    41  
    42  func (s *testMydumpLoaderSuite) SetUpSuite(c *C)    {}
    43  func (s *testMydumpLoaderSuite) TearDownSuite(c *C) {}
    44  
    45  func newConfigWithSourceDir(sourceDir string) *config.Config {
    46  	path, _ := filepath.Abs(sourceDir)
    47  	return &config.Config{
    48  		Mydumper: config.MydumperRuntime{
    49  			SourceDir:        "file://" + filepath.ToSlash(path),
    50  			Filter:           []string{"*.*"},
    51  			DefaultFileRules: true,
    52  		},
    53  	}
    54  }
    55  
    56  func (s *testMydumpLoaderSuite) SetUpTest(c *C) {
    57  	s.sourceDir = c.MkDir()
    58  	s.cfg = newConfigWithSourceDir(s.sourceDir)
    59  }
    60  
    61  func (s *testMydumpLoaderSuite) touch(c *C, filename ...string) {
    62  	components := make([]string, len(filename)+1)
    63  	components = append(components, s.sourceDir)
    64  	components = append(components, filename...)
    65  	path := filepath.Join(components...)
    66  	err := os.WriteFile(path, nil, 0o644)
    67  	c.Assert(err, IsNil)
    68  }
    69  
    70  func (s *testMydumpLoaderSuite) mkdir(c *C, dirname string) {
    71  	path := filepath.Join(s.sourceDir, dirname)
    72  	err := os.Mkdir(path, 0o755)
    73  	c.Assert(err, IsNil)
    74  }
    75  
    76  func (s *testMydumpLoaderSuite) TestLoader(c *C) {
    77  	ctx := context.Background()
    78  	cfg := newConfigWithSourceDir("./not-exists")
    79  	_, err := md.NewMyDumpLoader(ctx, cfg)
    80  	// will check schema in tidb and data file later in DataCheck.
    81  	c.Assert(err, IsNil)
    82  
    83  	cfg = newConfigWithSourceDir("./examples")
    84  	mdl, err := md.NewMyDumpLoader(ctx, cfg)
    85  	c.Assert(err, IsNil)
    86  
    87  	dbMetas := mdl.GetDatabases()
    88  	c.Assert(len(dbMetas), Equals, 1)
    89  	dbMeta := dbMetas[0]
    90  	c.Assert(dbMeta.Name, Equals, "mocker_test")
    91  	c.Assert(len(dbMeta.Tables), Equals, 4)
    92  
    93  	expected := []struct {
    94  		name      string
    95  		dataFiles int
    96  	}{
    97  		{name: "i", dataFiles: 1},
    98  		{name: "report_case_high_risk", dataFiles: 1},
    99  		{name: "tbl_multi_index", dataFiles: 1},
   100  		{name: "tbl_autoid", dataFiles: 1},
   101  	}
   102  
   103  	for i, table := range expected {
   104  		c.Assert(dbMeta.Tables[i].Name, Equals, table.name)
   105  		c.Assert(len(dbMeta.Tables[i].DataFiles), Equals, table.dataFiles)
   106  	}
   107  }
   108  
   109  func (s *testMydumpLoaderSuite) TestEmptyDB(c *C) {
   110  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   111  	// will check schema in tidb and data file later in DataCheck.
   112  	c.Assert(err, IsNil)
   113  }
   114  
   115  func (s *testMydumpLoaderSuite) TestDuplicatedDB(c *C) {
   116  	/*
   117  		Path/
   118  			a/
   119  				db-schema-create.sql
   120  			b/
   121  				db-schema-create.sql
   122  	*/
   123  	s.mkdir(c, "a")
   124  	s.touch(c, "a", "db-schema-create.sql")
   125  	s.mkdir(c, "b")
   126  	s.touch(c, "b", "db-schema-create.sql")
   127  
   128  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   129  	c.Assert(err, ErrorMatches, `invalid database schema file, duplicated item - .*[/\\]db-schema-create\.sql`)
   130  }
   131  
   132  func (s *testMydumpLoaderSuite) TestTableNoHostDB(c *C) {
   133  	/*
   134  		Path/
   135  			notdb-schema-create.sql
   136  			db.tbl-schema.sql
   137  	*/
   138  
   139  	dir := s.sourceDir
   140  	err := os.WriteFile(filepath.Join(dir, "notdb-schema-create.sql"), nil, 0o644)
   141  	c.Assert(err, IsNil)
   142  	err = os.WriteFile(filepath.Join(dir, "db.tbl-schema.sql"), nil, 0o644)
   143  	c.Assert(err, IsNil)
   144  
   145  	_, err = md.NewMyDumpLoader(context.Background(), s.cfg)
   146  	c.Assert(err, IsNil)
   147  }
   148  
   149  func (s *testMydumpLoaderSuite) TestDuplicatedTable(c *C) {
   150  	/*
   151  		Path/
   152  			db-schema-create.sql
   153  			a/
   154  				db.tbl-schema.sql
   155  			b/
   156  				db.tbl-schema.sql
   157  	*/
   158  
   159  	s.touch(c, "db-schema-create.sql")
   160  	s.mkdir(c, "a")
   161  	s.touch(c, "a", "db.tbl-schema.sql")
   162  	s.mkdir(c, "b")
   163  	s.touch(c, "b", "db.tbl-schema.sql")
   164  
   165  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   166  	c.Assert(err, ErrorMatches, `invalid table schema file, duplicated item - .*db\.tbl-schema\.sql`)
   167  }
   168  
   169  func (s *testMydumpLoaderSuite) TestTableInfoNotFound(c *C) {
   170  	s.cfg.Mydumper.CharacterSet = "auto"
   171  
   172  	s.touch(c, "db-schema-create.sql")
   173  	s.touch(c, "db.tbl-schema.sql")
   174  
   175  	ctx := context.Background()
   176  	store, err := storage.NewLocalStorage(s.sourceDir)
   177  	c.Assert(err, IsNil)
   178  
   179  	loader, err := md.NewMyDumpLoader(ctx, s.cfg)
   180  	c.Assert(err, IsNil)
   181  	for _, dbMeta := range loader.GetDatabases() {
   182  		for _, tblMeta := range dbMeta.Tables {
   183  			sql, err := tblMeta.GetSchema(ctx, store)
   184  			c.Assert(sql, Equals, "")
   185  			c.Assert(err, IsNil)
   186  		}
   187  	}
   188  }
   189  
   190  func (s *testMydumpLoaderSuite) TestTableUnexpectedError(c *C) {
   191  	s.touch(c, "db-schema-create.sql")
   192  	s.touch(c, "db.tbl-schema.sql")
   193  
   194  	ctx := context.Background()
   195  	store, err := storage.NewLocalStorage(s.sourceDir)
   196  	c.Assert(err, IsNil)
   197  
   198  	loader, err := md.NewMyDumpLoader(ctx, s.cfg)
   199  	c.Assert(err, IsNil)
   200  	for _, dbMeta := range loader.GetDatabases() {
   201  		for _, tblMeta := range dbMeta.Tables {
   202  			sql, err := tblMeta.GetSchema(ctx, store)
   203  			c.Assert(sql, Equals, "")
   204  			c.Assert(err, ErrorMatches, "failed to decode db.tbl-schema.sql as : Unsupported encoding ")
   205  		}
   206  	}
   207  }
   208  
   209  func (s *testMydumpLoaderSuite) TestDataNoHostDB(c *C) {
   210  	/*
   211  		Path/
   212  			notdb-schema-create.sql
   213  			db.tbl.sql
   214  	*/
   215  
   216  	s.touch(c, "notdb-schema-create.sql")
   217  	s.touch(c, "db.tbl.sql")
   218  
   219  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   220  	// will check schema in tidb and data file later in DataCheck.
   221  	c.Assert(err, IsNil)
   222  }
   223  
   224  func (s *testMydumpLoaderSuite) TestDataNoHostTable(c *C) {
   225  	/*
   226  		Path/
   227  			db-schema-create.sql
   228  			db.tbl.sql
   229  	*/
   230  
   231  	s.touch(c, "db-schema-create.sql")
   232  	s.touch(c, "db.tbl.sql")
   233  
   234  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   235  	// will check schema in tidb and data file later in DataCheck.
   236  	c.Assert(err, IsNil)
   237  }
   238  
   239  func (s *testMydumpLoaderSuite) TestViewNoHostDB(c *C) {
   240  	/*
   241  		Path/
   242  			notdb-schema-create.sql
   243  			db.tbl-schema-view.sql
   244  	*/
   245  	s.touch(c, "notdb-schema-create.sql")
   246  	s.touch(c, "db.tbl-schema-view.sql")
   247  
   248  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   249  	c.Assert(err, ErrorMatches, `invalid view schema file, miss host table schema for view 'tbl'`)
   250  }
   251  
   252  func (s *testMydumpLoaderSuite) TestViewNoHostTable(c *C) {
   253  	/*
   254  		Path/
   255  			db-schema-create.sql
   256  			db.tbl-schema-view.sql
   257  	*/
   258  
   259  	s.touch(c, "db-schema-create.sql")
   260  	s.touch(c, "db.tbl-schema-view.sql")
   261  
   262  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   263  	c.Assert(err, ErrorMatches, `invalid view schema file, miss host table schema for view 'tbl'`)
   264  }
   265  
   266  func (s *testMydumpLoaderSuite) TestDataWithoutSchema(c *C) {
   267  	dir := s.sourceDir
   268  	p := filepath.Join(dir, "db.tbl.sql")
   269  	err := os.WriteFile(p, nil, 0o644)
   270  	c.Assert(err, IsNil)
   271  
   272  	mdl, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   273  	c.Assert(err, IsNil)
   274  	c.Assert(mdl.GetDatabases(), DeepEquals, []*md.MDDatabaseMeta{{
   275  		Name:       "db",
   276  		SchemaFile: "",
   277  		Tables: []*md.MDTableMeta{{
   278  			DB:           "db",
   279  			Name:         "tbl",
   280  			SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "db", Name: "tbl"}},
   281  			DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "db", Name: "tbl"}, FileMeta: md.SourceFileMeta{Path: "db.tbl.sql", Type: md.SourceTypeSQL}}},
   282  			IsRowOrdered: true,
   283  			IndexRatio:   0.0,
   284  		}},
   285  	}})
   286  }
   287  
   288  func (s *testMydumpLoaderSuite) TestTablesWithDots(c *C) {
   289  	s.touch(c, "db-schema-create.sql")
   290  	s.touch(c, "db.tbl.with.dots-schema.sql")
   291  	s.touch(c, "db.tbl.with.dots.0001.sql")
   292  	s.touch(c, "db.0002-schema.sql")
   293  	s.touch(c, "db.0002.sql")
   294  
   295  	// insert some tables with file name structures which we're going to ignore.
   296  	s.touch(c, "db.v-schema-trigger.sql")
   297  	s.touch(c, "db.v-schema-post.sql")
   298  	s.touch(c, "db.sql")
   299  	s.touch(c, "db-schema.sql")
   300  
   301  	mdl, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   302  	c.Assert(err, IsNil)
   303  	c.Assert(mdl.GetDatabases(), DeepEquals, []*md.MDDatabaseMeta{{
   304  		Name:       "db",
   305  		SchemaFile: "db-schema-create.sql",
   306  		Tables: []*md.MDTableMeta{
   307  			{
   308  				DB:           "db",
   309  				Name:         "0002",
   310  				SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "db", Name: "0002"}, FileMeta: md.SourceFileMeta{Path: "db.0002-schema.sql", Type: md.SourceTypeTableSchema}},
   311  				DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "db", Name: "0002"}, FileMeta: md.SourceFileMeta{Path: "db.0002.sql", Type: md.SourceTypeSQL}}},
   312  				IsRowOrdered: true,
   313  				IndexRatio:   0.0,
   314  			},
   315  			{
   316  				DB:           "db",
   317  				Name:         "tbl.with.dots",
   318  				SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "db", Name: "tbl.with.dots"}, FileMeta: md.SourceFileMeta{Path: "db.tbl.with.dots-schema.sql", Type: md.SourceTypeTableSchema}},
   319  				DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "db", Name: "tbl.with.dots"}, FileMeta: md.SourceFileMeta{Path: "db.tbl.with.dots.0001.sql", Type: md.SourceTypeSQL, SortKey: "0001"}}},
   320  				IsRowOrdered: true,
   321  				IndexRatio:   0.0,
   322  			},
   323  		},
   324  	}})
   325  }
   326  
   327  func (s *testMydumpLoaderSuite) TestRouter(c *C) {
   328  	s.cfg.Routes = []*router.TableRule{
   329  		{
   330  			SchemaPattern: "a*",
   331  			TablePattern:  "t*",
   332  			TargetSchema:  "b",
   333  			TargetTable:   "u",
   334  		},
   335  		{
   336  			SchemaPattern: "c*",
   337  			TargetSchema:  "c",
   338  		},
   339  		{
   340  			SchemaPattern: "e*",
   341  			TablePattern:  "f*",
   342  			TargetSchema:  "v",
   343  			TargetTable:   "vv",
   344  		},
   345  	}
   346  
   347  	/*
   348  		Path/
   349  			a0-schema-create.sql
   350  			a0.t0-schema.sql
   351  			a0.t0.1.sql
   352  			a0.t1-schema.sql
   353  			a0.t1.1.sql
   354  			a1-schema-create.sql
   355  			a1.s1-schema.sql
   356  			a1.s1.1.schema.sql
   357  			a1.t2-schema.sql
   358  			a1.t2.1.sql
   359  			a1.v1-schema.sql
   360  			a1.v1-schema-view.sql
   361  			c0-schema-create.sql
   362  			c0.t3-schema.sql
   363  			c0.t3.1.sql
   364  			d0-schema-create.sql
   365  			e0-schema-create.sql
   366  			e0.f0-schema.sql
   367  			e0.f0-schema-view.sql
   368  	*/
   369  
   370  	s.touch(c, "a0-schema-create.sql")
   371  	s.touch(c, "a0.t0-schema.sql")
   372  	s.touch(c, "a0.t0.1.sql")
   373  	s.touch(c, "a0.t1-schema.sql")
   374  	s.touch(c, "a0.t1.1.sql")
   375  
   376  	s.touch(c, "a1-schema-create.sql")
   377  	s.touch(c, "a1.s1-schema.sql")
   378  	s.touch(c, "a1.s1.1.sql")
   379  	s.touch(c, "a1.t2-schema.sql")
   380  	s.touch(c, "a1.t2.1.sql")
   381  	s.touch(c, "a1.v1-schema.sql")
   382  	s.touch(c, "a1.v1-schema-view.sql")
   383  
   384  	s.touch(c, "c0-schema-create.sql")
   385  	s.touch(c, "c0.t3-schema.sql")
   386  	s.touch(c, "c0.t3.1.sql")
   387  
   388  	s.touch(c, "d0-schema-create.sql")
   389  
   390  	s.touch(c, "e0-schema-create.sql")
   391  	s.touch(c, "e0.f0-schema.sql")
   392  	s.touch(c, "e0.f0-schema-view.sql")
   393  
   394  	mdl, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   395  	c.Assert(err, IsNil)
   396  	c.Assert(mdl.GetDatabases(), DeepEquals, []*md.MDDatabaseMeta{
   397  		{
   398  			Name:       "a1",
   399  			SchemaFile: "a1-schema-create.sql",
   400  			Tables: []*md.MDTableMeta{
   401  				{
   402  					DB:           "a1",
   403  					Name:         "s1",
   404  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "a1", Name: "s1"}, FileMeta: md.SourceFileMeta{Path: "a1.s1-schema.sql", Type: md.SourceTypeTableSchema}},
   405  					DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "a1", Name: "s1"}, FileMeta: md.SourceFileMeta{Path: "a1.s1.1.sql", Type: md.SourceTypeSQL, SortKey: "1"}}},
   406  					IndexRatio:   0.0,
   407  					IsRowOrdered: true,
   408  				},
   409  				{
   410  					DB:           "a1",
   411  					Name:         "v1",
   412  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "a1", Name: "v1"}, FileMeta: md.SourceFileMeta{Path: "a1.v1-schema.sql", Type: md.SourceTypeTableSchema}},
   413  					DataFiles:    []md.FileInfo{},
   414  					IndexRatio:   0.0,
   415  					IsRowOrdered: true,
   416  				},
   417  			},
   418  			Views: []*md.MDTableMeta{
   419  				{
   420  					DB:           "a1",
   421  					Name:         "v1",
   422  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "a1", Name: "v1"}, FileMeta: md.SourceFileMeta{Path: "a1.v1-schema-view.sql", Type: md.SourceTypeViewSchema}},
   423  					IndexRatio:   0.0,
   424  					IsRowOrdered: true,
   425  				},
   426  			},
   427  		},
   428  		{
   429  			Name:       "d0",
   430  			SchemaFile: "d0-schema-create.sql",
   431  		},
   432  		{
   433  			Name:       "b",
   434  			SchemaFile: "a0-schema-create.sql",
   435  			Tables: []*md.MDTableMeta{
   436  				{
   437  					DB:         "b",
   438  					Name:       "u",
   439  					SchemaFile: md.FileInfo{TableName: filter.Table{Schema: "b", Name: "u"}, FileMeta: md.SourceFileMeta{Path: "a0.t0-schema.sql", Type: md.SourceTypeTableSchema}},
   440  					DataFiles: []md.FileInfo{
   441  						{TableName: filter.Table{Schema: "b", Name: "u"}, FileMeta: md.SourceFileMeta{Path: "a0.t0.1.sql", Type: md.SourceTypeSQL, SortKey: "1"}},
   442  						{TableName: filter.Table{Schema: "b", Name: "u"}, FileMeta: md.SourceFileMeta{Path: "a0.t1.1.sql", Type: md.SourceTypeSQL, SortKey: "1"}},
   443  						{TableName: filter.Table{Schema: "b", Name: "u"}, FileMeta: md.SourceFileMeta{Path: "a1.t2.1.sql", Type: md.SourceTypeSQL, SortKey: "1"}},
   444  					},
   445  					IndexRatio:   0.0,
   446  					IsRowOrdered: true,
   447  				},
   448  			},
   449  		},
   450  		{
   451  			Name:       "c",
   452  			SchemaFile: "c0-schema-create.sql",
   453  			Tables: []*md.MDTableMeta{
   454  				{
   455  					DB:           "c",
   456  					Name:         "t3",
   457  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "c", Name: "t3"}, FileMeta: md.SourceFileMeta{Path: "c0.t3-schema.sql", Type: md.SourceTypeTableSchema}},
   458  					DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "c", Name: "t3"}, FileMeta: md.SourceFileMeta{Path: "c0.t3.1.sql", Type: md.SourceTypeSQL, SortKey: "1"}}},
   459  					IndexRatio:   0.0,
   460  					IsRowOrdered: true,
   461  				},
   462  			},
   463  		},
   464  		{
   465  			Name:       "v",
   466  			SchemaFile: "e0-schema-create.sql",
   467  			Tables: []*md.MDTableMeta{
   468  				{
   469  					DB:           "v",
   470  					Name:         "vv",
   471  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "v", Name: "vv"}, FileMeta: md.SourceFileMeta{Path: "e0.f0-schema.sql", Type: md.SourceTypeTableSchema}},
   472  					DataFiles:    []md.FileInfo{},
   473  					IndexRatio:   0.0,
   474  					IsRowOrdered: true,
   475  				},
   476  			},
   477  			Views: []*md.MDTableMeta{
   478  				{
   479  					DB:           "v",
   480  					Name:         "vv",
   481  					SchemaFile:   md.FileInfo{TableName: filter.Table{Schema: "v", Name: "vv"}, FileMeta: md.SourceFileMeta{Path: "e0.f0-schema-view.sql", Type: md.SourceTypeViewSchema}},
   482  					IndexRatio:   0.0,
   483  					IsRowOrdered: true,
   484  				},
   485  			},
   486  		},
   487  	})
   488  }
   489  
   490  func (s *testMydumpLoaderSuite) TestBadRouterRule(c *C) {
   491  	s.cfg.Routes = []*router.TableRule{{
   492  		SchemaPattern: "a*b",
   493  		TargetSchema:  "ab",
   494  	}}
   495  
   496  	s.touch(c, "a1b-schema-create.sql")
   497  
   498  	_, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   499  	c.Assert(err, ErrorMatches, `.*pattern a\*b not valid`)
   500  }
   501  
   502  func (s *testMydumpLoaderSuite) TestFileRouting(c *C) {
   503  	s.cfg.Mydumper.DefaultFileRules = false
   504  	s.cfg.Mydumper.FileRouters = []*config.FileRouteRule{
   505  		{
   506  			Pattern: `(?i)^(?:[^./]*/)*([a-z0-9_]+)/schema\.sql$`,
   507  			Schema:  "$1",
   508  			Type:    "schema-schema",
   509  		},
   510  		{
   511  			Pattern: `(?i)^(?:[^./]*/)*([a-z0-9]+)/([a-z0-9_]+)-table\.sql$`,
   512  			Schema:  "$1",
   513  			Table:   "$2",
   514  			Type:    "table-schema",
   515  		},
   516  		{
   517  			Pattern: `(?i)^(?:[^./]*/)*([a-z0-9]+)/([a-z0-9_]+)-view\.sql$`,
   518  			Schema:  "$1",
   519  			Table:   "$2",
   520  			Type:    "view-schema",
   521  		},
   522  		{
   523  			Pattern: `(?i)^(?:[^./]*/)*([a-z][a-z0-9_]*)/([a-z]+)[0-9]*(?:\.([0-9]+))?\.(sql|csv)$`,
   524  			Schema:  "$1",
   525  			Table:   "$2",
   526  			Type:    "$4",
   527  		},
   528  		{
   529  			Pattern: `^(?:[^./]*/)*([a-z]+)(?:\.([0-9]+))?\.(sql|csv)$`,
   530  			Schema:  "d2",
   531  			Table:   "$1",
   532  			Type:    "$3",
   533  		},
   534  	}
   535  
   536  	s.mkdir(c, "d1")
   537  	s.mkdir(c, "d2")
   538  	s.touch(c, "d1/schema.sql")
   539  	s.touch(c, "d1/test-table.sql")
   540  	s.touch(c, "d1/test0.sql")
   541  	s.touch(c, "d1/test1.sql")
   542  	s.touch(c, "d1/test2.001.sql")
   543  	s.touch(c, "d1/v1-table.sql")
   544  	s.touch(c, "d1/v1-view.sql")
   545  	s.touch(c, "d1/t1-schema-create.sql")
   546  	s.touch(c, "d2/schema.sql")
   547  	s.touch(c, "d2/abc-table.sql")
   548  	s.touch(c, "abc.1.sql")
   549  
   550  	mdl, err := md.NewMyDumpLoader(context.Background(), s.cfg)
   551  	c.Assert(err, IsNil)
   552  	c.Assert(mdl.GetDatabases(), DeepEquals, []*md.MDDatabaseMeta{
   553  		{
   554  			Name:       "d1",
   555  			SchemaFile: filepath.FromSlash("d1/schema.sql"),
   556  			Tables: []*md.MDTableMeta{
   557  				{
   558  					DB:   "d1",
   559  					Name: "test",
   560  					SchemaFile: md.FileInfo{
   561  						TableName: filter.Table{Schema: "d1", Name: "test"},
   562  						FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/test-table.sql"), Type: md.SourceTypeTableSchema},
   563  					},
   564  					DataFiles: []md.FileInfo{
   565  						{
   566  							TableName: filter.Table{Schema: "d1", Name: "test"},
   567  							FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/test0.sql"), Type: md.SourceTypeSQL},
   568  						},
   569  						{
   570  							TableName: filter.Table{Schema: "d1", Name: "test"},
   571  							FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/test1.sql"), Type: md.SourceTypeSQL},
   572  						},
   573  						{
   574  							TableName: filter.Table{Schema: "d1", Name: "test"},
   575  							FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/test2.001.sql"), Type: md.SourceTypeSQL},
   576  						},
   577  					},
   578  					IndexRatio:   0.0,
   579  					IsRowOrdered: true,
   580  				},
   581  				{
   582  					DB:   "d1",
   583  					Name: "v1",
   584  					SchemaFile: md.FileInfo{
   585  						TableName: filter.Table{Schema: "d1", Name: "v1"},
   586  						FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/v1-table.sql"), Type: md.SourceTypeTableSchema},
   587  					},
   588  					DataFiles:    []md.FileInfo{},
   589  					IndexRatio:   0.0,
   590  					IsRowOrdered: true,
   591  				},
   592  			},
   593  			Views: []*md.MDTableMeta{
   594  				{
   595  					DB:   "d1",
   596  					Name: "v1",
   597  					SchemaFile: md.FileInfo{
   598  						TableName: filter.Table{Schema: "d1", Name: "v1"},
   599  						FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d1/v1-view.sql"), Type: md.SourceTypeViewSchema},
   600  					},
   601  					IndexRatio:   0.0,
   602  					IsRowOrdered: true,
   603  				},
   604  			},
   605  		},
   606  		{
   607  			Name:       "d2",
   608  			SchemaFile: filepath.FromSlash("d2/schema.sql"),
   609  			Tables: []*md.MDTableMeta{
   610  				{
   611  					DB:   "d2",
   612  					Name: "abc",
   613  					SchemaFile: md.FileInfo{
   614  						TableName: filter.Table{Schema: "d2", Name: "abc"},
   615  						FileMeta:  md.SourceFileMeta{Path: filepath.FromSlash("d2/abc-table.sql"), Type: md.SourceTypeTableSchema},
   616  					},
   617  					DataFiles:    []md.FileInfo{{TableName: filter.Table{Schema: "d2", Name: "abc"}, FileMeta: md.SourceFileMeta{Path: "abc.1.sql", Type: md.SourceTypeSQL}}},
   618  					IndexRatio:   0.0,
   619  					IsRowOrdered: true,
   620  				},
   621  			},
   622  		},
   623  	})
   624  }