Skip to content

Commit 3a542e1

Browse files
authored
Merge pull request #6 from benalucorp/arwego/feat/add_charges_stub
Charges - Add Stub
2 parents a4ac862 + b7b1740 commit 3a542e1

17 files changed

+961
-103
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

+50-2
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ import (
2727
"log"
2828

2929
"github.com/benalucorp/coinbase-commerce-go"
30+
"github.com/benalucorp/coinbase-commerce-go/pkg/api"
3031
"github.com/benalucorp/coinbase-commerce-go/pkg/entity"
3132
"github.com/benalucorp/coinbase-commerce-go/pkg/enum"
3233
)
3334

3435
func main() {
35-
client, err := coinbase.NewClient(coinbase.Config{
36+
client, err := coinbase.NewClient(api.Config{
3637
Key: "REPLACE_WITH_YOUR_API_KEY",
3738
Timeout: 0, // Default: 1 min.
3839
RetryCount: 0, // Default: 0 = disable.
@@ -78,6 +79,53 @@ func main() {
7879

7980
For more example check [here](main_integration_test.go).
8081

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+
81129
## Supported API
82130

83131
Version: 2018-03-22
@@ -86,4 +134,4 @@ Version: 2018-03-22
86134
- [Create a charge](https://commerce.coinbase.com/docs/api/#create-a-charge)
87135
- [Show a charge](https://commerce.coinbase.com/docs/api/#show-a-charge)
88136
- [List charges](https://commerce.coinbase.com/docs/api/#list-charges)
89-
- [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

+20-91
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,28 @@ package coinbase
22

33
import (
44
"context"
5-
"errors"
6-
"time"
75

86
"github.com/benalucorp/coinbase-commerce-go/pkg/api"
7+
"github.com/benalucorp/coinbase-commerce-go/pkg/api/stub"
98
"github.com/benalucorp/coinbase-commerce-go/pkg/entity"
10-
"github.com/go-resty/resty/v2"
119
)
1210

13-
type Config struct {
14-
// Key is the authentication API key.
15-
// Most requests to the Commerce API must be authenticated with an API key.
16-
// You can create an API key in your Settings page after creating a Coinbase Commerce account.
17-
// Reference: https://commerce.coinbase.com/docs/api/#authentication
18-
Key string
19-
// Timeout describes total waiting time before a request is treated as timeout.
20-
// Default: 1 min.
21-
Timeout time.Duration
22-
// RetryCount describes total number of retry in case error occurred.
23-
// Set 0 to disable retry mechanism.
24-
// Default: 3.
25-
RetryCount int
26-
// RetryMaxWaitTime describes total waiting time between each retry.
27-
// Default: 2 second.
28-
RetryMaxWaitTime time.Duration
29-
// Debug describes the client to enter debug mode.
30-
Debug bool
31-
}
32-
33-
func (c *Config) Validate() error {
34-
if c.Key == "" {
35-
return errors.New("config: invalid key")
36-
}
37-
if c.Timeout <= 0 {
38-
c.Timeout = time.Minute
39-
}
40-
if c.RetryCount < 0 {
41-
c.RetryCount = 3
42-
}
43-
if c.RetryMaxWaitTime <= 0 {
44-
c.RetryMaxWaitTime = 2 * time.Second
45-
}
46-
return nil
47-
}
48-
4911
// NewClient creates a client to interact with Coinbase Commerce API.
50-
func NewClient(cfg Config) (*Client, error) {
12+
func NewClient(cfg api.Config) (*Client, error) {
5113
if err := cfg.Validate(); err != nil {
5214
return nil, err
5315
}
5416

55-
r := resty.New().
56-
SetHostURL(api.HostURL).
57-
SetHeaders(api.DefaultHeaders(cfg.Key)).
58-
SetTimeout(cfg.Timeout).
59-
SetRetryCount(cfg.RetryCount).
60-
SetRetryMaxWaitTime(cfg.RetryMaxWaitTime).
61-
SetDebug(cfg.Debug)
62-
6317
return &Client{
64-
charges: api.NewCharges(r),
18+
charges: api.NewCharges(cfg),
19+
chargesStub: stub.NewCharges(),
6520
}, nil
6621
}
6722

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

7229
// CreateCharge charge a customer with certain amount of currency.
@@ -76,14 +33,9 @@ type Client struct {
7633
// to the blockchain before the charge expires.
7734
// Reference: https://commerce.coinbase.com/docs/api/#create-a-charge
7835
func (c Client) CreateCharge(ctx context.Context, req *entity.CreateChargeReq) (*entity.CreateChargeResp, error) {
79-
if c.charges == nil {
80-
return nil, errors.New("client: initialize first")
36+
if stub.Ok(ctx) {
37+
return c.chargesStub.Create(ctx, req)
8138
}
82-
83-
if req == nil {
84-
return nil, errors.New("payload: missing")
85-
}
86-
8739
return c.charges.Create(ctx, req)
8840
}
8941

@@ -92,32 +44,21 @@ func (c Client) CreateCharge(ctx context.Context, req *entity.CreateChargeReq) (
9244
// This information is also returned when a charge is first created.
9345
// Reference: https://commerce.coinbase.com/docs/api/#show-a-charge
9446
func (c Client) ShowCharge(ctx context.Context, req *entity.ShowChargeReq) (*entity.ShowChargeResp, error) {
95-
if c.charges == nil {
96-
return nil, errors.New("client: initialize first")
97-
}
98-
99-
if req == nil {
100-
return nil, errors.New("payload: missing")
101-
}
102-
10347
if err := req.Validate(); err != nil {
10448
return nil, err
10549
}
106-
50+
if stub.Ok(ctx) {
51+
return c.chargesStub.Show(ctx, req)
52+
}
10753
return c.charges.Show(ctx, req)
10854
}
10955

11056
// ListCharges lists all the charges.
11157
// Reference: https://commerce.coinbase.com/docs/api/#list-charges
11258
func (c Client) ListCharges(ctx context.Context, req *entity.ListChargesReq) (*entity.ListChargesResp, error) {
113-
if c.charges == nil {
114-
return nil, errors.New("client: initialize first")
115-
}
116-
117-
if req == nil {
118-
return nil, errors.New("payload: missing")
59+
if stub.Ok(ctx) {
60+
return c.chargesStub.List(ctx, req)
11961
}
120-
12162
return c.charges.List(ctx, req)
12263
}
12364

@@ -131,18 +72,12 @@ func (c Client) ListCharges(ctx context.Context, req *entity.ListChargesReq) (*e
13172
//
13273
// Reference: https://commerce.coinbase.com/docs/api/#cancel-a-charge
13374
func (c Client) CancelCharge(ctx context.Context, req *entity.CancelChargeReq) (*entity.CancelChargeResp, error) {
134-
if c.charges == nil {
135-
return nil, errors.New("client: initialize first")
136-
}
137-
138-
if req == nil {
139-
return nil, errors.New("payload: missing")
140-
}
141-
14275
if err := req.Validate(); err != nil {
14376
return nil, err
14477
}
145-
78+
if stub.Ok(ctx) {
79+
return c.chargesStub.Cancel(ctx, req)
80+
}
14681
return c.charges.Cancel(ctx, req)
14782
}
14883

@@ -155,17 +90,11 @@ func (c Client) CancelCharge(ctx context.Context, req *entity.CancelChargeReq) (
15590
//
15691
// Reference: https://commerce.coinbase.com/docs/api/#resolve-a-charge
15792
func (c Client) ResolveCharge(ctx context.Context, req *entity.ResolveChargeReq) (*entity.ResolveChargeResp, error) {
158-
if c.charges == nil {
159-
return nil, errors.New("client: initialize first")
160-
}
161-
162-
if req == nil {
163-
return nil, errors.New("payload: missing")
164-
}
165-
16693
if err := req.Validate(); err != nil {
16794
return nil, err
16895
}
169-
96+
if stub.Ok(ctx) {
97+
return c.chargesStub.Resolve(ctx, req)
98+
}
17099
return c.charges.Resolve(ctx, req)
171100
}

main_integration_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"testing"
88

9+
"github.com/benalucorp/coinbase-commerce-go/pkg/api"
910
"github.com/benalucorp/coinbase-commerce-go/pkg/entity"
1011
"github.com/benalucorp/coinbase-commerce-go/pkg/enum"
1112
"github.com/kokizzu/gotro/L"
@@ -29,7 +30,7 @@ func TestMain(m *testing.M) {
2930
}
3031

3132
var err error
32-
client, err = NewClient(Config{
33+
client, err = NewClient(api.Config{
3334
Key: os.Getenv("KEY"),
3435
Debug: true,
3536
})

0 commit comments

Comments
 (0)