1package main 2 3import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "io" 8 "os" 9 "os/exec" 10 "runtime" 11 "sync" 12 13 "strings" 14 15 "github.com/golang/protobuf/proto" 16 harness "github.com/envoyproxy/protoc-gen-validate/tests/harness/go" 17 "golang.org/x/net/context" 18) 19 20func Harnesses(goFlag bool, gogoFlag bool, ccFlag bool, javaFlag bool) []Harness { 21 harnesses := make([]Harness, 0) 22 if goFlag { 23 harnesses = append(harnesses, InitHarness("tests/harness/go/main/go-harness")) 24 } 25 if gogoFlag { 26 harnesses = append(harnesses, InitHarness("tests/harness/gogo/main/go-harness")) 27 } 28 if ccFlag { 29 harnesses = append(harnesses, InitHarness("tests/harness/cc/cc-harness")) 30 } 31 if javaFlag { 32 harnesses = append(harnesses, InitHarness("tests/harness/java/java-harness")) 33 } 34 return harnesses 35} 36 37type Harness struct { 38 Name string 39 Exec func(context.Context, io.Reader) (*harness.TestResult, error) 40} 41 42func InitHarness(cmd string, args ...string) Harness { 43 if runtime.GOOS == "windows" { 44 // Bazel runfiles are not symlinked in on windows, 45 // so we have to use the manifest instead. If the manifest 46 // doesn't exist, assume we're running in a non-Bazel context 47 f, err := os.Open("MANIFEST") 48 if err == nil { 49 defer f.Close() 50 51 s := bufio.NewScanner(f) 52 manifest := map[string]string{} 53 for s.Scan() { 54 values := strings.Split(s.Text(), " ") 55 manifest[values[0]] = values[1] 56 } 57 for k, v := range manifest { 58 if strings.Contains(k, cmd) { 59 cmd = v 60 } 61 } 62 } 63 } 64 65 return Harness{ 66 Name: cmd, 67 Exec: initHarness(cmd, args...), 68 } 69} 70 71func initHarness(cmd string, args ...string) func(context.Context, io.Reader) (*harness.TestResult, error) { 72 return func(ctx context.Context, r io.Reader) (*harness.TestResult, error) { 73 out, errs := getBuf(), getBuf() 74 defer relBuf(out) 75 defer relBuf(errs) 76 77 cmd := exec.CommandContext(ctx, cmd, args...) 78 cmd.Stdin = r 79 cmd.Stdout = out 80 cmd.Stderr = errs 81 82 if err := cmd.Run(); err != nil { 83 return nil, fmt.Errorf("[%s] failed execution (%v) - captured stderr:\n%s", cmdStr(cmd), err, errs.String()) 84 } 85 86 res := new(harness.TestResult) 87 if err := proto.Unmarshal(out.Bytes(), res); err != nil { 88 return nil, fmt.Errorf("[%s] failed to unmarshal result: %v", cmdStr(cmd), err) 89 } 90 91 return res, nil 92 } 93} 94 95var bufPool = &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }} 96 97func getBuf() *bytes.Buffer { 98 return bufPool.Get().(*bytes.Buffer) 99} 100 101func relBuf(b *bytes.Buffer) { 102 b.Reset() 103 bufPool.Put(b) 104} 105 106func cmdStr(cmd *exec.Cmd) string { 107 return fmt.Sprintf("%s %s", cmd.Path, strings.Join(cmd.Args, " ")) 108} 109