Merge pull request #23 from jun06t/test

Fixed tests
This commit is contained in:
Junpei Tsuji
2016-06-08 17:30:46 +09:00
5 changed files with 48 additions and 41 deletions

View File

@@ -1,12 +1,12 @@
language: go language: go
go: go:
- 1.3 - 1.6.2
before_install: before_install:
sudo pip install codecov - sudo pip install codecov
install: install:
- make setup - make setup
script: script:
- make cover - make cover
after_success: after_success:
codecov - codecov

View File

@@ -12,11 +12,13 @@ import (
) )
const ( const (
SandboxURL string = "http://localhost:8080/RVSSandbox" // SandboxURL is the endpoint for local environment.
SandboxURL string = "http://localhost:8080/RVSSandbox"
// ProductionURL is the endpoint for production environment.
ProductionURL string = "https://appstore-sdk.amazon.com" ProductionURL string = "https://appstore-sdk.amazon.com"
) )
func getSandboxUrl() string { func getSandboxURL() string {
url := os.Getenv("IAP_SANDBOX_URL") url := os.Getenv("IAP_SANDBOX_URL")
if url == "" { if url == "" {
url = SandboxURL url = SandboxURL
@@ -41,6 +43,7 @@ type IAPResponse struct {
TestTransaction bool `json:"testTransaction"` TestTransaction bool `json:"testTransaction"`
} }
// The IAPResponseError typs has error message and status.
type IAPResponseError struct { type IAPResponseError struct {
Message string `json:"message"` Message string `json:"message"`
Status bool `json:"status"` Status bool `json:"status"`
@@ -61,7 +64,7 @@ type Client struct {
// New creates a client object // New creates a client object
func New(secret string) IAPClient { func New(secret string) IAPClient {
client := Client{ client := Client{
URL: getSandboxUrl(), URL: getSandboxURL(),
Secret: secret, Secret: secret,
TimeOut: time.Second * 5, TimeOut: time.Second * 5,
} }
@@ -78,7 +81,7 @@ func NewWithConfig(config Config) Client {
} }
client := Client{ client := Client{
URL: getSandboxUrl(), URL: getSandboxURL(),
Secret: config.Secret, Secret: config.Secret,
TimeOut: config.TimeOut, TimeOut: config.TimeOut,
} }

View File

@@ -13,7 +13,9 @@ import (
) )
const ( const (
SandboxURL string = "https://sandbox.itunes.apple.com/verifyReceipt" // SandboxURL is the endpoint for sandbox environment.
SandboxURL string = "https://sandbox.itunes.apple.com/verifyReceipt"
// ProductionURL is the endpoint for production environment.
ProductionURL string = "https://buy.itunes.apple.com/verifyReceipt" ProductionURL string = "https://buy.itunes.apple.com/verifyReceipt"
) )

View File

@@ -63,8 +63,8 @@ func TestHandleError(t *testing.T) {
t.Errorf("got %v\nwant %v", actual, expected) t.Errorf("got %v\nwant %v", actual, expected)
} }
// status unkown // status unknown
expected = errors.New("An unknown error ocurred") expected = errors.New("An unknown error occurred")
actual = HandleError(100) actual = HandleError(100)
if !reflect.DeepEqual(actual, expected) { if !reflect.DeepEqual(actual, expected) {
t.Errorf("got %v\nwant %v", actual, expected) t.Errorf("got %v\nwant %v", actual, expected)

View File

@@ -1,7 +1,7 @@
package playstore package playstore
import ( import (
"encoding/json" "encoding/base64"
"errors" "errors"
"reflect" "reflect"
"testing" "testing"
@@ -10,28 +10,31 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
type testSignature struct { var base64JsonKey = "ew0KICAidHlwZSI6ICJzZXJ2aWNlX2FjY291bnQiLA0KICAicHJvamVjdF9pZCI6ICJnby1pYXAiLA0KICAicHJpdmF0ZV9rZXlfaWQiOiAiZjI0MGRmZTg4Y2NlMTBmMThhZjM2ZjdhNTEyNDUyZjE0Y2RkM2EyZSIsDQogICJwcml2YXRlX2tleSI6ICItLS0tLUJFR0lOIFBSSVZBVEUgS0VZLS0tLS1cbk1JSUV2Z0lCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktnd2dnU2tBZ0VBQW9JQkFRQ29sbndXRmhacjlmQUNcbjNqcEozbGk5SSt4ZzUyZGl3R0pzUnBoY0U0S0xielJpM1ZWdUEvMU1EMkcwMmNOYkZ5V3NDSWg4aDMvNE1sZmxcbmtMa29wVlJlNVFlczRMY3E4RDRVOUdubjZwWXduWlI5NVBlK2Z6TVdLNGJpSWgvdHhNMzJlemxvQWwvaU5Rbi9cbmdQQ3lUc0pHNlVlNzJsdFJyblFXdkM0L24vQzNHL3lLY2ZLaHo2ODZ6NTd4ODZma28yUnEra21RaFNmY3REY3pcbng3YlNmUDU4SFdUOVhDNHlHSERqZmkwMmxnVU1YaW5Fa2VQVzB1UC9SZG8ya0dlaWhSV1JGMFFNRHlld2p1S0pcbmtaL3pCOGhyZm9RVEdmMjE4L29lQXR0UWl0ZkxkVlkrajc5Y2VxQTlBUXorbGoxQjUrSVZiRjlOQ2toaTNYYThcbndHMml6WEViQWdNQkFBRUNnZ0VBTFZnRVdnQm8yWExWc2ovSlY3THBGVDVEUnJFV3VwWGFJeHM5d1k0eHo0VUNcbmh4RFcrSGMwT3Evc2JMTWhleStYbjFUUU9RWk00aG5RVUZ1RG9hNE9LbFBabzZMeFFTaEsybUgrMWpUZlhvWVRcbnVXVExTYjUycENEaTc1R1VHdVNUTFJkcGtsTUpMUk5zOC83ZlBtWTJsTklMekRmbjFlbGhLZmhGVERHZGtmSVNcbkprNjQvd0JTRUx5ZTFQOFdYM0JLV3hZdFBKajgvc0pqTDl0SVhXcitaSjR2bGgzM1c1b25BWS9lMFJoZkZDSjJcbjBFWkZFVXkrblNUVHBUR1JmYzYyMFl2c2JyVWozcFo3dDBIRE5IN3ovbnVEeVB4UUpORTg1RVlQRDBaeU9VNnpcbmV2aW9ObmJBKzFVREdFOVg5NFVVbnJNckJ5NU5Jbk13bCt3djZ5VWFJUUtCZ1FEYnFhazVXbTRla1FJZVpsMmhcbkZ3ZU9TR0FOek9ZVmE3TWExQm9hUHBLKzVuak1xbUQxRHB4cGlFYmFGNnpwVWMyZkVIT0ZEZ21zQUZrYUw1cmNcbnRzVC84amtXRHdKSjAvQlE4QlpiekZuU1I4bHhlbFBscFNySVcremcrNWdhbDZtTXpLS2J0a29TVUsxem5uMnpcbkEydmhTTis5N1VsYTByK2d3ZCttQ0gvTVN3S0JnUURFZWVPbE1vRzM2eWxlRXFOaDdhNUlySWt0dFlCbnJuMXFcblhCSFJmWFQ5c3ROOHhPL0pYQ2s1S1JIREkzUWZJbVcrSmdJV3NwRjY1Q00rZnFRN1l2UWNwV0RGdDZvc1hRNm5cbmVhZC9RYlJ5TzlLcXY3SEo2aHJycGJrS0NvSjBBbFRKZmt4T2svTDBnM3Zkblhia242L3pVeC9JZXRsZHE4T1NcbjNlU2FBbnBNY1FLQmdRQ3diQWQ2Qk9ORXNYcGVLQ0V5N0dncEluL2pGWm9Gd2taTFdlYk5CVXllL2tRdlBQZzZcbldjM09CS0hETUJpMEcvdGxzYlRXUEh3UUpRZHJQS2pJZEJLczdrSmpNUkxKY09zbVZtM2V0TFcvYWVDa3YzYjZcbmpqbGFTbHBxS0NmMTA3RmRZRTJKZWxMcmV0aVViOHJOS0FaUkhsSjFIRXM2SXVHOW4zaWN4VjYvR1FLQmdISElcbnJUK0Vpbjg2MzFBdHR4VUZrd05mZUdwU1RMUys1cjdyNXgzTmJDMW9uUFlMRDFzcjFtdldEd1ZWeVBBbStZa3ZcbmRkSXpRL0ZKb2VlVmJBTkFnV0w5bTVlbGtCWDFKb0Z6QUwvQUM0S0VocktBSmJScnNYOTdFRGh5Y2E1QmsxekZcbm1lZC80eG9iODJZYXhUb09DTlgvODg0azV6RktRZzhTRmt2aTEzVGhBb0dCQUxRV1krV0hDL0hDU3VhaVQ1ck5cbnFiclIwM01BVTg4T3UyelZLZ1FLa0t0eDhaN0RLY2duRmNEWktQOUdPcXJFVjdhZElxdDZIckwvR1FqdVFDSGFcblRoc3dGRmVZM005MEViempGTE1WWVhlaHlFYzJidkJmcFpFSG5UM1VSNXI1ZWRYWmpGYnJySFdDMGFsYnNSR1pcbnZoQ2dBT3c4bk54SFRtMlBrMkZ2bHZyWFxuLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLVxuIiwNCiAgImNsaWVudF9lbWFpbCI6ICJnby1pYXBAZ28taWFwLmlhbS5nc2VydmljZWFjY291bnQuY29tIiwNCiAgImNsaWVudF9pZCI6ICIxMDMxMTMwNDc5ODIwNjMwMTE3MjciLA0KICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL2F1dGgiLA0KICAidG9rZW5fdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsDQogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwNCiAgImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3JvYm90L3YxL21ldGFkYXRhL3g1MDkvZ28taWFwJTQwZ28taWFwLmlhbS5nc2VydmljZWFjY291bnQuY29tIg0KfQ=="
PrivateKeyID string `json:"private_key_id"`
PrivateKey string `json:"private_key"`
ClientEmail string `json:"client_email"`
ClientID string `json:"client_id"`
Type string `json:"type"`
}
var testJSON = testSignature{ var base64dummyKey = "ew0KICAidHlwZSI6ICJzZXJ2aWNlX2FjY291bnQiLA0KICAicHJvamVjdF9pZCI6ICJnby1pYXAiLA0KICAicHJpdmF0ZV9rZXlfaWQiOiAiZHVtbXkiLA0KICAicHJpdmF0ZV9rZXkiOiAiLS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tXG5NSUlFdmdJQkFEQU5CZ2txaGtpRzl3MEJBUUVGQUFTQ0JLZ3dnZ1NrQWdFQUFvSUJBUUNvbG53V0ZoWnI5ZkFDXG4zanBKM2xpOUkreGc1MmRpd0dKc1JwaGNFNEtMYnpSaTNWVnVBLzFNRDJHMDJjTmJGeVdzQ0loOGgzLzRNbGZsXG5rTGtvcFZSZTVRZXM0TGNxOEQ0VTlHbm42cFl3blpSOTVQZStmek1XSzRiaUloL3R4TTMyZXpsb0FsL2lOUW4vXG5nUEN5VHNKRzZVZTcybHRScm5RV3ZDNC9uL0MzRy95S2NmS2h6Njg2ejU3eDg2ZmtvMlJxK2ttUWhTZmN0RGN6XG54N2JTZlA1OEhXVDlYQzR5R0hEamZpMDJsZ1VNWGluRWtlUFcwdVAvUmRvMmtHZWloUldSRjBRTUR5ZXdqdUtKXG5rWi96QjhocmZvUVRHZjIxOC9vZUF0dFFpdGZMZFZZK2o3OWNlcUE5QVF6K2xqMUI1K0lWYkY5TkNraGkzWGE4XG53RzJpelhFYkFnTUJBQUVDZ2dFQUxWZ0VXZ0JvMlhMVnNqL0pWN0xwRlQ1RFJyRVd1cFhhSXhzOXdZNHh6NFVDXG5oeERXK0hjME9xL3NiTE1oZXkrWG4xVFFPUVpNNGhuUVVGdURvYTRPS2xQWm82THhRU2hLMm1IKzFqVGZYb1lUXG51V1RMU2I1MnBDRGk3NUdVR3VTVExSZHBrbE1KTFJOczgvN2ZQbVkybE5JTHpEZm4xZWxoS2ZoRlRER2RrZklTXG5KazY0L3dCU0VMeWUxUDhXWDNCS1d4WXRQSmo4L3NKakw5dElYV3IrWko0dmxoMzNXNW9uQVkvZTBSaGZGQ0oyXG4wRVpGRVV5K25TVFRwVEdSZmM2MjBZdnNiclVqM3BaN3QwSEROSDd6L251RHlQeFFKTkU4NUVZUEQwWnlPVTZ6XG5ldmlvTm5iQSsxVURHRTlYOTRVVW5yTXJCeTVOSW5Nd2wrd3Y2eVVhSVFLQmdRRGJxYWs1V200ZWtRSWVabDJoXG5Gd2VPU0dBTnpPWVZhN01hMUJvYVBwSys1bmpNcW1EMURweHBpRWJhRjZ6cFVjMmZFSE9GRGdtc0FGa2FMNXJjXG50c1QvOGprV0R3SkowL0JROEJaYnpGblNSOGx4ZWxQbHBTcklXK3pnKzVnYWw2bU16S0tidGtvU1VLMXpubjJ6XG5BMnZoU04rOTdVbGEwcitnd2QrbUNIL01Td0tCZ1FERWVlT2xNb0czNnlsZUVxTmg3YTVJcklrdHRZQm5ybjFxXG5YQkhSZlhUOXN0Tjh4Ty9KWENrNUtSSERJM1FmSW1XK0pnSVdzcEY2NUNNK2ZxUTdZdlFjcFdERnQ2b3NYUTZuXG5lYWQvUWJSeU85S3F2N0hKNmhycnBia0tDb0owQWxUSmZreE9rL0wwZzN2ZG5YYmtuNi96VXgvSWV0bGRxOE9TXG4zZVNhQW5wTWNRS0JnUUN3YkFkNkJPTkVzWHBlS0NFeTdHZ3BJbi9qRlpvRndrWkxXZWJOQlV5ZS9rUXZQUGc2XG5XYzNPQktIRE1CaTBHL3Rsc2JUV1BId1FKUWRyUEtqSWRCS3M3a0pqTVJMSmNPc21WbTNldExXL2FlQ2t2M2I2XG5qamxhU2xwcUtDZjEwN0ZkWUUySmVsTHJldGlVYjhyTktBWlJIbEoxSEVzNkl1RzluM2ljeFY2L0dRS0JnSEhJXG5yVCtFaW44NjMxQXR0eFVGa3dOZmVHcFNUTFMrNXI3cjV4M05iQzFvblBZTEQxc3IxbXZXRHdWVnlQQW0rWWt2XG5kZEl6US9GSm9lZVZiQU5BZ1dMOW01ZWxrQlgxSm9GekFML0FDNEtFaHJLQUpiUnJzWDk3RURoeWNhNUJrMXpGXG5tZWQvNHhvYjgyWWF4VG9PQ05YLzg4NGs1ekZLUWc4U0ZrdmkxM1RoQW9HQkFMUVdZK1dIQy9IQ1N1YWlUNXJOXG5xYnJSMDNNQVU4OE91MnpWS2dRS2tLdHg4WjdES2NnbkZjRFpLUDlHT3FyRVY3YWRJcXQ2SHJML0dRanVRQ0hhXG5UaHN3RkZlWTNNOTBFYnpqRkxNVllYZWh5RWMyYnZCZnBaRUhuVDNVUjVyNWVkWFpqRmJyckhXQzBhbGJzUkdaXG52aENnQU93OG5OeEhUbTJQazJGdmx2clhcbi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS1cbiIsDQogICJjbGllbnRfaWQiOiAiZHVtbXkiLA0KICAiYXV0aF91cmkiOiAiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tL28vb2F1dGgyL2F1dGgiLA0KICAidG9rZW5fdXJpIjogImh0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbS9vL29hdXRoMi90b2tlbiIsDQogICJhdXRoX3Byb3ZpZGVyX3g1MDlfY2VydF91cmwiOiAiaHR0cHM6Ly93d3cuZ29vZ2xlYXBpcy5jb20vb2F1dGgyL3YxL2NlcnRzIiwNCiAgImNsaWVudF94NTA5X2NlcnRfdXJsIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL3JvYm90L3YxL21ldGFkYXRhL3g1MDkvZ28taWFwJTQwZ28taWFwLmlhbS5nc2VydmljZWFjY291bnQuY29tIg0KfQ=="
PrivateKeyID: "dummyKeyID",
PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIIBOQIBAAJBANXOa7wgs5KHMEVJmVo2eoRxEgeqiYF2oABPGYrebU+cQiE7Mwdy\nxv153DHME+9L9QzAj+fR4y5Rwva/fAsGAssCAwEAAQJATQwrFMtwCtC+22kvYywY\nsJuSlMKm9MmL1TCsErgfCj2rksRK1U+/ZY709tE3XJVYlZalWCeVhHTjs5p0pnk6\nYQIhAOw0FksytfIfpdfcREbful+LhFp1um5WjcVf7kQ73JDxAiEA57nJkG9pwnUd\nBCyIcElTVIAKU0+iFpd1208OnGxyT3sCIGaEBNkGXWmEytnxQ8DvAVjOmNcaGZwh\n/M4ZYLREtupBAiAsrpFkTWdqPKTcsi2Y4Tq1N39GMzvA+XGbWTIrDWo5UwIgHhp9\nEOnHuUuPCjpLfYM2vSFiYzaj8UJCImjkMtDwzbA=\n-----END PRIVATE KEY-----\n", var jsonKey []byte
ClientEmail: "dummyEmail", var dummyKey []byte
ClientID: "dummyClientID",
Type: "service_account", func init() {
f, err := base64.StdEncoding.DecodeString(base64JsonKey)
if err != nil {
panic(err)
}
jsonKey = f
d, err := base64.StdEncoding.DecodeString(base64dummyKey)
if err != nil {
panic(err)
}
dummyKey = d
} }
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
// Exception scenario // Exception scenario
jsonKey, _ := json.Marshal(testJSON) expected := "oauth2: cannot fetch token: 401 Unauthorized\nResponse: {\n \"error\" : \"invalid_client\",\n \"error_description\" : \"The OAuth client was invalid.\"\n}"
expected := "oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}"
actual, _ := New(jsonKey) actual, _ := New(dummyKey)
val := actual.httpClient.Transport.(*oauth2.Transport) val := actual.httpClient.Transport.(*oauth2.Transport)
token, err := val.Source.Token() token, err := val.Source.Token()
if token != nil { if token != nil {
@@ -42,6 +45,12 @@ func TestNew(t *testing.T) {
} }
// TODO Normal scenario // TODO Normal scenario
actual, _ = New(jsonKey)
val = actual.httpClient.Transport.(*oauth2.Transport)
token, err = val.Source.Token()
if err != nil {
t.Errorf("got %#v", err)
}
} }
func TestSetTimeout(t *testing.T) { func TestSetTimeout(t *testing.T) {
@@ -55,9 +64,7 @@ func TestSetTimeout(t *testing.T) {
func TestVerifySubscription(t *testing.T) { func TestVerifySubscription(t *testing.T) {
// Exception scenario // Exception scenario
jsonKey, _ := json.Marshal(testJSON) expected := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
expected := "Get https://www.googleapis.com/androidpublisher/v2/applications/package/purchases/subscriptions/subscriptionID/tokens/purchaseToken?alt=json: oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}"
client, _ := New(jsonKey) client, _ := New(jsonKey)
_, err := client.VerifySubscription("package", "subscriptionID", "purchaseToken") _, err := client.VerifySubscription("package", "subscriptionID", "purchaseToken")
@@ -81,9 +88,7 @@ func TestVerifySubscriptionAndroidPublisherError(t *testing.T) {
func TestVerifyProduct(t *testing.T) { func TestVerifyProduct(t *testing.T) {
// Exception scenario // Exception scenario
jsonKey, _ := json.Marshal(testJSON) expected := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
expected := "Get https://www.googleapis.com/androidpublisher/v2/applications/package/purchases/products/productID/tokens/purchaseToken?alt=json: oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}"
client, _ := New(jsonKey) client, _ := New(jsonKey)
_, err := client.VerifyProduct("package", "productID", "purchaseToken") _, err := client.VerifyProduct("package", "productID", "purchaseToken")
@@ -115,9 +120,8 @@ func TestCancelSubscription(t *testing.T) {
t.Errorf("got %v\nwant %v", actual, expected) t.Errorf("got %v\nwant %v", actual, expected)
} }
jsonKey, _ := json.Marshal(testJSON)
client, _ = New(jsonKey) client, _ = New(jsonKey)
expectedStr := "Post https://www.googleapis.com/androidpublisher/v2/applications/package/purchases/subscriptions/productID/tokens/purchaseToken:cancel?alt=json: oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}" expectedStr := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
actual = client.CancelSubscription("package", "productID", "purchaseToken") actual = client.CancelSubscription("package", "productID", "purchaseToken")
if actual.Error() != expectedStr { if actual.Error() != expectedStr {
@@ -137,9 +141,8 @@ func TestRefundSubscription(t *testing.T) {
t.Errorf("got %v\nwant %v", actual, expected) t.Errorf("got %v\nwant %v", actual, expected)
} }
jsonKey, _ := json.Marshal(testJSON)
client, _ = New(jsonKey) client, _ = New(jsonKey)
expectedStr := "Post https://www.googleapis.com/androidpublisher/v2/applications/package/purchases/subscriptions/productID/tokens/purchaseToken:refund?alt=json: oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}" expectedStr := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
actual = client.RefundSubscription("package", "productID", "purchaseToken") actual = client.RefundSubscription("package", "productID", "purchaseToken")
if actual.Error() != expectedStr { if actual.Error() != expectedStr {
@@ -159,9 +162,8 @@ func TestRevokeSubscription(t *testing.T) {
t.Errorf("got %v\nwant %v", actual, expected) t.Errorf("got %v\nwant %v", actual, expected)
} }
jsonKey, _ := json.Marshal(testJSON)
client, _ = New(jsonKey) client, _ = New(jsonKey)
expectedStr := "Post https://www.googleapis.com/androidpublisher/v2/applications/package/purchases/subscriptions/productID/tokens/purchaseToken:revoke?alt=json: oauth2: cannot fetch token: 400 Bad Request\nResponse: {\n \"error\" : \"invalid_grant\"\n}" expectedStr := "googleapi: Error 404: No application was found for the given package name., applicationNotFound"
actual = client.RevokeSubscription("package", "productID", "purchaseToken") actual = client.RevokeSubscription("package", "productID", "purchaseToken")
if actual.Error() != expectedStr { if actual.Error() != expectedStr {