Hackaton: Add more unit tests, take 3 (#101525)

* serviceaccounts/secretscan: test Service more thoroughly

* middleware/cookies: add tests for CookieOptions

* anonymous/anonimpl: cover a couple more methods

* components/imguploader: Implement WebDAV integration tests

* components/apikeygen: also check IsValid method

* bus: cover invalid callback signature cases

* cloudmigration/objectstorage: add basic unit tests

* login/social/connectors: add test case for GitHub OAuth fetch emails+orgs

* expr/classic: cover more evaluator types in tests
This commit is contained in:
Matheus Macabu
2025-03-05 08:00:12 +01:00
committed by GitHub
parent dc2defd84f
commit 3539764008
9 changed files with 522 additions and 25 deletions
+55 -5
View File
@@ -16,6 +16,7 @@ import (
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/anonymous/anonimpl/anonstore"
"github.com/grafana/grafana/pkg/services/anonymous/validator"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/authn/authntest"
"github.com/grafana/grafana/pkg/services/org/orgtest"
"github.com/grafana/grafana/pkg/setting"
@@ -41,6 +42,7 @@ func TestIntegrationDeviceService_tag(t *testing.T) {
expectedAnonUICount int64
expectedKey string
expectedDevice *anonstore.Device
disableService bool
}{
{
name: "no requests",
@@ -118,20 +120,49 @@ func TestIntegrationDeviceService_tag(t *testing.T) {
},
expectedAnonUICount: 2,
},
{
name: "when the service is disabled, read operations return empty",
req: []tagReq{
{
httpReq: &http.Request{
Header: http.Header{
"User-Agent": []string{"test"},
"X-Forwarded-For": []string{"10.30.30.1"},
http.CanonicalHeaderKey(deviceIDHeader): []string{"32mdo31deeqwes"},
},
},
kind: anonymous.AnonDeviceUI,
},
},
disableService: true,
expectedAnonUICount: 0,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
store := db.InitTestDB(t)
anonService := ProvideAnonymousDeviceService(&usagestats.UsageStatsMock{},
&authntest.FakeService{}, store, setting.NewCfg(), orgtest.NewOrgServiceFake(), nil, actest.FakeAccessControl{}, &routing.RouteRegisterImpl{}, validator.FakeAnonUserLimitValidator{})
cfg := setting.NewCfg()
cfg.Anonymous.Enabled = !tc.disableService
anonService := ProvideAnonymousDeviceService(
&usagestats.UsageStatsMock{}, &authntest.FakeService{}, store, cfg, orgtest.NewOrgServiceFake(),
nil, actest.FakeAccessControl{}, &routing.RouteRegisterImpl{}, validator.FakeAnonUserLimitValidator{},
)
for _, req := range tc.req {
err := anonService.TagDevice(context.Background(), req.httpReq, req.kind)
err := anonService.TagDevice(ctx, req.httpReq, req.kind)
require.NoError(t, err)
t.Cleanup(func() {
anonService.untagDevice(ctx, nil, &authn.Request{HTTPRequest: req.httpReq}, nil)
})
}
devices, err := anonService.anonStore.ListDevices(context.Background(), nil, nil)
devices, err := anonService.ListDevices(ctx, nil, nil)
require.NoError(t, err)
require.Len(t, devices, int(tc.expectedAnonUICount))
if tc.expectedDevice != nil {
@@ -147,10 +178,29 @@ func TestIntegrationDeviceService_tag(t *testing.T) {
assert.Equal(t, tc.expectedDevice, devices[0])
}
to := time.Now()
from := to.AddDate(0, 0, -1)
devicesCount, err := anonService.CountDevices(ctx, from, to)
require.NoError(t, err)
require.Equal(t, tc.expectedAnonUICount, devicesCount)
devicesFound, err := anonService.SearchDevices(ctx, &anonstore.SearchDeviceQuery{
From: from,
To: to,
})
require.NoError(t, err)
if tc.expectedAnonUICount > 0 {
require.NotNil(t, devicesFound)
require.Equal(t, tc.expectedAnonUICount, devicesFound.TotalCount)
}
stats, err := anonService.usageStatFn(context.Background())
require.NoError(t, err)
assert.Equal(t, tc.expectedAnonUICount, stats["stats.anonymous.device.ui.count"].(int64), stats)
if !tc.disableService {
assert.Equal(t, tc.expectedAnonUICount, stats["stats.anonymous.device.ui.count"].(int64), stats)
}
})
}
}
@@ -0,0 +1,103 @@
package objectstorage
import (
"bytes"
"context"
"io"
"math"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/stretchr/testify/require"
)
func TestPresignedURLUpload(t *testing.T) {
t.Parallel()
t.Run("successfully send data to the server", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
key := "snapshot/uuid/key"
data := "sending-some-data"
reader := bytes.NewBufferString(data)
qs, err := url.ParseQuery("one=a&two=b")
require.NoError(t, err)
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
_, boundary, found := strings.Cut(contentType, "boundary=")
require.True(t, found)
mpr := multipart.NewReader(r.Body, boundary)
form, err := mpr.ReadForm(math.MaxInt64)
require.NoError(t, err)
require.NotNil(t, form)
require.NotNil(t, form.Value)
require.Equal(t, key, form.Value["key"][0])
require.Equal(t, qs.Get("one"), form.Value["one"][0])
require.Equal(t, qs.Get("two"), form.Value["two"][0])
require.Len(t, form.File, 1)
require.Len(t, form.File["file"], 1)
fileHeader := form.File["file"][0]
require.Equal(t, "file", fileHeader.Filename)
file, err := fileHeader.Open()
require.NoError(t, err)
contents, err := io.ReadAll(file)
require.NoError(t, err)
require.EqualValues(t, data, string(contents))
require.NoError(t, file.Close())
}))
t.Cleanup(server.Close)
s3 := NewS3(http.DefaultClient, tracing.NewNoopTracerService())
presignedURL, err := url.Parse(server.URL + "?" + qs.Encode())
require.NoError(t, err)
err = s3.PresignedURLUpload(ctx, presignedURL.String(), key, reader)
require.NoError(t, err)
})
t.Run("when the request to the server returns an error, it is propagated", func(t *testing.T) {
t.Parallel()
ctx := context.Background()
key := "snapshot/uuid/key"
data := "sending-some-data"
reader := bytes.NewBufferString(data)
body := "test error"
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(`{"message": "` + body + `}`))
}))
t.Cleanup(server.Close)
s3 := NewS3(http.DefaultClient, tracing.NewNoopTracerService())
presignedURL, err := url.Parse(server.URL)
require.NoError(t, err)
err = s3.PresignedURLUpload(ctx, presignedURL.String(), key, reader)
require.Error(t, err)
require.Contains(t, err.Error(), body)
})
}
@@ -2,13 +2,20 @@ package secretscan
import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/setting"
)
func TestService_CheckTokens(t *testing.T) {
@@ -170,3 +177,111 @@ func TestService_CheckTokens(t *testing.T) {
})
}
}
func TestService(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
// Fake Secret Scanner + Webhook.
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.RequestURI, "/tokens") {
_, err := io.Copy(io.Discard, r.Body)
require.NoError(t, err)
defer func() {
_ = r.Body.Close()
}()
_, _ = w.Write([]byte(`[
{"type": "token_type", "hash": "test-hash-1", "url": "http://example.com", "reported_at": "2006-01-20T01:02:03Z" }
]`))
}
if strings.Contains(r.RequestURI, "/oncall") {
var webhookReq struct {
State string `json:"state"`
Message string `json:"message"`
}
err := json.NewDecoder(r.Body).Decode(&webhookReq)
require.NoError(t, err)
defer func() {
_ = r.Body.Close()
}()
require.Equal(t, "alerting", webhookReq.State)
require.Contains(t, webhookReq.Message, "test-1")
}
}))
t.Cleanup(server.Close)
unixZero := time.Unix(0, 0).Unix()
revoked := true
tokenRetriever := &MockTokenRetriever{keys: []apikey.APIKey{
// Valid
{
ID: 1,
OrgID: 1,
Name: "test-1",
Key: "test-hash-1",
Role: "Viewer",
Expires: nil,
ServiceAccountId: new(int64),
IsRevoked: new(bool),
},
// Expired
{
ID: 2,
OrgID: 1,
Name: "test-2",
Key: "test-hash-2",
Role: "Viewer",
Expires: &unixZero,
ServiceAccountId: new(int64),
IsRevoked: new(bool),
},
// Revoked
{
ID: 3,
OrgID: 1,
Name: "test-3",
Key: "test-hash-3",
Role: "Viewer",
Expires: nil,
ServiceAccountId: new(int64),
IsRevoked: &revoked,
},
// Revoked + Expired
{
ID: 4,
OrgID: 1,
Name: "test-4",
Key: "test-hash-4",
Role: "Viewer",
Expires: &unixZero,
ServiceAccountId: new(int64),
IsRevoked: &revoked,
},
}}
cfg := setting.NewCfg()
section := cfg.Raw.Section("secretscan")
baseURL := section.Key("base_url")
baseURL.SetValue(server.URL)
oncallURL := section.Key("oncall_url")
oncallURL.SetValue(server.URL + "/oncall")
revoke := section.Key("revoke")
revoke.SetValue("true")
service, err := NewService(tokenRetriever, cfg)
require.NoError(t, err)
require.NotNil(t, service)
err = service.CheckTokens(ctx)
require.NoError(t, err)
}