main shinobi / tests / runner / main.go
  1package main
  2
  3import (
  4	"errors"
  5	"flag"
  6	"fmt"
  7	"os"
  8	"path/filepath"
  9	"runtime"
 10)
 11
 12func main() {
 13	reporoot, err := findreporoot()
 14	if err != nil {
 15		die(err)
 16	}
 17
 18	testsroot := filepath.Join(reporoot, "tests")
 19	defaultmake := filepath.Join(testsroot, "shin-make")
 20	defaultcases := filepath.Join(testsroot, "mk")
 21	defaultwork := filepath.Join(testsroot, "work")
 22
 23	var cfg suiteconfig
 24	cfg.reporoot = reporoot
 25	cfg.casesroot = defaultcases
 26	cfg.makepath = defaultmake
 27	cfg.workroot = defaultwork
 28	cfg.jobs = runtime.GOMAXPROCS(0)
 29
 30	flag.StringVar(&cfg.makepath, "make", cfg.makepath, "path to make executable to test")
 31	flag.StringVar(&cfg.workroot, "work", cfg.workroot, "directory to preserve test artifacts")
 32	flag.IntVar(&cfg.jobs, "j", cfg.jobs, "number of workers")
 33	flag.BoolVar(&cfg.keep, "keep", false, "preserve work directories for all cases including succeding ones")
 34	flag.BoolVar(&cfg.verbose, "verbose", false, "print category descriptions")
 35	flag.BoolVar(&cfg.detail, "detail", false, "print category details")
 36	flag.BoolVar(&cfg.list, "list", false, "list matching cases and exit")
 37	flag.Parse()
 38
 39	if cfg.jobs <= 0 {
 40		cfg.jobs = runtime.GOMAXPROCS(0)
 41	}
 42
 43	makepath, err := resolveexecutable(cfg.makepath)
 44	if err != nil {
 45		die(err)
 46	}
 47	cfg.makepath = makepath
 48
 49	selectors := flag.Args()
 50	cases, err := discovercases(cfg.casesroot, selectors)
 51	if err != nil {
 52		die(err)
 53	}
 54	if len(cases) == 0 {
 55		die(errors.New("no matching extracted test cases found"))
 56	}
 57
 58	if cfg.list {
 59		for _, tc := range cases {
 60			fmt.Println(tc.RelPath)
 61		}
 62		return
 63	}
 64
 65	categories := orderedcategories(cases)
 66	suites := orderedsuites(cases)
 67	fmt.Printf("testing %d test cases from %d categories from %d test suites on %s %s\n",
 68		len(cases), len(categories), len(suites), runtime.GOOS, runtime.GOARCH)
 69	if err := os.RemoveAll(cfg.workroot); err != nil {
 70		die(err)
 71	}
 72	if err := os.MkdirAll(cfg.workroot, 0o755); err != nil {
 73		die(err)
 74	}
 75
 76	temproot := filepath.Join(testsroot, ".runner")
 77	if err := os.RemoveAll(temproot); err != nil {
 78		die(err)
 79	}
 80	if err := os.MkdirAll(temproot, 0o755); err != nil {
 81		die(err)
 82	}
 83	cfg.temproot = temproot
 84	defer func() {
 85		if cfg.keep {
 86			return
 87		}
 88		_ = os.RemoveAll(temproot)
 89	}()
 90
 91	summaries := runsuite(cfg, cases, categories)
 92	printsummary(summaries)
 93	fmt.Printf("tested %d test cases from %d categories from %d test suites on %s %s\n",
 94		len(cases), len(categories), len(suites), runtime.GOOS, runtime.GOARCH)
 95	fmt.Printf("logs in tests/work \n")
 96
 97	failed := 0
 98	for _, summary := range summaries {
 99		failed += summary.FailedCases
100	}
101	if failed > 0 {
102		os.Exit(1)
103	}
104}
105
106func findreporoot() (string, error) {
107	wd, err := os.Getwd()
108	if err != nil {
109		return "", err
110	}
111
112	for dir := wd; ; dir = filepath.Dir(dir) {
113		if isdir(filepath.Join(dir, "tests", "mk")) && isdir(filepath.Join(dir, "tests", "runner")) {
114			return dir, nil
115		}
116		parent := filepath.Dir(dir)
117		if parent == dir {
118			return "", errors.New("could not locate repository root")
119		}
120	}
121}
122
123func isdir(path string) bool {
124	info, err := os.Stat(path)
125	return err == nil && info.IsDir()
126}
127
128func die(err error) {
129	fmt.Fprintln(os.Stderr, err)
130	os.Exit(1)
131}