grafana/pkg/services/queryhistory/queryhistory_test.go

190 lines
5.5 KiB
Go
Raw Normal View History

package queryhistory
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"
"net/url"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/tracing"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgimpl"
"github.com/grafana/grafana/pkg/services/quota/quotatest"
"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"
"github.com/grafana/grafana/pkg/web"
)
var (
testOrgID = int64(1)
testUserID = int64(1)
testDsUID1 = "NCzh67i"
testDsUID2 = "ABch1a1"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
type scenarioContext struct {
ctx *web.Context
service *QueryHistoryService
reqContext *contextmodel.ReqContext
sqlStore db.DB
initialResult QueryHistoryResponse
}
func testScenario(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
t.Helper()
t.Run(desc, func(t *testing.T) {
Security: Sync security changes on main (#45083) * * Teams: Appropriately apply user id filter in /api/teams/:id and /api/teams/search * Teams: Ensure that users searching for teams are only able see teams they have access to * Teams: Require teamGuardian admin privileges to list team members * Teams: Prevent org viewers from administering teams * Teams: Add org_id condition to team count query * Teams: clarify permission requirements in teams api docs * Teams: expand scenarios for team search tests * Teams: mock teamGuardian in tests Co-authored-by: Dan Cech <dcech@grafana.com> * remove duplicate WHERE statement * Fix for CVE-2022-21702 (cherry picked from commit 202d7c190082c094bc1dc13f7fe9464746c37f9e) * Lint and test fixes (cherry picked from commit 3e6b67d5504abf4a1d7b8d621f04d062c048e981) * check content type properly (cherry picked from commit 70b4458892bf2f776302720c10d24c9ff34edd98) * basic csrf origin check (cherry picked from commit 3adaa5ff39832364f6390881fb5b42ad47df92e1) * compare origin to host (cherry picked from commit 5443892699e8ed42836bb2b9a44744ff3e970f42) * simplify url parsing (cherry picked from commit b2ffbc9513fed75468628370a48b929d30af2b1d) * check csrf for GET requests, only compare origin (cherry picked from commit 8b81dc12d8f8a1f07852809c5b4d44f0f0b1d709) * parse content type properly (cherry picked from commit 16f76f4902e6f2188bea9606c68b551af186bdc0) * mentioned get in the comment (cherry picked from commit a7e61811ef8ae558ce721e2e3fed04ce7a5a5345) * add content-type: application/json to test HTTP requests * fix pluginproxy test * Fix linter when comparing errors Co-authored-by: Kevin Minehart <kmineh0151@gmail.com> Co-authored-by: Dan Cech <dcech@grafana.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com> Co-authored-by: Vardan Torosyan <vardants@gmail.com>
2022-02-09 06:44:38 -06:00
ctx := web.Context{Req: &http.Request{
Header: http.Header{},
Form: url.Values{},
Security: Sync security changes on main (#45083) * * Teams: Appropriately apply user id filter in /api/teams/:id and /api/teams/search * Teams: Ensure that users searching for teams are only able see teams they have access to * Teams: Require teamGuardian admin privileges to list team members * Teams: Prevent org viewers from administering teams * Teams: Add org_id condition to team count query * Teams: clarify permission requirements in teams api docs * Teams: expand scenarios for team search tests * Teams: mock teamGuardian in tests Co-authored-by: Dan Cech <dcech@grafana.com> * remove duplicate WHERE statement * Fix for CVE-2022-21702 (cherry picked from commit 202d7c190082c094bc1dc13f7fe9464746c37f9e) * Lint and test fixes (cherry picked from commit 3e6b67d5504abf4a1d7b8d621f04d062c048e981) * check content type properly (cherry picked from commit 70b4458892bf2f776302720c10d24c9ff34edd98) * basic csrf origin check (cherry picked from commit 3adaa5ff39832364f6390881fb5b42ad47df92e1) * compare origin to host (cherry picked from commit 5443892699e8ed42836bb2b9a44744ff3e970f42) * simplify url parsing (cherry picked from commit b2ffbc9513fed75468628370a48b929d30af2b1d) * check csrf for GET requests, only compare origin (cherry picked from commit 8b81dc12d8f8a1f07852809c5b4d44f0f0b1d709) * parse content type properly (cherry picked from commit 16f76f4902e6f2188bea9606c68b551af186bdc0) * mentioned get in the comment (cherry picked from commit a7e61811ef8ae558ce721e2e3fed04ce7a5a5345) * add content-type: application/json to test HTTP requests * fix pluginproxy test * Fix linter when comparing errors Co-authored-by: Kevin Minehart <kmineh0151@gmail.com> Co-authored-by: Dan Cech <dcech@grafana.com> Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com> Co-authored-by: Serge Zaitsev <serge.zaitsev@grafana.com> Co-authored-by: Vardan Torosyan <vardants@gmail.com>
2022-02-09 06:44:38 -06:00
}}
ctx.Req.Header.Add("Content-Type", "application/json")
sqlStore, cfg := db.InitTestDBWithCfg(t)
service := QueryHistoryService{
Cfg: setting.NewCfg(),
store: sqlStore,
now: time.Now,
}
service.Cfg.QueryHistoryEnabled = true
quotaService := quotatest.New(false, nil)
orgSvc, err := orgimpl.ProvideService(sqlStore, cfg, quotaService)
require.NoError(t, err)
usrSvc, err := userimpl.ProvideService(
sqlStore, orgSvc, cfg, nil, nil, tracing.InitializeTracerForTest(),
quotaService, supportbundlestest.NewFakeBundleService(),
)
require.NoError(t, err)
usr := user.SignedInUser{
UserID: testUserID,
Name: "Signed In User",
Login: "signed_in_user",
Email: "signed.in.user@test.com",
OrgID: testOrgID,
OrgRole: org.RoleViewer,
LastSeenAt: service.now(),
}
_, err = usrSvc.Create(context.Background(), &user.CreateUserCommand{
Email: "signed.in.user@test.com",
Name: "Signed In User",
Login: "signed_in_user",
})
require.NoError(t, err)
sc := scenarioContext{
ctx: &ctx,
service: &service,
sqlStore: sqlStore,
reqContext: &contextmodel.ReqContext{
Context: &ctx,
SignedInUser: &usr,
},
}
fn(t, sc)
})
}
func testScenarioWithQueryInQueryHistory(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
t.Helper()
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
command := CreateQueryInQueryHistoryCommand{
DatasourceUID: testDsUID1,
Queries: simplejson.NewFromAny(map[string]any{
"expr": "test",
}),
}
sc.reqContext.Req.Body = mockRequestBody(command)
resp := sc.service.createHandler(sc.reqContext)
sc.initialResult = validateAndUnMarshalResponse(t, resp)
fn(t, sc)
})
}
func testScenarioWithMultipleQueriesInQueryHistory(t *testing.T, desc string, fn func(t *testing.T, sc scenarioContext)) {
t.Helper()
testScenario(t, desc, func(t *testing.T, sc scenarioContext) {
start := time.Now().Add(-3 * time.Second)
sc.service.now = func() time.Time { return start }
command1 := CreateQueryInQueryHistoryCommand{
DatasourceUID: testDsUID1,
Queries: simplejson.NewFromAny(map[string]any{
"expr": "test",
}),
}
sc.reqContext.Req.Body = mockRequestBody(command1)
resp1 := sc.service.createHandler(sc.reqContext)
sc.initialResult = validateAndUnMarshalResponse(t, resp1)
// Add comment
cmd := PatchQueryCommentInQueryHistoryCommand{Comment: "test comment 2"}
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": sc.initialResult.Result.UID})
sc.reqContext.Req.Body = mockRequestBody(cmd)
sc.service.patchCommentHandler(sc.reqContext)
sc.service.now = func() time.Time { return start.Add(time.Second) }
command2 := CreateQueryInQueryHistoryCommand{
DatasourceUID: testDsUID1,
Queries: simplejson.NewFromAny(map[string]any{
"expr": "test2",
}),
}
sc.reqContext.Req.Body = mockRequestBody(command2)
resp2 := sc.service.createHandler(sc.reqContext)
result2 := validateAndUnMarshalResponse(t, resp2)
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result2.Result.UID})
sc.service.starHandler(sc.reqContext)
sc.service.now = func() time.Time { return start.Add(2 * time.Second) }
command3 := CreateQueryInQueryHistoryCommand{
DatasourceUID: testDsUID2,
Queries: simplejson.NewFromAny(map[string]any{
"expr": "test2",
}),
}
sc.reqContext.Req.Body = mockRequestBody(command3)
resp3 := sc.service.createHandler(sc.reqContext)
result3 := validateAndUnMarshalResponse(t, resp3)
sc.ctx.Req = web.SetURLParams(sc.ctx.Req, map[string]string{":uid": result3.Result.UID})
sc.service.starHandler(sc.reqContext)
fn(t, sc)
})
}
func mockRequestBody(v any) io.ReadCloser {
b, _ := json.Marshal(v)
return io.NopCloser(bytes.NewReader(b))
}
func validateAndUnMarshalResponse(t *testing.T, resp response.Response) QueryHistoryResponse {
t.Helper()
require.Equal(t, 200, resp.Status())
var result = QueryHistoryResponse{}
err := json.Unmarshal(resp.Body(), &result)
require.NoError(t, err)
return result
}