]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Test] functional: also wait for SSL/proxy ports in teardown
authorVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 1 Jun 2026 16:32:43 +0000 (17:32 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 1 Jun 2026 16:32:43 +0000 (17:32 +0100)
The teardown port-release wait added in the previous commit only covered
the normal + controller plain ports. The 440_ssl_server flake is the
same race on a port it missed: a test rspamd binds up to five sockets
(normal, controller, proxy, controller-SSL, normal-SSL), and a previous
suite's controller-SSL listener could still hold its port when the next
rspamd on that pabot worker started. The CI log shows it exactly:

  rspamd_fork_worker: prepare to fork process controller (0);
    listen on: 127.0.0.1:57190
  rspamd_inet_address_listen: bind 127.0.0.1:57196 failed: 98,
    'Address already in use'
  spawn_workers: cannot listen on normal socket 127.0.0.1:57196

57196 is PORT_CONTROLLER_SSL for that worker slot. main carried on and
forked the controller with only its plain socket, so the SSL listener
never came up and every HTTPS test hit connection-refused for the full
retry budget -- the "slow SSL controller" the two prior band-aids tried
to wait out.

Extend Wait For Rspamd Ports Released to loop over all five ports. All
RSPAMD_PORT_* vars are always defined in vars.py, and a port the current
config never bound refuses connection immediately, so Port Is Free
passes at once -- waiting on an unused port is a cheap no-op. Verified
001_merged (which owns 440_ssl_server) still passes serially with the
SSL ports now checked in teardown; the SSL bind race is timing-dependent
under CI contention, so the fedora/ubuntu runs are the real check.

test/functional/lib/rspamd.robot

index bc3fd60276a04800e4367b8fc77f88284b8da38c..f90bb85bff006ca792fa161d4bcc980e07d22f14 100644 (file)
@@ -334,18 +334,26 @@ Rspamd Redis Teardown
 Wait For Rspamd Ports Released
   [Documentation]  Block until this suite's rspamd listening ports are
   ...  free, so the next suite on the same pabot worker can rebind them.
-  ...  Checks the always-present normal + controller ports; each is given
-  ...  up to ~6s (matches a slow worker shutdown under CPU contention) and
-  ...  failure to free is a warning, not a hard error -- we don't want a
-  ...  stuck port to mask the real test result, just to close the common
-  ...  handoff race. See port_is_free in rspamd.py for why SO_REUSEADDR
-  ...  does not cover this.
-  Run Keyword And Warn On Failure
-  ...  Wait Until Keyword Succeeds  30x  0.2s
-  ...  Port Is Free  ${RSPAMD_LOCAL_ADDR}  ${RSPAMD_PORT_NORMAL}
-  Run Keyword And Warn On Failure
-  ...  Wait Until Keyword Succeeds  30x  0.2s
-  ...  Port Is Free  ${RSPAMD_LOCAL_ADDR}  ${RSPAMD_PORT_CONTROLLER}
+  ...  Covers every port a test rspamd may bind: normal, controller,
+  ...  proxy, and the two TLS listeners (controller + normal SSL). All
+  ...  five RSPAMD_PORT_* vars are always defined in vars.py; a port the
+  ...  current config never bound just refuses connection immediately, so
+  ...  Port Is Free passes at once -- waiting on it is a cheap no-op. The
+  ...  SSL listeners matter specifically: the 440_ssl_server flake was a
+  ...  previous suite's controller-SSL socket lingering on its port, so
+  ...  the next rspamd silently came up WITHOUT its SSL listener (it logs
+  ...  bind 98 for the SSL port, then forks the controller with only the
+  ...  plain socket) and every HTTPS test got connection-refused.
+  ...  Each port gets up to ~6s; failure to free is a warning, not a hard
+  ...  error, so a stuck port can't mask the real test result. See
+  ...  port_is_free in rspamd.py for why SO_REUSEADDR does not cover this.
+  FOR  ${port}  IN
+  ...  ${RSPAMD_PORT_NORMAL}  ${RSPAMD_PORT_CONTROLLER}  ${RSPAMD_PORT_PROXY}
+  ...  ${RSPAMD_PORT_CONTROLLER_SSL}  ${RSPAMD_PORT_NORMAL_SSL}
+    Run Keyword And Warn On Failure
+    ...  Wait Until Keyword Succeeds  30x  0.2s
+    ...  Port Is Free  ${RSPAMD_LOCAL_ADDR}  ${port}
+  END
 
 Run Redis
   ${RSPAMD_TMPDIR} =  Make Temporary Directory