From f4e28fabc285707395bd6db570bc06491240fcb6 Mon Sep 17 00:00:00 2001 From: Nicolas Rochelemagne Date: Thu, 10 Sep 2026 18:30:26 -0600 Subject: [PATCH] fix: drop stale test that required network_for_floating_ip Commit 8ae7cc1 made 'network_for_floating_ip' optional in create_vm, but a test asserting the old "field is required" die was merged in parallel from another branch. Neither branch saw the other, so main went red on every CI job. Without a floating network, create_vm now runs the whole create flow, so the test hit unmocked endpoints and died on "Connection refused" instead of the expected message. Remove the stale assertion and add t/create-vm-no-floating-ip.t, which covers the path nothing tested: create_vm succeeds with no floating network, returns the server, and never asks for a floating IP. That test fails if the requirement is reintroduced. Also ignore local/, the cpm dependency directory CI already builds. Co-Authored-By: Claude Opus 5 (1M context) --- .gitignore | 1 + t/create-vm-no-floating-ip.t | 151 +++++++++++++++++++++++++++++++++++ t/error-handling.t | 13 +-- 3 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 t/create-vm-no-floating-ip.t diff --git a/.gitignore b/.gitignore index 4886d27..bbb7047 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ OpenStack-* .DS_Store .idea/ .vscode/ +local/ diff --git a/t/create-vm-no-floating-ip.t b/t/create-vm-no-floating-ip.t new file mode 100644 index 0000000..2820cda --- /dev/null +++ b/t/create-vm-no-floating-ip.t @@ -0,0 +1,151 @@ +#!/usr/bin/env perl + +# create_vm() must work on a cloud with no tenant network to escape from. +# There the only network is external and shared, the server is given a +# routable address directly, and there is no floating IP to attach. +# 'network_for_floating_ip' is optional for exactly that reason. + +use strict; +use warnings; + +use OpenStack::MetaAPI (); + +use Test2::Bundle::Extended; +use Test2::Tools::Explain; +use Test2::Plugin::NoWarnings; + +use FindBin; +use lib "$FindBin::Bin/lib"; + +use Test::OpenStack::MetaAPI qw{:all}; +use Test::OpenStack::MetaAPI::Auth qw{:all}; + +use JSON; + +mock_lwp_useragent(); + +my $api = get_api_object(use_env => 0); +ok $api, "got one api object" or die; + +my $IMAGE_UID = '170fafa5-1329-44a3-9c27-9bb77b77206d'; +my $SERVER_UID = 'aaaaa-bbbb-ccccc-dddd'; + +mock_get_request( + 'http://127.0.0.1:8774/v2.1/flavors', + application_json(json_for_flavors()), +); + +mock_get_request( + 'http://127.0.0.1:9696/v2.0/networks', + application_json(json_for_networks()), +); + +mock_get_request( + 'http://127.0.0.1:9292/v2/images/' . $IMAGE_UID, + application_json(json_imageid()), +); + +mock_get_request( + 'http://127.0.0.1:9696/v2.0/security-groups', + application_json(json_for_security_groups()), +); + +mock_post_request( + 'http://127.0.0.1:8774/v2.1/servers', + application_json(json_create_server()), +); + +mock_get_request( + 'http://127.0.0.1:8774/v2.1/servers/' . $SERVER_UID, + application_json(json_active_server()), +); + +# Note: POST /v2.0/floatingips is intentionally NOT mocked. Asking for one +# would escape the mock layer and fail the test, which is the point. + +$api->create_max_timeout(60); +$api->create_loop_sleep(0); + +my $vm; +ok lives { + $vm = $api->create_vm( + name => "vm-no-floating-ip", + image => $IMAGE_UID, + flavor => 'small', + network => 'net1', + ); +}, "create_vm() succeeds without 'network_for_floating_ip'" + or note $@; + +is ref $vm, 'HASH', "got the server back"; +is $vm->{id}, $SERVER_UID, "server id is returned"; +is $vm->{status}, 'ACTIVE', "server is active"; + +is $vm->{floating_ip_address}, undef, "no floating ip address was set"; +is $vm->{floating_ip_id}, undef, "no floating ip id was set"; + +like last_http_request(), + qr{^GET \Qhttp://127.0.0.1:8774/v2.1/servers/$SERVER_UID\E$}, + "last call was the status poll, no floating ip was requested"; + +done_testing; + +# --- mock fixtures ------------------------------------------------------------ + +sub json_active_server { + return JSON::encode_json( + {server => {id => $SERVER_UID, status => 'ACTIVE'}}); +} + +sub json_create_server { + return <<'JSON'; +{ + "server" : { + "id": "aaaaa-bbbb-ccccc-dddd", + "name" : "vm-no-floating-ip" + } +} +JSON +} + +sub json_imageid { + return <<'JSON'; +{ + "OS-DCF:diskConfig": "AUTO", + "id": "70a599e0-31e7-49b7-b260-868f441e862b", + "name": "fakeimage7", + "status": "ACTIVE" +} +JSON +} + +sub json_for_flavors { + return <<'JSON'; +{ + "flavors": [ + { "id": "1", "name": "tiny" }, + { "id": "2", "name": "small" } + ] +} +JSON +} + +sub json_for_networks { + return <<'JSON'; +{ + "networks": [ + { "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", "name": "net1" } + ] +} +JSON +} + +sub json_for_security_groups { + return <<'JSON'; +{ + "security_groups": [ + { "id": "85cc3048-abc3-43cc-89b3-377341426ac5", "name": "default" } + ] +} +JSON +} diff --git a/t/error-handling.t b/t/error-handling.t index b6016bb..493b3ad 100644 --- a/t/error-handling.t +++ b/t/error-handling.t @@ -72,15 +72,10 @@ ok $api, "got one api object" or die; qr/'name' field is required/, "create_vm() without name gives useful error"; - like dies { - $api->create_vm( - flavor => 'small', - network => 'net1', - image => 'img1', - name => 'myvm') - }, - qr/'network_for_floating_ip' field is required/, - "create_vm() without network_for_floating_ip gives useful error"; + # 'network_for_floating_ip' is deliberately NOT checked here: it is an + # optional argument. A cloud whose only network is external and shared + # hands the server a routable address directly, so there is no floating + # IP to attach. See t/create-vm-no-floating-ip.t for that path. } # --- look_by_id_or_name error path ---