From 5460aa7eb7d033bae7e6c34961754645a0d2ed50 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 10:58:52 +0200 Subject: [PATCH 01/15] Fix failing assertions --- tests/integration/nodebalancers/test_node_balancers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index f41362061..1a0bac919 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -482,7 +482,7 @@ def test_update_node_for_node_balancer_udp_configuration( == node_id + ",defaultnode1," + nodebalancer_with_udp_config_and_node[3] - + ":80,Unknown,30,none" + + ":80,Unknown,30,none," ) @@ -511,7 +511,7 @@ def test_list_nodes_for_node_balancer_udp_configuration( == node_id + ",defaultnode1," + nodebalancer_with_udp_config_and_node[3] - + ":80,Unknown,100,none" + + ":80,Unknown,100,none," ) @@ -540,7 +540,7 @@ def test_view_node_for_node_balancer_udp_configuration( == node_id + ",defaultnode1," + nodebalancer_with_udp_config_and_node[3] - + ":80,Unknown,100,none" + + ":80,Unknown,100,none," ) From 04c2c3068f895a7e74e653dc1ef7475b63a3cccb Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 11:06:53 +0200 Subject: [PATCH 02/15] Replace fixtures.py with conftest.py --- .../integration/nodebalancers/{fixtures.py => conftest.py} | 4 ++-- tests/integration/nodebalancers/test_node_balancers.py | 7 ------- 2 files changed, 2 insertions(+), 9 deletions(-) rename tests/integration/nodebalancers/{fixtures.py => conftest.py} (99%) diff --git a/tests/integration/nodebalancers/fixtures.py b/tests/integration/nodebalancers/conftest.py similarity index 99% rename from tests/integration/nodebalancers/fixtures.py rename to tests/integration/nodebalancers/conftest.py index a1a973e66..100ac4ab6 100644 --- a/tests/integration/nodebalancers/fixtures.py +++ b/tests/integration/nodebalancers/conftest.py @@ -96,7 +96,7 @@ def nodebalancer_w_config_and_node(linode_cloud_firewall): config_id, "--format", "id", - ] + ] ) yield nodebalancer_id, config_id, node_id, node_ip @@ -280,7 +280,7 @@ def nodebalancer_with_udp_config_and_node(linode_cloud_firewall): "--no-headers", "--format", "id", - ] + ] ) yield nodebalancer_id, config_id, node_id, node_ip diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 1a0bac919..98835f7c4 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -8,13 +8,6 @@ exec_failing_test_command, exec_test_command, ) -from tests.integration.nodebalancers.fixtures import ( # noqa: F401 - linode_to_add, - nodebalancer_w_config_and_node, - nodebalancer_with_default_conf, - nodebalancer_with_udp_config_and_node, - simple_nodebalancer_with_config, -) def test_fail_to_create_nodebalancer_without_region(): From 3eae0f69dded854f3f8d4bd2e36268fde06515e0 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 13:56:19 +0200 Subject: [PATCH 03/15] Create test for backend_vpcs --- tests/integration/conftest.py | 2 +- tests/integration/nodebalancers/conftest.py | 10 +++ .../nodebalancers/test_node_balancers.py | 83 ++++++++++++++++++- 3 files changed, 92 insertions(+), 3 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 2f1e5ed76..a18ab27c1 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -214,7 +214,7 @@ def create_vpc_w_subnet(): See: https://github.com/pytest-dev/pytest/issues/1216 """ - region = get_random_region_with_caps(required_capabilities=["VPCs"]) + region = get_random_region_with_caps(required_capabilities=["VPCs", "NodeBalancers"]) vpc_label = get_random_text(5) + "label" subnet_label = get_random_text(5) + "label" diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index 100ac4ab6..f09e6da80 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -1,5 +1,6 @@ import pytest +from tests.integration.conftest import create_vpc_w_subnet from tests.integration.helpers import ( BASE_CMDS, check_attribute_value, @@ -336,3 +337,12 @@ def simple_nodebalancer_with_config(linode_cloud_firewall): yield nodebalancer_id, config_id delete_target_id(target="nodebalancers", id=nodebalancer_id) + + +@pytest.fixture +def get_vpc_with_subnet(): + vpc_json = create_vpc_w_subnet() + + yield vpc_json + + delete_target_id(target="vpcs", id=str(vpc_json["id"])) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 98835f7c4..d092a2f2f 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -1,3 +1,5 @@ +import ipaddress +import json import re import pytest @@ -5,11 +7,16 @@ from linodecli.exit_codes import ExitCodes from tests.integration.helpers import ( BASE_CMDS, + delete_target_id, exec_failing_test_command, exec_test_command, ) +def nodebalancer_created(): + return "[0-9]+,balancer[0-9]+,us-ord,[0-9]+-[0-9]+-[0-9]+-[0-9]+.ip.linodeusercontent.com,0" + + def test_fail_to_create_nodebalancer_without_region(): result = exec_failing_test_command( BASE_CMDS["nodebalancers"] @@ -537,5 +544,77 @@ def test_view_node_for_node_balancer_udp_configuration( ) -def nodebalancer_created(): - return "[0-9]+,balancer[0-9]+,us-ord,[0-9]+-[0-9]+-[0-9]+-[0-9]+.ip.linodeusercontent.com,0" +def test_nb_with_backend_vpc_only(get_vpc_with_subnet): + vpc = get_vpc_with_subnet + + nb_attrs = exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--backend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + "--text", + "--delimiter", + ",", + "--no-headers", + ] + ).split(",") + + assert isinstance(ipaddress.ip_address(nb_attrs[5]), ipaddress.IPv4Address) + assert isinstance(ipaddress.ip_address(nb_attrs[6]), ipaddress.IPv6Address) + assert nb_attrs[-2] == "public" + assert nb_attrs[-1] == "" + + nb_vpcs = exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "vpcs-list", + nb_attrs[0], + "--json", + ] + ) + nb_vpcs = json.loads(nb_vpcs) + + assert len(nb_vpcs) == 1 + assert nb_vpcs[0]["purpose"] == "backend" + + nb_vpc = exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "vpc-view", + nb_attrs[0], + str(nb_vpcs[0]["id"]), + "--json", + ] + ) + nb_vpc = json.loads(nb_vpc) + + assert nb_vpc[0]["purpose"] == "backend" + + # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished + # nb_backend_vpcs = exec_test_command( + # BASE_CMDS["nodebalancers"] + # + [ + # "backend_vpcs-list", + # nb_attrs[0], + # "--json", + # ] + # ) + # nb_backend_vpcs = json.loads(nb_backend_vpcs) + # assert len(nb_backend_vpcs) == 1 + # assert nb_backend_vpcs[0]["purpose"] == "backend" + # + # nb_frontend_vpcs = exec_test_command( + # BASE_CMDS["nodebalancers"] + # + [ + # "frontend_vpcs-list", + # nb_attrs[0], + # "--json", + # ] + # ) + # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) + # assert len(nb_frontend_vpcs) == 0 + + delete_target_id(target="nodebalancers", id=nb_attrs[0]) From fd3b6a10c85a4674528f5651d21410905da88a6d Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 15:37:13 +0200 Subject: [PATCH 04/15] Create test for frontend VPC IPv4 --- .../nodebalancers/test_node_balancers.py | 81 +++++++++++++++---- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index d092a2f2f..fc9fc57cc 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -555,23 +555,22 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): vpc["region"], "--backend_vpcs.subnet_id", str(vpc["subnets"][0]["id"]), - "--text", - "--delimiter", - ",", - "--no-headers", + "--json", ] - ).split(",") + ) + nb_attrs = json.loads(nb_attrs) + nb_id = str(nb_attrs[0]["id"]) - assert isinstance(ipaddress.ip_address(nb_attrs[5]), ipaddress.IPv4Address) - assert isinstance(ipaddress.ip_address(nb_attrs[6]), ipaddress.IPv6Address) - assert nb_attrs[-2] == "public" - assert nb_attrs[-1] == "" + assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv4"]), ipaddress.IPv4Address) + assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv6"]), ipaddress.IPv6Address) + assert nb_attrs[0]["frontend_address_type"] == "public" + assert nb_attrs[0]["frontend_vpc_subnet_id"] is None nb_vpcs = exec_test_command( BASE_CMDS["nodebalancers"] + [ "vpcs-list", - nb_attrs[0], + nb_id, "--json", ] ) @@ -584,7 +583,7 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): BASE_CMDS["nodebalancers"] + [ "vpc-view", - nb_attrs[0], + nb_id, str(nb_vpcs[0]["id"]), "--json", ] @@ -598,7 +597,7 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): # BASE_CMDS["nodebalancers"] # + [ # "backend_vpcs-list", - # nb_attrs[0], + # nb_id, # "--json", # ] # ) @@ -610,11 +609,65 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): # BASE_CMDS["nodebalancers"] # + [ # "frontend_vpcs-list", - # nb_attrs[0], + # nb_id, # "--json", # ] # ) # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) # assert len(nb_frontend_vpcs) == 0 - delete_target_id(target="nodebalancers", id=nb_attrs[0]) + delete_target_id(target="nodebalancers", id=nb_id) + + +def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): + vpc = get_vpc_with_subnet + ipv4_address = "10.0.0.2" # first available address + + nb_attrs = exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--frontend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + "--frontend_vpcs.ipv4_range", + "10.0.0.0/24", + "--type", + "premium", + "--json", + ] + ) + nb_attrs = json.loads(nb_attrs) + nb_id = str(nb_attrs[0]["id"]) + + assert nb_attrs[0]["ipv4"] == ipv4_address + assert nb_attrs[0]["ipv6"] is None + assert nb_attrs[0]["frontend_address_type"] == "vpc" + assert nb_attrs[0]["frontend_vpc_subnet_id"] == vpc["subnets"][0]["id"] + + # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished + # nb_frontend_vpcs = exec_test_command( + # BASE_CMDS["nodebalancers"] + # + [ + # "frontend_vpcs-list", + # nb_id, + # "--json", + # ] + # ) + # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) + # assert len(nb_frontend_vpcs) == 1 + # assert nb_frontend_vpcs[0]["purpose"] == "frontend" + # + # nb_backend_vpcs = exec_test_command( + # BASE_CMDS["nodebalancers"] + # + [ + # "backend_vpcs-list", + # nb_id, + # "--json", + # ] + # ) + # nb_backend_vpcs = json.loads(nb_backend_vpcs) + # assert len(nb_backend_vpcs) == 0 + + delete_target_id(target="nodebalancers", id=nb_id) From 397bc44ce570cd274864ba6a4f42f82dbf40f5b9 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 15:59:35 +0200 Subject: [PATCH 05/15] Refactor tests --- .../nodebalancers/test_node_balancers.py | 46 +++---------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index fc9fc57cc..d9eb36688 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -560,58 +560,34 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): ) nb_attrs = json.loads(nb_attrs) nb_id = str(nb_attrs[0]["id"]) - assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv4"]), ipaddress.IPv4Address) assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv6"]), ipaddress.IPv6Address) assert nb_attrs[0]["frontend_address_type"] == "public" assert nb_attrs[0]["frontend_vpc_subnet_id"] is None nb_vpcs = exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "vpcs-list", - nb_id, - "--json", - ] + BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] ) nb_vpcs = json.loads(nb_vpcs) - assert len(nb_vpcs) == 1 assert nb_vpcs[0]["purpose"] == "backend" nb_vpc = exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "vpc-view", - nb_id, - str(nb_vpcs[0]["id"]), - "--json", - ] + BASE_CMDS["nodebalancers"] + ["vpc-view", nb_id, str(nb_vpcs[0]["id"]), "--json",] ) nb_vpc = json.loads(nb_vpc) - assert nb_vpc[0]["purpose"] == "backend" # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished # nb_backend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] - # + [ - # "backend_vpcs-list", - # nb_id, - # "--json", - # ] + # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] # ) # nb_backend_vpcs = json.loads(nb_backend_vpcs) # assert len(nb_backend_vpcs) == 1 # assert nb_backend_vpcs[0]["purpose"] == "backend" # # nb_frontend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] - # + [ - # "frontend_vpcs-list", - # nb_id, - # "--json", - # ] + # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] # ) # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) # assert len(nb_frontend_vpcs) == 0 @@ -648,24 +624,14 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished # nb_frontend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] - # + [ - # "frontend_vpcs-list", - # nb_id, - # "--json", - # ] + # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] # ) # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) # assert len(nb_frontend_vpcs) == 1 # assert nb_frontend_vpcs[0]["purpose"] == "frontend" # # nb_backend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] - # + [ - # "backend_vpcs-list", - # nb_id, - # "--json", - # ] + # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] # ) # nb_backend_vpcs = json.loads(nb_backend_vpcs) # assert len(nb_backend_vpcs) == 0 From 49cfdffaa68c90cbaf73ec346479c0d0c21a95bd Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Mon, 30 Mar 2026 17:01:57 +0200 Subject: [PATCH 06/15] Create test for: premium_40gb & error msgs --- tests/integration/conftest.py | 9 +- tests/integration/helpers.py | 8 +- tests/integration/nodebalancers/conftest.py | 9 +- .../nodebalancers/test_node_balancers.py | 90 +++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index a18ab27c1..58b002648 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -11,7 +11,7 @@ from itertools import count from pathlib import Path from random import randint -from typing import Callable, Optional +from typing import Callable, List, Optional import pytest import requests @@ -203,7 +203,7 @@ def _generate_test_files( return _generate_test_files -def create_vpc_w_subnet(): +def create_vpc_w_subnet(valid_regions: List[str] = None): """ Creates and returns a VPC and a corresponding subnet. @@ -214,7 +214,10 @@ def create_vpc_w_subnet(): See: https://github.com/pytest-dev/pytest/issues/1216 """ - region = get_random_region_with_caps(required_capabilities=["VPCs", "NodeBalancers"]) + region = get_random_region_with_caps( + required_capabilities=["VPCs", "NodeBalancers"], + valid_regions=valid_regions, + ) vpc_label = get_random_text(5) + "label" subnet_label = get_random_text(5) + "label" diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 03a0fc30b..d273190a6 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -189,7 +189,9 @@ def retry_exec_test_command_with_delay( def get_random_region_with_caps( - required_capabilities: List[str], site_type="core" + required_capabilities: List[str], + site_type: str = "core", + valid_regions: List[str] = None, ): json_regions_data = exec_test_command( ["linode-cli", "regions", "ls", "--json"] @@ -208,6 +210,10 @@ def get_random_region_with_caps( # Extract the region ids matching_region_ids = [region["id"] for region in matching_regions] + # To filter out regions that cannot be used for the Linode resource + if valid_regions: + matching_region_ids = [reg for reg in matching_region_ids if reg in valid_regions] + return random.choice(matching_region_ids) if matching_region_ids else None diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index f09e6da80..16e4edd44 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -1,3 +1,5 @@ +import json + import pytest from tests.integration.conftest import create_vpc_w_subnet @@ -6,6 +8,8 @@ check_attribute_value, delete_target_id, exec_test_command, + get_random_region_with_caps, + get_random_text, wait_for_condition, ) from tests.integration.linodes.helpers import DEFAULT_TEST_IMAGE @@ -340,8 +344,9 @@ def simple_nodebalancer_with_config(linode_cloud_firewall): @pytest.fixture -def get_vpc_with_subnet(): - vpc_json = create_vpc_w_subnet() +def get_vpc_with_subnet(request): + premium_regions = getattr(request, "param", None) + vpc_json = create_vpc_w_subnet(premium_regions) yield vpc_json diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index d9eb36688..a0e3712bb 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -13,6 +13,30 @@ ) +# Lists of valid regions where NodeBalancers of type "premium" or "premium_40gb" can be created +PREMIUM_REGIONS = [ + "nl-ams", + "jp-tyo-3", + "sg-sin-2", + "de-fra-2", + "in-bom-2", + "gb-lon", + "us-lax", + "id-cgk", + "us-mia", + "it-mil", + "jp-osa", + "in-maa", + "se-sto", + "br-gru", + "us-sea", + "fr-par", + "us-iad", + "pl-labkrk-2", # DevCloud +] +PREMIUM_40GB_REGIONS = ["us-iad"] # No DevCloud region for premium_40gb type + + def nodebalancer_created(): return "[0-9]+,balancer[0-9]+,us-ord,[0-9]+-[0-9]+-[0-9]+-[0-9]+.ip.linodeusercontent.com,0" @@ -595,6 +619,7 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): delete_target_id(target="nodebalancers", id=nb_id) +@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): vpc = get_vpc_with_subnet ipv4_address = "10.0.0.2" # first available address @@ -637,3 +662,68 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): # assert len(nb_backend_vpcs) == 0 delete_target_id(target="nodebalancers", id=nb_id) + + +@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +def test_nb_with_frontend_ipv6_in_single_stack_vpc_fail(get_vpc_with_subnet): + vpc = get_vpc_with_subnet + + result = exec_failing_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--frontend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + "--frontend_vpcs.ipv6_range", + "/62", + "--type", + "premium", + ], + ) + assert "Request failed: 400" in result + assert "No IPv6 subnets available in VPC" in result + + +@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +def test_nb_with_frontend_and_default_type_fail(get_vpc_with_subnet): + vpc = get_vpc_with_subnet + + result = exec_failing_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--frontend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + ], + ) + assert "Request failed: 400" in result + assert "NodeBalancer with frontend VPC IP must be premium" in result + + +@pytest.mark.parametrize( + "get_vpc_with_subnet", + [PREMIUM_40GB_REGIONS], + indirect=True, +) +def test_nb_with_premium40gb_type(get_vpc_with_subnet): + vpc = get_vpc_with_subnet + + nb_attrs = exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--type", + "premium_40gb", + "--json", + ], + ) + nb_attrs = json.loads(nb_attrs) + assert nb_attrs[0]["type"] == "premium_40gb" + + delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) From d7cf679b7bbbf74285808c7ac2bfabda90197156 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 09:32:52 +0200 Subject: [PATCH 07/15] Clean up --- tests/integration/nodebalancers/conftest.py | 4 ++-- tests/integration/nodebalancers/test_node_balancers.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index 16e4edd44..982bd3567 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -101,7 +101,7 @@ def nodebalancer_w_config_and_node(linode_cloud_firewall): config_id, "--format", "id", - ] + ] ) yield nodebalancer_id, config_id, node_id, node_ip @@ -285,7 +285,7 @@ def nodebalancer_with_udp_config_and_node(linode_cloud_firewall): "--no-headers", "--format", "id", - ] + ] ) yield nodebalancer_id, config_id, node_id, node_ip diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index a0e3712bb..9a4bc4556 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -12,7 +12,6 @@ exec_test_command, ) - # Lists of valid regions where NodeBalancers of type "premium" or "premium_40gb" can be created PREMIUM_REGIONS = [ "nl-ams", From 69a14be8143c5d47d6740df70fab980558b4c7d8 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 09:47:48 +0200 Subject: [PATCH 08/15] Refactor to use json.loads straightaway --- tests/integration/nodebalancers/conftest.py | 4 - .../nodebalancers/test_node_balancers.py | 119 ++++++++++-------- 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index 982bd3567..ca4f5354b 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -1,5 +1,3 @@ -import json - import pytest from tests.integration.conftest import create_vpc_w_subnet @@ -8,8 +6,6 @@ check_attribute_value, delete_target_id, exec_test_command, - get_random_region_with_caps, - get_random_text, wait_for_condition, ) from tests.integration.linodes.helpers import DEFAULT_TEST_IMAGE diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 9a4bc4556..55cf14daf 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -570,49 +570,54 @@ def test_view_node_for_node_balancer_udp_configuration( def test_nb_with_backend_vpc_only(get_vpc_with_subnet): vpc = get_vpc_with_subnet - nb_attrs = exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "create", - "--region", - vpc["region"], - "--backend_vpcs.subnet_id", - str(vpc["subnets"][0]["id"]), - "--json", - ] + nb_attrs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--backend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + "--json", + ] + ), ) - nb_attrs = json.loads(nb_attrs) nb_id = str(nb_attrs[0]["id"]) assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv4"]), ipaddress.IPv4Address) assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv6"]), ipaddress.IPv6Address) assert nb_attrs[0]["frontend_address_type"] == "public" assert nb_attrs[0]["frontend_vpc_subnet_id"] is None - nb_vpcs = exec_test_command( - BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] + nb_vpcs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] + ), ) - nb_vpcs = json.loads(nb_vpcs) assert len(nb_vpcs) == 1 assert nb_vpcs[0]["purpose"] == "backend" - nb_vpc = exec_test_command( - BASE_CMDS["nodebalancers"] + ["vpc-view", nb_id, str(nb_vpcs[0]["id"]), "--json",] + nb_vpc = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + ["vpc-view", nb_id, str(nb_vpcs[0]["id"]), "--json",] + ), ) - nb_vpc = json.loads(nb_vpc) assert nb_vpc[0]["purpose"] == "backend" # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished - # nb_backend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] + # nb_backend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] + # ), # ) - # nb_backend_vpcs = json.loads(nb_backend_vpcs) # assert len(nb_backend_vpcs) == 1 # assert nb_backend_vpcs[0]["purpose"] == "backend" # - # nb_frontend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] + # nb_frontend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] + # ), # ) - # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) # assert len(nb_frontend_vpcs) == 0 delete_target_id(target="nodebalancers", id=nb_id) @@ -623,22 +628,23 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): vpc = get_vpc_with_subnet ipv4_address = "10.0.0.2" # first available address - nb_attrs = exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "create", - "--region", - vpc["region"], - "--frontend_vpcs.subnet_id", - str(vpc["subnets"][0]["id"]), - "--frontend_vpcs.ipv4_range", - "10.0.0.0/24", - "--type", - "premium", - "--json", - ] + nb_attrs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--frontend_vpcs.subnet_id", + str(vpc["subnets"][0]["id"]), + "--frontend_vpcs.ipv4_range", + "10.0.0.0/24", + "--type", + "premium", + "--json", + ], + ), ) - nb_attrs = json.loads(nb_attrs) nb_id = str(nb_attrs[0]["id"]) assert nb_attrs[0]["ipv4"] == ipv4_address @@ -647,17 +653,19 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): assert nb_attrs[0]["frontend_vpc_subnet_id"] == vpc["subnets"][0]["id"] # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished - # nb_frontend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] + # nb_frontend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] + # ), # ) - # nb_frontend_vpcs = json.loads(nb_frontend_vpcs) # assert len(nb_frontend_vpcs) == 1 # assert nb_frontend_vpcs[0]["purpose"] == "frontend" # - # nb_backend_vpcs = exec_test_command( - # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] + # nb_backend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] + # ), # ) - # nb_backend_vpcs = json.loads(nb_backend_vpcs) # assert len(nb_backend_vpcs) == 0 delete_target_id(target="nodebalancers", id=nb_id) @@ -711,18 +719,19 @@ def test_nb_with_frontend_and_default_type_fail(get_vpc_with_subnet): def test_nb_with_premium40gb_type(get_vpc_with_subnet): vpc = get_vpc_with_subnet - nb_attrs = exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "create", - "--region", - vpc["region"], - "--type", - "premium_40gb", - "--json", - ], + nb_attrs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc["region"], + "--type", + "premium_40gb", + "--json", + ], + ), ) - nb_attrs = json.loads(nb_attrs) assert nb_attrs[0]["type"] == "premium_40gb" delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) From afe85ccff096f904ad3df1525b7eaebf52d3c6c1 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 10:58:19 +0200 Subject: [PATCH 09/15] Add test for backend and frontend --- .../nodebalancers/test_node_balancers.py | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 55cf14daf..962616e74 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -10,6 +10,7 @@ delete_target_id, exec_failing_test_command, exec_test_command, + get_random_text, ) # Lists of valid regions where NodeBalancers of type "premium" or "premium_40gb" can be created @@ -735,3 +736,97 @@ def test_nb_with_premium40gb_type(get_vpc_with_subnet): assert nb_attrs[0]["type"] == "premium_40gb" delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) + + +@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +def test_nb_with_frontend_and_backend_in_different_vpcs(get_vpc_with_subnet): + vpc_backend = get_vpc_with_subnet + ipv4_range = "10.0.0.0/24" + ipv4_address = "10.0.0.2" # first available address + + vpc_frontend = json.loads( + exec_test_command( + [ + "linode-cli", + "vpcs", + "create", + "--label", + get_random_text(5) + "label", + "--region", + vpc_backend["region"], + # "--ipv6.range", TODO: Uncomment after VPC Dual Stack is ready to ship + # "auto", + "--subnets.ipv4", + "10.0.0.0/24", + "--subnets.label", + get_random_text(5) + "label", + "--json", + "--suppress-warnings", + ] + ) + )[0] + # ipv6_range = vpc_frontend.subnets[0]["ipv6"], TODO: Uncomment after VPC Dual Stack is ready to ship + # ipv6_address = ipv6_range.split("::")[0] + ":1::1" + + nb_attrs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "create", + "--region", + vpc_backend["region"], + "--backend_vpcs.subnet_id", + str(vpc_backend["subnets"][0]["id"]), + "--frontend_vpcs.subnet_id", + str(vpc_frontend["subnets"][0]["id"]), + "--frontend_vpcs.ipv4_range", + "10.0.0.0/24", + # "--frontend_vpcs.ipv6_range", TODO: Uncomment after VPC Dual Stack is ready to ship + # "auto", + "--type", + "premium", + "--json", + ] + ), + ) + nb_id = str(nb_attrs[0]["id"]) + + assert nb_attrs[0]["ipv4"] == ipv4_address + assert nb_attrs[0]["ipv6"] is None + # assert nb_attrs[0]["ipv6"] == ipv6_address TODO: Uncomment and remove above line after VPC Dual Stack is ready to ship + assert nb_attrs[0]["frontend_address_type"] == "vpc" + assert nb_attrs[0]["frontend_vpc_subnet_id"] == vpc_frontend["subnets"][0]["id"] + + nb_vpcs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] + ), + ) + nb_vpcs.sort(key=lambda x: x["purpose"]) + + assert len(nb_vpcs) == 2 + assert nb_vpcs[0]["purpose"] == "backend" + assert nb_vpcs[1]["ipv4_range"] == f"{ipv4_address}/32" + assert nb_vpcs[1]["ipv6_range"] is None + # assert nb_vpcs[1]["ipv6_range"] == f"{ipv6_address[:-1]}/64" TODO: Uncomment after VPC Dual Stack is ready to ship + assert nb_vpcs[1]["purpose"] == "frontend" + + # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished + # nb_backend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] + # ), + # ) + # assert len(nb_backend_vpcs) == 1 + # assert nb_backend_vpcs[0]["purpose"] == "backend" + # + # nb_frontend_vpcs = json.loads( + # exec_test_command( + # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] + # ), + # ) + # assert len(nb_frontend_vpcs) == 1 + # assert nb_frontend_vpcs[0]["purpose"] == "frontend" + + delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) + delete_target_id(target="vpcs", id=str(vpc_frontend["id"])) From b96b55eb6c4f56fde0c4f30fe38004e44ccd99ab Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 11:01:51 +0200 Subject: [PATCH 10/15] Reformat test_node_balancers.py --- .../nodebalancers/test_node_balancers.py | 130 ++++-------------- 1 file changed, 28 insertions(+), 102 deletions(-) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 962616e74..bfe4d80d3 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -10,7 +10,6 @@ delete_target_id, exec_failing_test_command, exec_test_command, - get_random_text, ) # Lists of valid regions where NodeBalancers of type "premium" or "premium_40gb" can be created @@ -585,14 +584,23 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): ), ) nb_id = str(nb_attrs[0]["id"]) - assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv4"]), ipaddress.IPv4Address) - assert isinstance(ipaddress.ip_address(nb_attrs[0]["ipv6"]), ipaddress.IPv6Address) + assert isinstance( + ipaddress.ip_address(nb_attrs[0]["ipv4"]), ipaddress.IPv4Address + ) + assert isinstance( + ipaddress.ip_address(nb_attrs[0]["ipv6"]), ipaddress.IPv6Address + ) assert nb_attrs[0]["frontend_address_type"] == "public" assert nb_attrs[0]["frontend_vpc_subnet_id"] is None nb_vpcs = json.loads( exec_test_command( - BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] + BASE_CMDS["nodebalancers"] + + [ + "vpcs-list", + nb_id, + "--json", + ] ), ) assert len(nb_vpcs) == 1 @@ -600,7 +608,13 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): nb_vpc = json.loads( exec_test_command( - BASE_CMDS["nodebalancers"] + ["vpc-view", nb_id, str(nb_vpcs[0]["id"]), "--json",] + BASE_CMDS["nodebalancers"] + + [ + "vpc-view", + nb_id, + str(nb_vpcs[0]["id"]), + "--json", + ] ), ) assert nb_vpc[0]["purpose"] == "backend" @@ -624,7 +638,9 @@ def test_nb_with_backend_vpc_only(get_vpc_with_subnet): delete_target_id(target="nodebalancers", id=nb_id) -@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +@pytest.mark.parametrize( + "get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True +) def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): vpc = get_vpc_with_subnet ipv4_address = "10.0.0.2" # first available address @@ -672,7 +688,9 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): delete_target_id(target="nodebalancers", id=nb_id) -@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +@pytest.mark.parametrize( + "get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True +) def test_nb_with_frontend_ipv6_in_single_stack_vpc_fail(get_vpc_with_subnet): vpc = get_vpc_with_subnet @@ -694,7 +712,9 @@ def test_nb_with_frontend_ipv6_in_single_stack_vpc_fail(get_vpc_with_subnet): assert "No IPv6 subnets available in VPC" in result -@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) +@pytest.mark.parametrize( + "get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True +) def test_nb_with_frontend_and_default_type_fail(get_vpc_with_subnet): vpc = get_vpc_with_subnet @@ -736,97 +756,3 @@ def test_nb_with_premium40gb_type(get_vpc_with_subnet): assert nb_attrs[0]["type"] == "premium_40gb" delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) - - -@pytest.mark.parametrize("get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True) -def test_nb_with_frontend_and_backend_in_different_vpcs(get_vpc_with_subnet): - vpc_backend = get_vpc_with_subnet - ipv4_range = "10.0.0.0/24" - ipv4_address = "10.0.0.2" # first available address - - vpc_frontend = json.loads( - exec_test_command( - [ - "linode-cli", - "vpcs", - "create", - "--label", - get_random_text(5) + "label", - "--region", - vpc_backend["region"], - # "--ipv6.range", TODO: Uncomment after VPC Dual Stack is ready to ship - # "auto", - "--subnets.ipv4", - "10.0.0.0/24", - "--subnets.label", - get_random_text(5) + "label", - "--json", - "--suppress-warnings", - ] - ) - )[0] - # ipv6_range = vpc_frontend.subnets[0]["ipv6"], TODO: Uncomment after VPC Dual Stack is ready to ship - # ipv6_address = ipv6_range.split("::")[0] + ":1::1" - - nb_attrs = json.loads( - exec_test_command( - BASE_CMDS["nodebalancers"] - + [ - "create", - "--region", - vpc_backend["region"], - "--backend_vpcs.subnet_id", - str(vpc_backend["subnets"][0]["id"]), - "--frontend_vpcs.subnet_id", - str(vpc_frontend["subnets"][0]["id"]), - "--frontend_vpcs.ipv4_range", - "10.0.0.0/24", - # "--frontend_vpcs.ipv6_range", TODO: Uncomment after VPC Dual Stack is ready to ship - # "auto", - "--type", - "premium", - "--json", - ] - ), - ) - nb_id = str(nb_attrs[0]["id"]) - - assert nb_attrs[0]["ipv4"] == ipv4_address - assert nb_attrs[0]["ipv6"] is None - # assert nb_attrs[0]["ipv6"] == ipv6_address TODO: Uncomment and remove above line after VPC Dual Stack is ready to ship - assert nb_attrs[0]["frontend_address_type"] == "vpc" - assert nb_attrs[0]["frontend_vpc_subnet_id"] == vpc_frontend["subnets"][0]["id"] - - nb_vpcs = json.loads( - exec_test_command( - BASE_CMDS["nodebalancers"] + ["vpcs-list", nb_id, "--json",] - ), - ) - nb_vpcs.sort(key=lambda x: x["purpose"]) - - assert len(nb_vpcs) == 2 - assert nb_vpcs[0]["purpose"] == "backend" - assert nb_vpcs[1]["ipv4_range"] == f"{ipv4_address}/32" - assert nb_vpcs[1]["ipv6_range"] is None - # assert nb_vpcs[1]["ipv6_range"] == f"{ipv6_address[:-1]}/64" TODO: Uncomment after VPC Dual Stack is ready to ship - assert nb_vpcs[1]["purpose"] == "frontend" - - # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished - # nb_backend_vpcs = json.loads( - # exec_test_command( - # BASE_CMDS["nodebalancers"] + ["backend_vpcs-list", nb_id, "--json",] - # ), - # ) - # assert len(nb_backend_vpcs) == 1 - # assert nb_backend_vpcs[0]["purpose"] == "backend" - # - # nb_frontend_vpcs = json.loads( - # exec_test_command( - # BASE_CMDS["nodebalancers"] + ["frontend_vpcs-list", nb_id, "--json",] - # ), - # ) - # assert len(nb_frontend_vpcs) == 1 - # assert nb_frontend_vpcs[0]["purpose"] == "frontend" - - delete_target_id(target="nodebalancers", id=str(nb_attrs[0]["id"])) - delete_target_id(target="vpcs", id=str(vpc_frontend["id"])) From 56e6aa1a6241ef0424ce1e254cb97f9f311f3660 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 11:03:22 +0200 Subject: [PATCH 11/15] Reformat helpers.py --- tests/integration/helpers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index d273190a6..002d47738 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -212,7 +212,9 @@ def get_random_region_with_caps( # To filter out regions that cannot be used for the Linode resource if valid_regions: - matching_region_ids = [reg for reg in matching_region_ids if reg in valid_regions] + matching_region_ids = [ + reg for reg in matching_region_ids if reg in valid_regions + ] return random.choice(matching_region_ids) if matching_region_ids else None From 40c36b668058a11d26c17a08a6dcf7f9ac90a2e2 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 11:38:53 +0200 Subject: [PATCH 12/15] Add premium regions to test_nb_with_backend_vpc_only Some of the regions (e.g. es-mad) cannot be used for nodebalancers and test fails --- tests/integration/nodebalancers/test_node_balancers.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index bfe4d80d3..17a5ebd9c 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -567,6 +567,9 @@ def test_view_node_for_node_balancer_udp_configuration( ) +@pytest.mark.parametrize( + "get_vpc_with_subnet", [PREMIUM_REGIONS], indirect=True +) def test_nb_with_backend_vpc_only(get_vpc_with_subnet): vpc = get_vpc_with_subnet From 0db27237cfdfca99a7d7be92d5968fd0afb7b7a4 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Tue, 31 Mar 2026 12:43:31 +0200 Subject: [PATCH 13/15] Add vpcs-list and vpc-view checks in test_nb_with_frontend_ipv4_only --- .../nodebalancers/test_node_balancers.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/integration/nodebalancers/test_node_balancers.py b/tests/integration/nodebalancers/test_node_balancers.py index 17a5ebd9c..e63b51d81 100644 --- a/tests/integration/nodebalancers/test_node_balancers.py +++ b/tests/integration/nodebalancers/test_node_balancers.py @@ -672,6 +672,32 @@ def test_nb_with_frontend_ipv4_only(get_vpc_with_subnet): assert nb_attrs[0]["frontend_address_type"] == "vpc" assert nb_attrs[0]["frontend_vpc_subnet_id"] == vpc["subnets"][0]["id"] + nb_vpcs = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "vpcs-list", + nb_id, + "--json", + ] + ), + ) + assert len(nb_vpcs) == 1 + assert nb_vpcs[0]["purpose"] == "frontend" + + nb_vpc = json.loads( + exec_test_command( + BASE_CMDS["nodebalancers"] + + [ + "vpc-view", + nb_id, + str(nb_vpcs[0]["id"]), + "--json", + ] + ), + ) + assert nb_vpc[0]["purpose"] == "frontend" + # TODO: Uncomment when API implementation of /backend_vpcs and /frontend_vpcs endpoints is finished # nb_frontend_vpcs = json.loads( # exec_test_command( From bcd812dbd67cd2ca7992d9c6d78375f7fff91a3a Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 1 Apr 2026 12:49:21 +0200 Subject: [PATCH 14/15] Change default scope to 'module' for get_vpc_with_subnet fixture --- tests/integration/nodebalancers/conftest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index ca4f5354b..71e353483 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -1,3 +1,5 @@ +import json + import pytest from tests.integration.conftest import create_vpc_w_subnet @@ -339,7 +341,7 @@ def simple_nodebalancer_with_config(linode_cloud_firewall): delete_target_id(target="nodebalancers", id=nodebalancer_id) -@pytest.fixture +@pytest.fixture(scope="module") def get_vpc_with_subnet(request): premium_regions = getattr(request, "param", None) vpc_json = create_vpc_w_subnet(premium_regions) From dddaea3c8289edf55efe7632121f455121bdafb3 Mon Sep 17 00:00:00 2001 From: Maciej Wilk Date: Wed, 1 Apr 2026 13:03:53 +0200 Subject: [PATCH 15/15] Linter --- tests/integration/nodebalancers/conftest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/integration/nodebalancers/conftest.py b/tests/integration/nodebalancers/conftest.py index 71e353483..871639989 100644 --- a/tests/integration/nodebalancers/conftest.py +++ b/tests/integration/nodebalancers/conftest.py @@ -1,5 +1,3 @@ -import json - import pytest from tests.integration.conftest import create_vpc_w_subnet