瀏覽代碼

Add tests for multildap (#17358)

That should get us to 100% coverage
Oleg Gaidarenko 6 年之前
父節點
當前提交
2316414786
共有 3 個文件被更改,包括 395 次插入6 次删除
  1. 7 6
      pkg/services/multildap/multildap.go
  2. 327 0
      pkg/services/multildap/multildap_test.go
  3. 61 0
      pkg/services/multildap/test.go

+ 7 - 6
pkg/services/multildap/multildap.go

@@ -22,6 +22,9 @@ var ErrNoLDAPServers = errors.New("No LDAP servers are configured")
 // ErrDidNotFindUser if request for user is unsuccessful
 var ErrDidNotFindUser = errors.New("Did not find a user")
 
+// newLDAP return instance of the single LDAP server
+var newLDAP = ldap.New
+
 // IMultiLDAP is interface for MultiLDAP
 type IMultiLDAP interface {
 	Login(query *models.LoginUserQuery) (
@@ -53,12 +56,13 @@ func New(configs []*ldap.ServerConfig) IMultiLDAP {
 func (multiples *MultiLDAP) Login(query *models.LoginUserQuery) (
 	*models.ExternalUserInfo, error,
 ) {
+
 	if len(multiples.configs) == 0 {
 		return nil, ErrNoLDAPServers
 	}
 
 	for _, config := range multiples.configs {
-		server := ldap.New(config)
+		server := newLDAP(config)
 
 		if err := server.Dial(); err != nil {
 			return nil, err
@@ -67,7 +71,6 @@ func (multiples *MultiLDAP) Login(query *models.LoginUserQuery) (
 		defer server.Close()
 
 		user, err := server.Login(query)
-
 		if user != nil {
 			return user, nil
 		}
@@ -80,8 +83,6 @@ func (multiples *MultiLDAP) Login(query *models.LoginUserQuery) (
 		if err != nil {
 			return nil, err
 		}
-
-		return user, nil
 	}
 
 	// Return invalid credentials if we couldn't find the user anywhere
@@ -100,7 +101,7 @@ func (multiples *MultiLDAP) User(login string) (
 
 	search := []string{login}
 	for _, config := range multiples.configs {
-		server := ldap.New(config)
+		server := newLDAP(config)
 
 		if err := server.Dial(); err != nil {
 			return nil, err
@@ -133,7 +134,7 @@ func (multiples *MultiLDAP) Users(logins []string) (
 	}
 
 	for _, config := range multiples.configs {
-		server := ldap.New(config)
+		server := newLDAP(config)
 
 		if err := server.Dial(); err != nil {
 			return nil, err

+ 327 - 0
pkg/services/multildap/multildap_test.go

@@ -0,0 +1,327 @@
+package multildap
+
+import (
+	"errors"
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+
+	"github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/services/ldap"
+)
+
+func TestMultiLDAP(t *testing.T) {
+	Convey("Multildap", t, func() {
+		Convey("Login()", func() {
+			Convey("Should return error for absent config list", func() {
+				setup()
+
+				multi := New([]*ldap.ServerConfig{})
+				_, err := multi.Login(&models.LoginUserQuery{})
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, ErrNoLDAPServers)
+
+				teardown()
+			})
+
+			Convey("Should return a dial error", func() {
+				mock := setup()
+
+				expected := errors.New("Dial error")
+				mock.dialErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+
+				_, err := multi.Login(&models.LoginUserQuery{})
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+
+			Convey("Should call underlying LDAP methods", func() {
+				mock := setup()
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.Login(&models.LoginUserQuery{})
+
+				So(mock.dialCalledTimes, ShouldEqual, 2)
+				So(mock.loginCalledTimes, ShouldEqual, 2)
+				So(mock.closeCalledTimes, ShouldEqual, 2)
+
+				So(err, ShouldEqual, ErrInvalidCredentials)
+
+				teardown()
+			})
+
+			Convey("Should get login result", func() {
+				mock := setup()
+
+				mock.loginReturn = &models.ExternalUserInfo{
+					Login: "killa",
+				}
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				result, err := multi.Login(&models.LoginUserQuery{})
+
+				So(mock.dialCalledTimes, ShouldEqual, 1)
+				So(mock.loginCalledTimes, ShouldEqual, 1)
+				So(mock.closeCalledTimes, ShouldEqual, 1)
+
+				So(result.Login, ShouldEqual, "killa")
+				So(err, ShouldBeNil)
+
+				teardown()
+			})
+
+			Convey("Should still call a second error for invalid cred error", func() {
+				mock := setup()
+
+				mock.loginErrReturn = ErrInvalidCredentials
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.Login(&models.LoginUserQuery{})
+
+				So(mock.dialCalledTimes, ShouldEqual, 2)
+				So(mock.loginCalledTimes, ShouldEqual, 2)
+				So(mock.closeCalledTimes, ShouldEqual, 2)
+
+				So(err, ShouldEqual, ErrInvalidCredentials)
+
+				teardown()
+			})
+
+			Convey("Should return unknown error", func() {
+				mock := setup()
+
+				expected := errors.New("Something unknown")
+				mock.loginErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.Login(&models.LoginUserQuery{})
+
+				So(mock.dialCalledTimes, ShouldEqual, 1)
+				So(mock.loginCalledTimes, ShouldEqual, 1)
+				So(mock.closeCalledTimes, ShouldEqual, 1)
+
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+		})
+
+		Convey("User()", func() {
+			Convey("Should return error for absent config list", func() {
+				setup()
+
+				multi := New([]*ldap.ServerConfig{})
+				_, err := multi.User("test")
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, ErrNoLDAPServers)
+
+				teardown()
+			})
+
+			Convey("Should return a dial error", func() {
+				mock := setup()
+
+				expected := errors.New("Dial error")
+				mock.dialErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+
+				_, err := multi.User("test")
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+
+			Convey("Should call underlying LDAP methods", func() {
+				mock := setup()
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.User("test")
+
+				So(mock.dialCalledTimes, ShouldEqual, 2)
+				So(mock.usersCalledTimes, ShouldEqual, 2)
+				So(mock.closeCalledTimes, ShouldEqual, 2)
+
+				So(err, ShouldEqual, ErrDidNotFindUser)
+
+				teardown()
+			})
+
+			Convey("Should return some error", func() {
+				mock := setup()
+
+				expected := errors.New("Killa Gorilla")
+				mock.usersErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.User("test")
+
+				So(mock.dialCalledTimes, ShouldEqual, 1)
+				So(mock.usersCalledTimes, ShouldEqual, 1)
+				So(mock.closeCalledTimes, ShouldEqual, 1)
+
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+
+			Convey("Should get only one user", func() {
+				mock := setup()
+
+				mock.usersFirstReturn = []*models.ExternalUserInfo{
+					{
+						Login: "one",
+					},
+
+					{
+						Login: "two",
+					},
+				}
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				user, err := multi.User("test")
+
+				So(mock.dialCalledTimes, ShouldEqual, 1)
+				So(mock.usersCalledTimes, ShouldEqual, 1)
+				So(mock.closeCalledTimes, ShouldEqual, 1)
+
+				So(err, ShouldBeNil)
+				So(user.Login, ShouldEqual, "one")
+
+				teardown()
+			})
+		})
+
+		Convey("Users()", func() {
+			Convey("Should return error for absent config list", func() {
+				setup()
+
+				multi := New([]*ldap.ServerConfig{})
+				_, err := multi.Users([]string{"test"})
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, ErrNoLDAPServers)
+
+				teardown()
+			})
+
+			Convey("Should return a dial error", func() {
+				mock := setup()
+
+				expected := errors.New("Dial error")
+				mock.dialErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+
+				_, err := multi.Users([]string{"test"})
+
+				So(err, ShouldBeError)
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+
+			Convey("Should call underlying LDAP methods", func() {
+				mock := setup()
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.Users([]string{"test"})
+
+				So(mock.dialCalledTimes, ShouldEqual, 2)
+				So(mock.usersCalledTimes, ShouldEqual, 2)
+				So(mock.closeCalledTimes, ShouldEqual, 2)
+
+				So(err, ShouldBeNil)
+
+				teardown()
+			})
+
+			Convey("Should return some error", func() {
+				mock := setup()
+
+				expected := errors.New("Killa Gorilla")
+				mock.usersErrReturn = expected
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				_, err := multi.Users([]string{"test"})
+
+				So(mock.dialCalledTimes, ShouldEqual, 1)
+				So(mock.usersCalledTimes, ShouldEqual, 1)
+				So(mock.closeCalledTimes, ShouldEqual, 1)
+
+				So(err, ShouldEqual, expected)
+
+				teardown()
+			})
+
+			Convey("Should get users", func() {
+				mock := setup()
+
+				mock.usersFirstReturn = []*models.ExternalUserInfo{
+					{
+						Login: "one",
+					},
+
+					{
+						Login: "two",
+					},
+				}
+
+				mock.usersRestReturn = []*models.ExternalUserInfo{
+					{
+						Login: "three",
+					},
+				}
+
+				multi := New([]*ldap.ServerConfig{
+					{}, {},
+				})
+				users, err := multi.Users([]string{"test"})
+
+				So(mock.dialCalledTimes, ShouldEqual, 2)
+				So(mock.usersCalledTimes, ShouldEqual, 2)
+				So(mock.closeCalledTimes, ShouldEqual, 2)
+
+				So(err, ShouldBeNil)
+				So(users[0].Login, ShouldEqual, "one")
+				So(users[1].Login, ShouldEqual, "two")
+				So(users[2].Login, ShouldEqual, "three")
+
+				teardown()
+			})
+		})
+	})
+}

+ 61 - 0
pkg/services/multildap/test.go

@@ -0,0 +1,61 @@
+package multildap
+
+import (
+	"github.com/grafana/grafana/pkg/models"
+	"github.com/grafana/grafana/pkg/services/ldap"
+)
+
+type mockLDAP struct {
+	dialCalledTimes  int
+	loginCalledTimes int
+	closeCalledTimes int
+	usersCalledTimes int
+
+	dialErrReturn error
+
+	loginErrReturn error
+	loginReturn    *models.ExternalUserInfo
+
+	usersErrReturn   error
+	usersFirstReturn []*models.ExternalUserInfo
+	usersRestReturn  []*models.ExternalUserInfo
+}
+
+func (mock *mockLDAP) Login(*models.LoginUserQuery) (*models.ExternalUserInfo, error) {
+
+	mock.loginCalledTimes = mock.loginCalledTimes + 1
+	return mock.loginReturn, mock.loginErrReturn
+}
+func (mock *mockLDAP) Users([]string) ([]*models.ExternalUserInfo, error) {
+	mock.usersCalledTimes = mock.usersCalledTimes + 1
+
+	if mock.usersCalledTimes == 1 {
+		return mock.usersFirstReturn, mock.usersErrReturn
+	}
+
+	return mock.usersRestReturn, mock.usersErrReturn
+}
+func (mock *mockLDAP) InitialBind(string, string) error {
+	return nil
+}
+func (mock *mockLDAP) Dial() error {
+	mock.dialCalledTimes = mock.dialCalledTimes + 1
+	return mock.dialErrReturn
+}
+func (mock *mockLDAP) Close() {
+	mock.closeCalledTimes = mock.closeCalledTimes + 1
+}
+
+func setup() *mockLDAP {
+	mock := &mockLDAP{}
+
+	newLDAP = func(config *ldap.ServerConfig) ldap.IServer {
+		return mock
+	}
+
+	return mock
+}
+
+func teardown() {
+	newLDAP = ldap.New
+}