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
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
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
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
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
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