github.com/pingcap/tidb-lightning@v5.0.0-rc.0.20210428090220-84b649866577+incompatible/lightning/mydump/router_test.go (about) 1 package mydump 2 3 import ( 4 "strings" 5 6 . "github.com/pingcap/check" 7 "github.com/pingcap/tidb-tools/pkg/filter" 8 9 "github.com/pingcap/tidb-lightning/lightning/config" 10 ) 11 12 var _ = Suite(&testFileRouterSuite{}) 13 14 type testFileRouterSuite struct{} 15 16 func (t *testFileRouterSuite) TestRouteParser(c *C) { 17 // valid rules 18 rules := []*config.FileRouteRule{ 19 {Pattern: `^(?:[^/]*/)*([^/.]+)\.([^./]+)(?:\.[0-9]+)?\.(csv|sql)`, Schema: "$1", Table: "$2", Type: "$3"}, 20 {Pattern: `^.+\.(csv|sql)`, Schema: "test", Table: "t", Type: "$1"}, 21 {Pattern: `^(?:[^/]*/)*(?P<schema>[^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "$schema", Table: "$table", Type: "$type", Key: "$key", Compression: "$cp"}, 22 {Pattern: `^(?:[^/]*/)*(?P<schema>[^/.]+)\.(?P<table>[^./]+)(?:\.([0-9]+))?\.(csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "${schema}s", Table: "$table", Type: "${3}_0", Key: "$4", Compression: "$cp"}, 23 {Pattern: `^(?:[^/]*/)*([^/.]+)\.(?P<table>[^./]+)(?:\.([0-9]+))?\.(csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "${1}s", Table: "$table", Type: "${3}_0", Key: "$4", Compression: "$cp"}, 24 {Pattern: `^(?:[^/]*/)*([^/.]+)\.([^./]+)(?:\.[0-9]+)?\.(csv|sql)`, Schema: "$1-schema", Table: "$1-table", Type: "$2"}, 25 } 26 for _, r := range rules { 27 _, err := NewFileRouter([]*config.FileRouteRule{r}) 28 c.Assert(err, IsNil) 29 } 30 31 // invalid rules 32 invalidRules := []*config.FileRouteRule{ 33 {Pattern: `^(?:[^/]*/)*(?P<schema>\.(?P<table>[^./]+).*$`, Schema: "$test", Table: "$table"}, 34 {Pattern: `^(?:[^/]*/)*(?P<schema>[^/.]+)\.(?P<table>[^./]+).*$`, Schema: "$schemas", Table: "$table"}, 35 {Pattern: `^(?:[^/]*/)*([^/.]+)\.([^./]+)(?:\.[0-9]+)?\.(csv|sql)`, Schema: "$1", Table: "$2", Type: "$3", Key: "$4"}, 36 } 37 for _, r := range invalidRules { 38 _, err := NewFileRouter([]*config.FileRouteRule{r}) 39 c.Assert(err, NotNil) 40 } 41 } 42 43 func (t *testFileRouterSuite) TestInvalidRouteRule(c *C) { 44 rule := &config.FileRouteRule{} 45 rules := []*config.FileRouteRule{rule} 46 _, err := NewFileRouter(rules) 47 c.Assert(err, ErrorMatches, "`path` and `pattern` must not be both empty in \\[\\[mydumper.files\\]\\]") 48 49 rule.Pattern = `^(?:[^/]*/)*([^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$` 50 _, err = NewFileRouter(rules) 51 c.Assert(err, ErrorMatches, "field 'type' match pattern can't be empty") 52 53 rule.Type = "$type" 54 _, err = NewFileRouter(rules) 55 c.Assert(err, ErrorMatches, "field 'schema' match pattern can't be empty") 56 57 rule.Schema = "$schema" 58 _, err = NewFileRouter(rules) 59 c.Assert(err, ErrorMatches, "invalid named capture '\\$schema'") 60 61 rule.Schema = "$1" 62 _, err = NewFileRouter(rules) 63 c.Assert(err, ErrorMatches, "field 'table' match pattern can't be empty") 64 65 rule.Table = "$table" 66 _, err = NewFileRouter(rules) 67 c.Assert(err, IsNil) 68 69 rule.Path = "/tmp/1.sql" 70 _, err = NewFileRouter(rules) 71 c.Assert(err, ErrorMatches, "can't set both `path` and `pattern` field in \\[\\[mydumper.files\\]\\]") 72 } 73 74 func (t *testFileRouterSuite) TestSingleRouteRule(c *C) { 75 rules := []*config.FileRouteRule{ 76 {Pattern: `^(?:[^/]*/)*([^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "$1", Table: "$table", Type: "$type", Key: "$key", Compression: "$cp"}, 77 } 78 79 r, err := NewFileRouter(rules) 80 c.Assert(err, IsNil) 81 82 inputOutputMap := map[string][]string{ 83 "my_schema.my_table.sql": {"my_schema", "my_table", "", "", "sql"}, 84 "/test/123/my_schema.my_table.sql": {"my_schema", "my_table", "", "", "sql"}, 85 "my_dir/my_schema.my_table.csv": {"my_schema", "my_table", "", "", "csv"}, 86 "my_schema.my_table.0001.sql": {"my_schema", "my_table", "0001", "", "sql"}, 87 } 88 for path, fields := range inputOutputMap { 89 res, err := r.Route(path) 90 c.Assert(err, IsNil) 91 compress, e := parseCompressionType(fields[3]) 92 c.Assert(e, IsNil) 93 ty, e := parseSourceType(fields[4]) 94 c.Assert(e, IsNil) 95 exp := &RouteResult{filter.Table{Schema: fields[0], Name: fields[1]}, fields[2], compress, ty} 96 c.Assert(res, DeepEquals, exp) 97 } 98 99 notMatchPaths := []string{ 100 "my_table.sql", 101 "/schema/table.sql", 102 "my_schema.my_table.txt", 103 "my_schema.my_table.001.txt", 104 "my_schema.my_table.0001-002.sql", 105 } 106 for _, p := range notMatchPaths { 107 res, err := r.Route(p) 108 c.Assert(res, IsNil) 109 c.Assert(err, IsNil) 110 } 111 112 rule := &config.FileRouteRule{Pattern: `^(?:[^/]*/)*([^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>\w+)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "$1", Table: "$table", Type: "$type", Key: "$key", Compression: "$cp"} 113 r, err = NewFileRouter([]*config.FileRouteRule{rule}) 114 c.Assert(err, IsNil) 115 c.Assert(r, NotNil) 116 invalidMatchPaths := []string{ 117 "my_schema.my_table.sql.gz", 118 "my_schema.my_table.sql.rar", 119 "my_schema.my_table.txt", 120 } 121 for _, p := range invalidMatchPaths { 122 res, err := r.Route(p) 123 c.Assert(res, IsNil) 124 c.Assert(err, NotNil) 125 } 126 } 127 128 func (t *testFileRouterSuite) TestMultiRouteRule(c *C) { 129 // multi rule don't intersect with each other 130 rules := []*config.FileRouteRule{ 131 {Pattern: `(?:[^/]*/)*([^/.]+)-schema-create\.sql`, Schema: "$1", Type: SchemaSchema}, 132 {Pattern: `(?:[^/]*/)*([^/.]+)\.([^/.]+)-schema\.sql$`, Schema: "$1", Table: "$2", Type: TableSchema}, 133 {Pattern: `(?:[^/]*/)*([^/.]+)\.([^/.]+)-schema-view\.sql$`, Schema: "$1", Table: "$2", Type: ViewSchema}, 134 {Pattern: `^(?:[^/]*/)*(?P<schema>[^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "$schema", Table: "$table", Type: "$type", Key: "$key", Compression: "$cp"}, 135 } 136 137 r, err := NewFileRouter(rules) 138 c.Assert(err, IsNil) 139 140 inputOutputMap := map[string][]string{ 141 "test-schema-create.sql": {"test", "", "", "", SchemaSchema}, 142 "test.t-schema.sql": {"test", "t", "", "", TableSchema}, 143 "test.v1-schema-view.sql": {"test", "v1", "", "", ViewSchema}, 144 "my_schema.my_table.sql": {"my_schema", "my_table", "", "", "sql"}, 145 "/test/123/my_schema.my_table.sql": {"my_schema", "my_table", "", "", "sql"}, 146 "my_dir/my_schema.my_table.csv": {"my_schema", "my_table", "", "", "csv"}, 147 "my_schema.my_table.0001.sql": {"my_schema", "my_table", "0001", "", "sql"}, 148 //"my_schema.my_table.0001.sql.gz": {"my_schema", "my_table", "0001", "gz", "sql"}, 149 } 150 for path, fields := range inputOutputMap { 151 res, err := r.Route(path) 152 c.Assert(err, IsNil) 153 if len(fields) == 0 { 154 c.Assert(res, IsNil) 155 } else { 156 compress, e := parseCompressionType(fields[3]) 157 c.Assert(e, IsNil) 158 ty, e := parseSourceType(fields[4]) 159 c.Assert(e, IsNil) 160 exp := &RouteResult{filter.Table{Schema: fields[0], Name: fields[1]}, fields[2], compress, ty} 161 c.Assert(res, DeepEquals, exp) 162 } 163 } 164 165 // multi rule don't intersect with each other 166 // add another rule that math same pattern with the third rule, the result should be no different 167 p := &config.FileRouteRule{Pattern: `^(?P<schema>[^/.]+)\.(?P<table>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, Schema: "test_schema", Table: "test_table", Type: "$type", Key: "$key", Compression: "$cp"} 168 rules = append(rules, p) 169 r, err = NewFileRouter(rules) 170 c.Assert(err, IsNil) 171 for path, fields := range inputOutputMap { 172 res, err := r.Route(path) 173 c.Assert(err, IsNil) 174 if len(fields) == 0 { 175 c.Assert(res, IsNil) 176 } else { 177 compress, e := parseCompressionType(fields[3]) 178 c.Assert(e, IsNil) 179 ty, e := parseSourceType(fields[4]) 180 c.Assert(e, IsNil) 181 exp := &RouteResult{filter.Table{Schema: fields[0], Name: fields[1]}, fields[2], compress, ty} 182 c.Assert(res, DeepEquals, exp) 183 } 184 } 185 } 186 187 func (t *testFileRouterSuite) TestRouteExpanding(c *C) { 188 rule := &config.FileRouteRule{ 189 Pattern: `^(?:[^/]*/)*(?P<schema>[^/.]+)\.(?P<table_name>[^./]+)(?:\.(?P<key>[0-9]+))?\.(?P<type>csv|sql)(?:\.(?P<cp>[A-Za-z0-9]+))?$`, 190 Schema: "$schema", 191 Type: "$type", 192 Key: "$key", 193 Compression: "$cp", 194 } 195 path := "db.table.001.sql" 196 tablePatternResMap := map[string]string{ 197 "$schema": "db", 198 "$table_name": "table", 199 "$schema.$table_name": "db.table", 200 "${1}": "db", 201 "${1}_$table_name": "db_table", 202 "${2}.schema": "table.schema", 203 "$${2}": "${2}", 204 "$$table_name": "$table_name", 205 "$table_name-123": "table-123", 206 "$$12$1$schema": "$12dbdb", 207 "${table_name}$$2": "table$2", 208 "${table_name}$$": "table$", 209 "{1}$$": "{1}$", 210 "my_table": "my_table", 211 } 212 213 for pat, value := range tablePatternResMap { 214 rule.Table = pat 215 router, err := NewFileRouter([]*config.FileRouteRule{rule}) 216 c.Assert(err, IsNil) 217 res, err := router.Route(path) 218 c.Assert(err, IsNil) 219 c.Assert(res, NotNil) 220 c.Assert(res.Name, Equals, value) 221 } 222 223 invalidPatterns := []string{"$1_$schema", "$schema_$table_name", "$6"} 224 for _, pat := range invalidPatterns { 225 rule.Table = pat 226 _, err := NewFileRouter([]*config.FileRouteRule{rule}) 227 c.Assert(err, NotNil) 228 } 229 } 230 231 func (t *testFileRouterSuite) TestRouteWithPath(c *C) { 232 fileName := "myschema.(my_table$1).000.sql" 233 rule := &config.FileRouteRule{ 234 Path: fileName, 235 Schema: "schema", 236 Table: "my_table$1", 237 Type: "sql", 238 Key: "$key", 239 } 240 r := *rule 241 router, err := NewFileRouter([]*config.FileRouteRule{&r}) 242 c.Assert(err, IsNil) 243 res, err := router.Route(fileName) 244 c.Assert(err, IsNil) 245 c.Assert(res, NotNil) 246 c.Assert(res.Schema, Equals, rule.Schema) 247 c.Assert(res.Name, Equals, rule.Table) 248 ty, _ := parseSourceType(rule.Type) 249 c.Assert(res.Type, Equals, ty) 250 c.Assert(res.Key, Equals, rule.Key) 251 252 // replace all '.' by '-', if with plain regex pattern, will still match 253 res, err = router.Route(strings.ReplaceAll(fileName, ".", "-")) 254 c.Assert(err, IsNil) 255 c.Assert(res, IsNil) 256 }