Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/referenceclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

func main() {
err := referenceclient.Run(context.Background(), os.Args, os.Stdin, os.Stdout, os.Stderr, nil)
err := referenceclient.Run(context.Background(), os.Args, os.Stdin, os.Stdout, os.Stderr)
if err != nil {
log.Fatalf("an error occurred running the reference client: %s", err.Error())
}
Expand Down
2 changes: 1 addition & 1 deletion internal/app/connectconformance/connectconformance.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func run( //nolint:gocyclo
"reference-client",
"-p", strconv.Itoa(int(flags.Parallelism)),
}, func(ctx context.Context, args []string, inReader io.ReadCloser, outWriter, errWriter io.WriteCloser) error {
return referenceclient.Run(ctx, args, inReader, outWriter, errWriter, trace)
return referenceclient.RunInReferenceMode(ctx, args, inReader, outWriter, errWriter, trace)
}),
isReferenceImpl: true,
},
Expand Down
61 changes: 20 additions & 41 deletions internal/app/connectconformance/results_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ package connectconformance

import (
"errors"
"fmt"
"strings"
"testing"

"connectrpc.com/conformance/internal"
conformancev1 "connectrpc.com/conformance/internal/gen/proto/go/connectrpc/conformance/v1"
"connectrpc.com/connect"
"github.com/stretchr/testify/assert"
Expand All @@ -41,10 +41,10 @@ func TestResults_SetOutcome(t *testing.T) {
results.setOutcome("known-to-flake/2", true, errors.New("flake"))
results.setOutcome("known-to-flake/3", false, errors.New("flake"))

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 7)
require.Equal(t, lines[0], "FAILED: foo/bar/2:\n\tfail\n")
require.Equal(t, lines[1], "FAILED: foo/bar/3:\n\tfail\n")
Expand All @@ -64,10 +64,10 @@ func TestResults_FailedToStart(t *testing.T) {
{Request: &conformancev1.ClientCompatRequest{TestName: "known-to-fail/1"}},
}, errors.New("fail"))

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 2)
require.Equal(t, lines[0], "FAILED: foo/bar/1:\n\tfail\n")
// Marked as failure even though expected to fail because it failed to start.
Expand All @@ -86,10 +86,10 @@ func TestResults_FailRemaining(t *testing.T) {
{Request: &conformancev1.ClientCompatRequest{TestName: "known-to-fail/2"}},
}, errors.New("something went wrong"))

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 3)
require.Equal(t, lines[0], "FAILED: foo/bar/2:\n\tsomething went wrong\n")
require.Equal(t, lines[1], "INFO: known-to-fail/1 failed (as expected):\n\tfail\n")
Expand All @@ -105,10 +105,10 @@ func TestResults_Failed(t *testing.T) {
results.failed("foo/bar/1", &conformancev1.ClientErrorResult{Message: "fail"})
results.failed("known-to-fail/1", &conformancev1.ClientErrorResult{Message: "fail"})

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 2)
require.Equal(t, lines[0], "FAILED: foo/bar/1:\n\tfail\n")
require.Equal(t, lines[1], "INFO: known-to-fail/1 failed (as expected):\n\tfail\n")
Expand Down Expand Up @@ -136,10 +136,10 @@ func TestResults_Assert(t *testing.T) {
results.assert("known-to-fail/3", testCase1, payload1)
results.assert("known-to-fail/4", testCase2, payload2)

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 6)
require.Contains(t, lines[0], "FAILED: foo/bar/1:\n\t")
require.Contains(t, lines[1], "FAILED: foo/bar/2:\n\t")
Expand Down Expand Up @@ -734,10 +734,10 @@ func TestResults_ServerSideband(t *testing.T) {
results.recordSideband("foo/bar/3", "something awkward in wire format")
results.recordSideband("known-to-fail/1", "something awkward in wire format")

logger := &linePrinter{}
logger := &internal.SimplePrinter{}
success := results.report(logger)
require.False(t, success)
lines := logger.errorLines()
lines := errorMessages(logger.Messages)
require.Len(t, lines, 4)
require.Equal(t, lines[0], "FAILED: foo/bar/2:\n\tsomething awkward in wire format; fail\n")
require.Equal(t, lines[1], "FAILED: foo/bar/3:\n\tsomething awkward in wire format\n")
Expand All @@ -748,7 +748,7 @@ func TestResults_ServerSideband(t *testing.T) {
func TestResults_Report(t *testing.T) {
t.Parallel()
results := newResults(makeKnownFailing(), makeKnownFlaky(), nil)
logger := &linePrinter{}
logger := &internal.SimplePrinter{}

// No test cases? Report success.
success := results.report(logger)
Expand Down Expand Up @@ -860,33 +860,12 @@ func makeKnownFlaky() *testTrie {
return parsePatterns([]string{"known-to-flake/**"})
}

type linePrinter struct {
lines []string
}

func (l *linePrinter) Printf(msg string, args ...any) {
line := fmt.Sprintf(msg, args...)
if !strings.HasSuffix(line, "\n") {
line += "\n"
}
l.lines = append(l.lines, line)
}

func (l *linePrinter) PrefixPrintf(prefix, msg string, args ...any) {
msg = fmt.Sprintf(msg, args...)
line := fmt.Sprintf("%s: %s", prefix, msg)
if !strings.HasSuffix(line, "\n") {
line += "\n"
}
l.lines = append(l.lines, line)
}

func (l *linePrinter) errorLines() []string {
var lines []string
for _, line := range l.lines {
if strings.HasPrefix(line, "FAILED: ") || strings.HasPrefix(line, "INFO: ") {
lines = append(lines, line)
func errorMessages(msgs []string) []string {
var errs []string
for _, msg := range msgs {
if strings.HasPrefix(msg, "FAILED: ") || strings.HasPrefix(msg, "INFO: ") {
errs = append(errs, msg)
}
}
return lines
return errs
}
41 changes: 29 additions & 12 deletions internal/app/referenceclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,18 @@ import (
// is written to the 'out' writer, including any errors encountered during the actual run. Any error
// returned from this function is indicative of an issue with the reader or writer and should not be related
// to the actual run.
func Run(ctx context.Context, args []string, inReader io.ReadCloser, outWriter, _ io.WriteCloser, trace *tracer.Tracer) (retErr error) {
func Run(ctx context.Context, args []string, inReader io.ReadCloser, outWriter, errWriter io.WriteCloser) error {
return run(ctx, false, args, inReader, outWriter, errWriter, nil)
}

// RunInReferenceMode is just like Run except that it performs additional checks
// that only the conformance reference client runs. These checks do not work if
// the client is run as a client under test, only when run as a reference client.
func RunInReferenceMode(ctx context.Context, args []string, inReader io.ReadCloser, outWriter, errWriter io.WriteCloser, tracer *tracer.Tracer) error {
return run(ctx, true, args, inReader, outWriter, errWriter, tracer)
}

func run(ctx context.Context, referenceMode bool, args []string, inReader io.ReadCloser, outWriter, _ io.WriteCloser, trace *tracer.Tracer) (retErr error) {
flags := flag.NewFlagSet(args[0], flag.ContinueOnError)
json := flags.Bool("json", false, "whether to use the JSON format for marshaling / unmarshaling messages")
parallel := flags.Uint("p", uint(runtime.GOMAXPROCS(0))*4, "the number of parallel RPCs to issue")
Expand Down Expand Up @@ -110,7 +121,7 @@ func Run(ctx context.Context, args []string, inReader io.ReadCloser, outWriter,
defer wg.Done()
defer sema.Release(1)

result, err := invoke(ctx, &req, trace)
result, err := invoke(ctx, &req, referenceMode, trace)

// Build the result for the out writer.
resp := &v1.ClientCompatResponse{
Expand All @@ -126,6 +137,11 @@ func Run(ctx context.Context, args []string, inReader io.ReadCloser, outWriter,
},
}
} else {
if !referenceMode {
// clear out reference-mode-specific details
result.HttpStatusCode = nil
result.Feedback = nil
}
resp.Result = &v1.ClientCompatResponse_Response{
Response: result,
}
Expand All @@ -147,7 +163,7 @@ func Run(ctx context.Context, args []string, inReader io.ReadCloser, outWriter,
// returned from this function indicates a runtime/unexpected internal error and is not indicative of a
// Connect error returned from calling an RPC. Any error (i.e. a Connect error) that _is_ returned from
// the actual RPC invocation will be present in the returned ClientResponseResult.
func invoke(ctx context.Context, req *v1.ClientCompatRequest, trace *tracer.Tracer) (*v1.ClientResponseResult, error) {
func invoke(ctx context.Context, req *v1.ClientCompatRequest, referenceMode bool, trace *tracer.Tracer) (*v1.ClientResponseResult, error) { //nolint:gocyclo
tlsConf, err := createTLSConfig(req)
if err != nil {
return nil, err
Expand Down Expand Up @@ -217,14 +233,15 @@ func invoke(ctx context.Context, req *v1.ClientCompatRequest, trace *tracer.Trac
return nil, errors.New("an HTTP version must be specified")
}

// Wrap the transport with a wire interceptor and an optional tracer.
// The wire interceptor wraps a TracingRoundTripper and intercepts values on the
// wire using the tracer framework. Note that 'trace' could be nil, in which case,
// any error traces will simply not be printed. The trace itself will still be built.
transport = newWireInterceptor(transport, trace)

if req.RawRequest != nil {
transport = &rawRequestSender{transport: transport, rawRequest: req.RawRequest}
if referenceMode {
// Wrap the transport with a wire interceptor and an optional tracer.
// The wire interceptor wraps a TracingRoundTripper and intercepts values on the
// wire using the tracer framework. Note that 'trace' could be nil, in which case,
// any error traces will simply not be printed. The trace itself will still be built.
transport = newWireCaptureTransport(transport, trace)
if req.RawRequest != nil {
transport = &rawRequestSender{transport: transport, rawRequest: req.RawRequest}
}
}

// Create client options based on protocol of the implementation
Expand Down Expand Up @@ -314,7 +331,7 @@ func invoke(ctx context.Context, req *v1.ClientCompatRequest, trace *tracer.Trac

switch req.Service {
case conformancev1connect.ConformanceServiceName:
return newInvoker(transport, serverURL, clientOptions).Invoke(ctx, req)
return newInvoker(transport, referenceMode, serverURL, clientOptions).Invoke(ctx, req)
default:
return nil, errors.New("service name " + req.Service + " is not a valid service")
}
Expand Down
Loading