зеркало из https://github.com/github/vitess-gh.git
Merge pull request #600 from yaoshengzhe/fix_add_queryz_unit_test
add queryz unit test
This commit is contained in:
Коммит
297bbda2fc
|
@ -382,6 +382,12 @@ func (rqsc *realQueryServiceControl) registerDebugHealthHandler() {
|
|||
})
|
||||
}
|
||||
|
||||
func (rqsc *realQueryServiceControl) registerQueryzHandler() {
|
||||
http.HandleFunc("/queryz", func(w http.ResponseWriter, r *http.Request) {
|
||||
queryzHandler(rqsc.sqlQueryRPCService.qe.schemaInfo, w, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (rqsc *realQueryServiceControl) registerStreamQueryzHandlers() {
|
||||
http.HandleFunc("/streamqueryz", func(w http.ResponseWriter, r *http.Request) {
|
||||
streamQueryzHandler(rqsc.sqlQueryRPCService.qe.streamQList, w, r)
|
||||
|
|
|
@ -109,51 +109,48 @@ func (sorter *queryzSorter) Less(i, j int) bool {
|
|||
return sorter.less(sorter.rows[i], sorter.rows[j])
|
||||
}
|
||||
|
||||
func (rqsc *realQueryServiceControl) registerQueryzHandler() {
|
||||
http.HandleFunc("/queryz", func(w http.ResponseWriter, r *http.Request) {
|
||||
if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil {
|
||||
acl.SendError(w, err)
|
||||
return
|
||||
}
|
||||
startHTMLTable(w)
|
||||
defer endHTMLTable(w)
|
||||
w.Write(queryzHeader)
|
||||
func queryzHandler(si *SchemaInfo, w http.ResponseWriter, r *http.Request) {
|
||||
if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil {
|
||||
acl.SendError(w, err)
|
||||
return
|
||||
}
|
||||
startHTMLTable(w)
|
||||
defer endHTMLTable(w)
|
||||
w.Write(queryzHeader)
|
||||
|
||||
si := rqsc.sqlQueryRPCService.qe.schemaInfo
|
||||
keys := si.queries.Keys()
|
||||
sorter := queryzSorter{
|
||||
rows: make([]*queryzRow, 0, len(keys)),
|
||||
less: func(row1, row2 *queryzRow) bool {
|
||||
return row1.timePQ() > row2.timePQ()
|
||||
},
|
||||
keys := si.queries.Keys()
|
||||
sorter := queryzSorter{
|
||||
rows: make([]*queryzRow, 0, len(keys)),
|
||||
less: func(row1, row2 *queryzRow) bool {
|
||||
return row1.timePQ() > row2.timePQ()
|
||||
},
|
||||
}
|
||||
for _, v := range si.queries.Keys() {
|
||||
plan := si.getQuery(v)
|
||||
if plan == nil {
|
||||
continue
|
||||
}
|
||||
for _, v := range si.queries.Keys() {
|
||||
plan := si.getQuery(v)
|
||||
if plan == nil {
|
||||
continue
|
||||
}
|
||||
Value := &queryzRow{
|
||||
Query: wrappable(v),
|
||||
Table: plan.TableName,
|
||||
Plan: plan.PlanId,
|
||||
Reason: plan.Reason,
|
||||
}
|
||||
Value.Count, Value.tm, Value.Rows, Value.Errors = plan.Stats()
|
||||
timepq := time.Duration(int64(Value.tm) / Value.Count)
|
||||
if timepq < 10*time.Millisecond {
|
||||
Value.Color = "low"
|
||||
} else if timepq < 100*time.Millisecond {
|
||||
Value.Color = "medium"
|
||||
} else {
|
||||
Value.Color = "high"
|
||||
}
|
||||
sorter.rows = append(sorter.rows, Value)
|
||||
Value := &queryzRow{
|
||||
Query: wrappable(v),
|
||||
Table: plan.TableName,
|
||||
Plan: plan.PlanId,
|
||||
Reason: plan.Reason,
|
||||
}
|
||||
sort.Sort(&sorter)
|
||||
for _, Value := range sorter.rows {
|
||||
if err := queryzTmpl.Execute(w, Value); err != nil {
|
||||
log.Errorf("queryz: couldn't execute template: %v", err)
|
||||
}
|
||||
Value.Count, Value.tm, Value.Rows, Value.Errors = plan.Stats()
|
||||
timepq := time.Duration(int64(Value.tm) / Value.Count)
|
||||
if timepq < 10*time.Millisecond {
|
||||
Value.Color = "low"
|
||||
} else if timepq < 100*time.Millisecond {
|
||||
Value.Color = "medium"
|
||||
} else {
|
||||
Value.Color = "high"
|
||||
}
|
||||
})
|
||||
sorter.rows = append(sorter.rows, Value)
|
||||
}
|
||||
sort.Sort(&sorter)
|
||||
for _, Value := range sorter.rows {
|
||||
if err := queryzTmpl.Execute(w, Value); err != nil {
|
||||
log.Errorf("queryz: couldn't execute template: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2015, Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package tabletserver
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/tabletserver/planbuilder"
|
||||
)
|
||||
|
||||
func TestQueryzHandler(t *testing.T) {
|
||||
resp := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/schemaz", nil)
|
||||
schemaInfo := newTestSchemaInfo(100, 10*time.Second, 10*time.Second)
|
||||
|
||||
plan1 := &ExecPlan{
|
||||
ExecPlan: &planbuilder.ExecPlan{
|
||||
TableName: "test_table",
|
||||
PlanId: planbuilder.PLAN_PASS_SELECT,
|
||||
Reason: planbuilder.REASON_SELECT,
|
||||
},
|
||||
}
|
||||
plan1.AddStats(10, 1*time.Second, 2, 0)
|
||||
schemaInfo.queries.Set("select name from test_table", plan1)
|
||||
|
||||
plan2 := &ExecPlan{
|
||||
ExecPlan: &planbuilder.ExecPlan{
|
||||
TableName: "test_table",
|
||||
PlanId: planbuilder.PLAN_DDL,
|
||||
Reason: planbuilder.REASON_DEFAULT,
|
||||
},
|
||||
}
|
||||
plan2.AddStats(1, 1*time.Millisecond, 1, 0)
|
||||
schemaInfo.queries.Set("insert into test_table values 1", plan2)
|
||||
|
||||
plan3 := &ExecPlan{
|
||||
ExecPlan: &planbuilder.ExecPlan{
|
||||
TableName: "",
|
||||
PlanId: planbuilder.PLAN_OTHER,
|
||||
Reason: planbuilder.REASON_DEFAULT,
|
||||
},
|
||||
}
|
||||
plan3.AddStats(1, 50*time.Millisecond, 1, 0)
|
||||
schemaInfo.queries.Set("show tables", plan3)
|
||||
schemaInfo.queries.Set("", (*ExecPlan)(nil))
|
||||
|
||||
queryzHandler(schemaInfo, resp, req)
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
planPattern1 := []string{
|
||||
`<tr class="high">`,
|
||||
`<td>select name from test_table</td>`,
|
||||
`<td>test_table</td>`,
|
||||
`<td>PASS_SELECT</td>`,
|
||||
`<td>SELECT</td>`,
|
||||
`<td>10</td>`,
|
||||
`<td>1.000000</td>`,
|
||||
`<td>2</td>`,
|
||||
`<td>0</td>`,
|
||||
`<td>0.100000</td>`,
|
||||
`<td>0.200000</td>`,
|
||||
`<td>0.000000</td>`,
|
||||
}
|
||||
checkQueryzHasPlan(t, planPattern1, plan1, body)
|
||||
planPattern2 := []string{
|
||||
`<tr class="low">`,
|
||||
`<td>insert into test_table values 1</td>`,
|
||||
`<td>test_table</td>`,
|
||||
`<td>DDL</td>`,
|
||||
`<td>DEFAULT</td>`,
|
||||
`<td>1</td>`,
|
||||
`<td>0.001000</td>`,
|
||||
`<td>1</td>`,
|
||||
`<td>0</td>`,
|
||||
`<td>0.001000</td>`,
|
||||
`<td>1.000000</td>`,
|
||||
`<td>0.000000</td>`,
|
||||
}
|
||||
checkQueryzHasPlan(t, planPattern2, plan2, body)
|
||||
planPattern3 := []string{
|
||||
`<tr class="medium">`,
|
||||
`<td>show tables</td>`,
|
||||
`<td></td>`,
|
||||
`<td>OTHER</td>`,
|
||||
`<td>DEFAULT</td>`,
|
||||
`<td>1</td>`,
|
||||
`<td>0.050000</td>`,
|
||||
`<td>1</td>`,
|
||||
`<td>0</td>`,
|
||||
`<td>0.050000</td>`,
|
||||
`<td>1.000000</td>`,
|
||||
`<td>0.000000</td>`,
|
||||
}
|
||||
checkQueryzHasPlan(t, planPattern3, plan3, body)
|
||||
}
|
||||
|
||||
func checkQueryzHasPlan(t *testing.T, planPattern []string, plan *ExecPlan, page []byte) {
|
||||
matcher := regexp.MustCompile(strings.Join(planPattern, `\s*`))
|
||||
if !matcher.Match(page) {
|
||||
t.Fatalf("schemaz page does not contain plan: %v, page: %s", plan, string(page))
|
||||
}
|
||||
}
|
|
@ -29,7 +29,7 @@ func TestSchemaInfoStrictMode(t *testing.T) {
|
|||
for query, result := range getSchemaInfoBaseTestQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -54,7 +54,7 @@ func TestSchemaInfoOpenFailedDueToMissMySQLTime(t *testing.T) {
|
|||
[]sqltypes.Value{sqltypes.MakeString([]byte("1427325875"))},
|
||||
},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -78,7 +78,7 @@ func TestSchemaInfoOpenFailedDueToIncorrectMysqlRowNum(t *testing.T) {
|
|||
nil,
|
||||
},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -102,7 +102,7 @@ func TestSchemaInfoOpenFailedDueToInvalidTimeFormat(t *testing.T) {
|
|||
[]sqltypes.Value{sqltypes.MakeString([]byte("invalid_time"))},
|
||||
},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -126,7 +126,7 @@ func TestSchemaInfoOpenFailedDueToExecErr(t *testing.T) {
|
|||
// this will cause connection failed to execute baseShowTables query
|
||||
RowsAffected: math.MaxUint64,
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -156,7 +156,7 @@ func TestSchemaInfoOpenFailedDueToTableInfoErr(t *testing.T) {
|
|||
// this will cause NewTableInfo error
|
||||
RowsAffected: math.MaxUint64,
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -176,7 +176,7 @@ func TestSchemaInfoOpenWithSchemaOverride(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, 10*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 10*time.Second, 10*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -206,7 +206,7 @@ func TestSchemaInfoReload(t *testing.T) {
|
|||
db.AddQuery(query, result)
|
||||
}
|
||||
idleTimeout := 10 * time.Second
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, idleTimeout)
|
||||
schemaInfo := newTestSchemaInfo(10, 10*time.Second, idleTimeout)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -289,7 +289,7 @@ func TestSchemaInfoCreateOrUpdateTableFailedDuetoExecErr(t *testing.T) {
|
|||
RowsAffected: math.MaxUint64,
|
||||
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -317,7 +317,7 @@ func TestSchemaInfoCreateOrUpdateTable(t *testing.T) {
|
|||
RowsAffected: 1,
|
||||
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -340,7 +340,7 @@ func TestSchemaInfoDropTable(t *testing.T) {
|
|||
RowsAffected: 1,
|
||||
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")},
|
||||
})
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -365,7 +365,7 @@ func TestSchemaInfoGetPlanPanicDuetoEmptyQuery(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, 10*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 10*time.Second, 10*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -392,7 +392,7 @@ func TestSchemaInfoQueryCacheFailDueToInvalidCacheSize(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, 10*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 10*time.Second, 10*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -416,7 +416,7 @@ func TestSchemaInfoQueryCache(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, 10*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 10*time.Second, 10*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -452,7 +452,7 @@ func TestSchemaInfoExportVars(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -471,7 +471,7 @@ func TestSchemaInfoStatsURL(t *testing.T) {
|
|||
for query, result := range getSchemaInfoTestSupportedQueries() {
|
||||
db.AddQuery(query, result)
|
||||
}
|
||||
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second)
|
||||
schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
|
||||
appParams := sqldb.ConnParams{}
|
||||
dbaParams := sqldb.ConnParams{}
|
||||
cachePool := newTestSchemaInfoCachePool()
|
||||
|
@ -506,25 +506,6 @@ func TestSchemaInfoStatsURL(t *testing.T) {
|
|||
schemaInfo.ServeHTTP(response, request)
|
||||
}
|
||||
|
||||
func newTestSchemaInfo(
|
||||
queryCacheSize int,
|
||||
httpEndpoints []string,
|
||||
reloadTime time.Duration,
|
||||
idleTimeout time.Duration) *SchemaInfo {
|
||||
randID := rand.Int63()
|
||||
return NewSchemaInfo(
|
||||
queryCacheSize,
|
||||
fmt.Sprintf("TestSchemaInfo-%d-", randID),
|
||||
map[string]string{
|
||||
debugQueryPlansKey: fmt.Sprintf("/debug/query_plans_%d", randID),
|
||||
debugQueryStatsKey: fmt.Sprintf("/debug/query_stats_%d", randID),
|
||||
debugTableStatsKey: fmt.Sprintf("/debug/table_stats_%d", randID),
|
||||
debugSchemaKey: fmt.Sprintf("/debug/schema_%d", randID),
|
||||
},
|
||||
reloadTime,
|
||||
idleTimeout)
|
||||
}
|
||||
|
||||
func newTestSchemaInfoCachePool() *CachePool {
|
||||
rowCacheConfig := RowCacheConfig{
|
||||
Binary: "ls",
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
package tabletserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type fakeCallInfo struct {
|
||||
|
@ -40,3 +43,21 @@ func (util *testUtils) checkEqual(t *testing.T, expected interface{}, result int
|
|||
t.Fatalf("expect to get: %v, but got: %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func newTestSchemaInfo(
|
||||
queryCacheSize int,
|
||||
reloadTime time.Duration,
|
||||
idleTimeout time.Duration) *SchemaInfo {
|
||||
randID := rand.Int63()
|
||||
return NewSchemaInfo(
|
||||
queryCacheSize,
|
||||
fmt.Sprintf("TestSchemaInfo-%d-", randID),
|
||||
map[string]string{
|
||||
debugQueryPlansKey: fmt.Sprintf("/debug/query_plans_%d", randID),
|
||||
debugQueryStatsKey: fmt.Sprintf("/debug/query_stats_%d", randID),
|
||||
debugTableStatsKey: fmt.Sprintf("/debug/table_stats_%d", randID),
|
||||
debugSchemaKey: fmt.Sprintf("/debug/schema_%d", randID),
|
||||
},
|
||||
reloadTime,
|
||||
idleTimeout)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче