harness.go 2.8 KB

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