...

Source file src/oss.terrastruct.com/d2/e2etests/report/main.go

Documentation: oss.terrastruct.com/d2/e2etests/report

     1  package main
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"flag"
     7  	"fmt"
     8  	"io/ioutil"
     9  	stdlog "log"
    10  	"os"
    11  	"os/exec"
    12  	"path/filepath"
    13  	"regexp"
    14  	"strings"
    15  	"text/template"
    16  	"time"
    17  
    18  	"oss.terrastruct.com/d2/lib/log"
    19  	timelib "oss.terrastruct.com/d2/lib/time"
    20  )
    21  
    22  //go:embed template.html
    23  var TEMPLATE_HTML string
    24  
    25  type TemplateData struct {
    26  	Tests []TestItem
    27  }
    28  
    29  type TestItem struct {
    30  	Name   string
    31  	ExpSVG *string
    32  	GotSVG string
    33  }
    34  
    35  func main() {
    36  	deltaFlag := false
    37  	vFlag := false
    38  	testCaseFlag := ""
    39  	testSetFlag := ""
    40  	cpuProfileFlag := false
    41  	memProfileFlag := false
    42  	flag.BoolVar(&deltaFlag, "delta", false, "Generate the report only for cases that changed.")
    43  	flag.StringVar(&testSetFlag, "test-set", "", "Only run set of tests matching this string. e.g. regressions")
    44  	flag.StringVar(&testCaseFlag, "test-case", "", "Only run tests matching this string. e.g. all_shapes")
    45  	flag.BoolVar(&cpuProfileFlag, "cpuprofile", false, "Profile test cpu usage. `go tool pprof out/cpu.prof`")
    46  	flag.BoolVar(&memProfileFlag, "memprofile", false, "Profile test memory usage. `go tool pprof out/mem.prof`")
    47  	skipTests := flag.Bool("skip-tests", false, "Skip running tests first")
    48  	flag.BoolVar(&vFlag, "v", false, "verbose")
    49  	flag.Parse()
    50  
    51  	vString := ""
    52  	if vFlag {
    53  		vString = "-v"
    54  	}
    55  	testMatchString := fmt.Sprintf("-run=TestE2E/%s/%s", testSetFlag, testCaseFlag)
    56  
    57  	cpuProfileStr := ""
    58  	if cpuProfileFlag {
    59  		cpuProfileStr = `-cpuprofile=out/cpu.prof`
    60  	}
    61  	memProfileStr := ""
    62  	if memProfileFlag {
    63  		memProfileStr = `-memprofile=out/mem.prof`
    64  	}
    65  
    66  	testDir := os.Getenv("TEST_DIR")
    67  	if testDir == "" {
    68  		testDir = "./e2etests"
    69  	}
    70  
    71  	if !*skipTests {
    72  		ctx := log.Stderr(context.Background())
    73  
    74  		ctx, cancel := timelib.WithTimeout(ctx, 2*time.Minute)
    75  		defer cancel()
    76  
    77  		// don't want to pass empty args to CommandContext
    78  		args := []string{"test", testDir, testMatchString}
    79  		if cpuProfileStr != "" {
    80  			args = append(args, cpuProfileStr)
    81  		}
    82  		if memProfileStr != "" {
    83  			args = append(args, memProfileStr)
    84  		}
    85  		if vString != "" {
    86  			args = append(args, vString)
    87  		}
    88  		cmd := exec.CommandContext(ctx, "go", args...)
    89  		cmd.Env = os.Environ()
    90  		cmd.Env = append(cmd.Env, "FORCE_COLOR=1")
    91  		cmd.Env = append(cmd.Env, "DEBUG=1")
    92  		cmd.Env = append(cmd.Env, "TEST_MODE=on")
    93  		cmd.Stdout = os.Stdout
    94  		cmd.Stderr = os.Stderr
    95  		log.Debug(ctx, cmd.String())
    96  		_ = cmd.Run()
    97  	}
    98  
    99  	var tests []TestItem
   100  	err := filepath.Walk(filepath.Join(testDir, "testdata"), func(path string, info os.FileInfo, err error) error {
   101  		if err != nil {
   102  			return err
   103  		}
   104  		if info.IsDir() {
   105  			files, err := ioutil.ReadDir(path)
   106  			if err != nil {
   107  				panic(err)
   108  			}
   109  
   110  			var testFile os.FileInfo
   111  			for _, f := range files {
   112  				if strings.HasSuffix(f.Name(), "exp.svg") {
   113  					testFile = f
   114  					break
   115  				}
   116  			}
   117  
   118  			if testFile != nil {
   119  				testCaseRoot := filepath.Dir(path)
   120  				matchTestCase := true
   121  				if testCaseFlag != "" {
   122  					matchTestCase, _ = regexp.MatchString(testCaseFlag, filepath.Base(testCaseRoot))
   123  				}
   124  				matchTestSet := true
   125  				if testSetFlag != "" {
   126  					matchTestSet, _ = regexp.MatchString(testSetFlag, filepath.Base(filepath.Dir(testCaseRoot)))
   127  				}
   128  
   129  				if matchTestSet && matchTestCase {
   130  					absPath, err := filepath.Abs(path)
   131  					if err != nil {
   132  						stdlog.Fatal(err)
   133  					}
   134  					fullPath := filepath.Join(absPath, testFile.Name())
   135  					hasGot := false
   136  					gotPath := strings.Replace(fullPath, "exp.svg", "got.svg", 1)
   137  					if _, err := os.Stat(gotPath); err == nil {
   138  						hasGot = true
   139  					}
   140  					// e.g. arrowhead_adjustment/dagre
   141  					name := filepath.Join(filepath.Base(testCaseRoot), info.Name())
   142  					if deltaFlag {
   143  						if hasGot {
   144  							tests = append(tests, TestItem{
   145  								Name:   name,
   146  								ExpSVG: &fullPath,
   147  								GotSVG: gotPath,
   148  							})
   149  						}
   150  					} else {
   151  						test := TestItem{
   152  							Name:   name,
   153  							ExpSVG: nil,
   154  							GotSVG: fullPath,
   155  						}
   156  						if hasGot {
   157  							test.GotSVG = gotPath
   158  						}
   159  						tests = append(tests, test)
   160  					}
   161  				}
   162  			}
   163  		}
   164  		return nil
   165  	},
   166  	)
   167  	if err != nil {
   168  		panic(err)
   169  	}
   170  
   171  	if len(tests) > 0 {
   172  		tmpl, err := template.New("report").Parse(TEMPLATE_HTML)
   173  		if err != nil {
   174  			panic(err)
   175  		}
   176  
   177  		path := os.Getenv("REPORT_OUTPUT")
   178  		if path == "" {
   179  			path = filepath.Join(testDir, "./out/e2e_report.html")
   180  		}
   181  		err = os.MkdirAll(filepath.Dir(path), 0755)
   182  		if err != nil {
   183  			stdlog.Fatal(err)
   184  		}
   185  		f, err := os.Create(path)
   186  		if err != nil {
   187  			panic(fmt.Errorf("error creating file `%s`. %v", path, err))
   188  		}
   189  		absReportDir, err := filepath.Abs(filepath.Dir(path))
   190  		if err != nil {
   191  			stdlog.Fatal(err)
   192  		}
   193  
   194  		// get the test path relative to the report
   195  		reportRelPath := func(testPath string) string {
   196  			relTestPath, err := filepath.Rel(absReportDir, testPath)
   197  			if err != nil {
   198  				stdlog.Fatal(err)
   199  			}
   200  			return relTestPath
   201  		}
   202  
   203  		// update test paths to be relative to report file
   204  		for i := range tests {
   205  			testItem := &tests[i]
   206  			testItem.GotSVG = reportRelPath(testItem.GotSVG)
   207  			if testItem.ExpSVG != nil {
   208  				*testItem.ExpSVG = reportRelPath(*testItem.ExpSVG)
   209  			}
   210  		}
   211  
   212  		if err := tmpl.Execute(f, TemplateData{Tests: tests}); err != nil {
   213  			panic(err)
   214  		}
   215  	}
   216  }
   217  

View as plain text