From 203479be89daab0e6f74dde1d3fa4d9e32bafc9c Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Fri, 15 May 2026 14:24:31 +0200 Subject: [PATCH 1/3] Fix flaky integration tests --- .../linode_client/test_linode_client.py | 43 +++++++++++-------- test/integration/models/domain/test_domain.py | 3 +- test/integration/models/linode/test_linode.py | 2 +- .../models/placement/test_placement.py | 2 +- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/test/integration/linode_client/test_linode_client.py b/test/integration/linode_client/test_linode_client.py index 762462220..84c17f831 100644 --- a/test/integration/linode_client/test_linode_client.py +++ b/test/integration/linode_client/test_linode_client.py @@ -1,7 +1,7 @@ import re import time from test.integration.conftest import get_region -from test.integration.helpers import get_test_label +from test.integration.helpers import get_test_label, wait_for_condition import pytest @@ -55,10 +55,11 @@ def test_fails_to_create_domain_without_soa_email(setup_client_and_linode): timestamp = str(time.time_ns()) domain_addr = timestamp + "example.com" - try: - domain = client.domain_create(domain=domain_addr) - except ApiError as e: - assert e.status == 400 + + with pytest.raises(ApiError) as exc_info: + client.domain_create(domain=domain_addr) + + assert exc_info.value.status == 400 @pytest.mark.smoke @@ -90,11 +91,16 @@ def test_get_regions(test_linode_client): def test_image_create(setup_client_and_linode): client = setup_client_and_linode[0] linode = setup_client_and_linode[1] - label = get_test_label() description = "Test description" tags = ["test"] - usable_disk = [v for v in linode.disks if v.filesystem != "swap"] + + def linode_disks_are_ready(linode_instance): + linode_instance.invalidate() + disks = [d for d in linode_instance.disks if d.filesystem != "swap"] + return disks if disks else None + + usable_disk = wait_for_condition(5, 120, linode_disks_are_ready, linode) image = client.image_create( disk=usable_disk[0].id, label=label, description=description, tags=tags @@ -116,10 +122,11 @@ def test_fails_to_create_image_with_non_existing_disk_id( description = "Test description" disk_id = 111111 - try: + with pytest.raises(ApiError) as exc_info: client.image_create(disk=disk_id, label=label, description=description) - except ApiError as e: - assert 400 <= e.status < 500 + + # TODO: Specific status code may be used when defect is solved: ARB-7797 + assert 400 <= exc_info.value.status < 500 def test_fails_to_delete_predefined_images(setup_client_and_linode): @@ -127,12 +134,11 @@ def test_fails_to_delete_predefined_images(setup_client_and_linode): images = client.images() - try: + with pytest.raises(ApiError, match="Unauthorized") as exc_info: # new images go on top of the list thus choose last image images.last().delete() - except ApiError as e: - assert "Unauthorized" in str(e.json) - assert e.status == 403 + + assert exc_info.value.status == 403 def test_get_volume(test_linode_client, test_volume): @@ -345,16 +351,15 @@ def test_fails_to_create_cluster_with_invalid_version(test_linode_client): client = test_linode_client region = get_region(client, {"Kubernetes"}).id - try: - cluster = client.lke.cluster_create( + with pytest.raises(ApiError, match="not valid") as exc_info: + client.lke.cluster_create( region, "example-cluster", invalid_version, {"type": "g6-standard-1", "count": 3}, ) - except ApiError as e: - assert "not valid" in str(e.json) - assert e.status == 400 + + assert exc_info.value.status == 400 # ObjectStorageGroupTests diff --git a/test/integration/models/domain/test_domain.py b/test/integration/models/domain/test_domain.py index d7956d421..0ca674f1a 100644 --- a/test/integration/models/domain/test_domain.py +++ b/test/integration/models/domain/test_domain.py @@ -43,10 +43,9 @@ def test_clone(test_linode_client, test_domain): dom = "example.clone-" + timestamp + "-inttestsdk.org" domain.clone(dom) - time.sleep(1) + time.sleep(3) ds = test_linode_client.domains() - domains = [i.domain for i in ds] assert dom in domains diff --git a/test/integration/models/linode/test_linode.py b/test/integration/models/linode/test_linode.py index f73fbfc0a..0e677b67a 100644 --- a/test/integration/models/linode/test_linode.py +++ b/test/integration/models/linode/test_linode.py @@ -304,7 +304,7 @@ def test_linode_rebuild(test_linode_client): root_pass="aComplex@Password123", ) - wait_for_condition(10, 100, get_status, linode, "running") + wait_for_condition(10, 150, get_status, linode, "running") retry_sending_request( 3, diff --git a/test/integration/models/placement/test_placement.py b/test/integration/models/placement/test_placement.py index 21c6519f5..1a7e38e27 100644 --- a/test/integration/models/placement/test_placement.py +++ b/test/integration/models/placement/test_placement.py @@ -92,7 +92,7 @@ def test_pg_migration( # Says it could take up to ~6 hrs for migration to fully complete send_request_when_resource_available( - 300, + 400, linode.initiate_migration, placement_group=pg_inbound.id, migration_type=MigrationType.COLD, From f6a02ce918dbe1fb2810183cbc9fda95076cfd4e Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Fri, 15 May 2026 15:19:24 +0200 Subject: [PATCH 2/3] Update test_domain and test_volume with waits --- test/integration/conftest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/integration/conftest.py b/test/integration/conftest.py index 74c7a8fd5..85c86aa90 100644 --- a/test/integration/conftest.py +++ b/test/integration/conftest.py @@ -310,6 +310,12 @@ def test_domain(test_linode_client): domain=domain_addr, soa_email=soa_email, tags=["test-tag"] ) + def get_domain_status(): + domain.invalidate() + return domain.status == "active" + + wait_for_condition(3, 30, get_domain_status) + # Create a SRV record domain.record_create( "SRV", @@ -333,6 +339,12 @@ def test_volume(test_linode_client): volume = client.volume_create(label=label, region=region) + def get_volume_status(): + volume.invalidate() + return volume.status == "active" + + wait_for_condition(5, 45, get_volume_status) + yield volume send_request_when_resource_available(timeout=100, func=volume.delete) From d35ffe806ca383c4d96ea6f123e09066902833e1 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 18 May 2026 16:51:58 +0200 Subject: [PATCH 3/3] Update test_linode_client and test_account with waits --- .../linode_client/test_linode_client.py | 27 +++++++------------ .../models/account/test_account.py | 2 +- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/test/integration/linode_client/test_linode_client.py b/test/integration/linode_client/test_linode_client.py index 84c17f831..c471e9544 100644 --- a/test/integration/linode_client/test_linode_client.py +++ b/test/integration/linode_client/test_linode_client.py @@ -9,6 +9,13 @@ from linode_api4.objects import ConfigInterface, ObjectStorageKeys, Region +def is_tag_created(client, tag_label): + tags = client.tags() + tag_label_list = [i.label for i in tags] + + return tag_label in tag_label_list + + @pytest.fixture(scope="session") def setup_client_and_linode(test_linode_client, e2e_test_firewall): client = test_linode_client @@ -156,11 +163,7 @@ def test_get_tag(test_linode_client, test_tag): client = test_linode_client label = test_tag.label - tags = client.tags() - - tag_label_list = [i.label for i in tags] - - assert label in tag_label_list + assert wait_for_condition(3, 1, is_tag_created, client, label) def test_create_tag_with_id( @@ -182,15 +185,10 @@ def test_create_tag_with_id( volumes=[volume.id, volume], ) - # Get tags after creation - tags = client.tags() - - tag_label_list = [i.label for i in tags] + assert wait_for_condition(3, 30, is_tag_created, client, label) tag.delete() - assert label in tag_label_list - @pytest.mark.smoke def test_create_tag_with_entities( @@ -208,15 +206,10 @@ def test_create_tag_with_entities( label, entities=[linode, domain, nodebalancer, volume] ) - # Get tags after creation - tags = client.tags() - - tag_label_list = [i.label for i in tags] + assert wait_for_condition(3, 30, is_tag_created, client, label) tag.delete() - assert label in tag_label_list - # AccountGroupTests def test_get_account_settings(test_linode_client): diff --git a/test/integration/models/account/test_account.py b/test/integration/models/account/test_account.py index 2bb3c48f0..1c97798f7 100644 --- a/test/integration/models/account/test_account.py +++ b/test/integration/models/account/test_account.py @@ -111,7 +111,7 @@ def get_linode_status(): return linode.status == "running" # To ensure the Linode is running and the 'event' key has been populated - wait_for_condition(3, 100, get_linode_status) + wait_for_condition(5, 150, get_linode_status) events = client.load(Event, "") latest_events = events._raw_json.get("data")[:15]