1package main
2
3import (
4	"bytes"
5	"context"
6	"fmt"
7	"log"
8	"sync"
9	"time"
10
11	"github.com/golang/protobuf/proto"
12	"github.com/golang/protobuf/ptypes"
13	harness "github.com/envoyproxy/protoc-gen-validate/tests/harness/go"
14)
15
16func Work(wg *sync.WaitGroup, in <-chan TestCase, out chan<- TestResult, goFlag bool, gogoFlag bool, ccFlag bool, javaFlag bool) {
17	for tc := range in {
18		ok, skip := execTestCase(tc, goFlag, gogoFlag, ccFlag, javaFlag)
19		out <- TestResult{ok, skip}
20	}
21	wg.Done()
22}
23
24func execTestCase(tc TestCase, goFlag bool, gogoFlag bool, ccFlag bool, javaFlag bool) (ok, skip bool) {
25	any, err := ptypes.MarshalAny(tc.Message)
26	if err != nil {
27		log.Printf("unable to convert test case %q to Any - %v", tc.Name, err)
28		return false, false
29	}
30
31	b, err := proto.Marshal(&harness.TestCase{Message: any})
32	if err != nil {
33		log.Printf("unable to marshal test case %q - %v", tc.Name, err)
34		return false, false
35	}
36
37	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
38	defer cancel()
39
40	harnesses := Harnesses(goFlag, gogoFlag, ccFlag, javaFlag)
41
42	wg := new(sync.WaitGroup)
43	wg.Add(len(harnesses))
44
45	errs := make(chan error, len(harnesses))
46	skips := make(chan string, len(harnesses))
47
48	for _, h := range harnesses {
49		h := h
50		go func() {
51			defer wg.Done()
52
53			res, err := h.Exec(ctx, bytes.NewReader(b))
54			if err != nil {
55				errs <- err
56				return
57			}
58
59			if res.Error {
60				errs <- fmt.Errorf("%s: internal harness error: %s", h.Name, res.Reason)
61			} else if res.Valid != tc.Valid {
62				if res.AllowFailure {
63					skips <- fmt.Sprintf("%s: ignoring test failure: %s", h.Name, res.Reason)
64				} else if tc.Valid {
65					errs <- fmt.Errorf("%s: expected valid, got: %s", h.Name, res.Reason)
66				} else {
67					errs <- fmt.Errorf("%s: expected invalid, but got valid", h.Name)
68				}
69			}
70		}()
71	}
72
73	wg.Wait()
74	close(errs)
75	close(skips)
76
77	ok = true
78
79	for err := range errs {
80		log.Printf("[%s] %v", tc.Name, err)
81		ok = false
82	}
83	for out := range skips {
84		log.Printf("[%s] %v", tc.Name, out)
85		skip = true
86	}
87
88	return
89}
90