Merge pull request #600 from yaoshengzhe/fix_add_queryz_unit_test

add queryz unit test
This commit is contained in:
Shengzhe 2015-04-20 13:52:35 -07:00
Родитель ca436c6b40 489fd1a840
Коммит 297bbda2fc
5 изменённых файлов: 192 добавлений и 78 удалений

Просмотреть файл

@ -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() { func (rqsc *realQueryServiceControl) registerStreamQueryzHandlers() {
http.HandleFunc("/streamqueryz", func(w http.ResponseWriter, r *http.Request) { http.HandleFunc("/streamqueryz", func(w http.ResponseWriter, r *http.Request) {
streamQueryzHandler(rqsc.sqlQueryRPCService.qe.streamQList, w, r) 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]) return sorter.less(sorter.rows[i], sorter.rows[j])
} }
func (rqsc *realQueryServiceControl) registerQueryzHandler() { func queryzHandler(si *SchemaInfo, w http.ResponseWriter, r *http.Request) {
http.HandleFunc("/queryz", func(w http.ResponseWriter, r *http.Request) { if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil {
if err := acl.CheckAccessHTTP(r, acl.DEBUGGING); err != nil { acl.SendError(w, err)
acl.SendError(w, err) return
return }
} startHTMLTable(w)
startHTMLTable(w) defer endHTMLTable(w)
defer endHTMLTable(w) w.Write(queryzHeader)
w.Write(queryzHeader)
si := rqsc.sqlQueryRPCService.qe.schemaInfo keys := si.queries.Keys()
keys := si.queries.Keys() sorter := queryzSorter{
sorter := queryzSorter{ rows: make([]*queryzRow, 0, len(keys)),
rows: make([]*queryzRow, 0, len(keys)), less: func(row1, row2 *queryzRow) bool {
less: func(row1, row2 *queryzRow) bool { return row1.timePQ() > row2.timePQ()
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() { Value := &queryzRow{
plan := si.getQuery(v) Query: wrappable(v),
if plan == nil { Table: plan.TableName,
continue Plan: plan.PlanId,
} Reason: plan.Reason,
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)
} }
sort.Sort(&sorter) Value.Count, Value.tm, Value.Rows, Value.Errors = plan.Stats()
for _, Value := range sorter.rows { timepq := time.Duration(int64(Value.tm) / Value.Count)
if err := queryzTmpl.Execute(w, Value); err != nil { if timepq < 10*time.Millisecond {
log.Errorf("queryz: couldn't execute template: %v", err) 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() { for query, result := range getSchemaInfoBaseTestQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -54,7 +54,7 @@ func TestSchemaInfoOpenFailedDueToMissMySQLTime(t *testing.T) {
[]sqltypes.Value{sqltypes.MakeString([]byte("1427325875"))}, []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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -78,7 +78,7 @@ func TestSchemaInfoOpenFailedDueToIncorrectMysqlRowNum(t *testing.T) {
nil, nil,
}, },
}) })
schemaInfo := newTestSchemaInfo(10, []string{}, 1*time.Second, 1*time.Second) schemaInfo := newTestSchemaInfo(10, 1*time.Second, 1*time.Second)
appParams := sqldb.ConnParams{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -102,7 +102,7 @@ func TestSchemaInfoOpenFailedDueToInvalidTimeFormat(t *testing.T) {
[]sqltypes.Value{sqltypes.MakeString([]byte("invalid_time"))}, []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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -126,7 +126,7 @@ func TestSchemaInfoOpenFailedDueToExecErr(t *testing.T) {
// this will cause connection failed to execute baseShowTables query // this will cause connection failed to execute baseShowTables query
RowsAffected: math.MaxUint64, 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -156,7 +156,7 @@ func TestSchemaInfoOpenFailedDueToTableInfoErr(t *testing.T) {
// this will cause NewTableInfo error // this will cause NewTableInfo error
RowsAffected: math.MaxUint64, 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -176,7 +176,7 @@ func TestSchemaInfoOpenWithSchemaOverride(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -206,7 +206,7 @@ func TestSchemaInfoReload(t *testing.T) {
db.AddQuery(query, result) db.AddQuery(query, result)
} }
idleTimeout := 10 * time.Second idleTimeout := 10 * time.Second
schemaInfo := newTestSchemaInfo(10, []string{}, 10*time.Second, idleTimeout) schemaInfo := newTestSchemaInfo(10, 10*time.Second, idleTimeout)
appParams := sqldb.ConnParams{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -289,7 +289,7 @@ func TestSchemaInfoCreateOrUpdateTableFailedDuetoExecErr(t *testing.T) {
RowsAffected: math.MaxUint64, RowsAffected: math.MaxUint64,
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")}, 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -317,7 +317,7 @@ func TestSchemaInfoCreateOrUpdateTable(t *testing.T) {
RowsAffected: 1, RowsAffected: 1,
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")}, 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -340,7 +340,7 @@ func TestSchemaInfoDropTable(t *testing.T) {
RowsAffected: 1, RowsAffected: 1,
Rows: [][]sqltypes.Value{createTestTableDescribe("pk")}, 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -365,7 +365,7 @@ func TestSchemaInfoGetPlanPanicDuetoEmptyQuery(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -392,7 +392,7 @@ func TestSchemaInfoQueryCacheFailDueToInvalidCacheSize(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -416,7 +416,7 @@ func TestSchemaInfoQueryCache(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -452,7 +452,7 @@ func TestSchemaInfoExportVars(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -471,7 +471,7 @@ func TestSchemaInfoStatsURL(t *testing.T) {
for query, result := range getSchemaInfoTestSupportedQueries() { for query, result := range getSchemaInfoTestSupportedQueries() {
db.AddQuery(query, result) 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{} appParams := sqldb.ConnParams{}
dbaParams := sqldb.ConnParams{} dbaParams := sqldb.ConnParams{}
cachePool := newTestSchemaInfoCachePool() cachePool := newTestSchemaInfoCachePool()
@ -506,25 +506,6 @@ func TestSchemaInfoStatsURL(t *testing.T) {
schemaInfo.ServeHTTP(response, request) 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 { func newTestSchemaInfoCachePool() *CachePool {
rowCacheConfig := RowCacheConfig{ rowCacheConfig := RowCacheConfig{
Binary: "ls", Binary: "ls",

Просмотреть файл

@ -5,9 +5,12 @@
package tabletserver package tabletserver
import ( import (
"fmt"
"html/template" "html/template"
"math/rand"
"reflect" "reflect"
"testing" "testing"
"time"
) )
type fakeCallInfo struct { 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) 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)
}