github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/foreign_key_test.go (about)

     1  // Copyright 2016 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 ddl
    15  
    16  import (
    17  	"strings"
    18  	"time"
    19  
    20  	. "github.com/insionng/yougam/libraries/pingcap/check"
    21  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    22  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    23  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    24  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    25  	"github.com/insionng/yougam/libraries/pingcap/tidb/table"
    26  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/testleak"
    27  )
    28  
    29  var _ = Suite(&testForeighKeySuite{})
    30  
    31  type testForeighKeySuite struct {
    32  	store  kv.Storage
    33  	dbInfo *model.DBInfo
    34  	d      *ddl
    35  	ctx    context.Context
    36  }
    37  
    38  func (s *testForeighKeySuite) SetUpSuite(c *C) {
    39  	trySkipTest(c)
    40  
    41  	s.store = testCreateStore(c, "test_foreign")
    42  }
    43  
    44  func (s *testForeighKeySuite) TearDownSuite(c *C) {
    45  	trySkipTest(c)
    46  
    47  	err := s.store.Close()
    48  	c.Assert(err, IsNil)
    49  }
    50  
    51  func (s *testForeighKeySuite) testCreateForeignKey(c *C, tblInfo *model.TableInfo, fkName string, keys []string, refTable string, refKeys []string, onDelete ast.ReferOptionType, onUpdate ast.ReferOptionType) *model.Job {
    52  	FKName := model.NewCIStr(fkName)
    53  	Keys := make([]model.CIStr, len(keys))
    54  	for i, key := range keys {
    55  		Keys[i] = model.NewCIStr(key)
    56  	}
    57  
    58  	RefTable := model.NewCIStr(refTable)
    59  	RefKeys := make([]model.CIStr, len(refKeys))
    60  	for i, key := range refKeys {
    61  		RefKeys[i] = model.NewCIStr(key)
    62  	}
    63  
    64  	fkID, err := s.d.genGlobalID()
    65  	c.Assert(err, IsNil)
    66  	fkInfo := &model.FKInfo{
    67  		ID:       fkID,
    68  		Name:     FKName,
    69  		RefTable: RefTable,
    70  		RefCols:  RefKeys,
    71  		Cols:     Keys,
    72  		OnDelete: int(onDelete),
    73  		OnUpdate: int(onUpdate),
    74  		State:    model.StateNone,
    75  	}
    76  
    77  	job := &model.Job{
    78  		SchemaID: s.dbInfo.ID,
    79  		TableID:  tblInfo.ID,
    80  		Type:     model.ActionAddForeignKey,
    81  		Args:     []interface{}{fkInfo},
    82  	}
    83  	err = s.d.doDDLJob(s.ctx, job)
    84  	c.Assert(err, IsNil)
    85  	return job
    86  }
    87  
    88  func testDropForeignKey(c *C, ctx context.Context, d *ddl, dbInfo *model.DBInfo, tblInfo *model.TableInfo, foreignKeyName string) *model.Job {
    89  	job := &model.Job{
    90  		SchemaID: dbInfo.ID,
    91  		TableID:  tblInfo.ID,
    92  		Type:     model.ActionDropForeignKey,
    93  		Args:     []interface{}{model.NewCIStr(foreignKeyName)},
    94  	}
    95  	err := d.doDDLJob(ctx, job)
    96  	c.Assert(err, IsNil)
    97  	return job
    98  }
    99  
   100  func getForeignKey(t table.Table, name string) *model.FKInfo {
   101  	for _, fk := range t.Meta().ForeignKeys {
   102  		// only public foreign key can be read.
   103  		if fk.State != model.StatePublic {
   104  			continue
   105  		}
   106  		if fk.Name.L == strings.ToLower(name) {
   107  			return fk
   108  		}
   109  	}
   110  	return nil
   111  }
   112  
   113  func (s *testForeighKeySuite) testForeignKeyExist(c *C, t table.Table, name string, isExist bool) {
   114  	fk := getForeignKey(t, name)
   115  	if isExist {
   116  		c.Assert(fk, NotNil)
   117  	} else {
   118  		c.Assert(fk, IsNil)
   119  	}
   120  }
   121  
   122  func (s *testForeighKeySuite) TestForeignKey(c *C) {
   123  	defer testleak.AfterTest(c)()
   124  	d := newDDL(s.store, nil, nil, 100*time.Millisecond)
   125  	s.d = d
   126  	s.dbInfo = testSchemaInfo(c, d, "test_foreign")
   127  	ctx := testNewContext(c, d)
   128  	s.ctx = ctx
   129  	testCreateSchema(c, ctx, d, s.dbInfo)
   130  	tblInfo := testTableInfo(c, d, "t", 3)
   131  
   132  	_, err := ctx.GetTxn(true)
   133  	c.Assert(err, IsNil)
   134  
   135  	testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   136  
   137  	err = ctx.FinishTxn(false)
   138  	c.Assert(err, IsNil)
   139  
   140  	checkOK := false
   141  	tc := &testDDLCallback{}
   142  	tc.onJobUpdated = func(job *model.Job) {
   143  		if job.State != model.JobDone {
   144  			return
   145  		}
   146  
   147  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   148  		s.testForeignKeyExist(c, t, "c1_fk", true)
   149  		checkOK = true
   150  	}
   151  
   152  	d.hook = tc
   153  
   154  	d.close()
   155  	d.start()
   156  
   157  	job := s.testCreateForeignKey(c, tblInfo, "c1_fk", []string{"c1"}, "t2", []string{"c1"}, ast.ReferOptionCascade, ast.ReferOptionSetNull)
   158  
   159  	testCheckJobDone(c, d, job, true)
   160  
   161  	err = ctx.FinishTxn(false)
   162  	c.Assert(err, IsNil)
   163  	c.Assert(checkOK, IsTrue)
   164  
   165  	checkOK = false
   166  	tc.onJobUpdated = func(job *model.Job) {
   167  		if job.State != model.JobDone {
   168  			return
   169  		}
   170  		t := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   171  		s.testForeignKeyExist(c, t, "c1_fk", false)
   172  		checkOK = true
   173  	}
   174  
   175  	d.close()
   176  	d.start()
   177  
   178  	job = testDropForeignKey(c, ctx, d, s.dbInfo, tblInfo, "c1_fk")
   179  	testCheckJobDone(c, d, job, false)
   180  	c.Assert(checkOK, IsTrue)
   181  
   182  	_, err = ctx.GetTxn(true)
   183  	c.Assert(err, IsNil)
   184  
   185  	tc.onJobUpdated = func(job *model.Job) {
   186  	}
   187  
   188  	d.close()
   189  	d.start()
   190  
   191  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   192  	testCheckJobDone(c, d, job, false)
   193  
   194  	err = ctx.FinishTxn(false)
   195  	c.Assert(err, IsNil)
   196  
   197  	d.close()
   198  }