Skip to content

Commit 2d242b4

Browse files
authored
Merge pull request tokopedia#141 from pojlter/add_result_code
feat: add response code
2 parents cc0d60d + a907d3c commit 2d242b4

File tree

6 files changed

+152
-7
lines changed

6 files changed

+152
-7
lines changed

Readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Stub Format is JSON text format. It has a skeleton as follows:
7777
// put result fields here
7878
},
7979
"error":"<error message>" // Optional. if you want to return error instead.
80+
"code":"<response code>" // Optional. Grpc response code. if code !=0 return error instead.
8081
}
8182
}
8283
```

example/simple/client/main.go

+12
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,16 @@ func main() {
4040
log.Fatalf("error from grpc: %v", err)
4141
}
4242
log.Printf("Greeting: %s (return code %d)", r.Message, r.ReturnCode)
43+
name = "error"
44+
r, err = c.SayHello(context.Background(), &pb.Request{Name: name})
45+
if err == nil {
46+
log.Fatalf("Expected error, but return %d", r.ReturnCode)
47+
}
48+
log.Printf("Greeting error: %s", err)
49+
name = "error_code"
50+
r, err = c.SayHello(context.Background(), &pb.Request{Name: name})
51+
if err == nil {
52+
log.Fatalf("Expected error, but return %d", r.ReturnCode)
53+
}
54+
log.Printf("Greeting error: %s", err)
4355
}

example/simple/stub/simple.json

+25
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,30 @@
2828
"return_code": 1
2929
}
3030
}
31+
},
32+
{
33+
"service": "Gripmock",
34+
"method": "SayHello",
35+
"input": {
36+
"equals": {
37+
"name": "error"
38+
}
39+
},
40+
"output": {
41+
"error": "test_error"
42+
}
43+
},
44+
{
45+
"service": "Gripmock",
46+
"method": "SayHello",
47+
"input": {
48+
"equals": {
49+
"name": "error_code"
50+
}
51+
},
52+
"output": {
53+
"error": "test_error_code",
54+
"code": 3
55+
}
3156
}
3257
]

protoc-gen-gripmock/server.tmpl

+11-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"github.com/golang/protobuf/jsonpb"
1515
"golang.org/x/net/context"
1616
"google.golang.org/grpc"
17+
"google.golang.org/grpc/codes"
18+
"google.golang.org/grpc/status"
1719
"google.golang.org/grpc/reflection"
1820
"google.golang.org/protobuf/runtime/protoiface"
1921
)
@@ -144,6 +146,7 @@ type payload struct {
144146
type response struct {
145147
Data interface{} `json:"data"`
146148
Error string `json:"error"`
149+
Code *codes.Code `json:"code,omitempty"`
147150
}
148151

149152
func findStub(service, method string, in, out protoiface.MessageV1) error {
@@ -174,8 +177,14 @@ func findStub(service, method string, in, out protoiface.MessageV1) error {
174177
return fmt.Errorf("decoding json response %v",err)
175178
}
176179

177-
if respRPC.Error != "" {
178-
return fmt.Errorf(respRPC.Error)
180+
if respRPC.Error != "" || respRPC.Code != nil {
181+
if respRPC.Code == nil {
182+
abortedCode := codes.Aborted
183+
respRPC.Code = &abortedCode
184+
}
185+
if *respRPC.Code != codes.OK {
186+
return status.Error(*respRPC.Code, respRPC.Error)
187+
}
179188
}
180189

181190
data, _ := json.Marshal(respRPC.Data)

stub/stub.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ package stub
33
import (
44
"encoding/json"
55
"fmt"
6+
"google.golang.org/grpc/codes"
67
"io/ioutil"
78
"log"
89
"net/http"
910
"strings"
10-
11+
1112
"github.com/go-chi/chi"
1213
)
1314

@@ -62,6 +63,7 @@ type Input struct {
6263
type Output struct {
6364
Data map[string]interface{} `json:"data"`
6465
Error string `json:"error"`
66+
Code *codes.Code `json:"code,omitempty"`
6567
}
6668

6769
func addStub(w http.ResponseWriter, r *http.Request) {
@@ -106,7 +108,7 @@ func validateStub(stub *Stub) error {
106108
if stub.Method == "" {
107109
return fmt.Errorf("Method name can't be emtpy")
108110
}
109-
111+
110112
// due to golang implementation
111113
// method name must capital
112114
stub.Method = strings.Title(stub.Method)
@@ -124,7 +126,7 @@ func validateStub(stub *Stub) error {
124126

125127
// TODO: validate all input case
126128

127-
if stub.Output.Error == "" && stub.Output.Data == nil {
129+
if stub.Output.Error == "" && stub.Output.Data == nil && stub.Output.Code == nil {
128130
return fmt.Errorf("Output can't be empty")
129131
}
130132
return nil
@@ -143,11 +145,11 @@ func handleFindStub(w http.ResponseWriter, r *http.Request) {
143145
responseError(err, w)
144146
return
145147
}
146-
148+
147149
// due to golang implementation
148150
// method name must capital
149151
stub.Method = strings.Title(stub.Method)
150-
152+
151153
output, err := findStub(stub)
152154
if err != nil {
153155
log.Println(err)

stub/stub_test.go

+96
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,102 @@ func TestStub(t *testing.T) {
166166
handler: addStub,
167167
expect: `Success add stub`,
168168
},
169+
{
170+
name: "add error stub with result code contains",
171+
mock: func() *http.Request {
172+
payload := `{
173+
"service": "ErrorStabWithCode",
174+
"method":"TestMethod",
175+
"input":{
176+
"contains":{
177+
"key": "value",
178+
"greetings": {
179+
"hola": "mundo",
180+
"merhaba": "dunya"
181+
},
182+
"cities": ["Istanbul", "Jakarta"]
183+
}
184+
},
185+
"output":{
186+
"error":"error msg",
187+
"code": 3
188+
}
189+
}`
190+
return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload)))
191+
},
192+
handler: addStub,
193+
expect: `Success add stub`,
194+
},
195+
{
196+
name: "find error stub with result code contains",
197+
mock: func() *http.Request {
198+
payload := `{
199+
"service": "ErrorStabWithCode",
200+
"method":"TestMethod",
201+
"data":{
202+
"key": "value",
203+
"anotherKey": "anotherValue",
204+
"greetings": {
205+
"hola": "mundo",
206+
"merhaba": "dunya",
207+
"hello": "world"
208+
},
209+
"cities": ["Istanbul", "Jakarta", "Winterfell"]
210+
}
211+
}`
212+
return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload)))
213+
},
214+
handler: handleFindStub,
215+
expect: "{\"data\":null,\"error\":\"error msg\",\"code\":3}\n",
216+
},
217+
218+
{
219+
name: "add error stub without result code contains",
220+
mock: func() *http.Request {
221+
payload := `{
222+
"service": "ErrorStab",
223+
"method":"TestMethod",
224+
"input":{
225+
"contains":{
226+
"key": "value",
227+
"greetings": {
228+
"hola": "mundo",
229+
"merhaba": "dunya"
230+
},
231+
"cities": ["Istanbul", "Jakarta"]
232+
}
233+
},
234+
"output":{
235+
"error":"error msg"
236+
}
237+
}`
238+
return httptest.NewRequest("POST", "/add", bytes.NewReader([]byte(payload)))
239+
},
240+
handler: addStub,
241+
expect: `Success add stub`,
242+
},
243+
{
244+
name: "find error stub without result code contains",
245+
mock: func() *http.Request {
246+
payload := `{
247+
"service": "ErrorStab",
248+
"method":"TestMethod",
249+
"data":{
250+
"key": "value",
251+
"anotherKey": "anotherValue",
252+
"greetings": {
253+
"hola": "mundo",
254+
"merhaba": "dunya",
255+
"hello": "world"
256+
},
257+
"cities": ["Istanbul", "Jakarta", "Winterfell"]
258+
}
259+
}`
260+
return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload)))
261+
},
262+
handler: handleFindStub,
263+
expect: "{\"data\":null,\"error\":\"error msg\"}\n",
264+
},
169265
{
170266
name: "find nested stub contains",
171267
mock: func() *http.Request {

0 commit comments

Comments
 (0)