* Add config provider and integrate with wire setup * Refactor quota service to use config provider for configuration management * Enhance OSSConfigProvider to include logging and update ProvideService to return an error. Refactor server initialization to handle potential errors from config provider. Remove unnecessary wire binding for OSSConfigProvider. * Update CODEOWNERS to include the configprovider package under the grafana-backend-services-squad. * Refactor quota service initialization to include context in multiple service providers. Update tests and service implementations to ensure proper context handling during service creation.
158 lines
4.7 KiB
Go
158 lines
4.7 KiB
Go
package shorturl
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/configprovider"
|
|
"github.com/grafana/grafana/pkg/infra/db"
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
"github.com/grafana/grafana/pkg/services/org"
|
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
|
"github.com/grafana/grafana/pkg/services/quota/quotaimpl"
|
|
"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/testinfra"
|
|
"github.com/grafana/grafana/pkg/tests/testsuite"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
testsuite.Run(m)
|
|
}
|
|
|
|
func TestShortURL(t *testing.T) {
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
AppModeProduction: true,
|
|
DisableAnonymous: true,
|
|
})
|
|
|
|
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path)
|
|
|
|
// Test that the endpoint is accessible with authentication.
|
|
username, password := "viewer", "viewer"
|
|
createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
|
DefaultOrgRole: string(org.RoleEditor),
|
|
Password: user.Password(password),
|
|
Login: username,
|
|
})
|
|
|
|
c := client(grafanaListedAddr, username, password)
|
|
|
|
// Create a valid short-urls
|
|
res, err := c.post("/api/short-urls", bytes.NewReader([]byte(`{"path":"explore"}`)))
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_ = res.Body.Close()
|
|
}()
|
|
assert.Equal(t, http.StatusOK, res.StatusCode)
|
|
|
|
bodyRaw, err := io.ReadAll(res.Body)
|
|
require.NoError(t, err)
|
|
|
|
resParsed := struct {
|
|
UID string `json:"uid"`
|
|
}{}
|
|
err = json.Unmarshal(bodyRaw, &resParsed)
|
|
require.NoError(t, err)
|
|
|
|
// If the go-to exists, it should be set in the location and the status should match 302.
|
|
res, err = c.get(fmt.Sprintf("/goto/%s", resParsed.UID))
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_ = res.Body.Close()
|
|
}()
|
|
assert.Equal(t, "http://localhost:3000/explore", res.Header.Get("Location"))
|
|
assert.Equal(t, http.StatusFound, res.StatusCode)
|
|
|
|
// If the go-to does not exist, it should redirect to the home page and return 308.
|
|
res, err = c.get("/goto/DoesNotExist")
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_ = res.Body.Close()
|
|
}()
|
|
assert.Equal(t, "http://localhost:3000/", res.Header.Get("Location"))
|
|
assert.Equal(t, http.StatusPermanentRedirect, res.StatusCode)
|
|
|
|
// Create a client that does not have authentication.
|
|
notLoggedInClient := client(grafanaListedAddr, "", "")
|
|
// Test that the short-urls endpoint is not accessible without authentication.
|
|
res, err = notLoggedInClient.post("/api/short-urls", bytes.NewReader([]byte(`{"path":"explore"}`)))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, http.StatusUnauthorized, res.StatusCode)
|
|
defer func() {
|
|
_ = res.Body.Close()
|
|
}()
|
|
|
|
// If the user is not logged in, it should redirect to the login page and return 302.
|
|
res, err = notLoggedInClient.get(fmt.Sprintf("/goto/%s", resParsed.UID))
|
|
require.NoError(t, err)
|
|
defer func() {
|
|
_ = res.Body.Close()
|
|
}()
|
|
expectedRedirect := "/login?redirectTo=" + url.QueryEscape("/goto/"+resParsed.UID)
|
|
assert.Equal(t, expectedRedirect, res.Header.Get("Location"))
|
|
assert.Equal(t, http.StatusFound, res.StatusCode)
|
|
}
|
|
|
|
func createUser(t *testing.T, db db.DB, cfg *setting.Cfg, cmd user.CreateUserCommand) int64 {
|
|
t.Helper()
|
|
|
|
cfg.AutoAssignOrg = true
|
|
cfg.AutoAssignOrgId = 1
|
|
|
|
cfgProvider, err := configprovider.ProvideService(cfg)
|
|
require.NoError(t, err)
|
|
quotaService := quotaimpl.ProvideService(context.Background(), db, cfgProvider)
|
|
orgService, err := orgimpl.ProvideService(db, cfg, quotaService)
|
|
require.NoError(t, err)
|
|
usrSvc, err := userimpl.ProvideService(
|
|
db, orgService, cfg, nil, nil, tracing.InitializeTracerForTest(),
|
|
quotaService, supportbundlestest.NewFakeBundleService(),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
u, err := usrSvc.Create(context.Background(), &cmd)
|
|
require.NoError(t, err)
|
|
return u.ID
|
|
}
|
|
|
|
type apiClient struct {
|
|
url string
|
|
}
|
|
|
|
func client(host, user, pass string) apiClient {
|
|
if len(user) == 0 && len(pass) == 0 {
|
|
return apiClient{url: fmt.Sprintf("http://%s", host)}
|
|
}
|
|
return apiClient{url: fmt.Sprintf("http://%s:%s@%s", user, pass, host)}
|
|
}
|
|
|
|
func (a apiClient) get(path string) (*http.Response, error) {
|
|
u := fmt.Sprintf("%s%s", a.url, path)
|
|
// Setup a client that doesn't follow redirects.
|
|
client := &http.Client{
|
|
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
},
|
|
}
|
|
// nolint:gosec
|
|
return client.Get(u)
|
|
}
|
|
|
|
func (a apiClient) post(path string, body io.Reader) (*http.Response, error) {
|
|
u := fmt.Sprintf("%s%s", a.url, path)
|
|
// nolint:gosec
|
|
return http.Post(u, "application/json", body)
|
|
}
|