d2/e2etests/report/main.go

218 lines
5.1 KiB
Go
Raw Normal View History

package main
import (
"context"
_ "embed"
"flag"
"fmt"
stdlog "log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"text/template"
"time"
"oss.terrastruct.com/d2/lib/log"
2023-06-14 18:47:43 +00:00
timelib "oss.terrastruct.com/d2/lib/time"
)
//go:embed template.html
var TEMPLATE_HTML string
type TemplateData struct {
Tests []TestItem
}
type TestItem struct {
Name string
ExpSVG *string
GotSVG string
}
func main() {
deltaFlag := false
vFlag := false
testCaseFlag := ""
testSetFlag := ""
2024-02-23 20:12:42 +00:00
testNameFlag := ""
2023-04-28 18:25:22 +00:00
cpuProfileFlag := false
memProfileFlag := false
flag.BoolVar(&deltaFlag, "delta", false, "Generate the report only for cases that changed.")
2024-02-23 20:12:42 +00:00
flag.StringVar(&testNameFlag, "test-name", "E2E", "Name of e2e tests. Defaults to E2E")
flag.StringVar(&testSetFlag, "test-set", "", "Only run set of tests matching this string. e.g. regressions")
flag.StringVar(&testCaseFlag, "test-case", "", "Only run tests matching this string. e.g. all_shapes")
2023-04-28 18:25:22 +00:00
flag.BoolVar(&cpuProfileFlag, "cpuprofile", false, "Profile test cpu usage. `go tool pprof out/cpu.prof`")
flag.BoolVar(&memProfileFlag, "memprofile", false, "Profile test memory usage. `go tool pprof out/mem.prof`")
2023-02-02 18:48:28 +00:00
skipTests := flag.Bool("skip-tests", false, "Skip running tests first")
flag.BoolVar(&vFlag, "v", false, "verbose")
flag.Parse()
vString := ""
if vFlag {
vString = "-v"
}
2024-02-23 20:12:42 +00:00
testMatchString := fmt.Sprintf("-run=Test%s/%s/%s", testNameFlag, testSetFlag, testCaseFlag)
2023-04-28 18:25:22 +00:00
cpuProfileStr := ""
if cpuProfileFlag {
cpuProfileStr = `-cpuprofile=out/cpu.prof`
}
memProfileStr := ""
if memProfileFlag {
memProfileStr = `-memprofile=out/mem.prof`
}
testDir := os.Getenv("TEST_DIR")
if testDir == "" {
testDir = "./e2etests"
}
2023-02-02 18:48:28 +00:00
if !*skipTests {
ctx := context.Background()
2023-06-09 23:44:10 +00:00
2023-06-14 18:47:43 +00:00
ctx, cancel := timelib.WithTimeout(ctx, 2*time.Minute)
defer cancel()
2023-06-09 23:44:10 +00:00
2023-04-29 03:27:06 +00:00
// don't want to pass empty args to CommandContext
args := []string{"test", testDir, testMatchString}
if cpuProfileStr != "" {
args = append(args, cpuProfileStr)
}
if memProfileStr != "" {
args = append(args, memProfileStr)
}
if vString != "" {
args = append(args, vString)
}
cmd := exec.CommandContext(ctx, "go", args...)
2023-02-02 18:48:28 +00:00
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "FORCE_COLOR=1")
cmd.Env = append(cmd.Env, "DEBUG=1")
cmd.Env = append(cmd.Env, "TEST_MODE=on")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Debug(ctx, cmd.String())
_ = cmd.Run()
}
var tests []TestItem
err := filepath.Walk(filepath.Join(testDir, "testdata"), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
files, err := os.ReadDir(path)
if err != nil {
panic(err)
}
var testFile os.FileInfo
for _, f := range files {
if strings.HasSuffix(f.Name(), "exp.svg") {
testFile, _ = f.Info()
break
}
}
if testFile != nil {
testCaseRoot := filepath.Dir(path)
matchTestCase := true
if testCaseFlag != "" {
matchTestCase, _ = regexp.MatchString(testCaseFlag, filepath.Base(testCaseRoot))
}
matchTestSet := true
if testSetFlag != "" {
matchTestSet, _ = regexp.MatchString(testSetFlag, filepath.Base(filepath.Dir(testCaseRoot)))
}
if matchTestSet && matchTestCase {
absPath, err := filepath.Abs(path)
if err != nil {
stdlog.Fatal(err)
}
fullPath := filepath.Join(absPath, testFile.Name())
hasGot := false
gotPath := strings.Replace(fullPath, "exp.svg", "got.svg", 1)
if _, err := os.Stat(gotPath); err == nil {
hasGot = true
}
2022-11-24 04:30:48 +00:00
// e.g. arrowhead_adjustment/dagre
name := filepath.Join(filepath.Base(testCaseRoot), info.Name())
if deltaFlag {
if hasGot {
tests = append(tests, TestItem{
2022-11-24 04:30:48 +00:00
Name: name,
ExpSVG: &fullPath,
GotSVG: gotPath,
})
}
} else {
test := TestItem{
2022-11-24 04:30:48 +00:00
Name: name,
ExpSVG: nil,
GotSVG: fullPath,
}
if hasGot {
test.GotSVG = gotPath
}
tests = append(tests, test)
}
}
}
}
return nil
},
)
if err != nil {
panic(err)
}
if len(tests) > 0 {
tmpl, err := template.New("report").Parse(TEMPLATE_HTML)
if err != nil {
panic(err)
}
2022-11-04 20:01:35 +00:00
path := os.Getenv("REPORT_OUTPUT")
if path == "" {
path = filepath.Join(testDir, "./out/e2e_report.html")
}
err = os.MkdirAll(filepath.Dir(path), 0755)
if err != nil {
stdlog.Fatal(err)
}
f, err := os.Create(path)
if err != nil {
2022-11-04 20:04:26 +00:00
panic(fmt.Errorf("error creating file `%s`. %v", path, err))
}
absReportDir, err := filepath.Abs(filepath.Dir(path))
if err != nil {
stdlog.Fatal(err)
}
// get the test path relative to the report
reportRelPath := func(testPath string) string {
2023-02-10 21:42:30 +00:00
relTestPath, err := filepath.Rel(absReportDir, testPath)
if err != nil {
stdlog.Fatal(err)
}
return relTestPath
}
// update test paths to be relative to report file
for i := range tests {
testItem := &tests[i]
testItem.GotSVG = reportRelPath(testItem.GotSVG)
if testItem.ExpSVG != nil {
*testItem.ExpSVG = reportRelPath(*testItem.ExpSVG)
}
}
if err := tmpl.Execute(f, TemplateData{Tests: tests}); err != nil {
panic(err)
}
}
}