@@ -84,3 +84,68 @@ func TestV3CreateCreditGrantMissingTaxCode(t *testing.T) {
8484 }
8585 assert .True (t , mentionsTaxCode , "response should name the missing tax code, problem: %+v" , problem )
8686}
87+
88+ func TestV3CreateCreditGrantIdempotencyKey (t * testing.T ) {
89+ c := newV3Client (t )
90+ currency := apiv3 .CurrencyCode ("USD" )
91+
92+ createCustomer := func (prefix string ) string {
93+ status , customer , problem := c .CreateCustomer (apiv3.CreateCustomerRequest {
94+ Key : uniqueKey (prefix ),
95+ Name : "Credit Grant Idempotency Test Customer" ,
96+ Currency : & currency ,
97+ })
98+ require .Equal (t , http .StatusCreated , status , "problem: %+v" , problem )
99+ require .NotNil (t , customer )
100+ return customer .Id
101+ }
102+
103+ grant := func (key * string ) apiv3.CreateCreditGrantRequest {
104+ return apiv3.CreateCreditGrantRequest {
105+ Name : "idempotency grant" ,
106+ Amount : apiv3 .Numeric ("10" ),
107+ Currency : currency ,
108+ FundingMethod : apiv3 .BillingCreditFundingMethodNone ,
109+ Key : key ,
110+ }
111+ }
112+
113+ t .Run ("reusing a key for the same customer returns 409" , func (t * testing.T ) {
114+ customerID := createCustomer ("credit_grant_idem_conflict" )
115+ key := ulid .Make ().String ()
116+
117+ status , _ , problem := c .CreateCreditGrant (customerID , grant (& key ))
118+ require .Equal (t , http .StatusCreated , status , "first create must succeed, problem: %+v" , problem )
119+
120+ status , _ , problem = c .CreateCreditGrant (customerID , grant (& key ))
121+ require .Equal (t , http .StatusConflict , status , "reusing an idempotency key must be a 409, problem: %+v" , problem )
122+ })
123+
124+ t .Run ("omitting the key allows duplicates" , func (t * testing.T ) {
125+ customerID := createCustomer ("credit_grant_idem_nil" )
126+
127+ status , _ , problem := c .CreateCreditGrant (customerID , grant (nil ))
128+ require .Equal (t , http .StatusCreated , status , "problem: %+v" , problem )
129+
130+ status , _ , problem = c .CreateCreditGrant (customerID , grant (nil ))
131+ require .Equal (t , http .StatusCreated , status , "grants without a key must not collide, problem: %+v" , problem )
132+ })
133+
134+ t .Run ("the same key conflicts across different customers in a namespace" , func (t * testing.T ) {
135+ key := ulid .Make ().String ()
136+
137+ status , _ , problem := c .CreateCreditGrant (createCustomer ("credit_grant_idem_cust_a" ), grant (& key ))
138+ require .Equal (t , http .StatusCreated , status , "problem: %+v" , problem )
139+
140+ status , _ , problem = c .CreateCreditGrant (createCustomer ("credit_grant_idem_cust_b" ), grant (& key ))
141+ require .Equal (t , http .StatusConflict , status , "the key is unique per namespace, not per customer, problem: %+v" , problem )
142+ })
143+
144+ t .Run ("an over-length key is rejected with 400" , func (t * testing.T ) {
145+ customerID := createCustomer ("credit_grant_idem_overlong" )
146+ key := strings .Repeat ("k" , 257 )
147+
148+ status , _ , problem := c .CreateCreditGrant (customerID , grant (& key ))
149+ require .Equal (t , http .StatusBadRequest , status , "an over-length key must be a 400, problem: %+v" , problem )
150+ })
151+ }
0 commit comments