Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support multiple stubs in a file #129

Merged
merged 1 commit into from
Feb 17, 2023
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
7 changes: 7 additions & 0 deletions example/simple/client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,11 @@ func main() {
log.Fatalf("error from grpc: %v", err)
}
log.Printf("Greeting: %s (return code %d)", r.Message, r.ReturnCode)

name = "world"
r, err = c.SayHello(context.Background(), &pb.Request{Name: name})
if err != nil {
log.Fatalf("error from grpc: %v", err)
}
log.Printf("Greeting: %s (return code %d)", r.Message, r.ReturnCode)
}
39 changes: 28 additions & 11 deletions example/simple/stub/simple.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
{
"service": "Gripmock",
"method": "SayHello",
"input": {
"equals": {
"name": "tokopedia"
[
{
"service": "Gripmock",
"method": "SayHello",
"input": {
"equals": {
"name": "tokopedia"
}
},
"output": {
"data": {
"message": "Hello Tokopedia",
"return_code": 1
}
}
},
"output": {
"data": {
"message": "Hello Tokopedia",
"return_code": 1
{
"service": "Gripmock",
"method": "SayHello",
"input": {
"equals": {
"name": "world"
}
},
"output": {
"data": {
"message": "Hello World",
"return_code": 1
}
}
}
}
]
31 changes: 26 additions & 5 deletions stub/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,21 @@ type storage struct {
}

func storeStub(stub *Stub) error {
return stubStorage.storeStub(stub)
}

func (sm *stubMapping) storeStub(stub *Stub) error {
mx.Lock()
defer mx.Unlock()

strg := storage{
Input: stub.Input,
Output: stub.Output,
}
if stubStorage[stub.Service] == nil {
stubStorage[stub.Service] = make(map[string][]storage)
if (*sm)[stub.Service] == nil {
(*sm)[stub.Service] = make(map[string][]storage)
}
stubStorage[stub.Service][stub.Method] = append(stubStorage[stub.Service][stub.Method], strg)
(*sm)[stub.Service][stub.Method] = append((*sm)[stub.Service][stub.Method], strg)
return nil
}

Expand Down Expand Up @@ -269,6 +273,10 @@ func clearStorage() {
}

func readStubFromFile(path string) {
stubStorage.readStubFromFile(path)
}

func (sm *stubMapping) readStubFromFile(path string) {
files, err := ioutil.ReadDir(path)
if err != nil {
log.Printf("Can't read stub from %s. %v\n", path, err)
Expand All @@ -287,13 +295,26 @@ func readStubFromFile(path string) {
continue
}

if byt[0] == '[' && byt[len(byt)-1] == ']' {
var stubs []*Stub
err = json.Unmarshal(byt, &stubs)
if err != nil {
log.Printf("Error when unmarshalling file %s. %v. skipping...", file.Name(), err)
continue
}
for _, s := range stubs {
sm.storeStub(s)
}
continue
}

stub := new(Stub)
err = json.Unmarshal(byt, stub)
if err != nil {
log.Printf("Error when reading file %s. %v. skipping...", file.Name(), err)
log.Printf("Error when unmarshalling file %s. %v. skipping...", file.Name(), err)
continue
}

storeStub(stub)
sm.storeStub(stub)
}
}
137 changes: 137 additions & 0 deletions stub/storage_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package stub

import (
"encoding/json"
"io/ioutil"
"testing"

"github.com/stretchr/testify/require"
)

func Test_readStubFromFile(t *testing.T) {
tests := []struct {
name string
mock func(service, method string, data []storage) (path string)
service string
method string
data []storage
}{
{
name: "single file, single stub",
mock: func(service, method string, data []storage) (path string) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
tempF, err := ioutil.TempFile(dir, "")
require.NoError(t, err)
defer tempF.Close()

var stubs []Stub
for _, d := range data {
stubs = append(stubs, Stub{
Service: service,
Method: method,
Input: d.Input,
Output: d.Output,
})
}
byt, err := json.Marshal(stubs)
require.NoError(t, err)
_, err = tempF.Write(byt)
require.NoError(t, err)

return dir
},
service: "user",
method: "getname",
data: []storage{
{
Input: Input{Equals: map[string]interface{}{"id": float64(1)}},
Output: Output{Data: map[string]interface{}{"name": "user1"}},
},
},
},
{
name: "single file, multiple stub",
mock: func(service, method string, data []storage) (path string) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)
tempF, err := ioutil.TempFile(dir, "")
require.NoError(t, err)
defer tempF.Close()

var stubs []Stub
for _, d := range data {
stubs = append(stubs, Stub{
Service: service,
Method: method,
Input: d.Input,
Output: d.Output,
})
}
byt, err := json.Marshal(stubs)
require.NoError(t, err)
_, err = tempF.Write(byt)
require.NoError(t, err)

return dir
},
service: "user",
method: "getname",
data: []storage{
{
Input: Input{Equals: map[string]interface{}{"id": float64(1)}},
Output: Output{Data: map[string]interface{}{"name": "user1"}},
},
{
Input: Input{Equals: map[string]interface{}{"id": float64(2)}},
Output: Output{Data: map[string]interface{}{"name": "user2"}},
},
},
},
{
name: "multiple file, single stub",
mock: func(service, method string, data []storage) (path string) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err)

for _, d := range data {
tempF, err := ioutil.TempFile(dir, "")
require.NoError(t, err)
defer tempF.Close()

stub := Stub{
Service: service,
Method: method,
Input: d.Input,
Output: d.Output,
}
byt, err := json.Marshal(stub)
require.NoError(t, err)
_, err = tempF.Write(byt)
require.NoError(t, err)
}

return dir
},
service: "user",
method: "getname",
data: []storage{
{
Input: Input{Equals: map[string]interface{}{"id": float64(1)}},
Output: Output{Data: map[string]interface{}{"name": "user1"}},
},
{
Input: Input{Equals: map[string]interface{}{"id": float64(2)}},
Output: Output{Data: map[string]interface{}{"name": "user2"}},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sm := stubMapping{}
sm.readStubFromFile(tt.mock(tt.service, tt.method, tt.data))
require.ElementsMatch(t, tt.data, sm[tt.service][tt.method])
})
}
}
6 changes: 2 additions & 4 deletions stub/stub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,15 +284,13 @@ func TestStub(t *testing.T) {
"service":"Testing",
"method":"TestMethod",
"data":{
"field1":"hello field1",
"field2":"hello field2",
"field3":"hello field4"
"field1":"hello field1"
}
}`
return httptest.NewRequest("GET", "/find", bytes.NewReader([]byte(payload)))
},
handler: handleFindStub,
expect: "Can't find stub \n\nService: Testing \n\nMethod: TestMethod \n\nInput\n\n{\n\tfield1: hello field1\n\tfield2: hello field2\n\tfield3: hello field4\n}\n\nClosest Match \n\ncontains:{\n\tfield1: hello field1\n\tfield3: hello field3\n}",
expect: "Can't find stub \n\nService: Testing \n\nMethod: TestMethod \n\nInput\n\n{\n\tfield1: hello field1\n}\n\nClosest Match \n\ncontains:{\n\tfield1: hello field1\n\tfield3: hello field3\n}",
},
{
name: "error find stub equals",
Expand Down