Skip to content

Commit b7b1740

Browse files
author
Rizal Widyarta Gowandy
committed
Charges - Add Stub
Sometime it's make sense to make an API call without actually calling the API. In order to support that this library has a built-in stub that can be triggered. You can enable stub by injecting certain value to the context data. You can also enforce that certain API call will always return error with specific type and message.
1 parent 3eefb33 commit b7b1740

16 files changed

+905
-39
lines changed

.golangci.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ issues:
132132
- stylecheck
133133
- funlen
134134
- lll
135+
- path: stub
136+
linters:
137+
- funlen
135138

136139
# https://github.com/go-critic/go-critic/issues/926
137140
- linters:

README.md

+48-1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,53 @@ func main() {
7979

8080
For more example check [here](main_integration_test.go).
8181

82+
## Test Double / Stub
83+
84+
Sometime it's make sense to make an API call without actually calling the API. In order to support that this library has a built-in stub that can be triggered. You can enable stub by injecting certain value to the context data. You can also enforce that certain API call will always return error with specific type and
85+
message.
86+
87+
```go
88+
package main
89+
90+
import (
91+
"context"
92+
"log"
93+
94+
"github.com/benalucorp/coinbase-commerce-go"
95+
"github.com/benalucorp/coinbase-commerce-go/pkg/api"
96+
"github.com/benalucorp/coinbase-commerce-go/pkg/entity"
97+
"github.com/benalucorp/coinbase-commerce-go/pkg/enum"
98+
"github.com/benalucorp/coinbase-commerce-go/pkg/api/stub"
99+
)
100+
101+
func AlwaysSuccess(ctx context.Context, client *coinbase.Client) {
102+
// Enable stub that always success and return data.
103+
ctx = stub.Enable(ctx)
104+
105+
// Call any client method.
106+
resp, err := client.CreateCharge(ctx, &entity.CreateChargeReq{})
107+
if err != nil {
108+
log.Fatal(err)
109+
}
110+
log.Printf("%+v", resp)
111+
}
112+
113+
func AlwaysError(ctx context.Context, client *coinbase.Client) {
114+
// Enable stub that always error and return specific error.
115+
ctx = stub.SetErrDetailResp(context.Background(), entity.ErrDetailResp{
116+
Type: "bad_request",
117+
Message: "stub: error triggered",
118+
})
119+
120+
// Call any client method.
121+
resp, err := client.CreateCharge(ctx, &entity.CreateChargeReq{})
122+
if err != nil {
123+
log.Fatal(err)
124+
}
125+
log.Printf("%+v", resp)
126+
}
127+
```
128+
82129
## Supported API
83130

84131
Version: 2018-03-22
@@ -87,4 +134,4 @@ Version: 2018-03-22
87134
- [Create a charge](https://commerce.coinbase.com/docs/api/#create-a-charge)
88135
- [Show a charge](https://commerce.coinbase.com/docs/api/#show-a-charge)
89136
- [List charges](https://commerce.coinbase.com/docs/api/#list-charges)
90-
- [Cancel a charge](https://commerce.coinbase.com/docs/api/#cancel-a-charge)
137+
- [Cancel a charge](https://commerce.coinbase.com/docs/api/#cancel-a-charge)

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.14
55
require (
66
github.com/go-resty/resty/v2 v2.6.0
77
github.com/kokizzu/gotro v1.817.1737
8+
github.com/segmentio/ksuid v1.0.4
89
github.com/stretchr/testify v1.7.0
910
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect
1011
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
148148
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
149149
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
150150
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
151+
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
152+
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
151153
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
152154
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
153155
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=

main.go

+19-24
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ package coinbase
22

33
import (
44
"context"
5-
"errors"
65

76
"github.com/benalucorp/coinbase-commerce-go/pkg/api"
7+
"github.com/benalucorp/coinbase-commerce-go/pkg/api/stub"
88
"github.com/benalucorp/coinbase-commerce-go/pkg/entity"
99
)
1010

@@ -15,12 +15,15 @@ func NewClient(cfg api.Config) (*Client, error) {
1515
}
1616

1717
return &Client{
18-
charges: api.NewCharges(cfg),
18+
charges: api.NewCharges(cfg),
19+
chargesStub: stub.NewCharges(),
1920
}, nil
2021
}
2122

23+
// Client is the main client to interact with Coinbase Commerce API.
2224
type Client struct {
23-
charges *api.Charges
25+
charges api.ChargesItf
26+
chargesStub api.ChargesItf
2427
}
2528

2629
// CreateCharge charge a customer with certain amount of currency.
@@ -30,10 +33,9 @@ type Client struct {
3033
// to the blockchain before the charge expires.
3134
// Reference: https://commerce.coinbase.com/docs/api/#create-a-charge
3235
func (c Client) CreateCharge(ctx context.Context, req *entity.CreateChargeReq) (*entity.CreateChargeResp, error) {
33-
if req == nil {
34-
return nil, errors.New("payload: missing")
36+
if stub.Ok(ctx) {
37+
return c.chargesStub.Create(ctx, req)
3538
}
36-
3739
return c.charges.Create(ctx, req)
3840
}
3941

@@ -42,24 +44,21 @@ func (c Client) CreateCharge(ctx context.Context, req *entity.CreateChargeReq) (
4244
// This information is also returned when a charge is first created.
4345
// Reference: https://commerce.coinbase.com/docs/api/#show-a-charge
4446
func (c Client) ShowCharge(ctx context.Context, req *entity.ShowChargeReq) (*entity.ShowChargeResp, error) {
45-
if req == nil {
46-
return nil, errors.New("payload: missing")
47-
}
48-
4947
if err := req.Validate(); err != nil {
5048
return nil, err
5149
}
52-
50+
if stub.Ok(ctx) {
51+
return c.chargesStub.Show(ctx, req)
52+
}
5353
return c.charges.Show(ctx, req)
5454
}
5555

5656
// ListCharges lists all the charges.
5757
// Reference: https://commerce.coinbase.com/docs/api/#list-charges
5858
func (c Client) ListCharges(ctx context.Context, req *entity.ListChargesReq) (*entity.ListChargesResp, error) {
59-
if req == nil {
60-
return nil, errors.New("payload: missing")
59+
if stub.Ok(ctx) {
60+
return c.chargesStub.List(ctx, req)
6161
}
62-
6362
return c.charges.List(ctx, req)
6463
}
6564

@@ -73,14 +72,12 @@ func (c Client) ListCharges(ctx context.Context, req *entity.ListChargesReq) (*e
7372
//
7473
// Reference: https://commerce.coinbase.com/docs/api/#cancel-a-charge
7574
func (c Client) CancelCharge(ctx context.Context, req *entity.CancelChargeReq) (*entity.CancelChargeResp, error) {
76-
if req == nil {
77-
return nil, errors.New("payload: missing")
78-
}
79-
8075
if err := req.Validate(); err != nil {
8176
return nil, err
8277
}
83-
78+
if stub.Ok(ctx) {
79+
return c.chargesStub.Cancel(ctx, req)
80+
}
8481
return c.charges.Cancel(ctx, req)
8582
}
8683

@@ -93,13 +90,11 @@ func (c Client) CancelCharge(ctx context.Context, req *entity.CancelChargeReq) (
9390
//
9491
// Reference: https://commerce.coinbase.com/docs/api/#resolve-a-charge
9592
func (c Client) ResolveCharge(ctx context.Context, req *entity.ResolveChargeReq) (*entity.ResolveChargeResp, error) {
96-
if req == nil {
97-
return nil, errors.New("payload: missing")
98-
}
99-
10093
if err := req.Validate(); err != nil {
10194
return nil, err
10295
}
103-
96+
if stub.Ok(ctx) {
97+
return c.chargesStub.Resolve(ctx, req)
98+
}
10499
return c.charges.Resolve(ctx, req)
105100
}

0 commit comments

Comments
 (0)