The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/sqlstore/org_test.go

283 lines
9.8 KiB

package sqlstore
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/dashboards"
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
func TestIntegrationAccountDataAccess(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
t.Run("Testing Account DB Access", func(t *testing.T) {
sqlStore := InitTestDB(t)
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("Given two saved users", func(t *testing.T) {
sqlStore = InitTestDB(t)
sqlStore.Cfg.AutoAssignOrg = false
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}
serviceaccountcmd := user.CreateUserCommand{Login: "serviceaccount", Email: "service@test.com", Name: "serviceaccount name", IsAdmin: true, IsServiceAccount: true}
ac1, err := sqlStore.CreateUser(context.Background(), ac1cmd)
require.NoError(t, err)
ac2, err := sqlStore.CreateUser(context.Background(), ac2cmd)
require.NoError(t, err)
// user only used for making sure we filter out the service accounts
_, err = sqlStore.CreateUser(context.Background(), serviceaccountcmd)
require.NoError(t, err)
t.Run("Given an added org user", func(t *testing.T) {
cmd := models.AddOrgUserCommand{
OrgId: ac1.OrgID,
UserId: ac2.ID,
Role: org.RoleViewer,
}
err := sqlStore.AddOrgUser(context.Background(), &cmd)
t.Run("Should have been saved without error", func(t *testing.T) {
require.NoError(t, err)
})
t.Run("Can get logged in user projection", func(t *testing.T) {
query := models.GetSignedInUserQuery{UserId: ac2.ID}
err := sqlStore.GetSignedInUser(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.Email, "ac2@test.com")
require.Equal(t, query.Result.OrgID, ac2.OrgID)
require.Equal(t, query.Result.Name, "ac2 name")
require.Equal(t, query.Result.Login, "ac2")
require.EqualValues(t, query.Result.OrgRole, "Admin")
require.Equal(t, query.Result.OrgName, "ac2@test.com")
require.Equal(t, query.Result.IsGrafanaAdmin, true)
})
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("Can set using org", func(t *testing.T) {
cmd := models.SetUsingOrgCommand{UserId: ac2.ID, OrgId: ac1.OrgID}
err := sqlStore.SetUsingOrg(context.Background(), &cmd)
require.NoError(t, err)
t.Run("SignedInUserQuery with a different org", func(t *testing.T) {
query := models.GetSignedInUserQuery{UserId: ac2.ID}
err := sqlStore.GetSignedInUser(context.Background(), &query)
require.NoError(t, err)
require.Equal(t, query.Result.OrgID, ac1.OrgID)
require.Equal(t, query.Result.Email, "ac2@test.com")
require.Equal(t, query.Result.Name, "ac2 name")
require.Equal(t, query.Result.Login, "ac2")
require.Equal(t, query.Result.OrgName, "ac1@test.com")
})
// TODO: This test should be moved to user store
// t.Run("Should set last org as current when removing user from current", func(t *testing.T) {
// remCmd := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac2.ID}
// err := sqlStore.RemoveOrgUser(context.Background(), &remCmd)
// require.NoError(t, err)
// query := models.GetSignedInUserQuery{UserId: ac2.ID}
// err = sqlStore.GetSignedInUser(context.Background(), &query)
// require.NoError(t, err)
// require.Equal(t, query.Result.OrgID, ac2.OrgID)
// })
})
t.Run("Given an org user with dashboard permissions", func(t *testing.T) {
ac3cmd := user.CreateUserCommand{Login: "ac3", Email: "ac3@test.com", Name: "ac3 name", IsAdmin: false}
ac3, err := sqlStore.CreateUser(context.Background(), ac3cmd)
require.NoError(t, err)
orgUserCmd := models.AddOrgUserCommand{
OrgId: ac1.OrgID,
UserId: ac3.ID,
Role: org.RoleViewer,
}
err = sqlStore.AddOrgUser(context.Background(), &orgUserCmd)
require.NoError(t, err)
dash1 := insertTestDashboard(t, sqlStore, "1 test dash", ac1.OrgID, 0, false, "prod", "webapp")
dash2 := insertTestDashboard(t, sqlStore, "2 test dash", ac3.OrgID, 0, false, "prod", "webapp")
err = updateDashboardACL(t, sqlStore, dash1.Id, &models.DashboardACL{
DashboardID: dash1.Id, OrgID: ac1.OrgID, UserID: ac3.ID, Permission: models.PERMISSION_EDIT,
})
require.NoError(t, err)
err = updateDashboardACL(t, sqlStore, dash2.Id, &models.DashboardACL{
DashboardID: dash2.Id, OrgID: ac3.OrgID, UserID: ac3.ID, Permission: models.PERMISSION_EDIT,
})
require.NoError(t, err)
// TODO: should be moved to dashboard service
// t.Run("When org user is deleted", func(t *testing.T) {
// cmdRemove := models.RemoveOrgUserCommand{OrgId: ac1.OrgID, UserId: ac3.ID}
// err := sqlStore.RemoveOrgUser(context.Background(), &cmdRemove)
// require.NoError(t, err)
// t.Run("Should remove dependent permissions for deleted org user", func(t *testing.T) {
// permQuery := &models.GetDashboardACLInfoListQuery{DashboardID: dash1.Id, OrgID: ac1.OrgID}
// err = getDashboardACLInfoList(sqlStore, permQuery)
// require.NoError(t, err)
// require.Equal(t, len(permQuery.Result), 0)
// })
// t.Run("Should not remove dashboard permissions for same user in another org", func(t *testing.T) {
// permQuery := &models.GetDashboardACLInfoListQuery{DashboardID: dash2.Id, OrgID: ac3.OrgID}
// err = getDashboardACLInfoList(sqlStore, permQuery)
// require.NoError(t, err)
// require.Equal(t, len(permQuery.Result), 1)
// require.Equal(t, permQuery.Result[0].OrgId, ac3.OrgID)
// require.Equal(t, permQuery.Result[0].UserId, ac3.ID)
// })
// })
})
})
})
})
}
// TODO: Use FakeDashboardStore when org has its own service
func insertTestDashboard(t *testing.T, sqlStore *SQLStore, title string, orgId int64,
folderId int64, isFolder bool, tags ...interface{}) *models.Dashboard {
t.Helper()
cmd := models.SaveDashboardCommand{
OrgId: orgId,
FolderId: folderId,
IsFolder: isFolder,
Dashboard: simplejson.NewFromAny(map[string]interface{}{
"id": nil,
"title": title,
"tags": tags,
}),
}
var dash *models.Dashboard
err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
dash = cmd.GetDashboardModel()
dash.SetVersion(1)
dash.Created = time.Now()
dash.Updated = time.Now()
dash.Uid = util.GenerateShortUID()
_, err := sess.Insert(dash)
return err
})
require.NoError(t, err)
require.NotNil(t, dash)
dash.Data.Set("id", dash.Id)
dash.Data.Set("uid", dash.Uid)
err = sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
dashVersion := &dashver.DashboardVersion{
DashboardID: dash.Id,
ParentVersion: dash.Version,
RestoredFrom: cmd.RestoredFrom,
Version: dash.Version,
Created: time.Now(),
CreatedBy: dash.UpdatedBy,
Message: cmd.Message,
Data: dash.Data,
}
require.NoError(t, err)
if affectedRows, err := sess.Insert(dashVersion); err != nil {
return err
} else if affectedRows == 0 {
return dashboards.ErrDashboardNotFound
}
return nil
})
require.NoError(t, err)
return dash
}
// TODO: Use FakeDashboardStore when org has its own service
func updateDashboardACL(t *testing.T, sqlStore *SQLStore, dashboardID int64, items ...*models.DashboardACL) error {
t.Helper()
err := sqlStore.WithDbSession(context.Background(), func(sess *DBSession) error {
_, err := sess.Exec("DELETE FROM dashboard_acl WHERE dashboard_id=?", dashboardID)
if err != nil {
return fmt.Errorf("deleting from dashboard_acl failed: %w", err)
}
for _, item := range items {
item.Created = time.Now()
item.Updated = time.Now()
if item.UserID == 0 && item.TeamID == 0 && (item.Role == nil || !item.Role.IsValid()) {
return models.ErrDashboardACLInfoMissing
}
if item.DashboardID == 0 {
return models.ErrDashboardPermissionDashboardEmpty
}
sess.Nullable("user_id", "team_id")
if _, err := sess.Insert(item); err != nil {
return err
}
}
// Update dashboard HasACL flag
dashboard := models.Dashboard{HasACL: true}
_, err = sess.Cols("has_acl").Where("id=?", dashboardID).Update(&dashboard)
return err
})
return err
}