package jsonrpc_test import ( "context" "encoding/json" "io" "io/ioutil" "net/http" "net/http/httptest" "net/url" "testing" "github.com/go-kit/kit/transport/http/jsonrpc" ) type TestResponse struct { Body io.ReadCloser String string } func TestCanCallBeforeFunc(t *testing.T) { called := false u, _ := url.Parse("http://senseye.io/jsonrpc") sut := jsonrpc.NewClient( u, "add", jsonrpc.ClientBefore(func(ctx context.Context, req *http.Request) context.Context { called = true return ctx }), ) sut.Endpoint()(context.TODO(), "foo") if !called { t.Fatal("Expected client before func to be called. Wasn't.") } } type staticIDGenerator int func (g staticIDGenerator) Generate() interface{} { return g } func TestClientHappyPath(t *testing.T) { var ( afterCalledKey = "AC" beforeHeaderKey = "BF" beforeHeaderValue = "beforeFuncWozEre" testbody = `{"jsonrpc":"2.0", "result":5}` requestBody []byte beforeFunc = func(ctx context.Context, r *http.Request) context.Context { r.Header.Add(beforeHeaderKey, beforeHeaderValue) return ctx } encode = func(ctx context.Context, req interface{}) (json.RawMessage, error) { return json.Marshal(req) } afterFunc = func(ctx context.Context, r *http.Response) context.Context { return context.WithValue(ctx, afterCalledKey, true) } finalizerCalled = false fin = func(ctx context.Context, err error) { finalizerCalled = true } decode = func(ctx context.Context, res jsonrpc.Response) (interface{}, error) { if ac := ctx.Value(afterCalledKey); ac == nil { t.Fatal("after not called") } var result int err := json.Unmarshal(res.Result, &result) if err != nil { return nil, err } return result, nil } wantID = 666 gen = staticIDGenerator(wantID) ) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Header.Get(beforeHeaderKey) != beforeHeaderValue { t.Fatal("Header not set by before func.") } b, err := ioutil.ReadAll(r.Body) if err != nil && err != io.EOF { t.Fatal(err) } requestBody = b w.WriteHeader(http.StatusOK) w.Write([]byte(testbody)) })) sut := jsonrpc.NewClient( mustParse(server.URL), "add", jsonrpc.ClientRequestEncoder(encode), jsonrpc.ClientResponseDecoder(decode), jsonrpc.ClientBefore(beforeFunc), jsonrpc.ClientAfter(afterFunc), jsonrpc.ClientRequestIDGenerator(gen), jsonrpc.ClientFinalizer(fin), jsonrpc.SetClient(http.DefaultClient), jsonrpc.BufferedStream(false), ) type addRequest struct { A int B int } in := addRequest{2, 2} result, err := sut.Endpoint()(context.Background(), in) if err != nil { t.Fatal(err) } ri, ok := result.(int) if !ok { t.Fatalf("result is not int: (%T)%+v", result, result) } if ri != 5 { t.Fatalf("want=5, got=%d", ri) } var requestAtServer jsonrpc.Request err = json.Unmarshal(requestBody, &requestAtServer) if err != nil { t.Fatal(err) } if id, _ := requestAtServer.ID.Int(); id != wantID { t.Fatalf("Request ID at server: want=%d, got=%d", wantID, id) } var paramsAtServer addRequest err = json.Unmarshal(requestAtServer.Params, ¶msAtServer) if err != nil { t.Fatal(err) } if paramsAtServer != in { t.Fatalf("want=%+v, got=%+v", in, paramsAtServer) } if !finalizerCalled { t.Fatal("Expected finalizer to be called. Wasn't.") } } func TestCanUseDefaults(t *testing.T) { var ( testbody = `{"jsonrpc":"2.0", "result":"boogaloo"}` requestBody []byte ) server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { b, err := ioutil.ReadAll(r.Body) if err != nil && err != io.EOF { t.Fatal(err) } requestBody = b w.WriteHeader(http.StatusOK) w.Write([]byte(testbody)) })) sut := jsonrpc.NewClient( mustParse(server.URL), "add", ) type addRequest struct { A int B int } in := addRequest{2, 2} result, err := sut.Endpoint()(context.Background(), in) if err != nil { t.Fatal(err) } rs, ok := result.(string) if !ok { t.Fatalf("result is not string: (%T)%+v", result, result) } if rs != "boogaloo" { t.Fatalf("want=boogaloo, got=%s", rs) } var requestAtServer jsonrpc.Request err = json.Unmarshal(requestBody, &requestAtServer) if err != nil { t.Fatal(err) } var paramsAtServer addRequest err = json.Unmarshal(requestAtServer.Params, ¶msAtServer) if err != nil { t.Fatal(err) } if paramsAtServer != in { t.Fatalf("want=%+v, got=%+v", in, paramsAtServer) } } func TestClientCanHandleJSONRPCError(t *testing.T) { var testbody = `{ "jsonrpc": "2.0", "error": { "code": -32603, "message": "Bad thing happened." } }` server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte(testbody)) })) sut := jsonrpc.NewClient(mustParse(server.URL), "add") _, err := sut.Endpoint()(context.Background(), 5) if err == nil { t.Fatal("Expected error, got none.") } { want := "Bad thing happened." got := err.Error() if got != want { t.Fatalf("error message: want=%s, got=%s", want, got) } } type errorCoder interface { ErrorCode() int } ec, ok := err.(errorCoder) if !ok { t.Fatal("Error is not errorCoder") } { want := -32603 got := ec.ErrorCode() if got != want { t.Fatalf("error code: want=%d, got=%d", want, got) } } } func TestDefaultAutoIncrementer(t *testing.T) { sut := jsonrpc.NewAutoIncrementID(0) var want uint64 for ; want < 100; want++ { got := sut.Generate() if got != want { t.Fatalf("want=%d, got=%d", want, got) } } } func mustParse(s string) *url.URL { u, err := url.Parse(s) if err != nil { panic(err) } return u }