diff --git a/.travis.yml b/.travis.yml index 7e9721b..cd14def 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: -- 1.9 +- 1.10.2 before_install: - sudo pip install codecov install: diff --git a/Makefile b/Makefile index cbddea1..2a1e304 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,4 @@ test: go test -v ./... cover: - go test -v -coverprofile=coverage.txt -covermode=count ./appstore - go test -v -coverprofile=playstore.txt -covermode=count ./playstore - cat playstore.txt | grep -v "mode: count" >> coverage.txt - rm playstore.txt - go test -v -coverprofile=amazon.txt -covermode=count ./amazon - cat amazon.txt | grep -v "mode: count" >> coverage.txt - rm amazon.txt + go test -coverprofile=coverage.txt ./... diff --git a/README.md b/README.md index 4452db3..52a8b14 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ go-iap ====== -![](https://img.shields.io/badge/golang-1.9-blue.svg?style=flat) +![](https://img.shields.io/badge/golang-1.10-blue.svg?style=flat) [![Build Status](https://travis-ci.org/awa/go-iap.svg?branch=master)](https://travis-ci.org/awa/go-iap) [![codecov.io](https://codecov.io/github/awa/go-iap/coverage.svg?branch=master)](https://codecov.io/github/awa/go-iap?branch=master) diff --git a/amazon/validator.go b/amazon/validator.go index c2d2d6e..0861c1b 100644 --- a/amazon/validator.go +++ b/amazon/validator.go @@ -1,12 +1,12 @@ package amazon import ( + "context" "encoding/json" "errors" "fmt" "net/http" "os" - "time" ) const ( @@ -24,13 +24,6 @@ func getSandboxURL() string { return url } -// Config is a configuration to initialize client -type Config struct { - IsProduction bool - Secret string - TimeOut time.Duration -} - // The IAPResponse type has the response properties type IAPResponse struct { ReceiptID string `json:"receiptId"` @@ -49,41 +42,38 @@ type IAPResponseError struct { // IAPClient is an interface to call validation API in Amazon App Store type IAPClient interface { - Verify(string, string) (IAPResponse, error) + Verify(context.Context, string, string) (IAPResponse, error) } // Client implements IAPClient type Client struct { URL string Secret string - TimeOut time.Duration + httpCli *http.Client } // New creates a client object -func New(secret string) IAPClient { - client := Client{ +func New(secret string) *Client { + client := &Client{ URL: getSandboxURL(), Secret: secret, - TimeOut: time.Second * 5, + httpCli: http.DefaultClient, } if os.Getenv("IAP_ENVIRONMENT") == "production" { client.URL = ProductionURL } + return client } -// NewWithConfig creates a client with configuration -func NewWithConfig(config Config) Client { - if config.TimeOut == 0 { - config.TimeOut = time.Second * 5 - } - - client := Client{ +// NewWithClient creates a client with a custom client. +func NewWithClient(secret string, cli *http.Client) *Client { + client := &Client{ URL: getSandboxURL(), - Secret: config.Secret, - TimeOut: config.TimeOut, + Secret: secret, + httpCli: cli, } - if config.IsProduction { + if os.Getenv("IAP_ENVIRONMENT") == "production" { client.URL = ProductionURL } @@ -91,13 +81,16 @@ func NewWithConfig(config Config) Client { } // Verify sends receipts and gets validation result -func (c Client) Verify(userID string, receiptID string) (IAPResponse, error) { +func (c *Client) Verify(ctx context.Context, userID string, receiptID string) (IAPResponse, error) { result := IAPResponse{} url := fmt.Sprintf("%v/version/1.0/verifyReceiptId/developer/%v/user/%v/receiptId/%v", c.URL, c.Secret, userID, receiptID) - client := http.Client{ - Timeout: c.TimeOut, + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return result, err } - resp, err := client.Get(url) + req = req.WithContext(ctx) + + resp, err := c.httpCli.Do(req) if err != nil { return result, fmt.Errorf("%v", err) } diff --git a/amazon/validator_test.go b/amazon/validator_test.go index 1d76197..77e272d 100644 --- a/amazon/validator_test.go +++ b/amazon/validator_test.go @@ -1,6 +1,7 @@ package amazon import ( + "context" "errors" "fmt" "net/http" @@ -25,6 +26,7 @@ func TestHandle497Error(t *testing.T) { // status 400 expected = errors.New("Purchase token/app user mismatch") _, actual = client.Verify( + context.Background(), "99FD_DL23EMhrOGDnur9-ulvqomrSg6qyLPSD3CFE=", "q1YqVrJSSs7P1UvMTazKz9PLTCwoTswtyEktM9JLrShIzCvOzM-LL04tiTdW0lFKASo2NDEwMjCwMDM2MTC0AIqVAsUsLd1c4l18jIxdfTOK_N1d8kqLLHVLc8oK83OLgtPNCit9AoJdjJ3dXG2BGkqUrAxrAQ", ) @@ -47,6 +49,7 @@ func TestHandle400Error(t *testing.T) { // status 400 expected = errors.New("Failed to parse receipt Id") _, actual = client.Verify( + context.Background(), "99FD_DL23EMhrOGDnur9-ulvqomrSg6qyLPSD3CFE=", "q1YqVrJSSs7P1UvMTazKz9PLTCwoTswtyEktM9JLrShIzCvOzM-LL04tiTdW0lFKASo2NDEwMjCwMDM2MTC0AIqVAsUsLd1c4l18jIxdfTOK_N1d8kqLLHVLc8oK83OLgtPNCit9AoJdjJ3dXG2BGkqUrAxrAQ", ) @@ -56,11 +59,10 @@ func TestHandle400Error(t *testing.T) { } func TestNew(t *testing.T) { - t.Parallel() - expected := Client{ + expected := &Client{ URL: SandboxURL, - TimeOut: time.Second * 5, Secret: "developerSecret", + httpCli: http.DefaultClient, } actual := New("developerSecret") @@ -70,11 +72,10 @@ func TestNew(t *testing.T) { } func TestNewWithEnvironment(t *testing.T) { - t.Parallel() - expected := Client{ + expected := &Client{ URL: ProductionURL, - TimeOut: time.Second * 5, Secret: "developerSecret", + httpCli: http.DefaultClient, } os.Setenv("IAP_ENVIRONMENT", "production") @@ -86,40 +87,20 @@ func TestNewWithEnvironment(t *testing.T) { } } -func TestNewWithConfig(t *testing.T) { - t.Parallel() - config := Config{ - IsProduction: true, - Secret: "developerSecret", - TimeOut: time.Second * 2, +func TestNewWithClient(t *testing.T) { + expected := &Client{ + URL: ProductionURL, + Secret: "developerSecret", + httpCli: &http.Client{ + Timeout: time.Second * 2, + }, } + os.Setenv("IAP_ENVIRONMENT", "production") - expected := Client{ - URL: ProductionURL, - TimeOut: time.Second * 2, - Secret: "developerSecret", + cli := &http.Client{ + Timeout: time.Second * 2, } - - actual := NewWithConfig(config) - if !reflect.DeepEqual(actual, expected) { - t.Errorf("got %v\nwant %v", actual, expected) - } -} - -func TestNewWithConfigTimeout(t *testing.T) { - t.Parallel() - config := Config{ - IsProduction: true, - Secret: "developerSecret", - } - - expected := Client{ - URL: ProductionURL, - TimeOut: time.Second * 5, - Secret: "developerSecret", - } - - actual := NewWithConfig(config) + actual := NewWithClient("developerSecret", cli) if !reflect.DeepEqual(actual, expected) { t.Errorf("got %v\nwant %v", actual, expected) } @@ -143,6 +124,7 @@ func TestVerify(t *testing.T) { } actual, _ := client.Verify( + context.Background(), "99FD_DL23EMhrOGDnur9-ulvqomrSg6qyLPSD3CFE=", "q1YqVrJSSs7P1UvMTazKz9PLTCwoTswtyEktM9JLrShIzCvOzM-LL04tiTdW0lFKASo2NDEwMjCwMDM2MTC0AIqVAsUsLd1c4l18jIxdfTOK_N1d8kqLLHVLc8oK83OLgtPNCit9AoJdjJ3dXG2BGkqUrAxrAQ", ) @@ -158,7 +140,8 @@ func TestVerifyTimeout(t *testing.T) { defer server.Close() expected := errors.New("") - _, actual := client.Verify("timeout", "timeout") + ctx := context.Background() + _, actual := client.Verify(ctx, "timeout", "timeout") if !reflect.DeepEqual(reflect.TypeOf(actual), reflect.TypeOf(expected)) { t.Errorf("got %v\nwant %v", actual, expected) } @@ -172,6 +155,6 @@ func testTools(code int, body string) (*httptest.Server, *Client) { fmt.Fprintln(w, body) })) - client := &Client{URL: server.URL, TimeOut: time.Second * 2, Secret: "developerSecret"} + client := &Client{URL: server.URL, Secret: "developerSecret", httpCli: &http.Client{Timeout: 2 * time.Second}} return server, client }