mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 04:04:00 -06:00
242 lines
7.2 KiB
Go
242 lines
7.2 KiB
Go
package rendering
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/pkg/infra/log"
|
|
"github.com/grafana/grafana/pkg/models"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
func TestGetUrl(t *testing.T) {
|
|
path := "render/d-solo/5SdHCadmz/panel-tests-graph?orgId=1&from=1587390211965&to=1587393811965&panelId=5&width=1000&height=500&tz=Europe%2FStockholm"
|
|
cfg := setting.NewCfg()
|
|
rs := &RenderingService{
|
|
Cfg: cfg,
|
|
}
|
|
|
|
t.Run("When renderer and callback url configured should return callback url plus path", func(t *testing.T) {
|
|
rs.Cfg.RendererUrl = "http://localhost:8081/render"
|
|
rs.Cfg.RendererCallbackUrl = "http://public-grafana.com/"
|
|
url := rs.getGrafanaCallbackURL(path)
|
|
require.Equal(t, rs.Cfg.RendererCallbackUrl+path+"&render=1", url)
|
|
})
|
|
|
|
t.Run("When renderer url not configured", func(t *testing.T) {
|
|
rs.Cfg.RendererUrl = ""
|
|
rs.domain = "localhost"
|
|
rs.Cfg.HTTPPort = "3000"
|
|
|
|
t.Run("And protocol HTTP configured should return expected path", func(t *testing.T) {
|
|
rs.Cfg.ServeFromSubPath = false
|
|
rs.Cfg.AppSubURL = ""
|
|
rs.Cfg.Protocol = setting.HTTPScheme
|
|
url := rs.getGrafanaCallbackURL(path)
|
|
require.Equal(t, "http://localhost:3000/"+path+"&render=1", url)
|
|
|
|
t.Run("And serve from sub path should return expected path", func(t *testing.T) {
|
|
rs.Cfg.ServeFromSubPath = true
|
|
rs.Cfg.AppSubURL = "/grafana"
|
|
url := rs.getGrafanaCallbackURL(path)
|
|
require.Equal(t, "http://localhost:3000/grafana/"+path+"&render=1", url)
|
|
})
|
|
})
|
|
|
|
t.Run("And protocol HTTPS configured should return expected path", func(t *testing.T) {
|
|
rs.Cfg.ServeFromSubPath = false
|
|
rs.Cfg.AppSubURL = ""
|
|
rs.Cfg.Protocol = setting.HTTPSScheme
|
|
url := rs.getGrafanaCallbackURL(path)
|
|
require.Equal(t, "https://localhost:3000/"+path+"&render=1", url)
|
|
})
|
|
|
|
t.Run("And protocol HTTP2 configured should return expected path", func(t *testing.T) {
|
|
rs.Cfg.ServeFromSubPath = false
|
|
rs.Cfg.AppSubURL = ""
|
|
rs.Cfg.Protocol = setting.HTTP2Scheme
|
|
url := rs.getGrafanaCallbackURL(path)
|
|
require.Equal(t, "https://localhost:3000/"+path+"&render=1", url)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestRenderErrorImage(t *testing.T) {
|
|
path, err := filepath.Abs("../../../")
|
|
require.NoError(t, err)
|
|
|
|
rs := RenderingService{
|
|
Cfg: &setting.Cfg{
|
|
HomePath: path,
|
|
},
|
|
}
|
|
t.Run("No theme set returns error image with dark theme", func(t *testing.T) {
|
|
result, err := rs.RenderErrorImage("", nil)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, result.FilePath, path+"/public/img/rendering_error_dark.png")
|
|
})
|
|
|
|
t.Run("Timeout error returns timeout error image", func(t *testing.T) {
|
|
result, err := rs.RenderErrorImage(models.ThemeLight, ErrTimeout)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, result.FilePath, path+"/public/img/rendering_timeout_light.png")
|
|
})
|
|
|
|
t.Run("Generic error returns error image", func(t *testing.T) {
|
|
result, err := rs.RenderErrorImage(models.ThemeLight, errors.New("an error"))
|
|
require.NoError(t, err)
|
|
assert.Equal(t, result.FilePath, path+"/public/img/rendering_error_light.png")
|
|
})
|
|
|
|
t.Run("Unknown image path returns error", func(t *testing.T) {
|
|
result, err := rs.RenderErrorImage("abc", errors.New("random error"))
|
|
assert.Error(t, err)
|
|
assert.Nil(t, result)
|
|
})
|
|
}
|
|
|
|
func TestRenderUnavailableError(t *testing.T) {
|
|
rs := RenderingService{
|
|
Cfg: &setting.Cfg{},
|
|
log: log.New("test"),
|
|
RendererPluginManager: &dummyPluginManager{},
|
|
}
|
|
opts := Opts{ErrorOpts: ErrorOpts{ErrorRenderUnavailable: true}}
|
|
result, err := rs.Render(context.Background(), RenderPNG, opts, nil)
|
|
assert.Equal(t, ErrRenderUnavailable, err)
|
|
assert.Nil(t, result)
|
|
}
|
|
|
|
func TestRenderLimitImage(t *testing.T) {
|
|
path, err := filepath.Abs("../../../")
|
|
require.NoError(t, err)
|
|
|
|
rs := RenderingService{
|
|
Cfg: &setting.Cfg{
|
|
HomePath: path,
|
|
},
|
|
inProgressCount: 2,
|
|
log: log.New("test"),
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
theme models.Theme
|
|
expected string
|
|
}{
|
|
{
|
|
name: "Light theme returns light image",
|
|
theme: models.ThemeLight,
|
|
expected: path + "/public/img/rendering_limit_light.png",
|
|
},
|
|
{
|
|
name: "Dark theme returns dark image",
|
|
theme: models.ThemeDark,
|
|
expected: path + "/public/img/rendering_limit_dark.png",
|
|
},
|
|
{
|
|
name: "No theme returns dark image",
|
|
theme: "",
|
|
expected: path + "/public/img/rendering_limit_dark.png",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
opts := Opts{Theme: tc.theme, CommonOpts: CommonOpts{ConcurrentLimit: 1}}
|
|
result, err := rs.Render(context.Background(), RenderPNG, opts, nil)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tc.expected, result.FilePath)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRenderLimitImageError(t *testing.T) {
|
|
rs := RenderingService{
|
|
Cfg: &setting.Cfg{},
|
|
inProgressCount: 2,
|
|
log: log.New("test"),
|
|
}
|
|
opts := Opts{
|
|
CommonOpts: CommonOpts{ConcurrentLimit: 1},
|
|
ErrorOpts: ErrorOpts{ErrorConcurrentLimitReached: true},
|
|
Theme: models.ThemeDark,
|
|
}
|
|
result, err := rs.Render(context.Background(), RenderPNG, opts, nil)
|
|
assert.Equal(t, ErrConcurrentLimitReached, err)
|
|
assert.Nil(t, result)
|
|
}
|
|
|
|
func TestRenderingServiceGetRemotePluginVersion(t *testing.T) {
|
|
cfg := setting.NewCfg()
|
|
rs := &RenderingService{
|
|
Cfg: cfg,
|
|
log: log.New("rendering-test"),
|
|
}
|
|
|
|
t.Run("When renderer responds with correct version should return that version", func(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, err := w.Write([]byte("{\"version\":\"2.7.1828\"}"))
|
|
require.NoError(t, err)
|
|
}))
|
|
defer server.Close()
|
|
|
|
rs.Cfg.RendererUrl = server.URL + "/render"
|
|
version, err := rs.getRemotePluginVersion()
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, "2.7.1828", version)
|
|
})
|
|
|
|
t.Run("When renderer responds with 404 should assume a valid but old version", func(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
}))
|
|
defer server.Close()
|
|
|
|
rs.Cfg.RendererUrl = server.URL + "/render"
|
|
version, err := rs.getRemotePluginVersion()
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, version, "1.0.0")
|
|
})
|
|
|
|
t.Run("When renderer responds with 500 should retry until success", func(t *testing.T) {
|
|
tries := uint(0)
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
tries++
|
|
|
|
if tries < remoteVersionFetchRetries {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
} else {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, err := w.Write([]byte("{\"version\":\"3.1.4159\"}"))
|
|
require.NoError(t, err)
|
|
cancel()
|
|
}
|
|
}))
|
|
defer server.Close()
|
|
|
|
rs.Cfg.RendererUrl = server.URL + "/render"
|
|
remoteVersionFetchInterval = time.Millisecond
|
|
remoteVersionFetchRetries = 5
|
|
go func() {
|
|
require.NoError(t, rs.Run(ctx))
|
|
}()
|
|
|
|
require.Eventually(t, func() bool { return rs.Version() == "3.1.4159" }, time.Second, time.Millisecond)
|
|
})
|
|
}
|