浏览代码

fix(api): case insensitive sort for datasources

The data source list is case sensitive when sorted. This changes the
sort to be case insensitive. The test only tests the handler, not the
routing or database query.
Daniel Lee 9 年之前
父节点
当前提交
cbd1455c42
共有 2 个文件被更改,包括 125 次插入1 次删除
  1. 124 0
      pkg/api/datasources_test.go
  2. 1 1
      pkg/api/dtos/models.go

+ 124 - 0
pkg/api/datasources_test.go

@@ -0,0 +1,124 @@
+package api
+
+import (
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"path/filepath"
+	"testing"
+
+	m "github.com/grafana/grafana/pkg/models"
+	macaron "gopkg.in/macaron.v1"
+
+	"github.com/go-macaron/session"
+	"github.com/grafana/grafana/pkg/bus"
+	"github.com/grafana/grafana/pkg/middleware"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+const (
+	TestOrgID  = 1
+	TestUserID = 1
+)
+
+func TestDataSourcesProxy(t *testing.T) {
+	Convey("Given a user is logged in", t, func() {
+		loggedInUserScenario("When calling GET on", "/api/datasources/", func(sc *scenarioContext) {
+
+			// Stubs the database query
+			bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error {
+				So(query.OrgId, ShouldEqual, TestOrgID)
+				query.Result = []*m.DataSource{
+					{Name: "mmm"},
+					{Name: "ZZZ"},
+					{Name: "BBB"},
+					{Name: "aaa"},
+				}
+				return nil
+			})
+
+			// handler func being tested
+			sc.handlerFunc = GetDataSources
+			sc.fakeReq("GET", "/api/datasources").exec()
+
+			respJSON := []map[string]interface{}{}
+			err := json.NewDecoder(sc.resp.Body).Decode(&respJSON)
+			So(err, ShouldBeNil)
+
+			Convey("should return list of datasources for org sorted alphabetically and case insensitively", func() {
+				So(respJSON[0]["name"], ShouldEqual, "aaa")
+				So(respJSON[1]["name"], ShouldEqual, "BBB")
+				So(respJSON[2]["name"], ShouldEqual, "mmm")
+				So(respJSON[3]["name"], ShouldEqual, "ZZZ")
+			})
+		})
+	})
+}
+
+func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
+	Convey(desc+" "+url, func() {
+		defer bus.ClearBusHandlers()
+
+		sc := &scenarioContext{}
+		viewsPath, _ := filepath.Abs("../../public/views")
+
+		sc.m = macaron.New()
+		sc.m.Use(macaron.Renderer(macaron.RenderOptions{
+			Directory: viewsPath,
+			Delims:    macaron.Delims{Left: "[[", Right: "]]"},
+		}))
+
+		sc.m.Use(middleware.GetContextHandler())
+		sc.m.Use(middleware.Sessioner(&session.Options{}))
+
+		sc.defaultHandler = func(c *middleware.Context) {
+			sc.context = c
+			sc.context.UserId = TestUserID
+			sc.context.OrgId = TestOrgID
+			sc.context.OrgRole = m.ROLE_EDITOR
+			if sc.handlerFunc != nil {
+				sc.handlerFunc(sc.context)
+			}
+		}
+		sc.m.SetAutoHead(true)
+		sc.m.Get(url, sc.defaultHandler)
+
+		fn(sc)
+	})
+}
+
+func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
+	sc.resp = httptest.NewRecorder()
+	req, err := http.NewRequest(method, url, nil)
+	So(err, ShouldBeNil)
+	sc.req = req
+
+	return sc
+}
+
+type scenarioContext struct {
+	m              *macaron.Macaron
+	context        *middleware.Context
+	resp           *httptest.ResponseRecorder
+	apiKey         string
+	authHeader     string
+	handlerFunc    handlerFunc
+	defaultHandler macaron.Handler
+
+	req *http.Request
+}
+
+func (sc *scenarioContext) exec() {
+	if sc.apiKey != "" {
+		sc.req.Header.Add("Authorization", "Bearer "+sc.apiKey)
+	}
+
+	if sc.authHeader != "" {
+		sc.req.Header.Add("Authorization", sc.authHeader)
+	}
+
+	sc.m.ServeHTTP(sc.resp, sc.req)
+}
+
+type scenarioFunc func(c *scenarioContext)
+type handlerFunc func(c *middleware.Context)

+ 1 - 1
pkg/api/dtos/models.go

@@ -91,7 +91,7 @@ func (slice DataSourceList) Len() int {
 }
 
 func (slice DataSourceList) Less(i, j int) bool {
-	return slice[i].Name < slice[j].Name
+	return strings.ToLower(slice[i].Name) < strings.ToLower(slice[j].Name)
 }
 
 func (slice DataSourceList) Swap(i, j int) {