Files
grafana/pkg/build/e2e/main.go
2025-06-11 08:43:06 +02:00

175 lines
4.0 KiB
Go

package main
import (
"context"
"fmt"
"log"
"os"
"os/signal"
"path"
"dagger.io/dagger"
"github.com/urfave/cli/v3"
)
func main() {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
if err := NewApp().Run(ctx, os.Args); err != nil {
cancel()
fmt.Println(err)
os.Exit(1)
}
}
func NewApp() *cli.Command {
return &cli.Command{
Name: "e2e",
Usage: "Run the E2E tests for Grafana",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "suite",
Usage: "E2E test suite path (e.g. e2e/various-suite)",
Validator: mustBeDir("suite"),
TakesFile: true,
Required: true,
},
&cli.StringFlag{
Name: "grafana-dir",
Usage: "Path to the grafana/grafana clone directory",
Value: ".",
Validator: mustBeDir("grafana-dir"),
TakesFile: true,
},
&cli.StringFlag{
Name: "package",
Usage: "Path to the grafana tar.gz package",
Value: "grafana.tar.gz",
Validator: mustBeFile("package", false),
TakesFile: true,
},
&cli.StringFlag{
Name: "license",
Usage: "Path to the Grafana Enterprise license file (optional)",
Validator: mustBeFile("license", true),
TakesFile: true,
},
&cli.StringFlag{
Name: "flags",
Usage: "Flags to pass through to the e2e runner",
},
&cli.BoolFlag{
Name: "image-renderer",
Usage: "Install the image renderer plugin",
Value: false,
},
},
Action: run,
}
}
func run(ctx context.Context, cmd *cli.Command) error {
grafanaDir := cmd.String("grafana-dir")
suite := cmd.String("suite")
targzPath := cmd.String("package")
licensePath := cmd.String("license")
imageRenderer := cmd.Bool("image-renderer")
runnerFlags := cmd.String("flags")
d, err := dagger.Connect(ctx)
if err != nil {
return fmt.Errorf("failed to connect to Dagger: %w", err)
}
yarnCache := d.CacheVolume("yarn")
log.Println("grafana dir:", grafanaDir)
log.Println("targz:", targzPath)
log.Println("license path:", licensePath)
grafana := d.Host().Directory(".", dagger.HostDirectoryOpts{
Exclude: []string{"node_modules", "*.tar.gz"},
})
targz := d.Host().File(targzPath)
var license *dagger.File
if licensePath != "" {
license = d.Host().File(licensePath)
}
svc, err := GrafanaService(ctx, d, GrafanaServiceOpts{
GrafanaDir: grafana,
GrafanaTarGz: targz,
YarnCache: yarnCache,
License: license,
InstallImageRenderer: imageRenderer,
})
if err != nil {
return fmt.Errorf("failed to create Grafana service: %w", err)
}
videosDir := path.Join("/src", suite, "videos")
// *spec.ts.mp4
c := RunSuite(d, svc, grafana, yarnCache, suite, runnerFlags)
c, err = c.Sync(ctx)
if err != nil {
return fmt.Errorf("failed to run e2e test suite: %w", err)
}
code, err := c.ExitCode(ctx)
if err != nil {
return fmt.Errorf("failed to get exit code of e2e test suite: %w", err)
}
log.Println("exit code:", code)
// No sync error; export the videos dir
if _, err := c.Directory(videosDir).Export(ctx, "videos"); err != nil {
return fmt.Errorf("failed to export videos directory: %w", err)
}
if code != 0 {
return fmt.Errorf("e2e tests failed with exit code %d", code)
}
log.Println("e2e tests completed successfully")
return nil
}
func mustBeFile(arg string, emptyOk bool) func(string) error {
return func(s string) error {
if s == "" {
if emptyOk {
return nil
}
return cli.Exit(arg+" cannot be empty", 1)
}
stat, err := os.Stat(s)
if err != nil {
return cli.Exit(arg+" does not exist or cannot be read: "+s, 1)
}
if stat.IsDir() {
return cli.Exit(arg+" must be a file, not a directory: "+s, 1)
}
return nil
}
}
func mustBeDir(arg string) func(string) error {
return func(s string) error {
if s == "" {
return cli.Exit(arg+" cannot be empty", 1)
}
stat, err := os.Stat(s)
if err != nil {
return cli.Exit(arg+" does not exist or cannot be read: "+s, 1)
}
if !stat.IsDir() {
return cli.Exit(arg+" must be a directory: "+s, 1)
}
return nil
}
}