diff --git a/go.mod b/go.mod index 0086cea..fe32297 100644 --- a/go.mod +++ b/go.mod @@ -2,10 +2,10 @@ module github.com/ybbus/jsonrpc/v3 go 1.17 -require github.com/onsi/gomega v1.18.1 +require github.com/stretchr/testify v1.7.0 require ( - golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 // indirect - golang.org/x/text v0.3.6 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect + github.com/davecgh/go-spew v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect ) diff --git a/go.sum b/go.sum index cacb191..acb88a4 100644 --- a/go.sum +++ b/go.sum @@ -1,98 +1,11 @@ -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/jsonrpc.go b/jsonrpc.go index 876a944..8c4573a 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -441,6 +441,20 @@ func (client *rpcClient) doCall(ctx context.Context, RPCRequest *RPCRequest) (*R return nil, fmt.Errorf("rpc call %v() on %v status code: %v. rpc response missing", RPCRequest.Method, httpRequest.URL.String(), httpResponse.StatusCode) } + // if we have a response body, but also a http error situation, return both + if httpResponse.StatusCode >= 400 { + if rpcResponse.Error != nil { + return rpcResponse, &HTTPError{ + Code: httpResponse.StatusCode, + err: fmt.Errorf("rpc call %v() on %v status code: %v. rpc response error: %v", RPCRequest.Method, httpRequest.URL.String(), httpResponse.StatusCode, rpcResponse.Error), + } + } + return rpcResponse, &HTTPError{ + Code: httpResponse.StatusCode, + err: fmt.Errorf("rpc call %v() on %v status code: %v. no rpc error available", RPCRequest.Method, httpRequest.URL.String(), httpResponse.StatusCode), + } + } + return rpcResponse, nil } @@ -455,13 +469,13 @@ func (client *rpcClient) doBatchCall(ctx context.Context, rpcRequest []*RPCReque } defer httpResponse.Body.Close() - var rpcResponse RPCResponses + var rpcResponses RPCResponses decoder := json.NewDecoder(httpResponse.Body) if !client.allowUnknownFields { decoder.DisallowUnknownFields() } decoder.UseNumber() - err = decoder.Decode(&rpcResponse) + err = decoder.Decode(&rpcResponses) // parsing error if err != nil { @@ -476,7 +490,7 @@ func (client *rpcClient) doBatchCall(ctx context.Context, rpcRequest []*RPCReque } // response body empty - if rpcResponse == nil || len(rpcResponse) == 0 { + if rpcResponses == nil || len(rpcResponses) == 0 { // if we have some http error, return it if httpResponse.StatusCode >= 400 { return nil, &HTTPError{ @@ -487,7 +501,15 @@ func (client *rpcClient) doBatchCall(ctx context.Context, rpcRequest []*RPCReque return nil, fmt.Errorf("rpc batch call on %v status code: %v. rpc response missing", httpRequest.URL.String(), httpResponse.StatusCode) } - return rpcResponse, nil + // if we have a response body, but also a http error, return both + if httpResponse.StatusCode >= 400 { + return rpcResponses, &HTTPError{ + Code: httpResponse.StatusCode, + err: fmt.Errorf("rpc batch call on %v status code: %v. check rpc responses for potential rpc error", httpRequest.URL.String(), httpResponse.StatusCode), + } + } + + return rpcResponses, nil } // Params is a helper function that uses the same parameter syntax as Call(). diff --git a/jsonrpc_test.go b/jsonrpc_test.go index 9221679..be2b3e9 100644 --- a/jsonrpc_test.go +++ b/jsonrpc_test.go @@ -9,7 +9,7 @@ import ( "os" "testing" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" ) // needed to retrieve requests that arrived at httpServer for further investigation @@ -24,9 +24,10 @@ type RequestData struct { // set the response body the httpServer should return for the next request var responseBody = "" +var httpStatusCode = http.StatusOK var httpServer *httptest.Server -// start the testhttp server and stop it when tests are finished +// start the test-http server and stop it when tests are finished func TestMain(m *testing.M) { httpServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, _ := ioutil.ReadAll(r.Body) @@ -34,6 +35,7 @@ func TestMain(m *testing.M) { // put request and body to channel for the client to investigate them requestChan <- &RequestData{r, string(data)} + w.WriteHeader(httpStatusCode) fmt.Fprintf(w, responseBody) })) defer httpServer.Close() @@ -42,21 +44,22 @@ func TestMain(m *testing.M) { } func TestSimpleRpcCallHeaderCorrect(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) rpcClient := NewClient(httpServer.URL) rpcClient.Call(context.Background(), "add", 1, 2) req := (<-requestChan).request - Expect(req.Method).To(Equal("POST")) - Expect(req.Header.Get("Content-Type")).To(Equal("application/json")) - Expect(req.Header.Get("Accept")).To(Equal("application/json")) + check.Equal("POST", req.Method) + check.Equal("application/json", req.Header.Get("Content-Type")) + check.Equal("application/json", req.Header.Get("Accept")) } -// test if the structure of an rpc request is built correctly by validating the data that arrived on the test server +// test if the structure of a rpc request is built correctly by validating the data that arrived at the test server func TestRpcClient_Call(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) person := Person{ @@ -71,95 +74,95 @@ func TestRpcClient_Call(t *testing.T) { } rpcClient.Call(context.Background(), "missingParam") - Expect((<-requestChan).body).To(Equal(`{"method":"missingParam","id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"missingParam","id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "nullParam", nil) - Expect((<-requestChan).body).To(Equal(`{"method":"nullParam","params":[null],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"nullParam","params":[null],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "nullParams", nil, nil) - Expect((<-requestChan).body).To(Equal(`{"method":"nullParams","params":[null,null],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"nullParams","params":[null,null],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "emptyParams", []interface{}{}) - Expect((<-requestChan).body).To(Equal(`{"method":"emptyParams","params":[],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"emptyParams","params":[],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "emptyAnyParams", []string{}) - Expect((<-requestChan).body).To(Equal(`{"method":"emptyAnyParams","params":[],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"emptyAnyParams","params":[],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "emptyObject", struct{}{}) - Expect((<-requestChan).body).To(Equal(`{"method":"emptyObject","params":{},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"emptyObject","params":{},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "emptyObjectList", []struct{}{{}, {}}) - Expect((<-requestChan).body).To(Equal(`{"method":"emptyObjectList","params":[{},{}],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"emptyObjectList","params":[{},{}],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "boolParam", true) - Expect((<-requestChan).body).To(Equal(`{"method":"boolParam","params":[true],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"boolParam","params":[true],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "boolParams", true, false, true) - Expect((<-requestChan).body).To(Equal(`{"method":"boolParams","params":[true,false,true],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"boolParams","params":[true,false,true],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "stringParam", "Alex") - Expect((<-requestChan).body).To(Equal(`{"method":"stringParam","params":["Alex"],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"stringParam","params":["Alex"],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "stringParams", "JSON", "RPC") - Expect((<-requestChan).body).To(Equal(`{"method":"stringParams","params":["JSON","RPC"],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"stringParams","params":["JSON","RPC"],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "numberParam", 123) - Expect((<-requestChan).body).To(Equal(`{"method":"numberParam","params":[123],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"numberParam","params":[123],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "numberParams", 123, 321) - Expect((<-requestChan).body).To(Equal(`{"method":"numberParams","params":[123,321],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"numberParams","params":[123,321],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "floatParam", 1.23) - Expect((<-requestChan).body).To(Equal(`{"method":"floatParam","params":[1.23],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"floatParam","params":[1.23],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "floatParams", 1.23, 3.21) - Expect((<-requestChan).body).To(Equal(`{"method":"floatParams","params":[1.23,3.21],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"floatParams","params":[1.23,3.21],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "manyParams", "Alex", 35, true, nil, 2.34) - Expect((<-requestChan).body).To(Equal(`{"method":"manyParams","params":["Alex",35,true,null,2.34],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"manyParams","params":["Alex",35,true,null,2.34],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "emptyMissingPublicFieldObject", struct{ name string }{name: "Alex"}) - Expect((<-requestChan).body).To(Equal(`{"method":"emptyMissingPublicFieldObject","params":{},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"emptyMissingPublicFieldObject","params":{},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "singleStruct", person) - Expect((<-requestChan).body).To(Equal(`{"method":"singleStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"singleStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "singlePointerToStruct", &person) - Expect((<-requestChan).body).To(Equal(`{"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) pp := &person rpcClient.Call(context.Background(), "doublePointerStruct", &pp) - Expect((<-requestChan).body).To(Equal(`{"method":"doublePointerStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"doublePointerStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "multipleStructs", person, &drink) - Expect((<-requestChan).body).To(Equal(`{"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "singleStructInArray", []interface{}{person}) - Expect((<-requestChan).body).To(Equal(`{"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}],"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}],"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "namedParameters", map[string]interface{}{ "name": "Alex", "age": 35, }) - Expect((<-requestChan).body).To(Equal(`{"method":"namedParameters","params":{"age":35,"name":"Alex"},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"namedParameters","params":{"age":35,"name":"Alex"},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "anonymousStructNoTags", struct { Name string Age int }{"Alex", 33}) - Expect((<-requestChan).body).To(Equal(`{"method":"anonymousStructNoTags","params":{"Name":"Alex","Age":33},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"anonymousStructNoTags","params":{"Name":"Alex","Age":33},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "anonymousStructWithTags", struct { Name string `json:"name"` Age int `json:"age"` }{"Alex", 33}) - Expect((<-requestChan).body).To(Equal(`{"method":"anonymousStructWithTags","params":{"name":"Alex","age":33},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"anonymousStructWithTags","params":{"name":"Alex","age":33},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "structWithNullField", struct { Name string `json:"name"` Address *string `json:"address"` }{"Alex", nil}) - Expect((<-requestChan).body).To(Equal(`{"method":"structWithNullField","params":{"name":"Alex","address":null},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"structWithNullField","params":{"name":"Alex","address":null},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) rpcClient.Call(context.Background(), "nestedStruct", Planet{ @@ -169,11 +172,12 @@ func TestRpcClient_Call(t *testing.T) { Color: "red", }, }) - Expect((<-requestChan).body).To(Equal(`{"method":"nestedStruct","params":{"name":"Mars","properties":{"distance":54600000,"color":"red"}},"id":0,"jsonrpc":"2.0"}`)) + check.Equal(`{"method":"nestedStruct","params":{"name":"Mars","properties":{"distance":54600000,"color":"red"}},"id":0,"jsonrpc":"2.0"}`, (<-requestChan).body) } func TestRpcClient_CallBatch(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) person := Person{ @@ -194,7 +198,7 @@ func TestRpcClient_CallBatch(t *testing.T) { Params: 3, // invalid, should be []int{3} }, }) - Expect((<-requestChan).body).To(Equal(`[{"method":"singleRequest","params":3,"id":0,"jsonrpc":"2.0"}]`)) + check.Equal(`[{"method":"singleRequest","params":3,"id":0,"jsonrpc":"2.0"}]`, (<-requestChan).body) // better use Params() unless you know what you are doing rpcClient.CallBatch(context.Background(), RPCRequests{ @@ -203,7 +207,7 @@ func TestRpcClient_CallBatch(t *testing.T) { Params: Params(3), // always valid json rpc }, }) - Expect((<-requestChan).body).To(Equal(`[{"method":"singleRequest","params":[3],"id":0,"jsonrpc":"2.0"}]`)) + check.Equal(`[{"method":"singleRequest","params":[3],"id":0,"jsonrpc":"2.0"}]`, (<-requestChan).body) // even better, use NewRequest() rpcClient.CallBatch(context.Background(), RPCRequests{ @@ -211,7 +215,7 @@ func TestRpcClient_CallBatch(t *testing.T) { NewRequest("multipleRequests2", 2), NewRequest("multipleRequests3", 3), }) - Expect((<-requestChan).body).To(Equal(`[{"method":"multipleRequests1","params":[1],"id":0,"jsonrpc":"2.0"},{"method":"multipleRequests2","params":[2],"id":1,"jsonrpc":"2.0"},{"method":"multipleRequests3","params":[3],"id":2,"jsonrpc":"2.0"}]`)) + check.Equal(`[{"method":"multipleRequests1","params":[1],"id":0,"jsonrpc":"2.0"},{"method":"multipleRequests2","params":[2],"id":1,"jsonrpc":"2.0"},{"method":"multipleRequests3","params":[3],"id":2,"jsonrpc":"2.0"}]`, (<-requestChan).body) // test a huge batch request requests := RPCRequests{ @@ -254,30 +258,30 @@ func TestRpcClient_CallBatch(t *testing.T) { } rpcClient.CallBatch(context.Background(), requests) - Expect((<-requestChan).body).To(Equal(`[{"method":"nullParam","params":[null],"id":0,"jsonrpc":"2.0"},` + - `{"method":"nullParams","params":[null,null],"id":1,"jsonrpc":"2.0"},` + - `{"method":"emptyParams","params":[],"id":2,"jsonrpc":"2.0"},` + - `{"method":"emptyAnyParams","params":[],"id":3,"jsonrpc":"2.0"},` + - `{"method":"emptyObject","params":{},"id":4,"jsonrpc":"2.0"},` + - `{"method":"emptyObjectList","params":[{},{}],"id":5,"jsonrpc":"2.0"},` + - `{"method":"boolParam","params":[true],"id":6,"jsonrpc":"2.0"},` + - `{"method":"boolParams","params":[true,false,true],"id":7,"jsonrpc":"2.0"},` + - `{"method":"stringParam","params":["Alex"],"id":8,"jsonrpc":"2.0"},` + - `{"method":"stringParams","params":["JSON","RPC"],"id":9,"jsonrpc":"2.0"},` + - `{"method":"numberParam","params":[123],"id":10,"jsonrpc":"2.0"},` + - `{"method":"numberParams","params":[123,321],"id":11,"jsonrpc":"2.0"},` + - `{"method":"floatParam","params":[1.23],"id":12,"jsonrpc":"2.0"},` + - `{"method":"floatParams","params":[1.23,3.21],"id":13,"jsonrpc":"2.0"},` + - `{"method":"manyParams","params":["Alex",35,true,null,2.34],"id":14,"jsonrpc":"2.0"},` + - `{"method":"emptyMissingPublicFieldObject","params":{},"id":15,"jsonrpc":"2.0"},` + - `{"method":"singleStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":16,"jsonrpc":"2.0"},` + - `{"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":17,"jsonrpc":"2.0"},` + - `{"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}],"id":18,"jsonrpc":"2.0"},` + - `{"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}],"id":19,"jsonrpc":"2.0"},` + - `{"method":"namedParameters","params":{"age":35,"name":"Alex"},"id":20,"jsonrpc":"2.0"},` + - `{"method":"anonymousStructNoTags","params":{"Name":"Alex","Age":33},"id":21,"jsonrpc":"2.0"},` + - `{"method":"anonymousStructWithTags","params":{"name":"Alex","age":33},"id":22,"jsonrpc":"2.0"},` + - `{"method":"structWithNullField","params":{"name":"Alex","address":null},"id":23,"jsonrpc":"2.0"}]`)) + check.Equal(`[{"method":"nullParam","params":[null],"id":0,"jsonrpc":"2.0"},`+ + `{"method":"nullParams","params":[null,null],"id":1,"jsonrpc":"2.0"},`+ + `{"method":"emptyParams","params":[],"id":2,"jsonrpc":"2.0"},`+ + `{"method":"emptyAnyParams","params":[],"id":3,"jsonrpc":"2.0"},`+ + `{"method":"emptyObject","params":{},"id":4,"jsonrpc":"2.0"},`+ + `{"method":"emptyObjectList","params":[{},{}],"id":5,"jsonrpc":"2.0"},`+ + `{"method":"boolParam","params":[true],"id":6,"jsonrpc":"2.0"},`+ + `{"method":"boolParams","params":[true,false,true],"id":7,"jsonrpc":"2.0"},`+ + `{"method":"stringParam","params":["Alex"],"id":8,"jsonrpc":"2.0"},`+ + `{"method":"stringParams","params":["JSON","RPC"],"id":9,"jsonrpc":"2.0"},`+ + `{"method":"numberParam","params":[123],"id":10,"jsonrpc":"2.0"},`+ + `{"method":"numberParams","params":[123,321],"id":11,"jsonrpc":"2.0"},`+ + `{"method":"floatParam","params":[1.23],"id":12,"jsonrpc":"2.0"},`+ + `{"method":"floatParams","params":[1.23,3.21],"id":13,"jsonrpc":"2.0"},`+ + `{"method":"manyParams","params":["Alex",35,true,null,2.34],"id":14,"jsonrpc":"2.0"},`+ + `{"method":"emptyMissingPublicFieldObject","params":{},"id":15,"jsonrpc":"2.0"},`+ + `{"method":"singleStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":16,"jsonrpc":"2.0"},`+ + `{"method":"singlePointerToStruct","params":{"name":"Alex","age":35,"country":"Germany"},"id":17,"jsonrpc":"2.0"},`+ + `{"method":"multipleStructs","params":[{"name":"Alex","age":35,"country":"Germany"},{"name":"Cuba Libre","ingredients":["rum","cola"]}],"id":18,"jsonrpc":"2.0"},`+ + `{"method":"singleStructInArray","params":[{"name":"Alex","age":35,"country":"Germany"}],"id":19,"jsonrpc":"2.0"},`+ + `{"method":"namedParameters","params":{"age":35,"name":"Alex"},"id":20,"jsonrpc":"2.0"},`+ + `{"method":"anonymousStructNoTags","params":{"Name":"Alex","Age":33},"id":21,"jsonrpc":"2.0"},`+ + `{"method":"anonymousStructWithTags","params":{"name":"Alex","age":33},"id":22,"jsonrpc":"2.0"},`+ + `{"method":"structWithNullField","params":{"name":"Alex","address":null},"id":23,"jsonrpc":"2.0"}]`, (<-requestChan).body) // create batch manually requests = []*RPCRequest{ @@ -296,8 +300,8 @@ func TestRpcClient_CallBatch(t *testing.T) { } rpcClient.CallBatch(context.Background(), requests) - Expect((<-requestChan).body).To(Equal(`[{"method":"myMethod1","params":[1],"id":0,"jsonrpc":"2.0"},` + - `{"method":"myMethod2","params":{"name":"Alex","age":35,"country":"Germany"},"id":1,"jsonrpc":"2.0"}]`)) + check.Equal(`[{"method":"myMethod1","params":[1],"id":0,"jsonrpc":"2.0"},`+ + `{"method":"myMethod2","params":{"name":"Alex","age":35,"country":"Germany"},"id":1,"jsonrpc":"2.0"}]`, (<-requestChan).body) // use raw batch requests = []*RPCRequest{ @@ -316,131 +320,92 @@ func TestRpcClient_CallBatch(t *testing.T) { } rpcClient.CallBatchRaw(context.Background(), requests) - Expect((<-requestChan).body).To(Equal(`[{"method":"myMethod1","params":[1],"id":123,"jsonrpc":"7.0"},` + - `{"method":"myMethod2","params":{"name":"Alex","age":35,"country":"Germany"},"id":321,"jsonrpc":"wrong"}]`)) + check.Equal(`[{"method":"myMethod1","params":[1],"id":123,"jsonrpc":"7.0"},`+ + `{"method":"myMethod2","params":{"name":"Alex","age":35,"country":"Germany"},"id":321,"jsonrpc":"wrong"}]`, (<-requestChan).body) } -// test if the result of an an rpc request is parsed correctly and if errors are thrown correctly +// test if the result of a rpc request is parsed correctly and if errors are thrown correctly func TestRpcJsonResponseStruct(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) // empty return body is an error responseBody = `` res, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) + check.NotNil(err) + check.Nil(res) // not a json body is an error responseBody = `{ "not": "a", "json": "object"` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) + check.NotNil(err) + check.Nil(res) // field "anotherField" not allowed in rpc response is an error responseBody = `{ "anotherField": "norpc"}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) - - // TODO: result must contain one of "result", "error" - // TODO: is there an efficient way to do this? - /*responseBody = `{}` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil())*/ + check.NotNil(err) + check.Nil(res) // result null is ok responseBody = `{"result": null}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Result) + check.Nil(res.Error) // error null is ok responseBody = `{"error": null}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Result) + check.Nil(res.Error) // result and error null is ok responseBody = `{"result": null, "error": null}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).To(BeNil()) - - // TODO: result must not contain both of "result", "error" != null - // TODO: is there an efficient way to do this? - /*responseBody = `{ "result": 123, "error": {"code": 123, "message": "something wrong"}}` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil())*/ + check.Nil(err) + check.Nil(res.Result) + check.Nil(res.Error) // result string is ok responseBody = `{"result": "ok"}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(Equal("ok")) + check.Nil(err) + check.Equal("ok", res.Result) // result with error null is ok responseBody = `{"result": "ok", "error": null}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(Equal("ok")) + check.Nil(err) + check.Equal("ok", res.Result) // error with result null is ok responseBody = `{"error": {"code": 123, "message": "something wrong"}, "result": null}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error.Code).To(Equal(123)) - Expect(res.Error.Message).To(Equal("something wrong")) - - // TODO: empty error is not ok, must at least contain code and message - /*responseBody = `{ "error": {}}` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).NotTo(BeNil())*/ - - // TODO: only code in error is not ok, must at least contain code and message - /*responseBody = `{ "error": {"code": 123}}` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).NotTo(BeNil())*/ - - // TODO: only message in error is not ok, must at least contain code and message - /*responseBody = `{ "error": {"message": "something wrong"}}` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error).NotTo(BeNil())*/ + check.Nil(err) + check.Nil(res.Result) + check.Equal(123, res.Error.Code) + check.Equal("something wrong", res.Error.Message) // error with code and message is ok responseBody = `{ "error": {"code": 123, "message": "something wrong"}}` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Result).To(BeNil()) - Expect(res.Error.Code).To(Equal(123)) - Expect(res.Error.Message).To(Equal("something wrong")) + check.Nil(err) + check.Nil(res.Result) + check.Equal(123, res.Error.Code) + check.Equal("something wrong", res.Error.Message) // check results @@ -448,110 +413,156 @@ func TestRpcJsonResponseStruct(t *testing.T) { responseBody = `{ "result": 1 }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) i, err := res.GetInt() - Expect(err).To(BeNil()) - Expect(i).To(Equal(int64(1))) + check.Nil(err) + check.Equal(int64(1), i) - // error on wrong type + // error on not int i = 3 responseBody = `{ "result": "notAnInt" }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) i, err = res.GetInt() - Expect(err).NotTo(BeNil()) - Expect(i).To(Equal(int64(0))) + check.NotNil(err) + check.Equal(int64(0), i) + + // error on not int but float + i = 3 + responseBody = `{ "result": 1.234 }` + res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.Nil(res.Error) + i, err = res.GetInt() + check.NotNil(err) + check.Equal(int64(0), i) // error on result null i = 3 responseBody = `{ "result": null }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) i, err = res.GetInt() - Expect(err).NotTo(BeNil()) - Expect(i).To(Equal(int64(0))) + check.NotNil(err) + check.Equal(int64(0), i) b := false responseBody = `{ "result": true }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) b, err = res.GetBool() - Expect(err).To(BeNil()) - Expect(b).To(Equal(true)) + check.Nil(err) + check.Equal(true, b) b = true responseBody = `{ "result": 123 }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) b, err = res.GetBool() - Expect(err).NotTo(BeNil()) - Expect(b).To(Equal(false)) + check.NotNil(err) + check.Equal(false, b) + + responseBody = `{ "result": "string" }` + res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.Nil(res.Error) + str, err := res.GetString() + check.Nil(err) + check.Equal("string", str) + + responseBody = `{ "result": 1.234 }` + res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.Nil(res.Error) + str, err = res.GetString() + check.NotNil(err) + check.Equal("", str) + + responseBody = `{ "result": 1.234 }` + res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.Nil(res.Error) + f, err := res.GetFloat() + check.Nil(err) + check.Equal(1.234, f) + + responseBody = `{ "result": "notfloat" }` + res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.Nil(res.Error) + f, err = res.GetFloat() + check.NotNil(err) + check.Equal(0.0, f) var p *Person responseBody = `{ "result": {"name": "Alex", "age": 35, "anotherField": "something"} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p) - Expect(err).To(BeNil()) - Expect(p.Name).To(Equal("Alex")) - Expect(p.Age).To(Equal(35)) - Expect(p.Country).To(Equal("")) + check.Nil(err) + check.Equal("Alex", p.Name) + check.Equal(35, p.Age) + check.Equal("", p.Country) // TODO: How to check if result could be parsed or if it is default? p = nil responseBody = `{ "result": {"anotherField": "something"} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p) - Expect(err).To(BeNil()) - Expect(p).NotTo(BeNil()) + check.Nil(err) + check.NotNil(p) - // TODO: HERE###### var pp *PointerFieldPerson responseBody = `{ "result": {"anotherField": "something", "country": "Germany"} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&pp) - Expect(err).To(BeNil()) - Expect(pp.Name).To(BeNil()) - Expect(pp.Age).To(BeNil()) - Expect(*pp.Country).To(Equal("Germany")) + check.Nil(err) + check.Nil(pp.Name) + check.Nil(pp.Age) + check.Equal("Germany", *pp.Country) p = nil responseBody = `{ "result": null }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p) - Expect(err).To(BeNil()) - Expect(p).To(BeNil()) + check.Nil(err) + check.Nil(p) // passing nil is an error p = nil responseBody = `{ "result": null }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(p) - Expect(err).NotTo(BeNil()) - Expect(p).To(BeNil()) + check.NotNil(err) + check.Nil(p) p2 := &Person{ Name: "Alex", @@ -559,11 +570,11 @@ func TestRpcJsonResponseStruct(t *testing.T) { responseBody = `{ "result": null }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p2) - Expect(err).To(BeNil()) - Expect(p2).To(BeNil()) + check.Nil(err) + check.Nil(p2) p2 = &Person{ Name: "Alex", @@ -571,12 +582,12 @@ func TestRpcJsonResponseStruct(t *testing.T) { responseBody = `{ "result": {"age": 35} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(p2) - Expect(err).To(BeNil()) - Expect(p2.Name).To(Equal("Alex")) - Expect(p2.Age).To(Equal(35)) + check.Nil(err) + check.Equal("Alex", p2.Name) + check.Equal(35, p2.Age) // prefilled struct is kept on no result p3 := Person{ @@ -585,11 +596,11 @@ func TestRpcJsonResponseStruct(t *testing.T) { responseBody = `{ "result": null }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p3) - Expect(err).To(BeNil()) - Expect(p3.Name).To(Equal("Alex")) + check.Nil(err) + check.Equal("Alex", p3.Name) // prefilled struct is extended / overwritten p3 = Person{ @@ -599,26 +610,26 @@ func TestRpcJsonResponseStruct(t *testing.T) { responseBody = `{ "result": {"age": 35, "country": "Germany"} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(&p3) - Expect(err).To(BeNil()) - Expect(p3.Name).To(Equal("Alex")) - Expect(p3.Age).To(Equal(35)) - Expect(p3.Country).To(Equal("Germany")) + check.Nil(err) + check.Equal("Alex", p3.Name) + check.Equal(35, p3.Age) + check.Equal("Germany", p3.Country) // nil is an error responseBody = `{ "result": {"age": 35} }` res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res.Error).To(BeNil()) + check.Nil(err) + check.Nil(res.Error) err = res.GetObject(nil) - Expect(err).NotTo(BeNil()) + check.NotNil(err) } -func TestRpcJsonAllowUnknownFields(t *testing.T) { - RegisterTestingT(t) +func TestRpcClientOptions(t *testing.T) { + check := assert.New(t) t.Run("allowUnknownFields false should return error on unknown field", func(t *testing.T) { rpcClient := NewClientWithOpts(httpServer.URL, &RPCClientOpts{AllowUnknownFields: false}) @@ -627,8 +638,8 @@ func TestRpcJsonAllowUnknownFields(t *testing.T) { responseBody = `{ "result": 1, "unknown_field": 2 }` res, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) + check.NotNil(err) + check.Nil(res) }) t.Run("allowUnknownFields true should not return error on unknown field", func(t *testing.T) { @@ -638,14 +649,31 @@ func TestRpcJsonAllowUnknownFields(t *testing.T) { responseBody = `{ "result": 1, "unknown_field": 2 }` res, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(res).NotTo(BeNil()) + check.Nil(err) + check.NotNil(res) }) + t.Run("customheaders should be added to request", func(t *testing.T) { + rpcClient := NewClientWithOpts(httpServer.URL, &RPCClientOpts{ + CustomHeaders: map[string]string{ + "X-Custom-Header": "custom-value", + "X-Custom-Header2": "custom-value2", + }, + }) + + responseBody = `{"result": 1}` + res, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) + reqObject := <-requestChan + check.Nil(err) + check.NotNil(res) + check.Equal("custom-value", reqObject.request.Header.Get("X-Custom-Header")) + check.Equal("custom-value2", reqObject.request.Header.Get("X-Custom-Header2")) + }) } func TestRpcBatchJsonResponseStruct(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) // empty return body is an error @@ -654,8 +682,8 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) + check.NotNil(err) + check.Nil(res) // not a json body is an error responseBody = `{ "not": "a", "json": "object"` @@ -663,8 +691,8 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) + check.NotNil(err) + check.Nil(res) // field "anotherField" not allowed in rpc response is an error responseBody = `{ "anotherField": "norpc"}` @@ -672,16 +700,8 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil()) - - // TODO: result must contain one of "result", "error" - // TODO: is there an efficient way to do this? - /*responseBody = `[{}]` - res, err = rpcClient.Call(context.Background(), "something", 1, 2, 3) - <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil())*/ + check.NotNil(err) + check.Nil(res) // result must be wrapped in array on batch request responseBody = `{"result": null}` @@ -689,7 +709,7 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err.Error()).NotTo(BeNil()) + check.NotNil(err.Error()) // result ok since in array responseBody = `[{"result": null}]` @@ -697,9 +717,9 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(len(res)).To(Equal(1)) - Expect(res[0].Result).To(BeNil()) + check.Nil(err) + check.Equal(1, len(res)) + check.Nil(res[0].Result) // error null is ok responseBody = `[{"error": null}]` @@ -707,9 +727,9 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error).To(BeNil()) + check.Nil(err) + check.Nil(res[0].Result) + check.Nil(res[0].Error) // result and error null is ok responseBody = `[{"result": null, "error": null}]` @@ -717,19 +737,9 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error).To(BeNil()) - - // TODO: result must not contain both of "result", "error" != null - // TODO: is there an efficient way to do this? - /*responseBody = `[{ "result": 123, "error": {"code": 123, "message": "something wrong"}}]` - res, err = rpcClient.CallBatch(context.Background(), RPCRequests{ - NewRequest("something",1, 2, 3), - }) - <-requestChan - Expect(err).NotTo(BeNil()) - Expect(res).To(BeNil())*/ + check.Nil(err) + check.Nil(res[0].Result) + check.Nil(res[0].Error) // result string is ok responseBody = `[{"result": "ok","id":0}]` @@ -737,9 +747,9 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(Equal("ok")) - Expect(res[0].ID).To(Equal(0)) + check.Nil(err) + check.Equal("ok", res[0].Result) + check.Equal(0, res[0].ID) // result with error null is ok responseBody = `[{"result": "ok", "error": null}]` @@ -747,8 +757,8 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(Equal("ok")) + check.Nil(err) + check.Equal("ok", res[0].Result) // error with result null is ok responseBody = `[{"error": {"code": 123, "message": "something wrong"}, "result": null}]` @@ -756,40 +766,10 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error.Code).To(Equal(123)) - Expect(res[0].Error.Message).To(Equal("something wrong")) - - // TODO: empty error is not ok, must at least contain code and message - /*responseBody = `[{ "error": {}}]` - res, err = rpcClient.CallBatch(context.Background(), RPCRequests{ - NewRequest("something",1, 2, 3), - }) - <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error).NotTo(BeNil())*/ /* - - // TODO: only code in error is not ok, must at least contain code and message - */ /*responseBody = `[{ "error": {"code": 123}}]` - res, err = rpcClient.CallBatch(context.Background(), RPCRequests{ - NewRequest("something",1, 2, 3), - }) - <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error).NotTo(BeNil())*/ /* - - // TODO: only message in error is not ok, must at least contain code and message - */ /*responseBody = `[{ "error": {"message": "something wrong"}}]` - res, err = rpcClient.CallBatch(context.Background(), RPCRequests{ - NewRequest("something",1, 2, 3), - }) - <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error).NotTo(BeNil())*/ + check.Nil(err) + check.Nil(res[0].Result) + check.Equal(123, res[0].Error.Code) + check.Equal("something wrong", res[0].Error.Message) // error with code and message is ok responseBody = `[{ "error": {"code": 123, "message": "something wrong"}}]` @@ -797,10 +777,10 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Result).To(BeNil()) - Expect(res[0].Error.Code).To(Equal(123)) - Expect(res[0].Error.Message).To(Equal("something wrong")) + check.Nil(err) + check.Nil(res[0].Result) + check.Equal(123, res[0].Error.Code) + check.Equal("something wrong", res[0].Error.Message) // check results @@ -810,11 +790,11 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Error).To(BeNil()) + check.Nil(err) + check.Nil(res[0].Error) i, err := res[0].GetInt() - Expect(err).To(BeNil()) - Expect(i).To(Equal(int64(1))) + check.Nil(err) + check.Equal(int64(1), i) // error on wrong type i = 3 @@ -823,11 +803,11 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res[0].Error).To(BeNil()) + check.Nil(err) + check.Nil(res[0].Error) i, err = res[0].GetInt() - Expect(err).NotTo(BeNil()) - Expect(i).To(Equal(int64(0))) + check.NotNil(err) + check.Equal(int64(0), i) var p *Person responseBody = `[{"id":0, "result": {"name": "Alex", "age": 35}}, {"id":2, "result": {"name": "Lena", "age": 2}}]` @@ -836,21 +816,21 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { }) <-requestChan - Expect(err).To(BeNil()) + check.Nil(err) - Expect(res[0].Error).To(BeNil()) - Expect(res[0].ID).To(Equal(0)) + check.Nil(res[0].Error) + check.Equal(0, res[0].ID) - Expect(res[1].Error).To(BeNil()) - Expect(res[1].ID).To(Equal(2)) + check.Nil(res[1].Error) + check.Equal(2, res[1].ID) err = res[0].GetObject(&p) - Expect(p.Name).To(Equal("Alex")) - Expect(p.Age).To(Equal(35)) + check.Equal("Alex", p.Name) + check.Equal(35, p.Age) err = res[1].GetObject(&p) - Expect(p.Name).To(Equal("Lena")) - Expect(p.Age).To(Equal(2)) + check.Equal("Lena", p.Name) + check.Equal(2, p.Age) // check if error occurred responseBody = `[{ "result": "someresult", "error": null}, { "result": null, "error": {"code": 123, "message": "something wrong"}}]` @@ -858,8 +838,8 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res.HasError()).To(BeTrue()) + check.Nil(err) + check.True(res.HasError()) // check if error occurred responseBody = `[{ "result": null, "error": {"code": 123, "message": "something wrong"}}]` @@ -867,16 +847,16 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res.HasError()).To(BeTrue()) + check.Nil(err) + check.True(res.HasError()) // check if error occurred responseBody = `[{ "result": null, "error": {"code": 123, "message": "something wrong"}}]` res, err = rpcClient.CallBatch(context.Background(), RPCRequests{ NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res.HasError()).To(BeTrue()) + check.Nil(err) + check.True(res.HasError()) // check if response mapping works responseBody = `[{ "id":123,"result": 123},{ "id":1,"result": 1}]` @@ -884,18 +864,22 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res.HasError()).To(BeFalse()) + check.Nil(err) + check.False(res.HasError()) resMap := res.AsMap() int1, _ := resMap[1].GetInt() int123, _ := resMap[123].GetInt() - Expect(int1).To(Equal(int64(1))) - Expect(int123).To(Equal(int64(123))) + check.Equal(int64(1), int1) + check.Equal(int64(123), int123) // check if getByID works int123, _ = res.GetByID(123).GetInt() - Expect(int123).To(Equal(int64(123))) + check.Equal(int64(123), int123) + + // check if missing id returns nil + missingIdRes := res.GetByID(124) + check.Nil(missingIdRes) // check if error occurred responseBody = `[{ "result": null, "error": {"code": 123, "message": "something wrong"}}]` @@ -903,20 +887,53 @@ func TestRpcBatchJsonResponseStruct(t *testing.T) { NewRequest("something", 1, 2, 3), }) <-requestChan - Expect(err).To(BeNil()) - Expect(res.HasError()).To(BeTrue()) + check.Nil(err) + check.True(res.HasError()) } func TestRpcClient_CallFor(t *testing.T) { - RegisterTestingT(t) + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) i := 0 responseBody = `{"result":3,"id":0,"jsonrpc":"2.0"}` err := rpcClient.CallFor(context.Background(), &i, "something", 1, 2, 3) <-requestChan - Expect(err).To(BeNil()) - Expect(i).To(Equal(3)) + check.Nil(err) + check.Equal(3, i) +} + +func TestErrorHandling(t *testing.T) { + check := assert.New(t) + rpcClient := NewClient(httpServer.URL) + + oldStatusCode := httpStatusCode + oldResponseBody := responseBody + defer func() { + httpStatusCode = oldStatusCode + responseBody = oldResponseBody + }() + + t.Run("check returned rpcerror", func(t *testing.T) { + responseBody = `{"error":{"code":123,"message":"something wrong"}}` + call, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.Nil(err) + check.NotNil(call.Error) + check.Equal("123: something wrong", call.Error.Error()) + }) + + t.Run("check returned httperror", func(t *testing.T) { + responseBody = `{"error":{"code":123,"message":"something wrong"}}` + httpStatusCode = http.StatusInternalServerError + call, err := rpcClient.Call(context.Background(), "something", 1, 2, 3) + <-requestChan + check.NotNil(err) + check.NotNil(call.Error) + check.Equal("123: something wrong", call.Error.Error()) + check.Contains(err.(*HTTPError).Error(), "status code: 500. rpc response error: 123: something wrong") + }) } type Person struct {