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/api/team_test.go

191 lines
6.4 KiB

package api
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"testing"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/resourcepermissions"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/web"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type testLogger struct {
log.Logger
warnCalled bool
warnMessage string
}
func (stub *testLogger) Warn(testMessage string, ctx ...interface{}) {
stub.warnCalled = true
stub.warnMessage = testMessage
}
func TestTeamAPIEndpoint(t *testing.T) {
t.Run("Given two teams", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.SQLStore = sqlstore.InitTestDB(t)
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1)
require.NoError(t, err)
_, err = hs.SQLStore.CreateTeam("team2", "", 1)
require.NoError(t, err)
sc.handlerFunc = hs.SearchTeams
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
require.Equal(t, http.StatusOK, sc.resp.Code)
var resp models.SearchTeamQueryResult
err = json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err)
assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 2, len(resp.Teams))
})
loggedInUserScenario(t, "When calling GET on", "/api/teams/search", "/api/teams/search", func(sc *scenarioContext) {
_, err := hs.SQLStore.CreateTeam("team1", "", 1)
require.NoError(t, err)
_, err = hs.SQLStore.CreateTeam("team2", "", 1)
require.NoError(t, err)
sc.handlerFunc = hs.SearchTeams
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
require.Equal(t, http.StatusOK, sc.resp.Code)
var resp models.SearchTeamQueryResult
err = json.Unmarshal(sc.resp.Body.Bytes(), &resp)
require.NoError(t, err)
assert.EqualValues(t, 2, resp.TotalCount)
assert.Equal(t, 0, len(resp.Teams))
})
})
t.Run("When creating team with API key", func(t *testing.T) {
hs := setupSimpleHTTPServer(nil)
hs.Cfg.EditorsCanAdmin = true
teamName := "team foo"
// TODO: Use a fake SQLStore when it's represented by an interface
orgCreateTeam := createTeam
orgAddTeamMember := addOrUpdateTeamMember
t.Cleanup(func() {
createTeam = orgCreateTeam
addOrUpdateTeamMember = orgAddTeamMember
})
createTeamCalled := 0
createTeam = func(sqlStore *sqlstore.SQLStore, name, email string, orgID int64) (models.Team, error) {
createTeamCalled++
return models.Team{Name: teamName, Id: 42}, nil
}
addTeamMemberCalled := 0
addOrUpdateTeamMember = func(ctx context.Context, resourcePermissionService *resourcepermissions.Service, userID, orgID, teamID int64,
permission string) error {
addTeamMemberCalled++
return nil
}
req, err := http.NewRequest("POST", "/api/teams", nil)
require.NoError(t, err)
t.Run("with no real signed in user", func(t *testing.T) {
stub := &testLogger{}
c := &models.ReqContext{
Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{},
Logger: stub,
}
c.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 0)
assert.True(t, stub.warnCalled)
assert.Equal(t, stub.warnMessage, "Could not add creator to team because is not a real user")
})
t.Run("with real signed in user", func(t *testing.T) {
stub := &testLogger{}
c := &models.ReqContext{
Context: &web.Context{Req: req},
SignedInUser: &models.SignedInUser{UserId: 42},
Logger: stub,
}
c.OrgRole = models.ROLE_EDITOR
c.Req.Body = mockRequestBody(models.CreateTeamCommand{Name: teamName})
createTeamCalled, addTeamMemberCalled = 0, 0
hs.CreateTeam(c)
assert.Equal(t, createTeamCalled, 1)
assert.Equal(t, addTeamMemberCalled, 1)
assert.False(t, stub.warnCalled)
})
})
}
var (
createTeamURL = "/api/teams/"
createTeamCmd = `{"name": "MyTestTeam%d"}`
)
func TestTeamAPIEndpoint_CreateTeam_LegacyAccessControl(t *testing.T) {
sc := setupHTTPServer(t, true, false)
setInitCtxSignedInOrgAdmin(sc.initCtx)
input := strings.NewReader(fmt.Sprintf(createTeamCmd, 1))
t.Run("Organisation admin can create a team", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPost, createTeamURL, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
setInitCtxSignedInEditor(sc.initCtx)
sc.initCtx.IsGrafanaAdmin = true
input = strings.NewReader(fmt.Sprintf(createTeamCmd, 2))
t.Run("Org editor and server admin cannot create a team", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPost, createTeamURL, strings.NewReader(createTeamCmd), t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
}
func TestTeamAPIEndpoint_CreateTeam_LegacyAccessControl_EditorsCanAdmin(t *testing.T) {
cfg := setting.NewCfg()
cfg.EditorsCanAdmin = true
sc := setupHTTPServerWithCfg(t, true, false, cfg)
setInitCtxSignedInEditor(sc.initCtx)
input := strings.NewReader(fmt.Sprintf(createTeamCmd, 1))
t.Run("Editors can create a team if editorsCanAdmin is set to true", func(t *testing.T) {
response := callAPI(sc.server, http.MethodPost, createTeamURL, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
}
func TestTeamAPIEndpoint_CreateTeam_FGAC(t *testing.T) {
sc := setupHTTPServer(t, true, true)
setInitCtxSignedInViewer(sc.initCtx)
input := strings.NewReader(fmt.Sprintf(createTeamCmd, 1))
t.Run("Access control allows creating teams with the correct permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: accesscontrol.ActionTeamsCreate}}, 1)
response := callAPI(sc.server, http.MethodPost, createTeamURL, input, t)
assert.Equal(t, http.StatusOK, response.Code)
})
input = strings.NewReader(fmt.Sprintf(createTeamCmd, 2))
t.Run("Access control prevents creating teams with the incorrect permissions", func(t *testing.T) {
setAccessControlPermissions(sc.acmock, []*accesscontrol.Permission{{Action: "teams:invalid"}}, accesscontrol.GlobalOrgID)
response := callAPI(sc.server, http.MethodPost, createTeamURL, input, t)
assert.Equal(t, http.StatusForbidden, response.Code)
})
}