mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 20:24:18 -06:00
a2cba3d0b5
* Inject tracer in tests * Annotate with traces Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
920 lines
28 KiB
Go
920 lines
28 KiB
Go
package orgimpl
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
"github.com/grafana/grafana/pkg/services/auth/identity"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
|
"github.com/grafana/grafana/pkg/services/searchusers/sortopts"
|
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
|
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
|
|
"github.com/grafana/grafana/pkg/services/user"
|
|
"github.com/grafana/grafana/pkg/services/user/userimpl"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/tests/testsuite"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
testsuite.Run(m)
|
|
}
|
|
|
|
func TestIntegrationOrgDataAccess(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ss := db.InitTestDB(t)
|
|
orgStore := sqlStore{
|
|
db: ss,
|
|
dialect: ss.GetDialect(),
|
|
}
|
|
|
|
t.Run("org not found", func(t *testing.T) {
|
|
_, err := orgStore.Get(context.Background(), 1)
|
|
require.Error(t, err, org.ErrOrgNotFound)
|
|
})
|
|
|
|
t.Run("org inserted", func(t *testing.T) {
|
|
_, err := orgStore.Insert(context.Background(), &org.Org{
|
|
Version: 1,
|
|
Name: "test1",
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("insert with org name taken", func(t *testing.T) {
|
|
_, err := orgStore.Insert(context.Background(), &org.Org{
|
|
Version: 1,
|
|
Name: "test1",
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
require.Error(t, err, org.ErrOrgNameTaken)
|
|
})
|
|
|
|
t.Run("org inserted with next available org ID", func(t *testing.T) {
|
|
orgID, err := orgStore.Insert(context.Background(), &org.Org{
|
|
ID: 55,
|
|
Version: 1,
|
|
Name: "test2",
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
require.NoError(t, err)
|
|
_, err = orgStore.Get(context.Background(), orgID)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("update with org name taken", func(t *testing.T) {
|
|
err := orgStore.Update(context.Background(), &org.UpdateOrgCommand{
|
|
OrgId: 55,
|
|
Name: "test1",
|
|
})
|
|
require.Error(t, err, org.ErrOrgNameTaken)
|
|
})
|
|
|
|
t.Run("delete by user", func(t *testing.T) {
|
|
err := orgStore.DeleteUserFromAll(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("Update org address", func(t *testing.T) {
|
|
// make sure ac2 has no org
|
|
ac2 := &org.Org{ID: 21, Name: "name", Version: 1, Created: time.Now(), Updated: time.Now()}
|
|
_, err := orgStore.Insert(context.Background(), ac2)
|
|
require.NoError(t, err)
|
|
err = orgStore.UpdateAddress(context.Background(), &org.UpdateOrgAddressCommand{
|
|
OrgID: ac2.ID,
|
|
Address: org.Address{
|
|
Address1: "address1",
|
|
Address2: "address2",
|
|
City: "city",
|
|
ZipCode: "zip",
|
|
State: "state",
|
|
Country: "country"},
|
|
})
|
|
require.NoError(t, err)
|
|
orga, err := orgStore.Get(context.Background(), ac2.ID)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "address1", orga.Address1)
|
|
})
|
|
|
|
t.Run("Removing org", func(t *testing.T) {
|
|
// make sure ac2 has no org
|
|
ac2 := &org.Org{ID: 22, Name: "ac2", Version: 1, Created: time.Now(), Updated: time.Now()}
|
|
_, err := orgStore.Insert(context.Background(), ac2)
|
|
require.NoError(t, err)
|
|
err = orgStore.Delete(context.Background(), &org.DeleteOrgCommand{ID: ac2.ID})
|
|
require.NoError(t, err)
|
|
|
|
// TODO: this part of the test will be added when we move RemoveOrgUser to org store
|
|
// "Removing user from org should delete user completely if in no other org"
|
|
// // remove ac2 user from ac1 org
|
|
// remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac2.ID, ShouldDeleteOrphanedUser: true}
|
|
// err = orgStore.RemoveOrgUser(context.Background(), &remCmd)
|
|
// require.NoError(t, err)
|
|
// require.True(t, remCmd.UserWasDeleted)
|
|
|
|
// err = orgStore.GetSignedInUser(context.Background(), &models.GetSignedInUserQuery{UserId: ac2.ID})
|
|
// require.Equal(t, err, user.ErrUserNotFound)
|
|
})
|
|
|
|
t.Run("Given we have organizations, we can query them by IDs", func(t *testing.T) {
|
|
var err error
|
|
var cmd *org.CreateOrgCommand
|
|
ids := []int64{}
|
|
|
|
for i := 1; i < 4; i++ {
|
|
cmd = &org.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
|
|
result, err := orgStore.CreateWithMember(context.Background(), cmd)
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, result.ID)
|
|
}
|
|
|
|
query := &org.SearchOrgsQuery{IDs: ids}
|
|
result, err := orgStore.Search(context.Background(), query)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 3, len(result))
|
|
})
|
|
|
|
t.Run("Given we have organizations, we can limit and paginate search", func(t *testing.T) {
|
|
ss = db.InitTestDB(t)
|
|
for i := 1; i < 4; i++ {
|
|
cmd := &org.CreateOrgCommand{Name: fmt.Sprint("Orga #", i)}
|
|
_, err := orgStore.CreateWithMember(context.Background(), cmd)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
t.Run("Should be able to search with defaults", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{}
|
|
result, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 3, len(result))
|
|
})
|
|
|
|
t.Run("Should be able to limit search", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{Limit: 1}
|
|
result, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, len(result))
|
|
})
|
|
|
|
t.Run("Should be able to limit and paginate search", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{Limit: 2, Page: 1}
|
|
result, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 1, len(result))
|
|
})
|
|
|
|
t.Run("Get org by ID", func(t *testing.T) {
|
|
query := &org.GetOrgByIDQuery{ID: 1}
|
|
result, err := orgStore.GetByID(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "Orga #1", result.Name)
|
|
})
|
|
|
|
t.Run("Get org by handler name", func(t *testing.T) {
|
|
query := &org.GetOrgByNameQuery{Name: "Orga #1"}
|
|
result, err := orgStore.GetByName(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
assert.Equal(t, int64(1), result.ID)
|
|
})
|
|
})
|
|
|
|
t.Run("Testing Account DB Access", func(t *testing.T) {
|
|
ss := db.InitTestDB(t)
|
|
orgStore = sqlStore{
|
|
db: ss,
|
|
dialect: ss.GetDialect(),
|
|
}
|
|
ids := []int64{}
|
|
|
|
for i := 1; i < 4; i++ {
|
|
cmd := &org.CreateOrgCommand{Name: fmt.Sprint("Org #", i)}
|
|
res, err := orgStore.CreateWithMember(context.Background(), cmd)
|
|
require.NoError(t, err)
|
|
ids = append(ids, res.ID)
|
|
}
|
|
|
|
t.Run("Given we have organizations, we can query them by IDs", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{IDs: ids}
|
|
queryResult, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(queryResult), 3)
|
|
})
|
|
|
|
t.Run("Should be able to search with defaults", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{}
|
|
queryResult, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(queryResult), 3)
|
|
})
|
|
|
|
t.Run("Should be able to limit search", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{Limit: 1}
|
|
queryResult, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(queryResult), 1)
|
|
})
|
|
|
|
t.Run("Should be able to limit and paginate search", func(t *testing.T) {
|
|
query := &org.SearchOrgsQuery{Limit: 2, Page: 1}
|
|
queryResult, err := orgStore.Search(context.Background(), query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(queryResult), 1)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestIntegrationOrgUserDataAccess(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
ss := db.InitTestDB(t)
|
|
orgUserStore := sqlStore{
|
|
db: ss,
|
|
dialect: ss.GetDialect(),
|
|
}
|
|
|
|
t.Run("org user inserted", func(t *testing.T) {
|
|
_, err := orgUserStore.InsertOrgUser(context.Background(), &org.OrgUser{
|
|
ID: 1,
|
|
OrgID: 1,
|
|
UserID: 1,
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("delete by user", func(t *testing.T) {
|
|
err := orgUserStore.DeleteUserFromAll(context.Background(), 1)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
// TODO: these test will be added when store will be CRUD
|
|
// t.Run("Given single org mode", func(t *testing.T) {
|
|
// sqlStore.Cfg.AutoAssignOrg = true
|
|
// sqlStore.Cfg.AutoAssignOrgId = 1
|
|
// sqlStore.Cfg.AutoAssignOrgRole = "Viewer"
|
|
|
|
// t.Run("Users should be added to default organization", func(t *testing.T) {
|
|
// ac1cmd := user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
|
|
// ac2cmd := user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name"}
|
|
|
|
// ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
|
|
// require.NoError(t, err)
|
|
// ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd)
|
|
// require.NoError(t, err)
|
|
|
|
// q1 := models.GetUserOrgListQuery{UserId: ac1.ID}
|
|
// q2 := models.GetUserOrgListQuery{UserId: ac2.ID}
|
|
// err = sqlStore.GetUserOrgList(context.Background(), &q1)
|
|
// require.NoError(t, err)
|
|
// err = sqlStore.GetUserOrgList(context.Background(), &q2)
|
|
// require.NoError(t, err)
|
|
|
|
// require.Equal(t, q1.Result[0].OrgId, q2.Result[0].OrgId)
|
|
// require.Equal(t, string(q1.Result[0].Role), "Viewer")
|
|
// })
|
|
// })
|
|
|
|
// t.Run("Can get user organizations", func(t *testing.T) {
|
|
// query := models.GetUserOrgListQuery{UserId: ac2.ID}
|
|
// err := sqlStore.GetUserOrgList(context.Background(), &query)
|
|
|
|
// require.NoError(t, err)
|
|
// require.Equal(t, len(query.Result), 2)
|
|
// })
|
|
|
|
t.Run("Update org users", func(t *testing.T) {
|
|
_, err := orgUserStore.InsertOrgUser(context.Background(), &org.OrgUser{
|
|
ID: 1,
|
|
OrgID: 1,
|
|
UserID: 1,
|
|
Created: time.Now(),
|
|
Updated: time.Now(),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
cmd := &org.UpdateOrgUserCommand{
|
|
Role: org.RoleAdmin,
|
|
UserID: 1,
|
|
OrgID: 1,
|
|
}
|
|
err = orgUserStore.UpdateOrgUser(context.Background(), cmd)
|
|
require.NoError(t, err)
|
|
})
|
|
t.Run("GetOrgUsers and UpdateOrgUsers", func(t *testing.T) {
|
|
ss, cfg := db.InitTestDBWithCfg(t)
|
|
_, usrSvc := createOrgAndUserSvc(t, ss, cfg)
|
|
ac1cmd := &user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name"}
|
|
ac2cmd := &user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", IsAdmin: true}
|
|
ac1, err := usrSvc.Create(context.Background(), ac1cmd)
|
|
require.NoError(t, err)
|
|
ac2, err := usrSvc.Create(context.Background(), ac2cmd)
|
|
require.NoError(t, err)
|
|
cmd := org.AddOrgUserCommand{
|
|
OrgID: ac1.OrgID,
|
|
UserID: ac2.ID,
|
|
Role: org.RoleViewer,
|
|
}
|
|
|
|
err = orgUserStore.AddOrgUser(context.Background(), &cmd)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Can update org user role", func(t *testing.T) {
|
|
updateCmd := org.UpdateOrgUserCommand{OrgID: ac1.OrgID, UserID: ac2.ID, Role: org.RoleAdmin}
|
|
err = orgUserStore.UpdateOrgUser(context.Background(), &updateCmd)
|
|
require.NoError(t, err)
|
|
|
|
orgUsersQuery := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &orgUsersQuery)
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, result.OrgUsers[1].Role, org.RoleAdmin)
|
|
})
|
|
t.Run("Can get organization users", func(t *testing.T) {
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(result.OrgUsers), 2)
|
|
require.Equal(t, result.OrgUsers[0].Role, "Admin")
|
|
})
|
|
|
|
t.Run("Can get organization users with query", func(t *testing.T) {
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
Query: "ac1",
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(result.OrgUsers), 1)
|
|
require.Equal(t, result.OrgUsers[0].Email, ac1.Email)
|
|
})
|
|
t.Run("Can get organization users with query and limit", func(t *testing.T) {
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
Query: "ac",
|
|
Limit: 1,
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(result.OrgUsers), 1)
|
|
require.Equal(t, result.OrgUsers[0].Email, ac1.Email)
|
|
})
|
|
t.Run("Can get organization users with custom ordering login-asc", func(t *testing.T) {
|
|
sortOpts, err := sortopts.ParseSortQueryParam("login-asc,email-asc")
|
|
require.NoError(t, err)
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
SortOpts: sortOpts,
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(result.OrgUsers), 2)
|
|
require.Equal(t, result.OrgUsers[0].Email, ac1.Email)
|
|
require.Equal(t, result.OrgUsers[1].Email, ac2.Email)
|
|
})
|
|
t.Run("Can get organization users with custom ordering login-desc", func(t *testing.T) {
|
|
sortOpts, err := sortopts.ParseSortQueryParam("login-desc,email-asc")
|
|
require.NoError(t, err)
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
SortOpts: sortOpts,
|
|
User: &user.SignedInUser{
|
|
OrgID: ac1.OrgID,
|
|
Permissions: map[int64]map[string][]string{ac1.OrgID: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, len(result.OrgUsers), 2)
|
|
require.Equal(t, result.OrgUsers[0].Email, ac2.Email)
|
|
require.Equal(t, result.OrgUsers[1].Email, ac1.Email)
|
|
})
|
|
t.Run("Cannot update role so no one is admin user", func(t *testing.T) {
|
|
remCmd := org.RemoveOrgUserCommand{OrgID: ac1.OrgID, UserID: ac2.ID, ShouldDeleteOrphanedUser: true}
|
|
err := orgUserStore.RemoveOrgUser(context.Background(), &remCmd)
|
|
require.NoError(t, err)
|
|
cmd := org.UpdateOrgUserCommand{OrgID: ac1.OrgID, UserID: ac1.ID, Role: org.RoleViewer}
|
|
err = orgUserStore.UpdateOrgUser(context.Background(), &cmd)
|
|
require.Equal(t, org.ErrLastOrgAdmin, err)
|
|
})
|
|
|
|
t.Run("Removing user from org should delete user completely if in no other org", func(t *testing.T) {
|
|
// make sure ac2 has no org
|
|
err := orgUserStore.Delete(context.Background(), &org.DeleteOrgCommand{ID: ac2.OrgID})
|
|
require.NoError(t, err)
|
|
|
|
// remove ac2 user from ac1 org
|
|
remCmd := org.RemoveOrgUserCommand{OrgID: ac1.OrgID, UserID: ac2.ID, ShouldDeleteOrphanedUser: true}
|
|
err = orgUserStore.RemoveOrgUser(context.Background(), &remCmd)
|
|
require.NoError(t, err)
|
|
require.True(t, remCmd.UserWasDeleted)
|
|
})
|
|
|
|
t.Run("Cannot delete last admin org user", func(t *testing.T) {
|
|
cmd := org.RemoveOrgUserCommand{OrgID: ac1.OrgID, UserID: ac1.ID}
|
|
err := orgUserStore.RemoveOrgUser(context.Background(), &cmd)
|
|
require.Equal(t, err, org.ErrLastOrgAdmin)
|
|
})
|
|
})
|
|
|
|
t.Run("Given single org and 2 users inserted", func(t *testing.T) {
|
|
ss, cfg := db.InitTestDBWithCfg(t)
|
|
cfg.AutoAssignOrg = true
|
|
cfg.AutoAssignOrgId = 1
|
|
cfg.AutoAssignOrgRole = "Viewer"
|
|
|
|
orgSvc, usrSvc := createOrgAndUserSvc(t, ss, cfg)
|
|
|
|
testUser := &user.SignedInUser{
|
|
Permissions: map[int64]map[string][]string{
|
|
1: {accesscontrol.ActionOrgUsersRead: []string{accesscontrol.ScopeUsersAll}},
|
|
},
|
|
}
|
|
|
|
o, err := orgSvc.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "test org"})
|
|
require.NoError(t, err)
|
|
|
|
ac1cmd := &user.CreateUserCommand{Login: "ac1", Email: "ac1@test.com", Name: "ac1 name", OrgID: o.ID}
|
|
ac2cmd := &user.CreateUserCommand{Login: "ac2", Email: "ac2@test.com", Name: "ac2 name", OrgID: o.ID}
|
|
|
|
ac1, err := usrSvc.Create(context.Background(), ac1cmd)
|
|
require.NoError(t, err)
|
|
testUser.OrgID = ac1.OrgID
|
|
require.Equal(t, int64(1), ac1.OrgID)
|
|
require.NoError(t, err)
|
|
|
|
ac2, err := usrSvc.Create(context.Background(), ac2cmd)
|
|
require.Equal(t, int64(1), ac2.OrgID)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("Can get organization users paginated with query", func(t *testing.T) {
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
Page: 1,
|
|
User: testUser,
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(result.OrgUsers))
|
|
})
|
|
|
|
t.Run("Can get organization users paginated and limited", func(t *testing.T) {
|
|
query := org.SearchOrgUsersQuery{
|
|
OrgID: ac1.OrgID,
|
|
Limit: 1,
|
|
Page: 1,
|
|
User: testUser,
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), &query)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(result.OrgUsers))
|
|
})
|
|
})
|
|
}
|
|
|
|
// This test will be refactore after the CRUD store refactor
|
|
func TestIntegrationSQLStore_AddOrgUser(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
store, cfg := db.InitTestDBWithCfg(t)
|
|
defer func() {
|
|
cfg.AutoAssignOrg, cfg.AutoAssignOrgId, cfg.AutoAssignOrgRole = false, 0, ""
|
|
}()
|
|
cfg.AutoAssignOrg = true
|
|
cfg.AutoAssignOrgId = 1
|
|
cfg.AutoAssignOrgRole = "Viewer"
|
|
orgUserStore := sqlStore{
|
|
db: store,
|
|
dialect: store.GetDialect(),
|
|
}
|
|
orgSvc, usrSvc := createOrgAndUserSvc(t, store, cfg)
|
|
|
|
o, err := orgSvc.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "test org"})
|
|
require.NoError(t, err)
|
|
|
|
// create org and admin
|
|
u, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "admin",
|
|
OrgID: o.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// create a service account with no org
|
|
sa, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "sa-no-org",
|
|
IsServiceAccount: true,
|
|
SkipOrgSetup: true,
|
|
})
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(-1), sa.OrgID)
|
|
|
|
// assign the sa to the org but without the override. should fail
|
|
err = orgUserStore.AddOrgUser(context.Background(), &org.AddOrgUserCommand{
|
|
Role: "Viewer",
|
|
OrgID: u.OrgID,
|
|
UserID: sa.ID,
|
|
})
|
|
require.Error(t, err)
|
|
|
|
// assign the sa to the org with the override. should succeed
|
|
err = orgUserStore.AddOrgUser(context.Background(), &org.AddOrgUserCommand{
|
|
Role: "Viewer",
|
|
OrgID: u.OrgID,
|
|
UserID: sa.ID,
|
|
AllowAddingServiceAccount: true,
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
// assert the org has been correctly set
|
|
saFound := new(user.User)
|
|
err = store.WithDbSession(context.Background(), func(sess *db.Session) error {
|
|
has, err := sess.ID(sa.ID).Get(saFound)
|
|
if err != nil {
|
|
return err
|
|
} else if !has {
|
|
return user.ErrUserNotFound
|
|
}
|
|
return nil
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, saFound.OrgID, u.OrgID)
|
|
}
|
|
|
|
func TestIntegration_SQLStore_GetOrgUsers(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
store, cfg := db.InitTestDBWithCfg(t)
|
|
orgUserStore := sqlStore{
|
|
db: store,
|
|
dialect: store.GetDialect(),
|
|
}
|
|
cfg.IsEnterprise = true
|
|
defer func() {
|
|
cfg.IsEnterprise = false
|
|
}()
|
|
|
|
orgSvc, userSvc := createOrgAndUserSvc(t, store, cfg)
|
|
|
|
o, err := orgSvc.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "test org"})
|
|
require.NoError(t, err)
|
|
|
|
seedOrgUsers(t, &orgUserStore, 10, userSvc, o.ID)
|
|
|
|
tests := []struct {
|
|
desc string
|
|
query *org.SearchOrgUsersQuery
|
|
expectedNumUsers int
|
|
}{
|
|
{
|
|
desc: "should return all users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 10,
|
|
},
|
|
{
|
|
desc: "should return no users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {""}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 0,
|
|
},
|
|
{
|
|
desc: "should return some users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {
|
|
"users:id:1",
|
|
"users:id:5",
|
|
"users:id:9",
|
|
}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 3,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), tt.query)
|
|
require.NoError(t, err)
|
|
require.Len(t, result.OrgUsers, tt.expectedNumUsers)
|
|
|
|
if !hasWildcardScope(tt.query.User, accesscontrol.ActionOrgUsersRead) {
|
|
for _, u := range result.OrgUsers {
|
|
assert.Contains(t, tt.query.User.GetPermissions()[accesscontrol.ActionOrgUsersRead], fmt.Sprintf("users:id:%d", u.UserID))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func seedOrgUsers(t *testing.T, orgUserStore store, numUsers int, usrSvc user.Service, orgID int64) {
|
|
t.Helper()
|
|
|
|
// Seed users
|
|
for i := 1; i <= numUsers; i++ {
|
|
user, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: fmt.Sprintf("user-%d", i),
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
role := org.RoleViewer
|
|
if i == 1 {
|
|
role = org.RoleAdmin
|
|
}
|
|
|
|
err = orgUserStore.AddOrgUser(context.Background(), &org.AddOrgUserCommand{
|
|
Role: role,
|
|
OrgID: orgID,
|
|
UserID: user.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func hasWildcardScope(user identity.Requester, action string) bool {
|
|
for _, scope := range user.GetPermissions()[action] {
|
|
if strings.HasSuffix(scope, ":*") {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func TestIntegration_SQLStore_GetOrgUsers_PopulatesCorrectly(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
// The millisecond part is not stored in the DB
|
|
constNow := time.Date(2022, 8, 17, 20, 34, 58, 0, time.UTC)
|
|
userimpl.MockTimeNow(constNow)
|
|
defer userimpl.ResetTimeNow()
|
|
|
|
store, cfg := db.InitTestDBWithCfg(t, sqlstore.InitTestDBOpt{})
|
|
orgUserStore := sqlStore{
|
|
db: store,
|
|
dialect: store.GetDialect(),
|
|
}
|
|
_, usrSvc := createOrgAndUserSvc(t, store, cfg)
|
|
|
|
id, err := orgUserStore.Insert(context.Background(),
|
|
&org.Org{
|
|
ID: 1,
|
|
Created: constNow,
|
|
Updated: constNow,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
newUser, err := usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "Viewer",
|
|
Email: "viewer@localhost",
|
|
OrgID: id,
|
|
IsDisabled: true,
|
|
Name: "Viewer Localhost",
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
err = orgUserStore.AddOrgUser(context.Background(), &org.AddOrgUserCommand{
|
|
Role: "Viewer",
|
|
OrgID: 1,
|
|
UserID: newUser.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
query := &org.SearchOrgUsersQuery{
|
|
OrgID: 1,
|
|
UserID: newUser.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: 1,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
}
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), query)
|
|
require.NoError(t, err)
|
|
require.Len(t, result.OrgUsers, 1)
|
|
|
|
actual := result.OrgUsers[0]
|
|
assert.Equal(t, int64(1), actual.OrgID)
|
|
assert.Equal(t, int64(1), actual.UserID)
|
|
assert.Equal(t, "viewer@localhost", actual.Email)
|
|
assert.Equal(t, "Viewer Localhost", actual.Name)
|
|
assert.Equal(t, "viewer", actual.Login)
|
|
assert.Equal(t, "Viewer", actual.Role)
|
|
assert.Equal(t, constNow.AddDate(-10, 0, 0), actual.LastSeenAt)
|
|
assert.Equal(t, constNow, actual.Created)
|
|
assert.Equal(t, constNow, actual.Updated)
|
|
assert.Equal(t, true, actual.IsDisabled)
|
|
}
|
|
|
|
func TestIntegration_SQLStore_SearchOrgUsers(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
|
|
store, cfg := db.InitTestDBWithCfg(t, sqlstore.InitTestDBOpt{})
|
|
orgUserStore := sqlStore{
|
|
db: store,
|
|
dialect: store.GetDialect(),
|
|
}
|
|
// orgUserStore.cfg.Skip
|
|
orgSvc, userSvc := createOrgAndUserSvc(t, store, cfg)
|
|
|
|
o, err := orgSvc.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "test org"})
|
|
require.NoError(t, err)
|
|
|
|
seedOrgUsers(t, &orgUserStore, 10, userSvc, o.ID)
|
|
|
|
tests := []struct {
|
|
desc string
|
|
query *org.SearchOrgUsersQuery
|
|
expectedNumUsers int
|
|
}{
|
|
{
|
|
desc: "should return all users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {accesscontrol.ScopeUsersAll}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 10,
|
|
},
|
|
{
|
|
desc: "should return no users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {""}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 0,
|
|
},
|
|
{
|
|
desc: "should return some users",
|
|
query: &org.SearchOrgUsersQuery{
|
|
OrgID: o.ID,
|
|
User: &user.SignedInUser{
|
|
OrgID: o.ID,
|
|
Permissions: map[int64]map[string][]string{1: {accesscontrol.ActionOrgUsersRead: {
|
|
"users:id:1",
|
|
"users:id:5",
|
|
"users:id:9",
|
|
}}},
|
|
},
|
|
},
|
|
expectedNumUsers: 3,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
result, err := orgUserStore.SearchOrgUsers(context.Background(), tt.query)
|
|
require.NoError(t, err)
|
|
assert.Len(t, result.OrgUsers, tt.expectedNumUsers)
|
|
|
|
if !hasWildcardScope(tt.query.User, accesscontrol.ActionOrgUsersRead) {
|
|
for _, u := range result.OrgUsers {
|
|
assert.Contains(t, tt.query.User.GetPermissions()[accesscontrol.ActionOrgUsersRead], fmt.Sprintf("users:id:%d", u.UserID))
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIntegration_SQLStore_RemoveOrgUser(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test")
|
|
}
|
|
store, cfg := db.InitTestDBWithCfg(t)
|
|
orgUserStore := sqlStore{
|
|
db: store,
|
|
dialect: store.GetDialect(),
|
|
}
|
|
orgSvc, usrSvc := createOrgAndUserSvc(t, store, cfg)
|
|
|
|
o, err := orgSvc.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: MainOrgName})
|
|
require.NoError(t, err)
|
|
|
|
// create org and admin
|
|
_, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "admin",
|
|
OrgID: o.ID,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// create a user with no org
|
|
_, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{
|
|
Login: "user",
|
|
OrgID: 1,
|
|
SkipOrgSetup: true,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// assign the user to the org
|
|
err = orgUserStore.AddOrgUser(context.Background(), &org.AddOrgUserCommand{
|
|
Role: "Viewer",
|
|
OrgID: 1,
|
|
UserID: 2,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// remove the user org
|
|
err = orgUserStore.RemoveOrgUser(context.Background(), &org.RemoveOrgUserCommand{
|
|
UserID: 2,
|
|
OrgID: 1,
|
|
ShouldDeleteOrphanedUser: false,
|
|
})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
func createOrgAndUserSvc(t *testing.T, store db.DB, cfg *setting.Cfg) (org.Service, user.Service) {
|
|
t.Helper()
|
|
|
|
quotaService := quotaimpl.ProvideService(store, cfg)
|
|
orgService, err := ProvideService(store, cfg, quotaService)
|
|
require.NoError(t, err)
|
|
usrSvc, err := userimpl.ProvideService(
|
|
store, orgService, cfg, nil, nil, tracing.InitializeTracerForTest(),
|
|
quotaService, supportbundlestest.NewFakeBundleService(),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
return orgService, usrSvc
|
|
}
|