Skip to content

Commit

Permalink
Add context.Context to exported functions that make outgoing remote c…
Browse files Browse the repository at this point in the history
…alls (braintree-go#194)

What
===
Add context to all exported functions that make an outgoing remote call. Insert as the first parameter in every function in the package that make an outgoing remote call a `context.Context`.

Why
===
To give the caller control over canceling remote calls.

Resolves braintree-go#156
Closes braintree-go#158
  • Loading branch information
leighmcculloch committed Nov 11, 2017
1 parent a246878 commit fdacac3
Show file tree
Hide file tree
Showing 46 changed files with 632 additions and 367 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ bt := braintree.New(
So is creating your first transaction.

```go
tx, err := bt.Transaction().Create(&braintree.TransactionRequest{
ctx := context.Background()
tx, err := bt.Transaction().Create(ctx, &braintree.TransactionRequest{
Type: "sale",
Amount: braintree.NewDecimal(100, 2), // 100 cents
CreditCard: &braintree.CreditCard{
Expand Down
6 changes: 4 additions & 2 deletions add_on_gateway.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package braintree

import "context"

type AddOnGateway struct {
*Braintree
}

func (g *AddOnGateway) All() ([]AddOn, error) {
resp, err := g.execute("GET", "add_ons", nil)
func (g *AddOnGateway) All(ctx context.Context) ([]AddOn, error) {
resp, err := g.execute(ctx, "GET", "add_ons", nil)
if err != nil {
return nil, err
}
Expand Down
5 changes: 4 additions & 1 deletion add_on_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package braintree

import (
"context"
"testing"
)

func TestAddOn(t *testing.T) {
t.Parallel()

addOns, err := testGateway.AddOn().All()
ctx := context.Background()

addOns, err := testGateway.AddOn().All(ctx)

if err != nil {
t.Fatal(err)
Expand Down
9 changes: 5 additions & 4 deletions address_gateway.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package braintree

import (
"context"
"encoding/xml"
)

Expand All @@ -9,13 +10,13 @@ type AddressGateway struct {
}

// Create creates a new address for the specified customer id.
func (g *AddressGateway) Create(a *Address) (*Address, error) {
func (g *AddressGateway) Create(ctx context.Context, a *Address) (*Address, error) {
// Copy address so that field sanitation won't affect original
var cp Address = *a
cp.CustomerId = ""
cp.XMLName = xml.Name{Local: "address"}

resp, err := g.execute("POST", "customers/"+a.CustomerId+"/addresses", &cp)
resp, err := g.execute(ctx, "POST", "customers/"+a.CustomerId+"/addresses", &cp)
if err != nil {
return nil, err
}
Expand All @@ -27,8 +28,8 @@ func (g *AddressGateway) Create(a *Address) (*Address, error) {
}

// Delete deletes the address for the specified id and customer id.
func (g *AddressGateway) Delete(customerId, addrId string) error {
resp, err := g.execute("DELETE", "customers/"+customerId+"/addresses/"+addrId, nil)
func (g *AddressGateway) Delete(ctx context.Context, customerId, addrId string) error {
resp, err := g.execute(ctx, "DELETE", "customers/"+customerId+"/addresses/"+addrId, nil)
if err != nil {
return err
}
Expand Down
13 changes: 9 additions & 4 deletions address_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package braintree

import "testing"
import (
"context"
"testing"
)

func TestAddress(t *testing.T) {
t.Parallel()

customer, err := testGateway.Customer().Create(&Customer{
ctx := context.Background()

customer, err := testGateway.Customer().Create(ctx, &Customer{
FirstName: "Jenna",
LastName: "Smith",
})
Expand All @@ -32,7 +37,7 @@ func TestAddress(t *testing.T) {
CountryName: "United States of America",
}

addr2, err := testGateway.Address().Create(addr)
addr2, err := testGateway.Address().Create(ctx, addr)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -89,7 +94,7 @@ func TestAddress(t *testing.T) {
t.Fatal("generated updated at is empty")
}

err = testGateway.Address().Delete(customer.Id, addr2.Id)
err = testGateway.Address().Delete(ctx, customer.Id, addr2.Id)
if err != nil {
t.Fatal(err)
}
Expand Down
9 changes: 6 additions & 3 deletions braintree.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package braintree

import (
"bytes"
"context"
"encoding/xml"
"errors"
"fmt"
Expand Down Expand Up @@ -62,11 +63,11 @@ func (g *Braintree) MerchantURL() string {
return g.Environment().BaseURL() + "/merchants/" + g.MerchantID()
}

func (g *Braintree) execute(method, path string, xmlObj interface{}) (*Response, error) {
return g.executeVersion(method, path, xmlObj, apiVersion3)
func (g *Braintree) execute(ctx context.Context, method, path string, xmlObj interface{}) (*Response, error) {
return g.executeVersion(ctx, method, path, xmlObj, apiVersion3)
}

func (g *Braintree) executeVersion(method, path string, xmlObj interface{}, v apiVersion) (*Response, error) {
func (g *Braintree) executeVersion(ctx context.Context, method, path string, xmlObj interface{}, v apiVersion) (*Response, error) {
var buf bytes.Buffer
if xmlObj != nil {
xmlBody, err := xml.Marshal(xmlObj)
Expand All @@ -90,6 +91,8 @@ func (g *Braintree) executeVersion(method, path string, xmlObj interface{}, v ap
return nil, err
}

req = req.WithContext(ctx)

req.Header.Set("Content-Type", "application/xml")
req.Header.Set("Accept", "application/xml")
req.Header.Set("Accept-Encoding", "gzip")
Expand Down
3 changes: 2 additions & 1 deletion braintree_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package braintree

import (
"context"
"net/http"
"net/http/httptest"
"strings"
Expand Down Expand Up @@ -53,7 +54,7 @@ func testHTTPClientTimeout(t *testing.T, braintreeFactory func(env Environment)

finished := make(chan bool)
go func() {
_, err := b.Transaction().Create(&TransactionRequest{})
_, err := b.Transaction().Create(context.Background(), &TransactionRequest{})
if err == nil {
t.Fatal("Expected timeout error, received no error")
}
Expand Down
17 changes: 10 additions & 7 deletions client_token_gateway.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
package braintree

import "encoding/xml"
import (
"context"
"encoding/xml"
)

const clientTokenVersion = 2

type ClientTokenGateway struct {
*Braintree
}

func (g *ClientTokenGateway) Generate() (string, error) {
return g.generate(&ClientTokenRequest{
func (g *ClientTokenGateway) Generate(ctx context.Context) (string, error) {
return g.generate(ctx, &ClientTokenRequest{
Version: clientTokenVersion,
})
}

func (g *ClientTokenGateway) GenerateWithCustomer(customerId string) (string, error) {
return g.generate(&ClientTokenRequest{
func (g *ClientTokenGateway) GenerateWithCustomer(ctx context.Context, customerId string) (string, error) {
return g.generate(ctx, &ClientTokenRequest{
Version: clientTokenVersion,
CustomerID: customerId,
})
}

func (g *ClientTokenGateway) generate(req *ClientTokenRequest) (string, error) {
resp, err := g.execute("POST", "client_token", req)
func (g *ClientTokenGateway) generate(ctx context.Context, req *ClientTokenRequest) (string, error) {
resp, err := g.execute(ctx, "POST", "client_token", req)
if err != nil {
return "", err
}
Expand Down
15 changes: 11 additions & 4 deletions client_token_integration_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package braintree

import "testing"
import (
"context"
"testing"
)

// This test will fail unless you set up your Braintree sandbox account correctly. See TESTING.md for details.
func TestClientToken(t *testing.T) {
t.Parallel()

ctx := context.Background()

g := testGateway.ClientToken()
token, err := g.Generate()
token, err := g.Generate(ctx)
if err != nil {
t.Fatalf("failed to generate client token: %s", err)
}
Expand All @@ -19,16 +24,18 @@ func TestClientToken(t *testing.T) {
func TestClientTokenWithCustomer(t *testing.T) {
t.Parallel()

ctx := context.Background()

customerRequest := &Customer{FirstName: "Lionel"}

customer, err := testGateway.Customer().Create(customerRequest)
customer, err := testGateway.Customer().Create(ctx, customerRequest)
if err != nil {
t.Error(err)
}

customerId := customer.Id

token, err := testGateway.ClientToken().GenerateWithCustomer(customerId)
token, err := testGateway.ClientToken().GenerateWithCustomer(ctx, customerId)
if err != nil {
t.Error(err)
} else if len(token) == 0 {
Expand Down
18 changes: 10 additions & 8 deletions credit_card_gateway.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package braintree

import "context"

type CreditCardGateway struct {
*Braintree
}

func (g *CreditCardGateway) Create(card *CreditCard) (*CreditCard, error) {
resp, err := g.execute("POST", "payment_methods", card)
func (g *CreditCardGateway) Create(ctx context.Context, card *CreditCard) (*CreditCard, error) {
resp, err := g.execute(ctx, "POST", "payment_methods", card)
if err != nil {
return nil, err
}
Expand All @@ -16,8 +18,8 @@ func (g *CreditCardGateway) Create(card *CreditCard) (*CreditCard, error) {
return nil, &invalidResponseError{resp}
}

func (g *CreditCardGateway) Update(card *CreditCard) (*CreditCard, error) {
resp, err := g.execute("PUT", "payment_methods/"+card.Token, card)
func (g *CreditCardGateway) Update(ctx context.Context, card *CreditCard) (*CreditCard, error) {
resp, err := g.execute(ctx, "PUT", "payment_methods/"+card.Token, card)
if err != nil {
return nil, err
}
Expand All @@ -28,8 +30,8 @@ func (g *CreditCardGateway) Update(card *CreditCard) (*CreditCard, error) {
return nil, &invalidResponseError{resp}
}

func (g *CreditCardGateway) Find(token string) (*CreditCard, error) {
resp, err := g.execute("GET", "payment_methods/"+token, nil)
func (g *CreditCardGateway) Find(ctx context.Context, token string) (*CreditCard, error) {
resp, err := g.execute(ctx, "GET", "payment_methods/"+token, nil)
if err != nil {
return nil, err
}
Expand All @@ -40,8 +42,8 @@ func (g *CreditCardGateway) Find(token string) (*CreditCard, error) {
return nil, &invalidResponseError{resp}
}

func (g *CreditCardGateway) Delete(card *CreditCard) error {
resp, err := g.execute("DELETE", "payment_methods/"+card.Token, nil)
func (g *CreditCardGateway) Delete(ctx context.Context, card *CreditCard) error {
resp, err := g.execute(ctx, "DELETE", "payment_methods/"+card.Token, nil)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit fdacac3

Please sign in to comment.