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 }