Beispiel #1
0
func Benchmark_TChannel_YARPCToYARPC(b *testing.B) {
	serverCh, err := tchannel.NewChannel("server", nil)
	require.NoError(b, err, "failed to build server TChannel")

	serverCfg := yarpc.Config{
		Name:     "server",
		Inbounds: []transport.Inbound{ytchannel.NewInbound(serverCh)},
	}

	clientCh, err := tchannel.NewChannel("client", nil)
	require.NoError(b, err, "failed to build client TChannel")

	// no defer close on channels because YARPC will take care of that

	withDispatcher(b, serverCfg, func(server yarpc.Dispatcher) {
		server.Register(raw.Procedure("echo", yarpcEcho))

		// Need server already started to build client config
		clientCfg := yarpc.Config{
			Name: "client",
			Outbounds: yarpc.Outbounds{
				"server": {
					Unary: ytchannel.NewOutbound(clientCh, ytchannel.HostPort(serverCh.PeerInfo().HostPort)),
				},
			},
		}
		withDispatcher(b, clientCfg, func(client yarpc.Dispatcher) {
			b.ResetTimer()
			runYARPCClient(b, raw.New(client.Channel("server")))
		})
	})
}
Beispiel #2
0
func Benchmark_TChannel_YARPCToTChannel(b *testing.B) {
	serverCh, err := tchannel.NewChannel("server", nil)
	require.NoError(b, err, "failed to build server TChannel")
	defer serverCh.Close()

	serverCh.Register(traw.Wrap(tchannelEcho{t: b}), "echo")
	require.NoError(b, serverCh.ListenAndServe(":0"), "failed to start up TChannel")

	clientCh, err := tchannel.NewChannel("client", nil)
	require.NoError(b, err, "failed to build client TChannel")

	clientCfg := yarpc.Config{
		Name: "client",
		Outbounds: yarpc.Outbounds{
			"server": {
				Unary: ytchannel.NewOutbound(clientCh, ytchannel.HostPort(serverCh.PeerInfo().HostPort)),
			},
		},
	}

	withDispatcher(b, clientCfg, func(client yarpc.Dispatcher) {
		b.ResetTimer()
		runYARPCClient(b, raw.New(client.Channel("server")))
	})
}
Beispiel #3
0
func withConnectedClient(t *testing.T, recorder *Recorder, f func(raw.Client)) {
	serverHTTP := http.NewInbound(":0")

	serverDisp := yarpc.NewDispatcher(yarpc.Config{
		Name:     "server",
		Inbounds: []transport.Inbound{serverHTTP},
	})

	serverDisp.Register(raw.Procedure("hello",
		func(ctx context.Context, reqMeta yarpc.ReqMeta, body []byte) ([]byte, yarpc.ResMeta, error) {
			return append(body, []byte(", World")...), nil, nil
		}))

	require.NoError(t, serverDisp.Start())
	defer serverDisp.Stop()

	clientDisp := yarpc.NewDispatcher(yarpc.Config{
		Name: "client",
		Outbounds: yarpc.Outbounds{
			"server": {
				Unary: http.NewOutbound(fmt.Sprintf("http://%s", serverHTTP.Addr().String())),
			},
		},
		Filter: recorder,
	})
	require.NoError(t, clientDisp.Start())
	defer clientDisp.Stop()

	client := raw.New(clientDisp.Channel("server"))
	f(client)
}
Beispiel #4
0
func rawCall(dispatcher yarpc.Dispatcher, headers yarpc.Headers, procedure string,
	token []byte) ([]byte, yarpc.CallResMeta, error) {
	client := raw.New(dispatcher.Channel(serverName))

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	reqMeta := yarpc.NewReqMeta().Procedure(procedure).Headers(headers)
	resBody, resMeta, err := client.Call(ctx, reqMeta, token)

	return resBody, resMeta, err
}
Beispiel #5
0
func withDisconnectedClient(t *testing.T, recorder *Recorder, f func(raw.Client)) {
	clientDisp := yarpc.NewDispatcher(yarpc.Config{
		Name: "client",
		Outbounds: yarpc.Outbounds{
			"server": {
				Unary: http.NewOutbound("http://localhost:65535"),
			},
		},
		Filter: recorder,
	})
	require.NoError(t, clientDisp.Start())
	defer clientDisp.Stop()

	client := raw.New(clientDisp.Channel("server"))
	f(client)
}
Beispiel #6
0
func Benchmark_HTTP_YARPCToNetHTTP(b *testing.B) {
	clientCfg := yarpc.Config{
		Name: "client",
		Outbounds: yarpc.Outbounds{
			"server": {
				Unary: yhttp.NewOutbound("http://localhost:8998"),
			},
		},
	}

	withHTTPServer(b, ":8998", httpEcho(b), func() {
		withDispatcher(b, clientCfg, func(client yarpc.Dispatcher) {
			b.ResetTimer()
			runYARPCClient(b, raw.New(client.Channel("server")))
		})
	})
}
Beispiel #7
0
// Raw implements the 'raw' behavior.
func Raw(t crossdock.T) {
	t = createEchoT("raw", t)
	fatals := crossdock.Fatals(t)

	dispatcher := disp.Create(t)
	fatals.NoError(dispatcher.Start(), "could not start Dispatcher")
	defer dispatcher.Stop()

	client := raw.New(dispatcher.Channel("yarpc-test"))
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	token := random.Bytes(5)
	resBody, _, err := client.Call(ctx, yarpc.NewReqMeta().Procedure("echo/raw"), token)

	crossdock.Fatals(t).NoError(err, "call to echo/raw failed: %v", err)
	crossdock.Assert(t).True(bytes.Equal(token, resBody), "server said: %v", resBody)
}
Beispiel #8
0
// runRaw tests if a yarpc client returns a remote timeout error behind the
// TimeoutError interface when a remote http handler returns a handler timeout.
func runRaw(t crossdock.T, disp yarpc.Dispatcher) {
	assert := crossdock.Assert(t)
	fatals := crossdock.Fatals(t)

	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	ch := raw.New(disp.Channel("yarpc-test"))
	_, _, err := ch.Call(ctx, yarpc.NewReqMeta().Procedure("handlertimeout/raw"), nil)
	fatals.Error(err, "expected an error")

	if transport.IsBadRequestError(err) {
		t.Skipf("handlertimeout/raw method not implemented: %v", err)
		return
	}

	assert.True(transport.IsTimeoutError(err), "returns a TimeoutError: %T", err)

	form := strings.HasPrefix(err.Error(),
		`Timeout: call to procedure "handlertimeout/raw" of service "service" from caller "caller" timed out after`)
	assert.True(form, "must be a remote handler timeout: %q", err.Error())
}
Beispiel #9
0
// Raw starts an http run using raw encoding
func Raw(t crossdock.T, dispatcher yarpc.Dispatcher) {
	fatals := crossdock.Fatals(t)

	client := raw.New(dispatcher.Channel("oneway-test"))
	ctx := context.Background()

	token := []byte(getRandomID())
	ack, err := client.CallOneway(ctx, yarpc.NewReqMeta().Procedure("echo/raw"), token)

	// ensure channel hasn't been filled yet
	select {
	case <-serverCalledBack:
		fatals.FailNow("oneway raw test failed", "client waited for server to fill channel")
	default:
	}

	fatals.NoError(err, "call to oneway/raw failed: %v", err)
	fatals.NotNil(ack, "ack is nil")

	serverToken := <-serverCalledBack
	fatals.Equal(token, serverToken, "Client/Server token mismatch.")
}
Beispiel #10
0
func Benchmark_HTTP_YARPCToYARPC(b *testing.B) {
	serverCfg := yarpc.Config{
		Name:     "server",
		Inbounds: []transport.Inbound{yhttp.NewInbound(":8999")},
	}

	clientCfg := yarpc.Config{
		Name: "client",
		Outbounds: yarpc.Outbounds{
			"server": {
				Unary: yhttp.NewOutbound("http://localhost:8999"),
			},
		},
	}

	withDispatcher(b, serverCfg, func(server yarpc.Dispatcher) {
		server.Register(raw.Procedure("echo", yarpcEcho))
		withDispatcher(b, clientCfg, func(client yarpc.Dispatcher) {
			b.ResetTimer()
			runYARPCClient(b, raw.New(client.Channel("server")))
		})
	})
}
Beispiel #11
0
// Run tests if a yarpc client returns correctly a client timeout error behind
// the TimeoutError interface when the context deadline is reached while the
// server is taking too long to respond.
func Run(t crossdock.T) {
	assert := crossdock.Assert(t)
	fatals := crossdock.Fatals(t)

	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()

	dispatcher := disp.Create(t)
	fatals.NoError(dispatcher.Start(), "could not start Dispatcher")
	defer dispatcher.Stop()

	ch := raw.New(dispatcher.Channel("yarpc-test"))
	_, _, err := ch.Call(ctx, yarpc.NewReqMeta().Procedure("sleep/raw"), nil)
	fatals.Error(err, "expected a failure for timeout")

	if transport.IsBadRequestError(err) {
		t.Skipf("sleep/raw method not implemented: %v", err)
		return
	}

	assert.True(transport.IsTimeoutError(err), "returns a TimeoutError: %T", err)

	trans := t.Param(params.Transport)
	switch trans {
	case "http":
		form := strings.HasPrefix(err.Error(),
			`client timeout for procedure "sleep/raw" of service "yarpc-test" after`)
		assert.True(form, "should be a client timeout: %q", err.Error())
	case "tchannel":
		form := strings.HasPrefix(err.Error(), `timeout`)
		assert.True(form,
			"should be a remote timeout (we cant represent client timeout with tchannel): %q",
			err.Error())
	default:
		fatals.Fail("", "unknown transport %q", trans)
	}
}
Beispiel #12
0
func TestHandlerPanic(t *testing.T) {
	inbound := NewInbound("localhost:0")
	serverDispatcher := yarpc.NewDispatcher(yarpc.Config{
		Name:     "yarpc-test",
		Inbounds: []transport.Inbound{inbound},
	})
	serverDispatcher.Register([]transport.Registrant{
		{
			Procedure:   "panic",
			HandlerSpec: transport.NewUnaryHandlerSpec(panickedHandler{}),
		},
	})

	require.NoError(t, serverDispatcher.Start())
	defer serverDispatcher.Stop()

	clientDispatcher := yarpc.NewDispatcher(yarpc.Config{
		Name: "yarpc-test-client",
		Outbounds: yarpc.Outbounds{
			"yarpc-test": {
				Unary: NewOutbound(fmt.Sprintf("http://%s", inbound.Addr().String())),
			},
		},
	})
	require.NoError(t, clientDispatcher.Start())
	defer clientDispatcher.Stop()

	client := raw.New(clientDispatcher.Channel("yarpc-test"))
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	_, _, err := client.Call(ctx, yarpc.NewReqMeta().Procedure("panic"), []byte{})

	assert.True(t, transport.IsUnexpectedError(err), "Must be an UnexpectedError")
	assert.Equal(t,
		`UnexpectedError: error for procedure "panic" of service "yarpc-test": panic: oops I panicked!`,
		err.Error())
}
Beispiel #13
0
// Run runs the headers behavior
func Run(t crossdock.T) {
	t = createHeadersT(t)

	fatals := crossdock.Fatals(t)
	assert := crossdock.Assert(t)
	checks := crossdock.Checks(t)

	dispatcher := disp.Create(t)
	fatals.NoError(dispatcher.Start(), "could not start Dispatcher")
	defer dispatcher.Stop()

	var caller headerCaller
	encoding := t.Param(params.Encoding)
	switch encoding {
	case "raw":
		caller = rawCaller{raw.New(dispatcher.Channel("yarpc-test"))}
	case "json":
		caller = jsonCaller{json.New(dispatcher.Channel("yarpc-test"))}
	case "thrift":
		caller = thriftCaller{echoclient.New(dispatcher.Channel("yarpc-test"))}
	default:
		fatals.Fail("", "unknown encoding %q", encoding)
	}

	token1 := random.String(10)
	token2 := random.String(10)

	tests := []struct {
		desc string
		give yarpc.Headers
		want yarpc.Headers
	}{
		{
			"valid headers",
			yarpc.NewHeaders().With("token1", token1).With("token2", token2),
			yarpc.NewHeaders().With("token1", token1).With("token2", token2),
		},
		{
			"non-string values",
			yarpc.NewHeaders().With("token", "42"),
			yarpc.NewHeaders().With("token", "42"),
		},
		{
			"empty strings",
			yarpc.NewHeaders().With("token", ""),
			yarpc.NewHeaders().With("token", ""),
		},
		{
			"no headers",
			yarpc.Headers{},
			yarpc.NewHeaders(),
		},
		{
			"empty map",
			yarpc.NewHeaders(),
			yarpc.NewHeaders(),
		},
		{
			"varying casing",
			yarpc.NewHeaders().With("ToKeN1", token1).With("tOkEn2", token2),
			yarpc.NewHeaders().With("token1", token1).With("token2", token2),
		},
		{
			"http header conflict",
			yarpc.NewHeaders().With("Rpc-Procedure", "does not exist"),
			yarpc.NewHeaders().With("rpc-procedure", "does not exist"),
		},
		{
			"mixed case value",
			yarpc.NewHeaders().With("token", "MIXED case Value"),
			yarpc.NewHeaders().With("token", "MIXED case Value"),
		},
	}

	for _, tt := range tests {
		got, err := caller.Call(tt.give)
		if checks.NoError(err, "%v: call failed", tt.desc) {
			gotHeaders := internal.RemoveVariableHeaderKeys(got)
			assert.Equal(tt.want, gotHeaders, "%v: returns valid headers", tt.desc)
		}
	}
}