From 8c93c4b714d7c0487eb3962666605311a4a87cdd Mon Sep 17 00:00:00 2001 From: Junpei Tsuji Date: Fri, 18 May 2018 11:20:58 +0900 Subject: [PATCH 1/3] Support context for amazon app store --- amazon/validator.go | 13 ++++++++++--- amazon/validator_test.go | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/amazon/validator.go b/amazon/validator.go index c2d2d6e..1d0b3fe 100644 --- a/amazon/validator.go +++ b/amazon/validator.go @@ -1,6 +1,7 @@ package amazon import ( + "context" "encoding/json" "errors" "fmt" @@ -49,7 +50,7 @@ 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 @@ -91,13 +92,19 @@ 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, } - resp, err := client.Get(url) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return result, err + } + req = req.WithContext(ctx) + + resp, err := client.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..681bc0d 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,7 +59,6 @@ func TestHandle400Error(t *testing.T) { } func TestNew(t *testing.T) { - t.Parallel() expected := Client{ URL: SandboxURL, TimeOut: time.Second * 5, @@ -70,7 +72,6 @@ func TestNew(t *testing.T) { } func TestNewWithEnvironment(t *testing.T) { - t.Parallel() expected := Client{ URL: ProductionURL, TimeOut: time.Second * 5, @@ -143,6 +144,7 @@ func TestVerify(t *testing.T) { } actual, _ := client.Verify( + context.Background(), "99FD_DL23EMhrOGDnur9-ulvqomrSg6qyLPSD3CFE=", "q1YqVrJSSs7P1UvMTazKz9PLTCwoTswtyEktM9JLrShIzCvOzM-LL04tiTdW0lFKASo2NDEwMjCwMDM2MTC0AIqVAsUsLd1c4l18jIxdfTOK_N1d8kqLLHVLc8oK83OLgtPNCit9AoJdjJ3dXG2BGkqUrAxrAQ", ) @@ -158,7 +160,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) } From d53311131ec77b1379f3a60bf239c4dcaf5d4428 Mon Sep 17 00:00:00 2001 From: Junpei Tsuji Date: Fri, 18 May 2018 11:21:17 +0900 Subject: [PATCH 2/3] Fixed coverage command --- .travis.yml | 2 +- Makefile | 8 +------- README.md | 2 +- 3 files changed, 3 insertions(+), 9 deletions(-) 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) From 034e269dc9e813650b0ba29ff5ce93018f486a12 Mon Sep 17 00:00:00 2001 From: Junpei Tsuji Date: Fri, 18 May 2018 11:42:20 +0900 Subject: [PATCH 3/3] Support custom client for amazon app store --- amazon/validator.go | 40 ++++++++++--------------------- amazon/validator_test.go | 52 +++++++++++++--------------------------- 2 files changed, 29 insertions(+), 63 deletions(-) diff --git a/amazon/validator.go b/amazon/validator.go index 1d0b3fe..0861c1b 100644 --- a/amazon/validator.go +++ b/amazon/validator.go @@ -7,7 +7,6 @@ import ( "fmt" "net/http" "os" - "time" ) const ( @@ -25,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"` @@ -57,34 +49,31 @@ type IAPClient interface { 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 } @@ -92,19 +81,16 @@ func NewWithConfig(config Config) Client { } // Verify sends receipts and gets validation result -func (c Client) Verify(ctx context.Context, 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 } req = req.WithContext(ctx) - resp, err := client.Do(req) + 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 681bc0d..77e272d 100644 --- a/amazon/validator_test.go +++ b/amazon/validator_test.go @@ -59,10 +59,10 @@ func TestHandle400Error(t *testing.T) { } func TestNew(t *testing.T) { - expected := Client{ + expected := &Client{ URL: SandboxURL, - TimeOut: time.Second * 5, Secret: "developerSecret", + httpCli: http.DefaultClient, } actual := New("developerSecret") @@ -72,10 +72,10 @@ func TestNew(t *testing.T) { } func TestNewWithEnvironment(t *testing.T) { - expected := Client{ + expected := &Client{ URL: ProductionURL, - TimeOut: time.Second * 5, Secret: "developerSecret", + httpCli: http.DefaultClient, } os.Setenv("IAP_ENVIRONMENT", "production") @@ -87,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) } @@ -175,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 }