github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/server/http_handler_test.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 server 15 16 import ( 17 "bytes" 18 "crypto/tls" 19 "crypto/x509" 20 "crypto/x509/pkix" 21 "database/allegrosql" 22 "encoding/base64" 23 "encoding/json" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "net" 28 "net/http" 29 "net/http/httputil" 30 "net/url" 31 "os" 32 "sort" 33 "strings" 34 "sync/atomic" 35 "time" 36 37 log "github.com/sirupsen/logrus" 38 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 39 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 40 . "github.com/whtcorpsinc/check" 41 "github.com/whtcorpsinc/ekvproto/pkg/ekvrpcpb" 42 "github.com/whtcorpsinc/failpoint" 43 zaplog "github.com/whtcorpsinc/log" 44 "github.com/whtcorpsinc/milevadb/blockcodec" 45 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 46 "github.com/whtcorpsinc/milevadb/causetstore/helper" 47 "github.com/whtcorpsinc/milevadb/causetstore/mockstore" 48 "github.com/whtcorpsinc/milevadb/config" 49 "github.com/whtcorpsinc/milevadb/dbs" 50 "github.com/whtcorpsinc/milevadb/ekv" 51 "github.com/whtcorpsinc/milevadb/petri" 52 "github.com/whtcorpsinc/milevadb/soliton/codec" 53 "github.com/whtcorpsinc/milevadb/soliton/rowcodec" 54 "github.com/whtcorpsinc/milevadb/soliton/versioninfo" 55 "github.com/whtcorpsinc/milevadb/spacetime" 56 "github.com/whtcorpsinc/milevadb/stochastik" 57 "github.com/whtcorpsinc/milevadb/stochastikctx" 58 "github.com/whtcorpsinc/milevadb/stochastikctx/binloginfo" 59 "github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx" 60 "github.com/whtcorpsinc/milevadb/stochastikctx/variable" 61 "github.com/whtcorpsinc/milevadb/types" 62 "go.uber.org/zap" 63 ) 64 65 type basicHTTPHandlerTestSuite struct { 66 *testServerClient 67 server *Server 68 causetstore ekv.CausetStorage 69 petri *petri.Petri 70 milevadbdrv *MilevaDBDriver 71 } 72 73 type HTTPHandlerTestSuite struct { 74 *basicHTTPHandlerTestSuite 75 } 76 77 type HTTPHandlerTestSerialSuite struct { 78 *basicHTTPHandlerTestSuite 79 } 80 81 var _ = Suite(&HTTPHandlerTestSuite{&basicHTTPHandlerTestSuite{}}) 82 83 var _ = SerialSuites(&HTTPHandlerTestSerialSuite{&basicHTTPHandlerTestSuite{}}) 84 85 func (ts *basicHTTPHandlerTestSuite) SetUpSuite(c *C) { 86 ts.testServerClient = newTestServerClient() 87 } 88 89 func (ts *HTTPHandlerTestSuite) TestRegionIndexRange(c *C) { 90 sBlockID := int64(3) 91 sIndex := int64(11) 92 eBlockID := int64(9) 93 recordID := int64(133) 94 indexValues := []types.Causet{ 95 types.NewIntCauset(100), 96 types.NewBytesCauset([]byte("foobar")), 97 types.NewFloat64Causet(-100.25), 98 } 99 expectIndexValues := make([]string, 0, len(indexValues)) 100 for _, v := range indexValues { 101 str, err := v.ToString() 102 if err != nil { 103 str = fmt.Sprintf("%d-%v", v.HoTT(), v.GetValue()) 104 } 105 expectIndexValues = append(expectIndexValues, str) 106 } 107 encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...) 108 c.Assert(err, IsNil) 109 110 startKey := blockcodec.EncodeIndexSeekKey(sBlockID, sIndex, encodedValue) 111 recordPrefix := blockcodec.GenBlockRecordPrefix(eBlockID) 112 endKey := blockcodec.EncodeRecordKey(recordPrefix, ekv.IntHandle(recordID)) 113 114 region := &einsteindb.KeyLocation{ 115 Region: einsteindb.RegionVerID{}, 116 StartKey: startKey, 117 EndKey: endKey, 118 } 119 r, err := helper.NewRegionFrameRange(region) 120 c.Assert(err, IsNil) 121 c.Assert(r.First.IndexID, Equals, sIndex) 122 c.Assert(r.First.IsRecord, IsFalse) 123 c.Assert(r.First.RecordID, Equals, int64(0)) 124 c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues) 125 c.Assert(r.Last.RecordID, Equals, recordID) 126 c.Assert(r.Last.IndexValues, IsNil) 127 128 testCases := []struct { 129 blockID int64 130 indexID int64 131 isCover bool 132 }{ 133 {2, 0, false}, 134 {3, 0, true}, 135 {9, 0, true}, 136 {10, 0, false}, 137 {2, 10, false}, 138 {3, 10, false}, 139 {3, 11, true}, 140 {3, 20, true}, 141 {9, 10, true}, 142 {10, 1, false}, 143 } 144 for _, t := range testCases { 145 var f *helper.FrameItem 146 if t.indexID == 0 { 147 f = r.GetRecordFrame(t.blockID, "", "", false) 148 } else { 149 f = r.GetIndexFrame(t.blockID, t.indexID, "", "", "") 150 } 151 if t.isCover { 152 c.Assert(f, NotNil) 153 } else { 154 c.Assert(f, IsNil) 155 } 156 } 157 } 158 159 func (ts *HTTPHandlerTestSuite) TestRegionCommonHandleRange(c *C) { 160 sBlockID := int64(3) 161 indexValues := []types.Causet{ 162 types.NewIntCauset(100), 163 types.NewBytesCauset([]byte("foobar")), 164 types.NewFloat64Causet(-100.25), 165 } 166 expectIndexValues := make([]string, 0, len(indexValues)) 167 for _, v := range indexValues { 168 str, err := v.ToString() 169 if err != nil { 170 str = fmt.Sprintf("%d-%v", v.HoTT(), v.GetValue()) 171 } 172 expectIndexValues = append(expectIndexValues, str) 173 } 174 encodedValue, err := codec.EncodeKey(&stmtctx.StatementContext{TimeZone: time.Local}, nil, indexValues...) 175 c.Assert(err, IsNil) 176 177 startKey := blockcodec.EncodeRowKey(sBlockID, encodedValue) 178 179 region := &einsteindb.KeyLocation{ 180 Region: einsteindb.RegionVerID{}, 181 StartKey: startKey, 182 } 183 r, err := helper.NewRegionFrameRange(region) 184 c.Assert(err, IsNil) 185 c.Assert(r.First.IsRecord, IsTrue) 186 c.Assert(r.First.RecordID, Equals, int64(0)) 187 c.Assert(r.First.IndexValues, DeepEquals, expectIndexValues) 188 c.Assert(r.First.IndexName, Equals, "PRIMARY") 189 c.Assert(r.Last.RecordID, Equals, int64(0)) 190 c.Assert(r.Last.IndexValues, IsNil) 191 } 192 193 func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithEndNoLimit(c *C) { 194 sBlockID := int64(15) 195 startKey := blockcodec.GenBlockRecordPrefix(sBlockID) 196 endKey := []byte("z_aaaaafdfd") 197 region := &einsteindb.KeyLocation{ 198 Region: einsteindb.RegionVerID{}, 199 StartKey: startKey, 200 EndKey: endKey, 201 } 202 r, err := helper.NewRegionFrameRange(region) 203 c.Assert(err, IsNil) 204 c.Assert(r.First.IsRecord, IsTrue) 205 c.Assert(r.Last.IsRecord, IsTrue) 206 c.Assert(r.GetRecordFrame(300, "", "", false), NotNil) 207 c.Assert(r.GetIndexFrame(200, 100, "", "", ""), NotNil) 208 } 209 210 func (ts *HTTPHandlerTestSuite) TestRegionIndexRangeWithStartNoLimit(c *C) { 211 eBlockID := int64(9) 212 startKey := []byte("m_aaaaafdfd") 213 endKey := blockcodec.GenBlockRecordPrefix(eBlockID) 214 region := &einsteindb.KeyLocation{ 215 Region: einsteindb.RegionVerID{}, 216 StartKey: startKey, 217 EndKey: endKey, 218 } 219 r, err := helper.NewRegionFrameRange(region) 220 c.Assert(err, IsNil) 221 c.Assert(r.First.IsRecord, IsFalse) 222 c.Assert(r.Last.IsRecord, IsTrue) 223 c.Assert(r.GetRecordFrame(3, "", "", false), NotNil) 224 c.Assert(r.GetIndexFrame(8, 1, "", "", ""), NotNil) 225 } 226 227 func (ts *HTTPHandlerTestSuite) TestRegionsAPI(c *C) { 228 ts.startServer(c) 229 defer ts.stopServer(c) 230 ts.prepareData(c) 231 resp, err := ts.fetchStatus("/blocks/milevadb/t/regions") 232 c.Assert(err, IsNil) 233 c.Assert(resp.StatusCode, Equals, http.StatusOK) 234 defer resp.Body.Close() 235 causetDecoder := json.NewCausetDecoder(resp.Body) 236 237 var data BlockRegions 238 err = causetDecoder.Decode(&data) 239 c.Assert(err, IsNil) 240 c.Assert(len(data.RecordRegions) > 0, IsTrue) 241 242 // list region 243 for _, region := range data.RecordRegions { 244 c.Assert(ts.regionContainsBlock(c, region.ID, data.BlockID), IsTrue) 245 } 246 } 247 248 func (ts *HTTPHandlerTestSuite) TestRegionsAPIForClusterIndex(c *C) { 249 ts.startServer(c) 250 defer ts.stopServer(c) 251 ts.prepareData(c) 252 resp, err := ts.fetchStatus("/blocks/milevadb/t/regions") 253 c.Assert(err, IsNil) 254 c.Assert(resp.StatusCode, Equals, http.StatusOK) 255 defer resp.Body.Close() 256 causetDecoder := json.NewCausetDecoder(resp.Body) 257 var data BlockRegions 258 err = causetDecoder.Decode(&data) 259 c.Assert(err, IsNil) 260 c.Assert(len(data.RecordRegions) > 0, IsTrue) 261 // list region 262 for _, region := range data.RecordRegions { 263 resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", region.ID)) 264 c.Assert(err, IsNil) 265 c.Assert(resp.StatusCode, Equals, http.StatusOK) 266 causetDecoder := json.NewCausetDecoder(resp.Body) 267 var data RegionDetail 268 err = causetDecoder.Decode(&data) 269 c.Assert(err, IsNil) 270 frameCnt := 0 271 for _, f := range data.Frames { 272 if f.DBName == "milevadb" && f.BlockName == "t" { 273 frameCnt++ 274 } 275 } 276 // Primary index is as the record frame, so frame count is 1. 277 c.Assert(frameCnt, Equals, 1) 278 c.Assert(resp.Body.Close(), IsNil) 279 } 280 } 281 282 func (ts *HTTPHandlerTestSuite) regionContainsBlock(c *C, regionID uint64, blockID int64) bool { 283 resp, err := ts.fetchStatus(fmt.Sprintf("/regions/%d", regionID)) 284 c.Assert(err, IsNil) 285 c.Assert(resp.StatusCode, Equals, http.StatusOK) 286 defer resp.Body.Close() 287 causetDecoder := json.NewCausetDecoder(resp.Body) 288 var data RegionDetail 289 err = causetDecoder.Decode(&data) 290 c.Assert(err, IsNil) 291 for _, index := range data.Frames { 292 if index.BlockID == blockID { 293 return true 294 } 295 } 296 return false 297 } 298 299 func (ts *HTTPHandlerTestSuite) TestListBlockRegions(c *C) { 300 ts.startServer(c) 301 defer ts.stopServer(c) 302 ts.prepareData(c) 303 // Test list causet regions with error 304 resp, err := ts.fetchStatus("/blocks/fdsfds/aaa/regions") 305 c.Assert(err, IsNil) 306 defer resp.Body.Close() 307 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 308 309 resp, err = ts.fetchStatus("/blocks/milevadb/pt/regions") 310 c.Assert(err, IsNil) 311 defer resp.Body.Close() 312 313 var data []*BlockRegions 314 dec := json.NewCausetDecoder(resp.Body) 315 err = dec.Decode(&data) 316 c.Assert(err, IsNil) 317 318 region := data[1] 319 _, err = ts.fetchStatus(fmt.Sprintf("/regions/%d", region.BlockID)) 320 c.Assert(err, IsNil) 321 } 322 323 func (ts *HTTPHandlerTestSuite) TestGetRegionByIDWithError(c *C) { 324 ts.startServer(c) 325 defer ts.stopServer(c) 326 resp, err := ts.fetchStatus("/regions/xxx") 327 c.Assert(err, IsNil) 328 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 329 defer resp.Body.Close() 330 } 331 332 func (ts *HTTPHandlerTestSuite) TestBinlogRecover(c *C) { 333 ts.startServer(c) 334 defer ts.stopServer(c) 335 binloginfo.EnableSkipBinlogFlag() 336 c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) 337 resp, err := ts.fetchStatus("/binlog/recover") 338 c.Assert(err, IsNil) 339 defer resp.Body.Close() 340 c.Assert(resp.StatusCode, Equals, http.StatusOK) 341 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 342 343 // Invalid operation will use the default operation. 344 binloginfo.EnableSkipBinlogFlag() 345 c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) 346 resp, err = ts.fetchStatus("/binlog/recover?op=abc") 347 c.Assert(err, IsNil) 348 defer resp.Body.Close() 349 c.Assert(resp.StatusCode, Equals, http.StatusOK) 350 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 351 352 binloginfo.EnableSkipBinlogFlag() 353 c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) 354 resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1") 355 c.Assert(err, IsNil) 356 defer resp.Body.Close() 357 c.Assert(resp.StatusCode, Equals, http.StatusOK) 358 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 359 360 binloginfo.EnableSkipBinlogFlag() 361 c.Assert(binloginfo.IsBinlogSkipped(), Equals, true) 362 binloginfo.AddOneSkippedCommitter() 363 resp, err = ts.fetchStatus("/binlog/recover?op=abc&seconds=1") 364 c.Assert(err, IsNil) 365 defer resp.Body.Close() 366 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 367 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 368 binloginfo.RemoveOneSkippedCommitter() 369 370 binloginfo.AddOneSkippedCommitter() 371 c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(1)) 372 resp, err = ts.fetchStatus("/binlog/recover?op=reset") 373 c.Assert(err, IsNil) 374 defer resp.Body.Close() 375 c.Assert(resp.StatusCode, Equals, http.StatusOK) 376 c.Assert(binloginfo.SkippedCommitterCount(), Equals, int32(0)) 377 378 binloginfo.EnableSkipBinlogFlag() 379 resp, err = ts.fetchStatus("/binlog/recover?op=nowait") 380 c.Assert(err, IsNil) 381 defer resp.Body.Close() 382 c.Assert(resp.StatusCode, Equals, http.StatusOK) 383 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 384 385 // Only the first should work. 386 binloginfo.EnableSkipBinlogFlag() 387 resp, err = ts.fetchStatus("/binlog/recover?op=nowait&op=reset") 388 c.Assert(err, IsNil) 389 defer resp.Body.Close() 390 c.Assert(resp.StatusCode, Equals, http.StatusOK) 391 c.Assert(binloginfo.IsBinlogSkipped(), Equals, false) 392 393 resp, err = ts.fetchStatus("/binlog/recover?op=status") 394 c.Assert(err, IsNil) 395 defer resp.Body.Close() 396 c.Assert(resp.StatusCode, Equals, http.StatusOK) 397 } 398 399 func (ts *HTTPHandlerTestSuite) TestRegionsFromMeta(c *C) { 400 ts.startServer(c) 401 defer ts.stopServer(c) 402 resp, err := ts.fetchStatus("/regions/spacetime") 403 c.Assert(err, IsNil) 404 defer resp.Body.Close() 405 c.Assert(resp.StatusCode, Equals, http.StatusOK) 406 407 // Verify the resp body. 408 causetDecoder := json.NewCausetDecoder(resp.Body) 409 spacetimes := make([]RegionMeta, 0) 410 err = causetDecoder.Decode(&spacetimes) 411 c.Assert(err, IsNil) 412 for _, spacetime := range spacetimes { 413 c.Assert(spacetime.ID != 0, IsTrue) 414 } 415 416 // test no panic 417 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/errGetRegionByIDEmpty", `return(true)`), IsNil) 418 resp1, err := ts.fetchStatus("/regions/spacetime") 419 c.Assert(err, IsNil) 420 defer resp1.Body.Close() 421 c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/server/errGetRegionByIDEmpty"), IsNil) 422 } 423 424 func (ts *basicHTTPHandlerTestSuite) startServer(c *C) { 425 var err error 426 ts.causetstore, err = mockstore.NewMockStore() 427 c.Assert(err, IsNil) 428 ts.petri, err = stochastik.BootstrapStochastik(ts.causetstore) 429 c.Assert(err, IsNil) 430 ts.milevadbdrv = NewMilevaDBDriver(ts.causetstore) 431 432 cfg := newTestConfig() 433 cfg.CausetStore = "einsteindb" 434 cfg.Port = 0 435 cfg.Status.StatusPort = 0 436 cfg.Status.ReportStatus = true 437 438 server, err := NewServer(cfg, ts.milevadbdrv) 439 c.Assert(err, IsNil) 440 ts.port = getPortFromTCPAddr(server.listener.Addr()) 441 ts.statusPort = getPortFromTCPAddr(server.statusListener.Addr()) 442 ts.server = server 443 go server.Run() 444 ts.waitUntilServerOnline() 445 } 446 447 func getPortFromTCPAddr(addr net.Addr) uint { 448 return uint(addr.(*net.TCPAddr).Port) 449 } 450 451 func (ts *basicHTTPHandlerTestSuite) stopServer(c *C) { 452 if ts.petri != nil { 453 ts.petri.Close() 454 } 455 if ts.causetstore != nil { 456 ts.causetstore.Close() 457 } 458 if ts.server != nil { 459 ts.server.Close() 460 } 461 } 462 463 func (ts *basicHTTPHandlerTestSuite) prepareData(c *C) { 464 EDB, err := allegrosql.Open("allegrosql", ts.getDSN()) 465 c.Assert(err, IsNil, Commentf("Error connecting")) 466 defer EDB.Close() 467 dbt := &DBTest{c, EDB} 468 469 dbt.mustInterDirc("create database milevadb;") 470 dbt.mustInterDirc("use milevadb;") 471 dbt.mustInterDirc("create causet milevadb.test (a int auto_increment primary key, b varchar(20));") 472 dbt.mustInterDirc("insert milevadb.test values (1, 1);") 473 txn1, err := dbt.EDB.Begin() 474 c.Assert(err, IsNil) 475 _, err = txn1.InterDirc("uFIDelate milevadb.test set b = b + 1 where a = 1;") 476 c.Assert(err, IsNil) 477 _, err = txn1.InterDirc("insert milevadb.test values (2, 2);") 478 c.Assert(err, IsNil) 479 _, err = txn1.InterDirc("insert milevadb.test (a) values (3);") 480 c.Assert(err, IsNil) 481 _, err = txn1.InterDirc("insert milevadb.test values (4, '');") 482 c.Assert(err, IsNil) 483 err = txn1.Commit() 484 c.Assert(err, IsNil) 485 dbt.mustInterDirc("alter causet milevadb.test add index idx1 (a, b);") 486 dbt.mustInterDirc("alter causet milevadb.test add unique index idx2 (a, b);") 487 488 dbt.mustInterDirc(`create causet milevadb.pt (a int primary key, b varchar(20), key idx(a, b)) 489 partition by range (a) 490 (partition p0 values less than (256), 491 partition p1 values less than (512), 492 partition p2 values less than (1024))`) 493 494 txn2, err := dbt.EDB.Begin() 495 c.Assert(err, IsNil) 496 txn2.InterDirc("insert into milevadb.pt values (42, '123')") 497 txn2.InterDirc("insert into milevadb.pt values (256, 'b')") 498 txn2.InterDirc("insert into milevadb.pt values (666, 'def')") 499 err = txn2.Commit() 500 c.Assert(err, IsNil) 501 502 dbt.mustInterDirc("set @@milevadb_enable_clustered_index = 1") 503 dbt.mustInterDirc("drop causet if exists t") 504 dbt.mustInterDirc("create causet t (a double, b varchar(20), c int, primary key(a,b))") 505 dbt.mustInterDirc("insert into t values(1.1,'111',1),(2.2,'222',2)") 506 } 507 508 func decodeKeyMvcc(closer io.ReadCloser, c *C, valid bool) { 509 causetDecoder := json.NewCausetDecoder(closer) 510 var data mvccKV 511 err := causetDecoder.Decode(&data) 512 c.Assert(err, IsNil) 513 if valid { 514 c.Assert(data.Value.Info, NotNil) 515 c.Assert(len(data.Value.Info.Writes), Greater, 0) 516 } else { 517 c.Assert(data.Value.Info.Lock, IsNil) 518 c.Assert(data.Value.Info.Writes, IsNil) 519 c.Assert(data.Value.Info.Values, IsNil) 520 } 521 } 522 523 func (ts *HTTPHandlerTestSuite) TestGetBlockMVCC(c *C) { 524 ts.startServer(c) 525 ts.prepareData(c) 526 defer ts.stopServer(c) 527 528 resp, err := ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1")) 529 c.Assert(err, IsNil) 530 causetDecoder := json.NewCausetDecoder(resp.Body) 531 var data mvccKV 532 err = causetDecoder.Decode(&data) 533 c.Assert(err, IsNil) 534 c.Assert(data.Value, NotNil) 535 info := data.Value.Info 536 c.Assert(info, NotNil) 537 c.Assert(len(info.Writes), Greater, 0) 538 539 // TODO: EntangledStore will not return Op_Lock. 540 // Use this workaround to support two backend, we can remove this replog after deprecated mockeinsteindb. 541 var startTs uint64 542 for _, w := range info.Writes { 543 if w.Type == ekvrpcpb.Op_Lock { 544 continue 545 } 546 startTs = w.StartTs 547 break 548 } 549 550 resp, err = ts.fetchStatus(fmt.Sprintf("/mvcc/txn/%d/milevadb/test", startTs)) 551 c.Assert(err, IsNil) 552 var p2 mvccKV 553 causetDecoder = json.NewCausetDecoder(resp.Body) 554 err = causetDecoder.Decode(&p2) 555 c.Assert(err, IsNil) 556 557 for i, expect := range info.Values { 558 v2 := p2.Value.Info.Values[i].Value 559 c.Assert(v2, BytesEquals, expect.Value) 560 } 561 562 hexKey := p2.Key 563 resp, err = ts.fetchStatus("/mvcc/hex/" + hexKey) 564 c.Assert(err, IsNil) 565 causetDecoder = json.NewCausetDecoder(resp.Body) 566 var data2 mvccKV 567 err = causetDecoder.Decode(&data2) 568 c.Assert(err, IsNil) 569 c.Assert(data2, DeepEquals, data) 570 571 resp, err = ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1?decode=true")) 572 c.Assert(err, IsNil) 573 causetDecoder = json.NewCausetDecoder(resp.Body) 574 var data3 map[string]interface{} 575 err = causetDecoder.Decode(&data3) 576 c.Assert(err, IsNil) 577 c.Assert(data3["key"], NotNil) 578 c.Assert(data3["info"], NotNil) 579 c.Assert(data3["data"], NotNil) 580 c.Assert(data3["decode_error"], IsNil) 581 582 resp, err = ts.fetchStatus("/mvcc/key/milevadb/pt(p0)/42?decode=true") 583 c.Assert(err, IsNil) 584 defer resp.Body.Close() 585 causetDecoder = json.NewCausetDecoder(resp.Body) 586 var data4 map[string]interface{} 587 err = causetDecoder.Decode(&data4) 588 c.Assert(err, IsNil) 589 c.Assert(data4["key"], NotNil) 590 c.Assert(data4["info"], NotNil) 591 c.Assert(data4["data"], NotNil) 592 c.Assert(data4["decode_error"], IsNil) 593 } 594 595 func (ts *HTTPHandlerTestSuite) TestGetMVCCNotFound(c *C) { 596 ts.startServer(c) 597 ts.prepareData(c) 598 defer ts.stopServer(c) 599 resp, err := ts.fetchStatus(fmt.Sprintf("/mvcc/key/milevadb/test/1234")) 600 c.Assert(err, IsNil) 601 causetDecoder := json.NewCausetDecoder(resp.Body) 602 var data mvccKV 603 err = causetDecoder.Decode(&data) 604 c.Assert(err, IsNil) 605 c.Assert(data.Value.Info.Lock, IsNil) 606 c.Assert(data.Value.Info.Writes, IsNil) 607 c.Assert(data.Value.Info.Values, IsNil) 608 } 609 610 func (ts *HTTPHandlerTestSuite) TestTiFlashReplica(c *C) { 611 ts.startServer(c) 612 ts.prepareData(c) 613 defer ts.stopServer(c) 614 615 EDB, err := allegrosql.Open("allegrosql", ts.getDSN()) 616 c.Assert(err, IsNil, Commentf("Error connecting")) 617 defer EDB.Close() 618 dbt := &DBTest{c, EDB} 619 620 defer func(originGC bool) { 621 if originGC { 622 dbs.EmulatorGCEnable() 623 } else { 624 dbs.EmulatorGCDisable() 625 } 626 }(dbs.IsEmulatorGCEnable()) 627 628 // Disable emulator GC. 629 // Otherwise emulator GC will delete causet record as soon as possible after execute drop causet DBS. 630 dbs.EmulatorGCDisable() 631 gcTimeFormat := "20060102-15:04:05 -0700 MST" 632 timeBeforeDrop := time.Now().Add(0 - 48*60*60*time.Second).Format(gcTimeFormat) 633 safePointALLEGROSQL := `INSERT HIGH_PRIORITY INTO allegrosql.milevadb VALUES ('einsteindb_gc_safe_point', '%[1]s', ''),('einsteindb_gc_enable','true','') 634 ON DUPLICATE KEY 635 UFIDelATE variable_value = '%[1]s'` 636 // Set GC safe point and enable GC. 637 dbt.mustInterDirc(fmt.Sprintf(safePointALLEGROSQL, timeBeforeDrop)) 638 639 resp, err := ts.fetchStatus("/tiflash/replica") 640 c.Assert(err, IsNil) 641 causetDecoder := json.NewCausetDecoder(resp.Body) 642 var data []blockFlashReplicaInfo 643 err = causetDecoder.Decode(&data) 644 c.Assert(err, IsNil) 645 c.Assert(len(data), Equals, 0) 646 647 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/schemareplicant/mockTiFlashStoreCount", `return(true)`), IsNil) 648 defer failpoint.Disable("github.com/whtcorpsinc/milevadb/schemareplicant/mockTiFlashStoreCount") 649 dbt.mustInterDirc("use milevadb") 650 dbt.mustInterDirc("alter causet test set tiflash replica 2 location labels 'a','b';") 651 652 resp, err = ts.fetchStatus("/tiflash/replica") 653 c.Assert(err, IsNil) 654 causetDecoder = json.NewCausetDecoder(resp.Body) 655 err = causetDecoder.Decode(&data) 656 c.Assert(err, IsNil) 657 c.Assert(len(data), Equals, 1) 658 c.Assert(data[0].ReplicaCount, Equals, uint64(2)) 659 c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") 660 c.Assert(data[0].Available, Equals, false) 661 662 resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(`{"id":84,"region_count":3,"flash_region_count":3}`))) 663 c.Assert(err, IsNil) 664 c.Assert(resp, NotNil) 665 body, err := ioutil.ReadAll(resp.Body) 666 c.Assert(err, IsNil) 667 c.Assert(string(body), Equals, "[schemaReplicant:1146]Block which ID = 84 does not exist.") 668 669 t, err := ts.petri.SchemaReplicant().BlockByName(perceptron.NewCIStr("milevadb"), perceptron.NewCIStr("test")) 670 c.Assert(err, IsNil) 671 req := fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, t.Meta().ID) 672 resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) 673 c.Assert(err, IsNil) 674 c.Assert(resp, NotNil) 675 body, err = ioutil.ReadAll(resp.Body) 676 c.Assert(err, IsNil) 677 c.Assert(string(body), Equals, "") 678 679 resp, err = ts.fetchStatus("/tiflash/replica") 680 c.Assert(err, IsNil) 681 causetDecoder = json.NewCausetDecoder(resp.Body) 682 err = causetDecoder.Decode(&data) 683 c.Assert(err, IsNil) 684 resp.Body.Close() 685 c.Assert(len(data), Equals, 1) 686 c.Assert(data[0].ReplicaCount, Equals, uint64(2)) 687 c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") 688 c.Assert(data[0].Available, Equals, true) // The status should be true now. 689 690 // Should not take effect. 691 dbt.mustInterDirc("alter causet test set tiflash replica 2 location labels 'a','b';") 692 checkFunc := func() { 693 resp, err = ts.fetchStatus("/tiflash/replica") 694 c.Assert(err, IsNil) 695 causetDecoder = json.NewCausetDecoder(resp.Body) 696 err = causetDecoder.Decode(&data) 697 c.Assert(err, IsNil) 698 resp.Body.Close() 699 c.Assert(len(data), Equals, 1) 700 c.Assert(data[0].ReplicaCount, Equals, uint64(2)) 701 c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") 702 c.Assert(data[0].Available, Equals, true) // The status should be true now. 703 } 704 705 // Test for get dropped causet tiflash replica info. 706 dbt.mustInterDirc("drop causet test") 707 checkFunc() 708 709 // Test unique causet id replica info. 710 dbt.mustInterDirc("flashback causet test") 711 checkFunc() 712 dbt.mustInterDirc("drop causet test") 713 checkFunc() 714 dbt.mustInterDirc("flashback causet test") 715 checkFunc() 716 717 // Test for partition causet. 718 dbt.mustInterDirc("alter causet pt set tiflash replica 2 location labels 'a','b';") 719 dbt.mustInterDirc("alter causet test set tiflash replica 0;") 720 resp, err = ts.fetchStatus("/tiflash/replica") 721 c.Assert(err, IsNil) 722 causetDecoder = json.NewCausetDecoder(resp.Body) 723 err = causetDecoder.Decode(&data) 724 c.Assert(err, IsNil) 725 resp.Body.Close() 726 c.Assert(len(data), Equals, 3) 727 c.Assert(data[0].ReplicaCount, Equals, uint64(2)) 728 c.Assert(strings.Join(data[0].LocationLabels, ","), Equals, "a,b") 729 c.Assert(data[0].Available, Equals, false) 730 731 pid0 := data[0].ID 732 pid1 := data[1].ID 733 pid2 := data[2].ID 734 735 // Mock for partition 1 replica was available. 736 req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid1) 737 resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) 738 c.Assert(err, IsNil) 739 resp.Body.Close() 740 resp, err = ts.fetchStatus("/tiflash/replica") 741 c.Assert(err, IsNil) 742 causetDecoder = json.NewCausetDecoder(resp.Body) 743 err = causetDecoder.Decode(&data) 744 c.Assert(err, IsNil) 745 resp.Body.Close() 746 c.Assert(len(data), Equals, 3) 747 c.Assert(data[0].Available, Equals, false) 748 c.Assert(data[1].Available, Equals, true) 749 c.Assert(data[2].Available, Equals, false) 750 751 // Mock for partition 0,2 replica was available. 752 req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid0) 753 resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) 754 c.Assert(err, IsNil) 755 resp.Body.Close() 756 req = fmt.Sprintf(`{"id":%d,"region_count":3,"flash_region_count":3}`, pid2) 757 resp, err = ts.postStatus("/tiflash/replica", "application/json", bytes.NewBuffer([]byte(req))) 758 c.Assert(err, IsNil) 759 resp.Body.Close() 760 checkFunc = func() { 761 resp, err = ts.fetchStatus("/tiflash/replica") 762 c.Assert(err, IsNil) 763 causetDecoder = json.NewCausetDecoder(resp.Body) 764 err = causetDecoder.Decode(&data) 765 c.Assert(err, IsNil) 766 resp.Body.Close() 767 c.Assert(len(data), Equals, 3) 768 c.Assert(data[0].Available, Equals, true) 769 c.Assert(data[1].Available, Equals, true) 770 c.Assert(data[2].Available, Equals, true) 771 } 772 773 // Test for get truncated causet tiflash replica info. 774 dbt.mustInterDirc("truncate causet pt") 775 dbt.mustInterDirc("alter causet pt set tiflash replica 0;") 776 checkFunc() 777 } 778 779 func (ts *HTTPHandlerTestSuite) TestDecodeDeferredCausetValue(c *C) { 780 ts.startServer(c) 781 ts.prepareData(c) 782 defer ts.stopServer(c) 783 784 // defCausumn is a structure used for test 785 type defCausumn struct { 786 id int64 787 tp *types.FieldType 788 } 789 // Backfill defCausumns. 790 c1 := &defCausumn{id: 1, tp: types.NewFieldType(allegrosql.TypeLonglong)} 791 c2 := &defCausumn{id: 2, tp: types.NewFieldType(allegrosql.TypeVarchar)} 792 c3 := &defCausumn{id: 3, tp: types.NewFieldType(allegrosql.TypeNewDecimal)} 793 c4 := &defCausumn{id: 4, tp: types.NewFieldType(allegrosql.TypeTimestamp)} 794 defcaus := []*defCausumn{c1, c2, c3, c4} 795 event := make([]types.Causet, len(defcaus)) 796 event[0] = types.NewIntCauset(100) 797 event[1] = types.NewBytesCauset([]byte("abc")) 798 event[2] = types.NewDecimalCauset(types.NewDecFromInt(1)) 799 event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Now()), allegrosql.TypeTimestamp, 6)) 800 801 // Encode the event. 802 defCausIDs := make([]int64, 0, 3) 803 for _, defCaus := range defcaus { 804 defCausIDs = append(defCausIDs, defCaus.id) 805 } 806 rd := rowcodec.CausetEncoder{Enable: true} 807 sc := &stmtctx.StatementContext{TimeZone: time.UTC} 808 bs, err := blockcodec.EncodeRow(sc, event, defCausIDs, nil, nil, &rd) 809 c.Assert(err, IsNil) 810 c.Assert(bs, NotNil) 811 bin := base64.StdEncoding.EncodeToString(bs) 812 813 unitTest := func(defCaus *defCausumn) { 814 path := fmt.Sprintf("/blocks/%d/%v/%d/%d?rowBin=%s", defCaus.id, defCaus.tp.Tp, defCaus.tp.Flag, defCaus.tp.Flen, bin) 815 resp, err := ts.fetchStatus(path) 816 c.Assert(err, IsNil, Commentf("url:%s", ts.statusURL(path))) 817 causetDecoder := json.NewCausetDecoder(resp.Body) 818 var data interface{} 819 err = causetDecoder.Decode(&data) 820 c.Assert(err, IsNil, Commentf("url:%v\ndata%v", ts.statusURL(path), data)) 821 defCausVal, err := types.CausetsToString([]types.Causet{event[defCaus.id-1]}, false) 822 c.Assert(err, IsNil) 823 c.Assert(data, Equals, defCausVal, Commentf("url:%v", ts.statusURL(path))) 824 } 825 826 for _, defCaus := range defcaus { 827 unitTest(defCaus) 828 } 829 830 // Test bin has `+`. 831 // 2020-03-08 16:01:00.315313 832 bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJsZ+TgISg1M8Z" 833 event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Date(2020, 3, 8, 16, 1, 0, 315313000, time.UTC)), allegrosql.TypeTimestamp, 6)) 834 unitTest(defcaus[3]) 835 836 // Test bin has `/`. 837 // 2020-03-08 02:44:46.409199 838 bin = "CAIIyAEIBAIGYWJjCAYGAQCBCAgJ7/yY8LKF1M8Z" 839 event[3] = types.NewTimeCauset(types.NewTime(types.FromGoTime(time.Date(2020, 3, 8, 2, 44, 46, 409199000, time.UTC)), allegrosql.TypeTimestamp, 6)) 840 unitTest(defcaus[3]) 841 } 842 843 func (ts *HTTPHandlerTestSuite) TestGetIndexMVCC(c *C) { 844 ts.startServer(c) 845 ts.prepareData(c) 846 defer ts.stopServer(c) 847 848 // tests for normal index key 849 resp, err := ts.fetchStatus("/mvcc/index/milevadb/test/idx1/1?a=1&b=2") 850 c.Assert(err, IsNil) 851 decodeKeyMvcc(resp.Body, c, true) 852 853 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/1?a=1&b=2") 854 c.Assert(err, IsNil) 855 decodeKeyMvcc(resp.Body, c, true) 856 857 // tests for index key which includes null 858 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/3?a=3&b") 859 c.Assert(err, IsNil) 860 decodeKeyMvcc(resp.Body, c, true) 861 862 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/3?a=3&b") 863 c.Assert(err, IsNil) 864 decodeKeyMvcc(resp.Body, c, true) 865 866 // tests for index key which includes empty string 867 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/4?a=4&b=") 868 c.Assert(err, IsNil) 869 decodeKeyMvcc(resp.Body, c, true) 870 871 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/3?a=4&b=") 872 c.Assert(err, IsNil) 873 decodeKeyMvcc(resp.Body, c, true) 874 875 // tests for wrong key 876 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/5?a=5&b=1") 877 c.Assert(err, IsNil) 878 decodeKeyMvcc(resp.Body, c, false) 879 880 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/5?a=5&b=1") 881 c.Assert(err, IsNil) 882 decodeKeyMvcc(resp.Body, c, false) 883 884 // tests for missing defCausumn value 885 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx1/1?a=1") 886 c.Assert(err, IsNil) 887 causetDecoder := json.NewCausetDecoder(resp.Body) 888 var data1 mvccKV 889 err = causetDecoder.Decode(&data1) 890 c.Assert(err, NotNil) 891 892 resp, err = ts.fetchStatus("/mvcc/index/milevadb/test/idx2/1?a=1") 893 c.Assert(err, IsNil) 894 causetDecoder = json.NewCausetDecoder(resp.Body) 895 var data2 mvccKV 896 err = causetDecoder.Decode(&data2) 897 c.Assert(err, NotNil) 898 899 resp, err = ts.fetchStatus("/mvcc/index/milevadb/pt(p2)/idx/666?a=666&b=def") 900 c.Assert(err, IsNil) 901 defer resp.Body.Close() 902 decodeKeyMvcc(resp.Body, c, true) 903 } 904 905 func (ts *HTTPHandlerTestSuite) TestGetSettings(c *C) { 906 ts.startServer(c) 907 ts.prepareData(c) 908 defer ts.stopServer(c) 909 resp, err := ts.fetchStatus("/settings") 910 c.Assert(err, IsNil) 911 causetDecoder := json.NewCausetDecoder(resp.Body) 912 var settings *config.Config 913 err = causetDecoder.Decode(&settings) 914 c.Assert(err, IsNil) 915 c.Assert(settings, DeepEquals, config.GetGlobalConfig()) 916 } 917 918 func (ts *HTTPHandlerTestSuite) TestGetSchema(c *C) { 919 ts.startServer(c) 920 ts.prepareData(c) 921 defer ts.stopServer(c) 922 resp, err := ts.fetchStatus("/schemaReplicant") 923 c.Assert(err, IsNil) 924 causetDecoder := json.NewCausetDecoder(resp.Body) 925 var dbs []*perceptron.DBInfo 926 err = causetDecoder.Decode(&dbs) 927 c.Assert(err, IsNil) 928 expects := []string{"information_schema", "metrics_schema", "allegrosql", "performance_schema", "test", "milevadb"} 929 names := make([]string, len(dbs)) 930 for i, v := range dbs { 931 names[i] = v.Name.L 932 } 933 sort.Strings(names) 934 c.Assert(names, DeepEquals, expects) 935 936 resp, err = ts.fetchStatus("/schemaReplicant?block_id=5") 937 c.Assert(err, IsNil) 938 var t *perceptron.BlockInfo 939 causetDecoder = json.NewCausetDecoder(resp.Body) 940 err = causetDecoder.Decode(&t) 941 c.Assert(err, IsNil) 942 c.Assert(t.Name.L, Equals, "user") 943 944 _, err = ts.fetchStatus("/schemaReplicant?block_id=a") 945 c.Assert(err, IsNil) 946 947 _, err = ts.fetchStatus("/schemaReplicant?block_id=1") 948 c.Assert(err, IsNil) 949 950 _, err = ts.fetchStatus("/schemaReplicant?block_id=-1") 951 c.Assert(err, IsNil) 952 953 resp, err = ts.fetchStatus("/schemaReplicant/milevadb") 954 c.Assert(err, IsNil) 955 var lt []*perceptron.BlockInfo 956 causetDecoder = json.NewCausetDecoder(resp.Body) 957 err = causetDecoder.Decode(<) 958 c.Assert(err, IsNil) 959 c.Assert(len(lt), Greater, 0) 960 961 _, err = ts.fetchStatus("/schemaReplicant/abc") 962 c.Assert(err, IsNil) 963 964 resp, err = ts.fetchStatus("/schemaReplicant/milevadb/test") 965 c.Assert(err, IsNil) 966 causetDecoder = json.NewCausetDecoder(resp.Body) 967 err = causetDecoder.Decode(&t) 968 c.Assert(err, IsNil) 969 c.Assert(t.Name.L, Equals, "test") 970 971 _, err = ts.fetchStatus("/schemaReplicant/milevadb/abc") 972 c.Assert(err, IsNil) 973 974 resp, err = ts.fetchStatus("/EDB-causet/5") 975 c.Assert(err, IsNil) 976 var dbtbl *dbBlockInfo 977 causetDecoder = json.NewCausetDecoder(resp.Body) 978 err = causetDecoder.Decode(&dbtbl) 979 c.Assert(err, IsNil) 980 c.Assert(dbtbl.BlockInfo.Name.L, Equals, "user") 981 c.Assert(dbtbl.DBInfo.Name.L, Equals, "allegrosql") 982 se, err := stochastik.CreateStochastik(ts.causetstore.(ekv.CausetStorage)) 983 c.Assert(err, IsNil) 984 c.Assert(dbtbl.SchemaVersion, Equals, petri.GetPetri(se.(stochastikctx.Context)).SchemaReplicant().SchemaMetaVersion()) 985 986 EDB, err := allegrosql.Open("allegrosql", ts.getDSN()) 987 c.Assert(err, IsNil, Commentf("Error connecting")) 988 defer EDB.Close() 989 dbt := &DBTest{c, EDB} 990 991 dbt.mustInterDirc("create database if not exists test;") 992 dbt.mustInterDirc("use test;") 993 dbt.mustInterDirc(` create causet t1 (id int KEY) 994 partition by range (id) ( 995 PARTITION p0 VALUES LESS THAN (3), 996 PARTITION p1 VALUES LESS THAN (5), 997 PARTITION p2 VALUES LESS THAN (7), 998 PARTITION p3 VALUES LESS THAN (9))`) 999 1000 resp, err = ts.fetchStatus("/schemaReplicant/test/t1") 1001 c.Assert(err, IsNil) 1002 causetDecoder = json.NewCausetDecoder(resp.Body) 1003 err = causetDecoder.Decode(&t) 1004 c.Assert(err, IsNil) 1005 c.Assert(t.Name.L, Equals, "t1") 1006 1007 resp, err = ts.fetchStatus(fmt.Sprintf("/EDB-causet/%v", t.GetPartitionInfo().Definitions[0].ID)) 1008 c.Assert(err, IsNil) 1009 causetDecoder = json.NewCausetDecoder(resp.Body) 1010 err = causetDecoder.Decode(&dbtbl) 1011 c.Assert(err, IsNil) 1012 c.Assert(dbtbl.BlockInfo.Name.L, Equals, "t1") 1013 c.Assert(dbtbl.DBInfo.Name.L, Equals, "test") 1014 c.Assert(dbtbl.BlockInfo, DeepEquals, t) 1015 } 1016 1017 func (ts *HTTPHandlerTestSuite) TestAllHistory(c *C) { 1018 ts.startServer(c) 1019 ts.prepareData(c) 1020 defer ts.stopServer(c) 1021 _, err := ts.fetchStatus("/dbs/history/?limit=3") 1022 c.Assert(err, IsNil) 1023 _, err = ts.fetchStatus("/dbs/history/?limit=-1") 1024 c.Assert(err, IsNil) 1025 1026 resp, err := ts.fetchStatus("/dbs/history") 1027 c.Assert(err, IsNil) 1028 causetDecoder := json.NewCausetDecoder(resp.Body) 1029 1030 var jobs []*perceptron.Job 1031 s, _ := stochastik.CreateStochastik(ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage)) 1032 defer s.Close() 1033 causetstore := petri.GetPetri(s.(stochastikctx.Context)).CausetStore() 1034 txn, _ := causetstore.Begin() 1035 txnMeta := spacetime.NewMeta(txn) 1036 txnMeta.GetAllHistoryDBSJobs() 1037 data, _ := txnMeta.GetAllHistoryDBSJobs() 1038 err = causetDecoder.Decode(&jobs) 1039 1040 c.Assert(err, IsNil) 1041 c.Assert(jobs, DeepEquals, data) 1042 } 1043 1044 func (ts *HTTPHandlerTestSuite) TestPostSettings(c *C) { 1045 ts.startServer(c) 1046 ts.prepareData(c) 1047 defer ts.stopServer(c) 1048 form := make(url.Values) 1049 form.Set("log_level", "error") 1050 form.Set("milevadb_general_log", "1") 1051 resp, err := ts.formStatus("/settings", form) 1052 c.Assert(err, IsNil) 1053 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1054 c.Assert(log.GetLevel(), Equals, log.ErrorLevel) 1055 c.Assert(zaplog.GetLevel(), Equals, zap.ErrorLevel) 1056 c.Assert(config.GetGlobalConfig().Log.Level, Equals, "error") 1057 c.Assert(atomic.LoadUint32(&variable.ProcessGeneralLog), Equals, uint32(1)) 1058 form = make(url.Values) 1059 form.Set("log_level", "fatal") 1060 form.Set("milevadb_general_log", "0") 1061 resp, err = ts.formStatus("/settings", form) 1062 c.Assert(err, IsNil) 1063 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1064 c.Assert(atomic.LoadUint32(&variable.ProcessGeneralLog), Equals, uint32(0)) 1065 c.Assert(log.GetLevel(), Equals, log.FatalLevel) 1066 c.Assert(zaplog.GetLevel(), Equals, zap.FatalLevel) 1067 c.Assert(config.GetGlobalConfig().Log.Level, Equals, "fatal") 1068 form.Set("log_level", os.Getenv("log_level")) 1069 1070 // test dbs_slow_threshold 1071 form = make(url.Values) 1072 form.Set("dbs_slow_threshold", "200") 1073 resp, err = ts.formStatus("/settings", form) 1074 c.Assert(err, IsNil) 1075 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1076 c.Assert(atomic.LoadUint32(&variable.DBSSlowOprThreshold), Equals, uint32(200)) 1077 1078 // test check_mb4_value_in_utf8 1079 EDB, err := allegrosql.Open("allegrosql", ts.getDSN()) 1080 c.Assert(err, IsNil, Commentf("Error connecting")) 1081 defer EDB.Close() 1082 dbt := &DBTest{c, EDB} 1083 1084 dbt.mustInterDirc("create database milevadb_test;") 1085 dbt.mustInterDirc("use milevadb_test;") 1086 dbt.mustInterDirc("drop causet if exists t2;") 1087 dbt.mustInterDirc("create causet t2(a varchar(100) charset utf8);") 1088 form.Set("check_mb4_value_in_utf8", "1") 1089 resp, err = ts.formStatus("/settings", form) 1090 c.Assert(err, IsNil) 1091 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1092 c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, true) 1093 txn1, err := dbt.EDB.Begin() 1094 c.Assert(err, IsNil) 1095 _, err = txn1.InterDirc("insert t2 values (unhex('F0A48BAE'));") 1096 c.Assert(err, NotNil) 1097 txn1.Commit() 1098 1099 // Disable CheckMb4ValueInUTF8. 1100 form = make(url.Values) 1101 form.Set("check_mb4_value_in_utf8", "0") 1102 resp, err = ts.formStatus("/settings", form) 1103 c.Assert(err, IsNil) 1104 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1105 c.Assert(config.GetGlobalConfig().CheckMb4ValueInUTF8, Equals, false) 1106 dbt.mustInterDirc("insert t2 values (unhex('f09f8c80'));") 1107 } 1108 1109 func (ts *HTTPHandlerTestSuite) TestPprof(c *C) { 1110 ts.startServer(c) 1111 defer ts.stopServer(c) 1112 retryTime := 100 1113 for retry := 0; retry < retryTime; retry++ { 1114 resp, err := ts.fetchStatus("/debug/pprof/heap") 1115 if err == nil { 1116 ioutil.ReadAll(resp.Body) 1117 resp.Body.Close() 1118 return 1119 } 1120 time.Sleep(time.Millisecond * 10) 1121 } 1122 zaplog.Fatal("failed to get profile for %d retries in every 10 ms", zap.Int("retryTime", retryTime)) 1123 } 1124 1125 func (ts *HTTPHandlerTestSuite) TestServerInfo(c *C) { 1126 ts.startServer(c) 1127 defer ts.stopServer(c) 1128 resp, err := ts.fetchStatus("/info") 1129 c.Assert(err, IsNil) 1130 defer resp.Body.Close() 1131 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1132 causetDecoder := json.NewCausetDecoder(resp.Body) 1133 1134 info := serverInfo{} 1135 err = causetDecoder.Decode(&info) 1136 c.Assert(err, IsNil) 1137 1138 cfg := config.GetGlobalConfig() 1139 c.Assert(info.IsTenant, IsTrue) 1140 c.Assert(info.IP, Equals, cfg.AdvertiseAddress) 1141 c.Assert(info.StatusPort, Equals, cfg.Status.StatusPort) 1142 c.Assert(info.Lease, Equals, cfg.Lease) 1143 c.Assert(info.Version, Equals, allegrosql.ServerVersion) 1144 c.Assert(info.GitHash, Equals, versioninfo.MilevaDBGitHash) 1145 1146 causetstore := ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage) 1147 do, err := stochastik.GetPetri(causetstore.(ekv.CausetStorage)) 1148 c.Assert(err, IsNil) 1149 dbs := do.DBS() 1150 c.Assert(info.ID, Equals, dbs.GetID()) 1151 } 1152 1153 func (ts *HTTPHandlerTestSerialSuite) TestAllServerInfo(c *C) { 1154 ts.startServer(c) 1155 defer ts.stopServer(c) 1156 resp, err := ts.fetchStatus("/info/all") 1157 c.Assert(err, IsNil) 1158 defer resp.Body.Close() 1159 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1160 causetDecoder := json.NewCausetDecoder(resp.Body) 1161 1162 clusterInfo := clusterServerInfo{} 1163 err = causetDecoder.Decode(&clusterInfo) 1164 c.Assert(err, IsNil) 1165 1166 c.Assert(clusterInfo.IsAllServerVersionConsistent, IsTrue) 1167 c.Assert(clusterInfo.ServersNum, Equals, 1) 1168 1169 causetstore := ts.server.newEinsteinDBHandlerTool().CausetStore.(ekv.CausetStorage) 1170 do, err := stochastik.GetPetri(causetstore.(ekv.CausetStorage)) 1171 c.Assert(err, IsNil) 1172 dbs := do.DBS() 1173 c.Assert(clusterInfo.TenantID, Equals, dbs.GetID()) 1174 serverInfo, ok := clusterInfo.AllServersInfo[dbs.GetID()] 1175 c.Assert(ok, Equals, true) 1176 1177 cfg := config.GetGlobalConfig() 1178 c.Assert(serverInfo.IP, Equals, cfg.AdvertiseAddress) 1179 c.Assert(serverInfo.StatusPort, Equals, cfg.Status.StatusPort) 1180 c.Assert(serverInfo.Lease, Equals, cfg.Lease) 1181 c.Assert(serverInfo.Version, Equals, allegrosql.ServerVersion) 1182 c.Assert(serverInfo.GitHash, Equals, versioninfo.MilevaDBGitHash) 1183 c.Assert(serverInfo.ID, Equals, dbs.GetID()) 1184 } 1185 1186 func (ts *HTTPHandlerTestSuite) TestHotRegionInfo(c *C) { 1187 ts.startServer(c) 1188 defer ts.stopServer(c) 1189 resp, err := ts.fetchStatus("/regions/hot") 1190 c.Assert(err, IsNil) 1191 defer resp.Body.Close() 1192 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1193 } 1194 1195 func (ts *HTTPHandlerTestSuite) TestDebugZip(c *C) { 1196 ts.startServer(c) 1197 defer ts.stopServer(c) 1198 resp, err := ts.fetchStatus("/debug/zip?seconds=1") 1199 c.Assert(err, IsNil) 1200 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1201 b, err := httputil.DumpResponse(resp, true) 1202 c.Assert(err, IsNil) 1203 c.Assert(len(b), Greater, 0) 1204 c.Assert(resp.Body.Close(), IsNil) 1205 } 1206 1207 func (ts *HTTPHandlerTestSuite) TestCheckCN(c *C) { 1208 s := &Server{cfg: &config.Config{Security: config.Security{ClusterVerifyCN: []string{"a ", "b", "c"}}}} 1209 tlsConfig := &tls.Config{} 1210 s.setCNChecker(tlsConfig) 1211 c.Assert(tlsConfig.VerifyPeerCertificate, NotNil) 1212 err := tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "a"}}}}) 1213 c.Assert(err, IsNil) 1214 err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "b"}}}}) 1215 c.Assert(err, IsNil) 1216 err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "d"}}}}) 1217 c.Assert(err, NotNil) 1218 } 1219 1220 func (ts *HTTPHandlerTestSuite) TestZipInfoForALLEGROSQL(c *C) { 1221 ts.startServer(c) 1222 defer ts.stopServer(c) 1223 1224 EDB, err := allegrosql.Open("allegrosql", ts.getDSN()) 1225 c.Assert(err, IsNil, Commentf("Error connecting")) 1226 defer EDB.Close() 1227 dbt := &DBTest{c, EDB} 1228 1229 dbt.mustInterDirc("use test") 1230 dbt.mustInterDirc("create causet if not exists t (a int)") 1231 1232 urlValues := url.Values{ 1233 "allegrosql": {"select * from t"}, 1234 "current_db": {"test"}, 1235 } 1236 resp, err := ts.formStatus("/debug/sub-optimal-plan", urlValues) 1237 c.Assert(err, IsNil) 1238 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1239 b, err := httputil.DumpResponse(resp, true) 1240 c.Assert(err, IsNil) 1241 c.Assert(len(b), Greater, 0) 1242 c.Assert(resp.Body.Close(), IsNil) 1243 1244 resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5&timeout=0", urlValues) 1245 c.Assert(err, IsNil) 1246 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1247 b, err = httputil.DumpResponse(resp, true) 1248 c.Assert(err, IsNil) 1249 c.Assert(len(b), Greater, 0) 1250 c.Assert(resp.Body.Close(), IsNil) 1251 1252 resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5", urlValues) 1253 c.Assert(err, IsNil) 1254 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1255 b, err = httputil.DumpResponse(resp, true) 1256 c.Assert(err, IsNil) 1257 c.Assert(len(b), Greater, 0) 1258 c.Assert(resp.Body.Close(), IsNil) 1259 1260 resp, err = ts.formStatus("/debug/sub-optimal-plan?timeout=1", urlValues) 1261 c.Assert(err, IsNil) 1262 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1263 b, err = httputil.DumpResponse(resp, true) 1264 c.Assert(err, IsNil) 1265 c.Assert(len(b), Greater, 0) 1266 c.Assert(resp.Body.Close(), IsNil) 1267 1268 urlValues.Set("current_db", "non_exists_db") 1269 resp, err = ts.formStatus("/debug/sub-optimal-plan", urlValues) 1270 c.Assert(err, IsNil) 1271 c.Assert(resp.StatusCode, Equals, http.StatusInternalServerError) 1272 b, err = ioutil.ReadAll(resp.Body) 1273 c.Assert(err, IsNil) 1274 c.Assert(string(b), Equals, "use database non_exists_db failed, err: [schemaReplicant:1049]Unknown database 'non_exists_db'\n") 1275 c.Assert(resp.Body.Close(), IsNil) 1276 } 1277 1278 func (ts *HTTPHandlerTestSuite) TestFailpointHandler(c *C) { 1279 defer ts.stopServer(c) 1280 1281 // start server without enabling failpoint integration 1282 ts.startServer(c) 1283 resp, err := ts.fetchStatus("/fail/") 1284 c.Assert(err, IsNil) 1285 c.Assert(resp.StatusCode, Equals, http.StatusNotFound) 1286 ts.stopServer(c) 1287 1288 // enable failpoint integration and start server 1289 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/enableTestAPI", "return"), IsNil) 1290 ts.startServer(c) 1291 resp, err = ts.fetchStatus("/fail/") 1292 c.Assert(err, IsNil) 1293 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1294 b, err := ioutil.ReadAll(resp.Body) 1295 c.Assert(err, IsNil) 1296 c.Assert(strings.Contains(string(b), "github.com/whtcorpsinc/milevadb/server/enableTestAPI=return"), IsTrue) 1297 c.Assert(resp.Body.Close(), IsNil) 1298 } 1299 1300 func (ts *HTTPHandlerTestSuite) TestTestHandler(c *C) { 1301 defer ts.stopServer(c) 1302 1303 // start server without enabling failpoint integration 1304 ts.startServer(c) 1305 resp, err := ts.fetchStatus("/test") 1306 c.Assert(err, IsNil) 1307 c.Assert(resp.StatusCode, Equals, http.StatusNotFound) 1308 ts.stopServer(c) 1309 1310 // enable failpoint integration and start server 1311 c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/server/enableTestAPI", "return"), IsNil) 1312 ts.startServer(c) 1313 1314 resp, err = ts.fetchStatus("/test/gc/gc") 1315 c.Assert(err, IsNil) 1316 resp.Body.Close() 1317 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1318 1319 resp, err = ts.fetchStatus("/test/gc/resolvelock") 1320 c.Assert(err, IsNil) 1321 resp.Body.Close() 1322 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1323 1324 resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=a") 1325 c.Assert(err, IsNil) 1326 resp.Body.Close() 1327 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1328 1329 resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=1") 1330 c.Assert(err, IsNil) 1331 resp.Body.Close() 1332 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1333 1334 resp, err = ts.fetchStatus("/test/gc/resolvelock?physical=true") 1335 c.Assert(err, IsNil) 1336 resp.Body.Close() 1337 c.Assert(resp.StatusCode, Equals, http.StatusBadRequest) 1338 1339 resp, err = ts.fetchStatus("/test/gc/resolvelock?safepoint=10000&physical=true") 1340 c.Assert(err, IsNil) 1341 resp.Body.Close() 1342 c.Assert(resp.StatusCode, Equals, http.StatusOK) 1343 }