Skip to content

Commit 18031a1

Browse files
authored
Merge pull request #159 from square/FixIntegrationTests
Add some delays to integration tests
2 parents 0b35c73 + f8bf5e6 commit 18031a1

File tree

3 files changed

+273
-59
lines changed

3 files changed

+273
-59
lines changed

tests/integration/test_catalog.py

Lines changed: 118 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import time
22
import uuid
3+
from functools import wraps
34

5+
from square.core.api_error import ApiError
46
from square.core.request_options import RequestOptions
57
from square.types.catalog_item import CatalogItem
68
from square.types.catalog_item_variation import CatalogItemVariation
@@ -20,55 +22,99 @@
2022
MAX_TIMEOUT = 120
2123

2224

25+
def retry_on_rate_limit(max_retries=5, base_delay=2):
26+
def decorator(func):
27+
@wraps(func)
28+
def wrapper(*args, **kwargs):
29+
for attempt in range(max_retries):
30+
try:
31+
return func(*args, **kwargs)
32+
except ApiError as e:
33+
if e.status_code == 429 and attempt < max_retries - 1:
34+
delay = base_delay * (2 ** attempt) # exponential backoff
35+
print(f"Rate limited. Retrying in {delay} seconds...")
36+
time.sleep(delay)
37+
continue
38+
raise
39+
return None
40+
return wrapper
41+
return decorator
42+
43+
44+
@retry_on_rate_limit()
2345
def test_upload_catalog_image():
2446
# Wait to kick off the first test to avoid being rate limited.
2547
time.sleep(3)
2648

2749
client = helpers.test_client()
2850

29-
# Setup: Create a catalog object to associate the image with
30-
catalog_object = helpers.create_test_catalog_item(
31-
helpers.CreateCatalogItemOptions()
32-
)
33-
create_catalog_resp = client.catalog.batch_upsert(
34-
idempotency_key=str(uuid.uuid4()),
35-
batches=[CatalogObjectBatch(objects=[catalog_object])],
36-
)
37-
38-
objects = create_catalog_resp.objects
39-
assert objects is not None
40-
assert 1 == len(objects)
41-
created_catalog_object = objects[0]
42-
assert isinstance(created_catalog_object, CatalogObjectItem)
43-
assert created_catalog_object.id is not None
44-
45-
# Create a new catalog image
46-
image_name = "Test Image " + str(uuid.uuid4())
47-
create_catalog_image_resp = client.catalog.images.create(
48-
image_file=helpers.get_test_file(),
49-
request={
50-
"idempotency_key": str(uuid.uuid4()),
51-
"image": {
52-
"type": "IMAGE",
53-
"id": helpers.new_test_square_id(),
54-
"image_data": {"name": image_name},
51+
try:
52+
# Setup: Create a catalog object to associate the image with
53+
catalog_object = helpers.create_test_catalog_item(
54+
helpers.CreateCatalogItemOptions()
55+
)
56+
create_catalog_resp = client.catalog.batch_upsert(
57+
idempotency_key=str(uuid.uuid4()),
58+
batches=[CatalogObjectBatch(objects=[catalog_object])],
59+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
60+
)
61+
62+
time.sleep(2) # Add delay after creation
63+
64+
objects = create_catalog_resp.objects
65+
assert objects is not None
66+
assert 1 == len(objects)
67+
created_catalog_object = objects[0]
68+
assert isinstance(created_catalog_object, CatalogObjectItem)
69+
assert created_catalog_object.id is not None
70+
71+
# Create a new catalog image
72+
image_name = "Test Image " + str(uuid.uuid4())
73+
create_catalog_image_resp = client.catalog.images.create(
74+
image_file=helpers.get_test_file(),
75+
request={
76+
"idempotency_key": str(uuid.uuid4()),
77+
"image": {
78+
"type": "IMAGE",
79+
"id": helpers.new_test_square_id(),
80+
"image_data": {"name": image_name},
81+
},
82+
"object_id": created_catalog_object.id,
5583
},
56-
"object_id": created_catalog_object.id,
57-
},
58-
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
59-
)
60-
image = create_catalog_image_resp.image
61-
assert image is not None
62-
assert isinstance(image, CatalogObjectImage)
63-
64-
# Cleanup
65-
client.catalog.batch_delete(
66-
object_ids=[created_catalog_object.id, image.id],
67-
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
68-
)
69-
70-
84+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
85+
)
86+
87+
time.sleep(2) # Add delay after image creation
88+
89+
image = create_catalog_image_resp.image
90+
assert image is not None
91+
assert isinstance(image, CatalogObjectImage)
92+
93+
# Add retry logic for cleanup
94+
for attempt in range(MAX_RETRIES):
95+
try:
96+
time.sleep(2) # Add delay before cleanup attempt
97+
# Cleanup
98+
client.catalog.batch_delete(
99+
object_ids=[created_catalog_object.id, image.id],
100+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
101+
)
102+
break
103+
except ApiError as e:
104+
if e.status_code == 429 and attempt < MAX_RETRIES - 1:
105+
delay = 2 * (2 ** attempt)
106+
print(f"Cleanup rate limited. Retrying in {delay} seconds...")
107+
time.sleep(delay)
108+
continue
109+
raise
110+
except Exception as e:
111+
print(f"Error in test_upload_catalog_image: {str(e)}")
112+
raise
113+
114+
115+
@retry_on_rate_limit()
71116
def test_upsert_catalog_object():
117+
time.sleep(2) # Add initial delay
72118
client = helpers.test_client()
73119

74120
coffee_variation_opts = helpers.CreateCatalogItemVariationOptions()
@@ -106,7 +152,9 @@ def test_upsert_catalog_object():
106152
assert "Colombian Fair Trade" == item_variation_data.name
107153

108154

155+
@retry_on_rate_limit()
109156
def test_catalog_info():
157+
time.sleep(2) # Add initial delay
110158
client = helpers.test_client()
111159
response = client.catalog.search(
112160
limit=1, request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT)
@@ -116,14 +164,17 @@ def test_catalog_info():
116164
assert len(response.objects) > 0
117165

118166

167+
@retry_on_rate_limit()
119168
def test_search_catalog_items():
169+
time.sleep(2) # Add initial delay
120170
client = helpers.test_client()
121171
response = client.catalog.search_items(
122172
limit=1, request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT)
123173
)
124174
assert response is not None
125175

126176

177+
@retry_on_rate_limit()
127178
def test_batch_upsert_catalog_objects():
128179
# Wait to kick off this test to avoid being rate limited.
129180
time.sleep(3)
@@ -187,8 +238,11 @@ def test_batch_upsert_catalog_objects():
187238
]
188239
}
189240
],
241+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
190242
)
191243

244+
time.sleep(2) # Add delay after batch upsert
245+
192246
objects = response.objects
193247
assert objects is not None
194248
assert 2 == len(objects)
@@ -220,6 +274,8 @@ def test_batch_upsert_catalog_objects():
220274
assert len(catalog_modifier_list_ids) > 0
221275
catalog_modifier_list_id = catalog_modifier_list_ids[0]
222276

277+
time.sleep(2) # Add delay before batch get
278+
223279
response = client.catalog.batch_get(
224280
object_ids=[catalog_modifier_id, catalog_modifier_list_id, catalog_tax_id],
225281
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
@@ -235,15 +291,21 @@ def test_batch_upsert_catalog_objects():
235291
catalog_tax_id,
236292
}
237293

294+
time.sleep(2) # Add delay before catalog item creation
295+
238296
catalog_item = helpers.create_test_catalog_item(helpers.CreateCatalogItemOptions())
239297
catalog_response = client.catalog.object.upsert(
240-
idempotency_key=str(uuid.uuid4()), object=catalog_item
298+
idempotency_key=str(uuid.uuid4()),
299+
object=catalog_item,
300+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
241301
)
242302
catalog_object = catalog_response.catalog_object
243303
assert catalog_object is not None
244304
assert isinstance(catalog_object, CatalogObjectItem)
245305
catalog_object_id = catalog_object.id
246306

307+
time.sleep(2) # Add delay before update taxes
308+
247309
response = client.catalog.update_item_taxes(
248310
item_ids=[catalog_object_id],
249311
taxes_to_enable=[catalog_tax_id],
@@ -253,6 +315,8 @@ def test_batch_upsert_catalog_objects():
253315
assert response.updated_at is not None
254316
assert response.errors is None
255317

318+
time.sleep(2) # Add delay before update modifier lists
319+
256320
response = client.catalog.update_item_modifier_lists(
257321
item_ids=[catalog_object_id],
258322
modifier_lists_to_enable=[catalog_modifier_list_id],
@@ -263,18 +327,27 @@ def test_batch_upsert_catalog_objects():
263327
assert response.errors is None
264328

265329

330+
@retry_on_rate_limit()
266331
def test_delete_catalog_object():
332+
time.sleep(2) # Add initial delay
267333
client = helpers.test_client()
268334

269335
catalog_item = helpers.create_test_catalog_item(helpers.CreateCatalogItemOptions())
270336
catalog_response = client.catalog.object.upsert(
271-
idempotency_key=str(uuid.uuid4()), object=catalog_item
337+
idempotency_key=str(uuid.uuid4()),
338+
object=catalog_item,
339+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
272340
)
273341
catalog_object = catalog_response.catalog_object
274342
assert catalog_object is not None
275343
assert isinstance(catalog_object, CatalogObjectItem)
276344
catalog_object_id = catalog_object.id
277345

278-
response = client.catalog.object.delete(object_id=catalog_object_id)
346+
time.sleep(2) # Add delay before delete
279347

280-
assert response is not None
348+
response = client.catalog.object.delete(
349+
object_id=catalog_object_id,
350+
request_options=RequestOptions(timeout_in_seconds=MAX_TIMEOUT),
351+
)
352+
353+
assert response is not None

0 commit comments

Comments
 (0)