Skip to content

Commit

Permalink
fix: Testing of chromium distributed by grafana-image-renderer
Browse files Browse the repository at this point in the history
* We need to do some basic test using chromium shipped by Grafana image renderer before using it. We were testing it using `--help` flag which does not exist on the application. If it works, it hangs which is not what we want.

* This commit fixes this test by using a command that returns upon successful execution. We also use a timeout just in case to avoid the command hanging in there forever.

* We also setup a special home directory for chromium and inject `XDG_CONFIG_HOME` and `XDG_CONFIG_HOME` env vars in chromium process. This avoids chromium attempting to create directories in read-only folders.

Signed-off-by: Mahendra Paipuri <mahendra.paipuri@gmail.com>
  • Loading branch information
mahendrapaipuri committed Jan 7, 2025
1 parent 1d721a4 commit 0aadedb
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 30 deletions.
26 changes: 24 additions & 2 deletions pkg/plugin/chrome/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os/exec"
"path/filepath"
"slices"
"time"

"github.com/chromedp/chromedp"
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
Expand All @@ -15,7 +16,10 @@ import (
)

// Path to chrome executable.
var chromeExec string
var (
chromeExec string
chromeHomeDir string
)

func init() {
// Get Grafana data path based on path of current executable
Expand All @@ -28,6 +32,12 @@ func init() {
// Now we attempt to get install_dir directory which is Grafana data path
dataPath := filepath.Dir(filepath.Dir(filepath.Dir(pluginExe)))

// Create a folder to use it as HOME for chrome process
homeDir := filepath.Join(dataPath, ".chrome")
if err := os.MkdirAll(homeDir, 0o750); err == nil {
chromeHomeDir = homeDir
}

// Walk through grafana-image-renderer plugin dir to find chrome executable
_ = filepath.Walk(filepath.Join(dataPath, "plugins", "grafana-image-renderer"),
func(path string, info fs.FileInfo, err error) error {
Expand All @@ -43,7 +53,13 @@ func init() {
// even a "usable" chrome (for instance chromium installed using snap on Ubuntu)
// exists.
// So, test the chromium before using it
if _, err := exec.Command(path, "--help").Output(); err == nil {
//
// Use a timeout to avoid indefinite hanging
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

// This command should print an empty DOM and exit
if _, err := exec.CommandContext(ctx, path, "--headless", "--no-sandbox", "--disable-gpu", "--dump-dom").Output(); err == nil {
chromeExec = path
}

Expand Down Expand Up @@ -71,6 +87,12 @@ func NewLocalBrowserInstance(ctx context.Context, logger log.Logger, insecureSki
chromedp.DisableGPU,
)

// If we managed to create a home for chrome in a "writable" location, set it to chrome options
if chromeHomeDir != "" {
logger.Debug("created home directory for chromium process", "home", chromeHomeDir)
chromeOptions = append(chromeOptions, chromedp.Env("XDG_CONFIG_HOME="+chromeHomeDir, "XDG_CACHE_HOME="+chromeHomeDir))
}

// If chromExec is not empty we found chrome binary shipped by grafana-image-renderer
if chromeExec != "" {
logger.Info("chrome executable provided by grafana-image-renderer will be used", "chrome", chromeExec)
Expand Down
60 changes: 32 additions & 28 deletions pkg/plugin/dashboard/panels_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,6 @@ func TestDashboardFetchWithLocalChrome(t *testing.T) {
}

Convey("When fetching a Dashboard", t, func() {
// Get CWD
cwd, err := os.Getwd()

Convey("getting CWD should not error", func() {
So(err, ShouldBeNil)
})

// Read sample HTML file
data, err := os.ReadFile(filepath.Join(cwd, "testdata/dashboard.html"))

Convey("setup a dashboard HTML page should not error", func() {
So(err, ShouldBeNil)
})

chromeInstance, err := chrome.NewLocalBrowserInstance(context.Background(), log.NewNullLogger(), true)
defer chromeInstance.Close(log.NewNullLogger()) //nolint:staticcheck

Expand All @@ -76,6 +62,22 @@ func TestDashboardFetchWithLocalChrome(t *testing.T) {
requestCookie := ""

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get CWD
cwd, err := os.Getwd()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

return
}

// Read sample HTML file
data, err := os.ReadFile(filepath.Join(cwd, "testdata/dashboard.html"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

return
}

muLock.Lock()
requestURI = append(requestURI, r.RequestURI)
requestCookie = r.Header.Get(backend.CookiesHeaderName)
Expand Down Expand Up @@ -149,20 +151,6 @@ func TestDashboardFetchWithRemoteChrome(t *testing.T) {
}

Convey("When fetching a Dashboard", t, func() {
// Get CWD
cwd, err := os.Getwd()

Convey("getting CWD should not error", func() {
So(err, ShouldBeNil)
})

// Read sample HTML file
data, err := os.ReadFile(filepath.Join(cwd, "testdata/dashboard.html"))

Convey("setup a dashboard HTML page should not error", func() {
So(err, ShouldBeNil)
})

chromeInstance, err := chrome.NewRemoteBrowserInstance(
context.Background(),
log.NewNullLogger(),
Expand All @@ -178,6 +166,22 @@ func TestDashboardFetchWithRemoteChrome(t *testing.T) {
requestCookie := ""

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get CWD
cwd, err := os.Getwd()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

return
}

// Read sample HTML file
data, err := os.ReadFile(filepath.Join(cwd, "testdata/dashboard.html"))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)

return
}

muLock.Lock()
requestURI = append(requestURI, r.RequestURI)
requestCookie = r.Header.Get(backend.CookiesHeaderName)
Expand Down

0 comments on commit 0aadedb

Please sign in to comment.