Преглед изворни кода

Merge pull request #7491 from grafana/sorting-datasources

Sorting datasources with case insensitive order
Daniel Lee пре 9 година
родитељ
комит
2b2368b189

+ 113 - 0
pkg/api/datasources_test.go

@@ -0,0 +1,113 @@
+package api
+
+import (
+	"encoding/json"
+	"net/http"
+	"net/http/httptest"
+	"path/filepath"
+	"testing"
+
+	"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 *models.GetDataSourcesQuery) error {
+				So(query.OrgId, ShouldEqual, TestOrgID)
+				query.Result = []*models.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 = models.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
+	handlerFunc    handlerFunc
+	defaultHandler macaron.Handler
+	req            *http.Request
+}
+
+func (sc *scenarioContext) exec() {
+	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) {

+ 11 - 2
public/app/core/services/datasource_srv.js

@@ -97,10 +97,19 @@ function (angular, _, coreModule, config) {
       }
 
       metricSources.sort(function(a, b) {
-        if (a.meta.builtIn || a.name > b.name) {
+        if (a.meta.builtIn) {
           return 1;
         }
-        if (a.name < b.name) {
+
+        if (b.meta.builtIn) {
+          return -1;
+        }
+
+        if (a.name.toLowerCase() > b.name.toLowerCase()) {
+          return 1;
+        }
+
+        if (a.name.toLowerCase() < b.name.toLowerCase()) {
           return -1;
         }
         return 0;

+ 58 - 0
public/test/specs/datasource_srv_specs.js

@@ -0,0 +1,58 @@
+define([
+  'app/core/config',
+  'app/core/services/datasource_srv'
+], function(config) {
+  'use strict';
+
+  describe('datasource_srv', function() {
+    var _datasourceSrv;
+    var metricSources;
+    var templateSrv = {};
+
+    beforeEach(module('grafana.core'));
+    beforeEach(module(function($provide) {
+      $provide.value('templateSrv', templateSrv);
+    }));
+    beforeEach(module('grafana.services'));
+    beforeEach(inject(function(datasourceSrv) {
+      _datasourceSrv = datasourceSrv;
+    }));
+
+    describe('when loading metric sources', function() {
+      var unsortedDatasources = {
+        'mmm': {
+          type: 'test-db',
+          meta: { metrics: {m: 1} }
+        },
+        '--Mixed--': {
+          type: 'test-db',
+          meta: {builtIn: true, metrics: {m: 1} }
+        },
+        'ZZZ': {
+          type: 'test-db',
+          meta: {metrics: {m: 1} }
+        },
+        'aaa': {
+          type: 'test-db',
+          meta: { metrics: {m: 1} }
+        },
+        'BBB': {
+          type: 'test-db',
+          meta: { metrics: {m: 1} }
+        },
+      };
+      beforeEach(function() {
+        config.datasources = unsortedDatasources;
+        metricSources = _datasourceSrv.getMetricSources({skipVariables: true});
+      });
+
+      it('should return a list of sources sorted case insensitively with builtin sources last', function() {
+        expect(metricSources[0].name).to.be('aaa');
+        expect(metricSources[1].name).to.be('BBB');
+        expect(metricSources[2].name).to.be('mmm');
+        expect(metricSources[3].name).to.be('ZZZ');
+        expect(metricSources[4].name).to.be('--Mixed--');
+      });
+    });
+  });
+});