Commit 111d9661 authored by Quentin Smith's avatar Quentin Smith

storage, analysis: report better errors

Show a meaningful error to the user if their query is invalid or
matches zero results.

Change-Id: I8894686b598e008bac418f85e5d6ab229b64ec09
Reviewed-on: https://go-review.googlesource.com/35504Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 5a7725d4
...@@ -79,11 +79,7 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) { ...@@ -79,11 +79,7 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) {
return return
} }
data, err := a.compareQuery(q) data := a.compareQuery(q)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8") w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := t.Execute(w, data); err != nil { if err := t.Execute(w, data); err != nil {
...@@ -94,32 +90,47 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) { ...@@ -94,32 +90,47 @@ func (a *App) compare(w http.ResponseWriter, r *http.Request) {
type compareData struct { type compareData struct {
Q string Q string
Error string
Benchstat template.HTML Benchstat template.HTML
Groups []*resultGroup Groups []*resultGroup
Labels map[string]bool Labels map[string]bool
} }
func (a *App) compareQuery(q string) (*compareData, error) { func (a *App) compareQuery(q string) *compareData {
// Parse query // Parse query
queries := parseQueryString(q) queries := parseQueryString(q)
// Send requests // Send requests
// TODO(quentin): Issue requests in parallel? // TODO(quentin): Issue requests in parallel?
var groups []*resultGroup var groups []*resultGroup
for _, q := range queries { var found int
for _, qPart := range queries {
group := &resultGroup{} group := &resultGroup{}
res := a.StorageClient.Query(q) res := a.StorageClient.Query(qPart)
defer res.Close() // TODO: Should happen each time through the loop defer res.Close() // TODO: Should happen each time through the loop
for res.Next() { for res.Next() {
group.add(res.Result()) group.add(res.Result())
found++
} }
if err := res.Err(); err != nil { err := res.Err()
res.Close()
if err != nil {
// TODO: If the query is invalid, surface that to the user. // TODO: If the query is invalid, surface that to the user.
return nil, err return &compareData{
Q: q,
Error: err.Error(),
}
} }
groups = append(groups, group) groups = append(groups, group)
} }
if found == 0 {
return &compareData{
Q: q,
Error: "No results matched the query string.",
}, nil
}
// Attempt to automatically split results. // Attempt to automatically split results.
if len(groups) == 1 { if len(groups) == 1 {
group := groups[0] group := groups[0]
...@@ -152,5 +163,5 @@ func (a *App) compareQuery(q string) (*compareData, error) { ...@@ -152,5 +163,5 @@ func (a *App) compareQuery(q string) (*compareData, error) {
Groups: groups, Groups: groups,
Labels: labels, Labels: labels,
} }
return data, nil return data
} }
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
<input type="submit" value="Search"> <input type="submit" value="Search">
</form> </form>
</div> </div>
{{with .Error}}
<p>{{.}}</p>
{{else}}
<div> <div>
{{.Benchstat}} {{.Benchstat}}
</div> </div>
...@@ -39,5 +42,6 @@ ...@@ -39,5 +42,6 @@
</tr> </tr>
{{end}} {{end}}
</table> </table>
{{end}}
</body> </body>
</html> </html>
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
package storage package storage
import ( import (
"fmt"
"io" "io"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
...@@ -45,6 +47,15 @@ func (c *Client) Query(q string) *Query { ...@@ -45,6 +47,15 @@ func (c *Client) Query(q string) *Query {
return &Query{err: err} return &Query{err: err}
} }
if resp.StatusCode != 200 {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return &Query{err: err}
}
return &Query{err: fmt.Errorf("%s", body)}
}
br := benchfmt.NewReader(resp.Body) br := benchfmt.NewReader(resp.Body)
return &Query{br: br, body: resp.Body} return &Query{br: br, body: resp.Body}
...@@ -93,7 +104,10 @@ func (q *Query) Err() error { ...@@ -93,7 +104,10 @@ func (q *Query) Err() error {
// Close frees resources associated with the query. // Close frees resources associated with the query.
func (q *Query) Close() error { func (q *Query) Close() error {
if q.body != nil {
q.body.Close() q.body.Close()
q.body = nil
}
return q.err return q.err
} }
......
...@@ -17,6 +17,25 @@ import ( ...@@ -17,6 +17,25 @@ import (
"golang.org/x/perf/storage/benchfmt" "golang.org/x/perf/storage/benchfmt"
) )
func TestQueryError(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "invalid query", 500)
}))
defer ts.Close()
c := &Client{BaseURL: ts.URL}
q := c.Query("invalid query")
defer q.Close()
if q.Next() {
t.Error("Next = true, want false")
}
if q.Err() == nil {
t.Error("Err = nil, want error")
}
}
func TestQuery(t *testing.T) { func TestQuery(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if have, want := r.URL.RequestURI(), "/search?q=key1%3Avalue+key2%3Avalue"; have != want { if have, want := r.URL.RequestURI(), "/search?q=key1%3Avalue+key2%3Avalue"; have != want {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment