github.com/XiaoMi/Gaea@v1.2.5/proxy/plan/plan_test.go (about)

     1  // Copyright 2019 The Gaea Authors. All Rights Reserved.
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package plan
    16  
    17  import (
    18  	"encoding/json"
    19  	"sync/atomic"
    20  	"testing"
    21  
    22  	"github.com/XiaoMi/Gaea/backend"
    23  	"github.com/XiaoMi/Gaea/models"
    24  	"github.com/XiaoMi/Gaea/parser"
    25  	"github.com/XiaoMi/Gaea/proxy/router"
    26  	"github.com/XiaoMi/Gaea/proxy/sequence"
    27  )
    28  
    29  type SQLTestcase struct {
    30  	db     string
    31  	sql    string
    32  	sqls   map[string]map[string][]string
    33  	hasErr bool
    34  }
    35  
    36  type OrderSequence struct {
    37  	v      int64
    38  	db     string
    39  	table  string
    40  	pkName string
    41  }
    42  
    43  type PlanInfo struct {
    44  	phyDBs map[string]string
    45  	rt     *router.Router
    46  	seqs   *sequence.SequenceManager
    47  }
    48  
    49  func NewOrderSequence(db, table, pkName string) *OrderSequence {
    50  	return &OrderSequence{
    51  		db:     db,
    52  		table:  table,
    53  		pkName: pkName,
    54  	}
    55  }
    56  
    57  func (s *OrderSequence) GetPKName() string {
    58  	return s.pkName
    59  }
    60  
    61  func (s *OrderSequence) NextSeq() (int64, error) {
    62  	newInt := atomic.AddInt64(&s.v, 1)
    63  	return newInt, nil
    64  }
    65  
    66  // 获取使用TiDB parser测试SQL改写结果的测试函数
    67  func getTestFunc(info *PlanInfo, test SQLTestcase) func(t *testing.T) {
    68  	return func(t *testing.T) {
    69  		stmt, err := parser.ParseSQL(test.sql)
    70  		if err != nil {
    71  			if test.hasErr {
    72  				t.Logf("parse sql error: %v", err)
    73  				return
    74  			}
    75  			t.Fatalf("parse sql error: %v", err)
    76  		}
    77  
    78  		p, err := BuildPlan(stmt, info.phyDBs, test.db, test.sql, info.rt, info.seqs)
    79  		if err != nil {
    80  			if test.hasErr {
    81  				t.Logf("BuildPlan got expect error, sql: %s, err: %v", test.sql, err)
    82  				return
    83  			}
    84  			t.Fatalf("BuildPlan error, sql: %s, err: %v", test.sql, err)
    85  		}
    86  
    87  		var actualSQLs map[string]map[string][]string
    88  		switch plan := p.(type) {
    89  		case *SelectPlan:
    90  			actualSQLs = plan.GetSQLs()
    91  		case *InsertPlan:
    92  			actualSQLs = plan.sqls
    93  		case *UpdatePlan:
    94  			actualSQLs = plan.sqls
    95  		case *DeletePlan:
    96  			actualSQLs = plan.sqls
    97  		case *ExplainPlan:
    98  			actualSQLs = plan.sqls
    99  		case *UnshardPlan:
   100  			actualSQLs = make(map[string]map[string][]string)
   101  			dbSQLs := make(map[string][]string)
   102  			if db, ok := info.phyDBs[plan.db]; ok {
   103  				plan.db = db
   104  			}
   105  			dbSQLs[plan.db] = []string{plan.sql}
   106  			actualSQLs[backend.DefaultSlice] = dbSQLs
   107  		}
   108  
   109  		if actualSQLs == nil {
   110  			t.Fatalf("get sqls error: %v", err)
   111  		}
   112  
   113  		if !checkSQLs(test.sqls, actualSQLs) {
   114  			t.Errorf("not equal, expect: %v, actual: %v", test.sqls, actualSQLs)
   115  		}
   116  	}
   117  }
   118  
   119  func createNamespace(nsStr string) (*models.Namespace, error) {
   120  	ns := &models.Namespace{}
   121  	err := json.Unmarshal([]byte(nsStr), ns)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	if err := ns.Verify(); err != nil {
   126  		return nil, err
   127  	}
   128  	return ns, nil
   129  }
   130  
   131  func createRouter(nsCfg *models.Namespace) (*router.Router, error) {
   132  	return router.NewRouter(nsCfg)
   133  }
   134  
   135  func createSequenceManager(nsCfg *models.Namespace) (*sequence.SequenceManager, error) {
   136  	sequences := sequence.NewSequenceManager()
   137  	for _, v := range nsCfg.GlobalSequences {
   138  		seq := NewOrderSequence(v.DB, v.Table, v.PKName)
   139  		sequences.SetSequence(v.DB, v.Table, seq)
   140  	}
   141  	return sequences, nil
   142  }
   143  
   144  func checkSQLs(expect, actual map[string]map[string][]string) bool {
   145  	aContainsB := func(a, b map[string]map[string][]string) bool {
   146  		for sliceName, dbSQLs := range a {
   147  			if len(b[sliceName]) == 0 {
   148  				return false
   149  			}
   150  			for dbName, sqls := range dbSQLs {
   151  				if len(b[sliceName][dbName]) == 0 {
   152  					return false
   153  				}
   154  				for i, sql := range sqls {
   155  					if b[sliceName][dbName][i] != sql {
   156  						return false
   157  					}
   158  				}
   159  			}
   160  		}
   161  		return true
   162  	}
   163  
   164  	return aContainsB(expect, actual) && aContainsB(actual, expect)
   165  }
   166  
   167  func preparePlanInfo() (*PlanInfo, error) {
   168  	nsStr := `
   169  {
   170      "name": "gaea_namespace_1",
   171      "online": true,
   172      "read_only": true,
   173      "allowed_dbs": {
   174          "db_ks": true,
   175          "db_mycat": true
   176      },
   177      "default_phy_dbs": {
   178          "db_ks": "db_ks",
   179          "db_mycat": "db_mycat_0"
   180      },
   181      "slices": [
   182          {
   183              "name": "slice-0",
   184              "user_name": "root",
   185              "password": "root",
   186              "master": "127.0.0.1:3306",
   187              "capacity": 64,
   188              "max_capacity": 128,
   189              "idle_timeout": 3600
   190          },
   191          {
   192              "name": "slice-1",
   193              "user_name": "root",
   194              "password": "root",
   195              "master": "127.0.0.1:3307",
   196              "capacity": 64,
   197              "max_capacity": 128,
   198              "idle_timeout": 3600
   199          }
   200      ],
   201      "shard_rules": [
   202          {
   203              "db": "db_ks",
   204              "table": "tbl_ks",
   205              "type": "mod",
   206              "key": "id",
   207              "locations": [
   208                  2,
   209                  2
   210              ],
   211              "slices": [
   212                  "slice-0",
   213                  "slice-1"
   214              ]
   215          },
   216          {
   217              "db": "db_ks",
   218              "table": "tbl_ks_child",
   219              "type": "linked",
   220              "key": "id",
   221              "parent_table": "tbl_ks"
   222          },
   223          {
   224              "db": "db_ks",
   225              "table": "tbl_ks_user_child",
   226              "type": "linked",
   227              "key": "user_id",
   228              "parent_table": "tbl_ks"
   229          },
   230  		{
   231              "db": "db_ks",
   232              "table": "tbl_ks_global_one",
   233              "type": "global",
   234              "locations": [
   235                  2,
   236                  2
   237              ],
   238              "slices": [
   239                  "slice-0",
   240                  "slice-1"
   241              ]
   242          },
   243  		{
   244              "db": "db_ks",
   245              "table": "tbl_ks_global_two",
   246              "type": "global",
   247              "locations": [
   248                  2,
   249                  2
   250              ],
   251              "slices": [
   252                  "slice-0",
   253                  "slice-1"
   254              ]
   255          },
   256  		{
   257  			"db": "db_ks",
   258              "table": "tbl_ks_range",
   259              "type": "range",
   260  			"key": "id",
   261              "locations": [
   262                  2,
   263                  2
   264              ],
   265              "slices": [
   266                  "slice-0",
   267                  "slice-1"
   268              ],
   269  			"table_row_limit": 100
   270  		},
   271  		{
   272  			"db": "db_ks",
   273              "table": "tbl_ks_year",
   274              "type": "date_year",
   275  			"key": "create_time",
   276              "slices": [
   277                  "slice-0",
   278                  "slice-1"
   279              ],
   280  			"date_range": [
   281  				"2014-2017",
   282  				"2018-2019"
   283  			]
   284  		},
   285  		{
   286  			"db": "db_ks",
   287              "table": "tbl_ks_month",
   288              "type": "date_month",
   289  			"key": "create_time",
   290              "slices": [
   291                  "slice-0",
   292                  "slice-1"
   293              ],
   294  			"date_range": [
   295  				"201405-201406",
   296  				"201408-201409"
   297  			]
   298  		},
   299  		{
   300  			"db": "db_ks",
   301              "table": "tbl_ks_day",
   302              "type": "date_day",
   303  			"key": "create_time",
   304              "slices": [
   305                  "slice-0",
   306                  "slice-1"
   307              ],
   308  			"date_range": [
   309  				"20140901-20140905",
   310  				"20140907-20140908"
   311  			]
   312          },
   313          {
   314              "db": "db_ks",
   315              "table": "TBL_KS_UPPERCASE",
   316              "type": "mod",
   317              "key": "id",
   318              "locations": [
   319                  2,
   320                  2
   321              ],
   322              "slices": [
   323                  "slice-0",
   324                  "slice-1"
   325              ]
   326          },
   327          {
   328              "db": "db_ks",
   329              "table": "TBL_KS_UPPERCASE_CHILD",
   330              "type": "linked",
   331              "key": "ID",
   332              "parent_table": "TBL_KS_UPPERCASE"
   333          },
   334          {
   335              "db": "db_mycat",
   336              "table": "tbl_mycat",
   337              "type": "mycat_mod",
   338              "key": "id",
   339              "locations": [
   340                  2,
   341                  2
   342              ],
   343              "slices": [
   344                  "slice-0",
   345                  "slice-1"
   346              ],
   347              "databases": [
   348                  "db_mycat_[0-3]"
   349              ]
   350          },
   351          {
   352              "db": "db_mycat",
   353              "table": "tbl_mycat_child",
   354              "type": "linked",
   355              "parent_table": "tbl_mycat",
   356              "key": "id"
   357          },
   358          {
   359              "db": "db_mycat",
   360              "table": "tbl_mycat_user_child",
   361              "type": "linked",
   362              "parent_table": "tbl_mycat",
   363              "key": "user_id"
   364          },
   365          {
   366              "db": "db_mycat",
   367              "table": "tbl_mycat_murmur",
   368              "type": "mycat_murmur",
   369              "key": "id",
   370              "locations": [
   371                  2,
   372                  2
   373              ],
   374              "slices": [
   375                  "slice-0",
   376                  "slice-1"
   377              ],
   378              "databases": [
   379                  "db_mycat_0","db_mycat_1","db_mycat_2","db_mycat_3"
   380              ],
   381  			"seed": "0",
   382  			"virtual_bucket_times": "160"
   383          },
   384          {
   385              "db": "db_mycat",
   386              "table": "tbl_mycat_long",
   387              "type": "mycat_long",
   388              "key": "id",
   389              "locations": [
   390                  2,
   391                  2
   392              ],
   393              "slices": [
   394                  "slice-0",
   395                  "slice-1"
   396              ],
   397              "databases": [
   398                  "db_mycat_[0-3]"
   399              ],
   400  			"partition_count": "4",
   401  			"partition_length": "256"
   402          },
   403  		{
   404              "db": "db_mycat",
   405              "table": "tbl_mycat_global_one",
   406              "type": "global",
   407              "locations": [
   408                  2,
   409                  2
   410              ],
   411              "slices": [
   412                  "slice-0",
   413                  "slice-1"
   414              ],
   415              "databases": [
   416                  "db_mycat_[0-3]"
   417              ]
   418          },
   419  		{
   420              "db": "db_mycat",
   421              "table": "tbl_mycat_global_two",
   422              "type": "global",
   423              "locations": [
   424                  2,
   425                  2
   426              ],
   427              "slices": [
   428                  "slice-0",
   429                  "slice-1"
   430              ],
   431              "databases": [
   432                  "db_mycat_[0-3]"
   433              ]
   434          },
   435          {
   436              "db": "db_mycat",
   437              "table": "tbl_mycat_string",
   438              "type": "mycat_string",
   439              "key": "id",
   440              "locations": [
   441                  2,
   442                  2
   443              ],
   444              "slices": [
   445                  "slice-0",
   446                  "slice-1"
   447              ],
   448              "databases": [
   449                  "db_mycat_[0-3]"
   450              ],
   451  			"partition_count": "4",
   452  			"partition_length": "256",
   453  			"hash_slice": "20"
   454          }
   455      ],
   456  	"global_sequences": [
   457  		{
   458  			"db": "db_mycat",
   459  			"table": "tbl_mycat",
   460  			"type": "test",
   461  			"pk_name": "id"
   462  		},
   463  		{
   464  			"db": "db_ks",
   465  			"table": "tbl_ks",
   466  			"type": "test",
   467  			"pk_name": "user_id"
   468  		}
   469  	],
   470      "users": [
   471          {
   472              "user_name": "test_shard_hash",
   473              "password": "test_shard_hash",
   474              "namespace": "gaea_namespace_1",
   475              "rw_flag": 2,
   476              "rw_split": 1
   477          }
   478      ],
   479      "default_slice": "slice-0"
   480  }`
   481  	nsModel, err := createNamespace(nsStr)
   482  	if err != nil {
   483  		return nil, err
   484  	}
   485  
   486  	rt, err := createRouter(nsModel)
   487  	if err != nil {
   488  		return nil, err
   489  	}
   490  
   491  	seqs, err := createSequenceManager(nsModel)
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  
   496  	planInfo := &PlanInfo{
   497  		phyDBs: nsModel.DefaultPhyDBS,
   498  		rt:     rt,
   499  		seqs:   seqs,
   500  	}
   501  	return planInfo, nil
   502  }