github.com/plutov/paypal/v4@v4.7.1/client_test.go (about) 1 package paypal 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "math/rand" 8 "net/http" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/assert" 14 ) 15 16 // testClientID, testSecret imported from order_test.go 17 18 // All test values are defined here 19 // var testClientID = "AXy9orp-CDaHhBZ9C78QHW2BKZpACgroqo85_NIOa9mIfJ9QnSVKzY-X_rivR_fTUUr6aLjcJsj6sDur" 20 // var testSecret = "EBoIiUSkCKeSk49hHSgTem1qnjzzJgRQHDEHvGpzlLEf_nIoJd91xu8rPOBDCdR_UYNKVxJE-UgS2iCw" 21 var testUserID = "https://www.paypal.com/webapps/auth/identity/user/VBqgHcgZwb1PBs69ybjjXfIW86_Hr93aBvF_Rgbh2II" 22 var testCardID = "CARD-54E6956910402550WKGRL6EA" 23 24 var testProductId = "" // will be fetched in func TestProduct(t *testing.T) 25 var testBillingPlan = "" // will be fetched in func TestSubscriptionPlans(t *testing.T) 26 27 const alphabet = "abcedfghijklmnopqrstuvwxyz" 28 29 func RandomString(n int) string { 30 var sb strings.Builder 31 k := len(alphabet) 32 33 for i := 0; i < n; i++ { 34 c := alphabet[rand.Intn(k)] 35 sb.WriteByte(c) 36 } 37 return sb.String() 38 } 39 40 func createRandomProduct(t *testing.T) Product { 41 //create a product 42 productData := Product{ 43 Name: RandomString(10), 44 Description: RandomString(100), 45 Category: ProductCategorySoftware, 46 Type: ProductTypeService, 47 ImageUrl: "https://example.com/image.png", 48 HomeUrl: "https://example.com", 49 } 50 return productData 51 } 52 53 // this is a simple copy of the SendWithAuth method, used to 54 // test the Lock and Unlock methods of the private mutex field 55 // of Client structure. 56 func (c *Client) sendWithAuth(req *http.Request, v interface{}) error { 57 // c.Lock() 58 c.mu.Lock() 59 // Note: Here we do not want to `defer c.Unlock()` because we need `c.Send(...)` 60 // to happen outside of the locked section. 61 62 if c.mu.TryLock() { 63 // if the code is able to acquire a lock 64 // despite the mutex of c being locked, throw an error 65 err := errors.New("TryLock succeeded inside sendWithAuth with mutex locked") 66 return err 67 } 68 if c.Token == nil || (!c.tokenExpiresAt.IsZero() && time.Until(c.tokenExpiresAt) < RequestNewTokenBeforeExpiresIn) { 69 // c.Token will be updated in GetAccessToken call 70 if _, err := c.GetAccessToken(req.Context()); err != nil { 71 // c.Unlock() 72 c.mu.Unlock() 73 return err 74 } 75 } 76 req.Header.Set("Authorization", "Bearer "+c.Token.Token) 77 // Unlock the client mutex before sending the request, this allows multiple requests 78 // to be in progress at the same time. 79 // c.Unlock() 80 c.mu.Unlock() 81 82 if !c.mu.TryLock() { 83 // if the code is unable to acquire a lock 84 // despite the mutex of c being unlocked, throw an error 85 err := errors.New("TryLock failed inside sendWithAuth with mutex unlocked") 86 return err 87 } 88 c.mu.Unlock() // undo changes from the previous TryLock 89 90 return c.Send(req, v) 91 } 92 93 // this method is used to invoke the sendWithAuth method, which will then check 94 // operationally the privated mutex field of Client structure. 95 func (c *Client) createProduct(ctx context.Context, product Product) (*CreateProductResponse, error) { 96 req, err := c.NewRequest(ctx, http.MethodPost, fmt.Sprintf("%s%s", c.APIBase, "/v1/catalogs/products"), product) 97 response := &CreateProductResponse{} 98 if err != nil { 99 return response, err 100 } 101 err = c.sendWithAuth(req, response) 102 return response, err 103 } 104 105 func TestClientMutex(t *testing.T) { 106 c, _ := NewClient(testClientID, testSecret, APIBaseSandBox) 107 c.GetAccessToken(context.Background()) 108 109 // Basic Testing of the private mutex field 110 c.mu.Lock() 111 if c.mu.TryLock() { 112 t.Fatalf("TryLock succeeded with mutex locked") 113 } 114 c.mu.Unlock() 115 if !c.mu.TryLock() { 116 t.Fatalf("TryLock failed with mutex unlocked") 117 } 118 c.mu.Unlock() // undo changes from the previous TryLock 119 120 // Operational testing of the private mutex field 121 n_iter := 2 122 123 errs := make(chan error) 124 125 for i := 0; i < n_iter; i++ { 126 go func() { 127 _, err := c.createProduct(context.Background(), createRandomProduct(t)) 128 errs <- err 129 }() 130 } 131 132 for i := 0; i < n_iter; i++ { 133 err := <-errs 134 assert.Equal(t, nil, err) 135 } 136 137 }