]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Test] functional: template dummy ports for parallel safety
authorVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 1 Jun 2026 12:46:04 +0000 (13:46 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Mon, 1 Jun 2026 12:46:04 +0000 (13:46 +0100)
The dummy_* helper ports already get a per-pabot-worker offset in
lib/vars.py (base + worker_index*100), but consumers hardcoded the
worker-0 literals (:18080/:18081/:18083), so under parallel pabot a
worker bound its dummy on an offset port while tests/configs still
pointed at :18080. That produced two failure modes: Errno 48 "address
already in use" when two workers raced the same literal port, and
cross-worker URL mismatches (worker 3's redirector fetching worker 0's
dummy, assertions expecting :18080 that never appeared).

Route every consumer through the existing per-worker value:

  * Lua test scripts (http/tcp/http_early_response): read the port from
    rspamd_env.PORT_DUMMY_HTTP/HTTPS/HTTP_EARLY (rspamd strips the
    RSPAMD_ prefix when building the Lua env table), defaulting to the
    historical literal for ad-hoc runs. Mirrors the existing maps_kv.lua
    pattern.
  * neural_llm.conf: Jinja {= env.PORT_DUMMY_HTTP =}, like the other
    templated configs.
  * test_tcp_client.lua (rspamadm): os.getenv fallback chain (it runs
    under `rspamadm lua`, not the config loader).

The url_redirector .eml fixtures embed the dummy URL but are fed raw to
the scanner -- the config-time Jinja engine does not touch them. Add a
Render Message Template keyword (Get File -> Replace Variables ->
Create File in the suite tmpdir) and have suites 162-169 render their
fixtures in setup, with ${RSPAMD_PORT_DUMMY_HTTP} placeholders in the
fixtures and assertions. Normalise redir_chain_tel_url.eml to LF while
touching it.

Verified: serial runs unchanged (worker-0 keeps the historical ports),
and 4x parallel pabot stress over the url_redirector + http/tcp/early +
antivirus/udp/p0f/settings/llm suites is stable at 142/143 with zero
Errno 48 / address-in-use and no cross-worker mismatches. The lone
remaining failure (169 path-less ?u= wrapper) is a pre-existing
redirector behaviour bug -- it fails identically on master.

22 files changed:
test/functional/cases/162_url_redirector.robot
test/functional/cases/163_url_redirector_chain.robot
test/functional/cases/164_url_redirector_pr6014.robot
test/functional/cases/165_url_redirector_cache.robot
test/functional/cases/166_url_redirector_config.robot
test/functional/cases/167_url_redirector_non_http_scheme.robot
test/functional/cases/168_url_redirector_phishing.robot
test/functional/cases/169_url_redirector_query_target.robot
test/functional/configs/neural_llm.conf
test/functional/lib/rspamd.robot
test/functional/lua/http.lua
test/functional/lua/http_early_response.lua
test/functional/lua/rspamadm/test_tcp_client.lua
test/functional/lua/tcp.lua
test/functional/messages/chain_multipart.eml
test/functional/messages/chain_redirect.eml
test/functional/messages/redir.eml
test/functional/messages/redir_chain_tel_url.eml
test/functional/messages/redir_multi_non_http.eml
test/functional/messages/redir_phishing_safe.eml
test/functional/messages/redir_query_target.eml
test/functional/messages/redir_tel_url.eml

index 5d7785a71b9e0989248cd071ab0c5506a081af5a..0ea34090478f6fb370acd724169c88824a92d0d1 100644 (file)
@@ -19,11 +19,11 @@ ${SETTINGS}        {symbols_enabled=[URL_REDIRECTOR_CHECK]}
 *** Test Cases ***
 RESOLVE URLS
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 RESOLVE URLS CACHED
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 STEALTH FINGERPRINT HEADERS
   # The live HEAD requests issued by RESOLVE URLS are logged by the dummy
@@ -38,6 +38,13 @@ STEALTH FINGERPRINT HEADERS
 Urlredirector Setup
   Run Dummy Http
   Rspamd Redis Setup
+  # .eml fixtures carry the dummy_http port as a ${RSPAMD_PORT_DUMMY_HTTP}
+  # placeholder; render them now that RSPAMD_TMPDIR exists so the per-worker
+  # offset is baked into the message the scanner reads.
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
+  ${CHAIN_MESSAGE} =  Render Message Template  ${CHAIN_MESSAGE}
+  Set Suite Variable  ${CHAIN_MESSAGE}
 
 Urlredirector Teardown
   Rspamd Redis Teardown
index 3f258c05a75ab9d03300ffb2f54be5d5781faa8b..7db645dfc1faa33ad9a888430d58dc2049597b92 100644 (file)
@@ -19,39 +19,41 @@ ${SETTINGS}        {symbols_enabled=[URL_REDIRECTOR_CHECK]}
 BASIC CHAIN RESOLUTION AND CACHING
   [Documentation]  Test chain resolution with intermediate hops and caching
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 NESTED LIMIT MARKER
   [Documentation]  Test ^nested: markers for limit exceeded
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CHAIN AWARE CACHE
   [Documentation]  Test per-hop Redis cache with markers
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 TIMEOUT SETTINGS
   [Documentation]  Test timeout, http_timeout, redis_timeout configuration
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 SAVE INTERMEDIATE REDIRECTS
   [Documentation]  Test save_intermediate_redirs configuration
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 REDIRECTOR SYMBOL
   [Documentation]  Test redirector_symbol with host path output
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 *** Keywords ***
 Urlredirector Chain Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
 
 Urlredirector Chain Teardown
   Rspamd Redis Teardown
index 96d7d625a967e1f62eac1262510e0f8b886ed5c9..bfe37816763e7066a3f9a02b82b4f73d50946c99 100644 (file)
@@ -22,19 +22,19 @@ CHAIN REDIRECT RESOLUTION
   [Documentation]  Test PR 6014 feature: resolve redirect chains with intermediate hops
   ...              Tests /redirect2 -> /redirect1 -> /hello chain
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CHAIN REDIRECT WITH SYMBOL
   [Documentation]  Test that redirector_symbol shows the full redirect path (host1->host2->...->hostN)
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CHAIN REDIRECT CACHED RESOLUTION
   [Documentation]  Test that cached chain resolution works correctly on second scan
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 REDIRECT CYCLE DETECTION
   [Documentation]  Test cycle detection with /redirect3 <-> /redirect4 cycle
@@ -43,27 +43,33 @@ REDIRECT CYCLE DETECTION
 NESTED LIMIT HANDLING
   [Documentation]  Test ^nested: marker behavior when nested_limit is exceeded
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 TIMEOUT CONFIGURATION
   [Documentation]  Test that timeout, http_timeout, and redis_timeout are correctly applied
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 SAVE INTERMEDIATE REDIRS
   [Documentation]  Test save_intermediate_redirs = {redirectors=false, non_redirectors=true}
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 BASIC URL RESOLUTION
   [Documentation]  Test basic URL resolution without redirects
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 *** Keywords ***
 Urlredirector PR6014 Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
+  ${CHAIN_MESSAGE} =  Render Message Template  ${CHAIN_MESSAGE}
+  Set Suite Variable  ${CHAIN_MESSAGE}
+  ${MULTIPART_MESSAGE} =  Render Message Template  ${MULTIPART_MESSAGE}
+  Set Suite Variable  ${MULTIPART_MESSAGE}
 
 Urlredirector PR6014 Teardown
   Rspamd Redis Teardown
index d34786f10baf454ec70e91db7eb919a218ee6bd2..776c65940706ab57ff2df19cf6b2cf4bcac274f7 100644 (file)
@@ -22,24 +22,24 @@ CACHE HOP MARKERS
   ...              - ^nested: for limit exceeded
   ...              - no marker for terminal URLs
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 PER-ADJACENT-PAIR CACHE LAYOUT
   [Documentation]  Test PR 6014 cache layout: one Redis entry per adjacent URL pair
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CACHE WALK WITH MARKERS
   [Documentation]  Test cache walk behavior: reader follows markers until terminal
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 SELF-HEALING CACHE
   [Documentation]  Test self-healing: ^nested: marker upgrade on extension
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CYCLE DETECTION
   [Documentation]  Test cycle protection with per-walk seen-set
@@ -48,22 +48,24 @@ CYCLE DETECTION
 REDIS TIMEOUT APPLIED
   [Documentation]  Test that redis_timeout setting is applied to Redis calls
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 TOP_URLS TRACKING
   [Documentation]  Test that ZINCRBY on top_urls uses canonical URL string
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 RESERVATION LOCK
   [Documentation]  Test that reservation lock has correct TTL = settings.timeout
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 *** Keywords ***
 Urlredirector Cache Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
 
 Urlredirector Cache Teardown
   Rspamd Redis Teardown
index 9d53205be640aa6a356893312773129b8e9f59a8..54bddb83eac88638af08295a222b7c18f793f3fb 100644 (file)
@@ -19,37 +19,39 @@ ${SETTINGS}        {symbols_enabled=[URL_REDIRECTOR_CHECK]}
 SAVE_INTERMEDIATE_REDIRECTORS_ONLY
   [Documentation]  Test save_intermediate_redirs={redirectors=true, non_redirectors=false}
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 SAVE_INTERMEDIATE_DISABLED
   [Documentation]  Test save_intermediate_redirs with both options disabled
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 DEFAULT_TIMEOUT_VALUE
   [Documentation]  Test default timeout value (8s) from settings
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CUSTOM_HTTP_TIMEOUT
   [Documentation]  Test custom http_timeout setting overrides default
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 CUSTOM_REDIS_TIMEOUT
   [Documentation]  Test custom redis_timeout setting
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 REDIRECTOR_SYMBOL_DISABLED
   [Documentation]  Test behavior when redirector_symbol is not configured
   Scan File  ${MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/hello
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/hello
 
 *** Keywords ***
 Urlredirector Config Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
 
 Urlredirector Config Teardown
   Rspamd Redis Teardown
index e1f17260d5cf09c0d2eb1cfd3280d4df0a7f66f5..bb0d0879e35a02de7ff4803305cbaea6b32a8fbc 100644 (file)
@@ -25,7 +25,7 @@ SKIP NON-HTTP SCHEME REDIRECT
   # but then stop when it encounters the tel: scheme and not attempt HTTP request
   Scan File  ${TEL_MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
   # The original URL should be processed
-  Expect Extended URL  http://127.0.0.1:18080/tel_redirect
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/tel_redirect
   Expect Symbol With Exact Options  URL_REDIRECTOR_NON_HTTP  telephone=127.0.0.1->tel:88006007775
   Do Not Expect Added URL  tel:88006007775
 
@@ -35,7 +35,7 @@ SKIP NON-HTTP SCHEME REDIRECT WITH INTERMEDIATE HOPS
   # Intermediate redirector hops are not saved to chain by default (redirectors=false),
   # so the chain string only shows the original redirector host and the tel: target.
   Scan File  ${CHAIN_TEL_MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/chain_intermediate_1
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/chain_intermediate_1
   Expect Symbol With Exact Options  URL_REDIRECTOR_NON_HTTP  telephone=127.0.0.1->tel:88006007776
   Do Not Expect Added URL  tel:88006007776
 
@@ -45,8 +45,8 @@ MULTIPLE NON-HTTP REDIRECT TARGETS
   # tel_redirect -> tel:88006007775 (rspamd scheme: telephone)
   # mailto_redirect -> mailto:user@example.net (rspamd scheme: mailto)
   Scan File  ${MULTI_NON_HTTP_MESSAGE}  Flags=ext_urls  Settings=${SETTINGS}
-  Expect Extended URL  http://127.0.0.1:18080/tel_redirect
-  Expect Extended URL  http://127.0.0.1:18080/mailto_redirect
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/tel_redirect
+  Expect Extended URL  http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/mailto_redirect
   Expect Symbol With Exact Options  URL_REDIRECTOR_NON_HTTP
   ...  telephone=127.0.0.1->tel:88006007775
   ...  mailto=127.0.0.1->mailto:user@example.net
@@ -57,6 +57,12 @@ MULTIPLE NON-HTTP REDIRECT TARGETS
 Urlredirector Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${TEL_MESSAGE} =  Render Message Template  ${TEL_MESSAGE}
+  Set Suite Variable  ${TEL_MESSAGE}
+  ${CHAIN_TEL_MESSAGE} =  Render Message Template  ${CHAIN_TEL_MESSAGE}
+  Set Suite Variable  ${CHAIN_TEL_MESSAGE}
+  ${MULTI_NON_HTTP_MESSAGE} =  Render Message Template  ${MULTI_NON_HTTP_MESSAGE}
+  Set Suite Variable  ${MULTI_NON_HTTP_MESSAGE}
 
 Urlredirector Teardown
   Rspamd Redis Teardown
index de77baf5d92d78d070f7e5d0874fdebd80987455..3acac88e7e11f30c6435f71cf1ae9047f6499662 100644 (file)
@@ -28,6 +28,8 @@ PHISHING NO FP WHEN DISPLAY TEXT EQUALS REDIRECT DEST
 Urlredirector Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
 
 Urlredirector Teardown
   Rspamd Redis Teardown
index cc02631586841e108d0516d61706b0e18a874f11..f708e45bce4026267f08fae8b861d195703cbcca 100644 (file)
@@ -33,6 +33,8 @@ RESOLVE ENCODED QUERY TARGET THROUGH PATH-LESS WRAPPER
 Urlredirector Setup
   Run Dummy Http
   Rspamd Redis Setup
+  ${MESSAGE} =  Render Message Template  ${MESSAGE}
+  Set Suite Variable  ${MESSAGE}
 
 Urlredirector Teardown
   Rspamd Redis Teardown
index 48c5e9fa08a13c075ab64078681b883fb15cec4f..f64876dfd34ed68e900cb6e98cb2428955375bb8 100644 (file)
@@ -52,7 +52,7 @@ neural {
       symbol_ham = "NEURAL_HAM";
       ann_expire = 86400;
       watch_interval = 0.5;
-      providers = [{ type = "llm"; model = "dummy-embed"; url = "http://127.0.0.1:18080"; weight = 1.0;
+      providers = [{ type = "llm"; model = "dummy-embed"; url = "http://127.0.0.1:{= env.PORT_DUMMY_HTTP|default('18080') =}"; weight = 1.0;
         #reply_trim_mode = "replies"; # always|none|replies
       }];
       fusion { normalization = "none"; }
index 1f0514502f586ef76313a898f17a09dbfa03c5f3..8fb7286abd4ef695946fea126a00cf85118afed4 100644 (file)
@@ -534,6 +534,22 @@ Run Rspamc
   Log  ${result.stdout}
   RETURN    ${result}
 
+Render Message Template
+  [Documentation]  Read an .eml fixture that contains Robot ${VARIABLE}
+  ...  placeholders (e.g. ${RSPAMD_PORT_DUMMY_HTTP}), expand them, write
+  ...  the result into the suite tmpdir and return the rendered path.
+  ...  .eml files are fed raw to the scanner and are NOT processed by the
+  ...  config-time Jinja engine, so per-pabot-worker values (dummy ports)
+  ...  must be substituted here at runtime. Requires ${RSPAMD_TMPDIR}
+  ...  (set by Rspamd Setup) -- call after the rspamd setup keyword.
+  [Arguments]  ${template_path}
+  ${template} =  Get File  ${template_path}
+  ${rendered} =  Replace Variables  ${template}
+  ${name} =  Evaluate  os.path.basename($template_path)  modules=os
+  ${out} =  Set Variable  ${RSPAMD_TMPDIR}/${name}
+  Create File  ${out}  ${rendered}
+  RETURN  ${out}
+
 Scan File By Reference
   [Arguments]  ${filename}  &{headers}
   Set To Dictionary  ${headers}  File=${filename}
index c5b91ff3db026a9d1680552cf2cebb574384865b..2fc8d977c4c6b01f246a76d426590faeec7233dc 100644 (file)
@@ -1,6 +1,12 @@
 local rspamd_http = require "rspamd_http"
 local rspamd_logger = require "rspamd_logger"
 
+-- dummy_http / dummy_https ports come from the test harness; rspamd_env
+-- strips the RSPAMD_ prefix so PORT_DUMMY_HTTP/HTTPS carry the per-pabot
+-- worker slot value. Default to the historical literals for ad-hoc runs.
+local http_port = tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTP) or 18080
+local https_port = tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTPS) or 18081
+
 local function http_symbol(task)
 
   local url = tostring(task:get_request_header('url'))
@@ -27,7 +33,7 @@ local function http_symbol(task)
 
   rspamd_logger.errx(task, 'do http request with callback')
   rspamd_http.request({
-    url = 'http://127.0.0.1:18080' .. url,
+    url = string.format('http://127.0.0.1:%d%s', http_port, url),
     task = task,
     method = method,
     callback = http_callback,
@@ -37,7 +43,7 @@ local function http_symbol(task)
   --[[ request to this address involved DNS resolver subsystem ]]
   rspamd_logger.errx(task, 'do http request with callback + dns resolving')
   rspamd_http.request({
-    url = 'http://site.resolveme:18080' .. url,
+    url = string.format('http://site.resolveme:%d%s', http_port, url),
     task = task,
     method = method,
     callback = http_dns_callback,
@@ -47,7 +53,7 @@ local function http_symbol(task)
   rspamd_logger.errx(task, 'rspamd_http.request[before]')
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18080' .. url,
+    url = string.format('http://127.0.0.1:%d%s', http_port, url),
     task = task,
     method = method,
     timeout = 1,
@@ -62,7 +68,7 @@ local function http_symbol(task)
 
   rspamd_logger.errx(task, 'do http request after coroutine finished')
   err, response = rspamd_http.request({
-    url = 'http://site.resolveme:18080' .. url,
+    url = string.format('http://site.resolveme:%d%s', http_port, url),
     task = task,
     method = method,
     timeout = 1,
@@ -79,7 +85,7 @@ end
 local function finish(task)
   rspamd_logger.errx('function finish')
   local err, response = rspamd_http.request({
-    url = 'http://site.resolveme:18080/timeout',
+    url = string.format('http://site.resolveme:%d/timeout', http_port),
     task = task,
     method = 'get',
     timeout = 1,
@@ -93,7 +99,7 @@ end
 
 local function periodic(cfg, ev_base)
   local err, response = rspamd_http.request({
-    url = 'http://site.resolveme:18080/request/periodic',
+    url = string.format('http://site.resolveme:%d/request/periodic', http_port),
     config = cfg,
   })
   if err then
@@ -134,7 +140,7 @@ local function http_large_symbol(task)
       end
     end
     rspamd_http.request({
-      url = 'https://127.0.0.1:18081/',
+      url = string.format('https://127.0.0.1:%d/', https_port),
       task = task,
       method = 'post',
       callback = http_callback,
@@ -156,7 +162,7 @@ rspamd_config:register_finish_script(finish)
 
 rspamd_config:add_on_load(function(cfg, ev_base, worker)
   local err, response = rspamd_http.request({
-    url = 'http://site.resolveme:18080/request/add_on_load',
+    url = string.format('http://site.resolveme:%d/request/add_on_load', http_port),
     config = cfg,
   })
   if err then
index fba8d3053ac0cab3b212f32e5303ee9a5ecbcdf8..3b71214da8b41c514340b3135737e569a33d8d06 100644 (file)
@@ -4,12 +4,19 @@ Test HTTP client behavior when server sends early responses.
 This tests edge cases where a server responds before the client has finished
 sending the request body (which is allowed by HTTP/1.1 spec).
 
-The test server (dummy_http_early_response.py) runs on port 18083.
+The test server (dummy_http_early_response.py) runs on port 18083
+(per-pabot-worker offset applied via rspamd_env.PORT_DUMMY_HTTP_EARLY).
 ]]
 
 local rspamd_http = require "rspamd_http"
 local rspamd_logger = require "rspamd_logger"
 
+-- dummy_http_early_response port comes from the test harness; rspamd_env
+-- strips the RSPAMD_ prefix so PORT_DUMMY_HTTP_EARLY carries the per-pabot
+-- worker slot value. Default to the historical literal for ad-hoc runs.
+local early_port = tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTP_EARLY) or 18083
+local base_url = string.format('http://127.0.0.1:%d', early_port)
+
 -- Register all possible result symbols upfront
 -- These are the symbols that will be inserted based on HTTP response codes
 local result_symbols = {
@@ -94,7 +101,7 @@ local function test_early_reply(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/early-reply',
+    url = base_url .. '/early-reply',
     task = task,
     method = 'post',
     body = large_body,
@@ -125,7 +132,7 @@ local function test_early_error_413(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/early-error-413',
+    url = base_url .. '/early-error-413',
     task = task,
     method = 'post',
     body = large_body,
@@ -151,7 +158,7 @@ local function test_keepalive_early(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/keepalive-early',
+    url = base_url .. '/keepalive-early',
     task = task,
     method = 'post',
     body = body,
@@ -172,7 +179,7 @@ local function test_early_reply_coro(task)
   local body = table.concat(body_parts)
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18083/early-reply',
+    url = base_url .. '/early-reply',
     task = task,
     method = 'post',
     body = body,
@@ -203,7 +210,7 @@ local function test_normal_request(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/request',
+    url = base_url .. '/request',
     task = task,
     method = 'post',
     body = 'normal test body',
@@ -258,7 +265,7 @@ local function test_keepalive_sequential(task)
   -- Make 3 sequential requests using keepalive
   for i = 1, 3 do
     local err, response = rspamd_http.request({
-      url = 'http://127.0.0.1:18083/keepalive-normal',
+      url = base_url .. '/keepalive-normal',
       task = task,
       method = 'post',
       body = string.format('request %d body', i),
@@ -312,7 +319,7 @@ local function test_early_keepalive_stress(task)
     end
 
     local err, response = rspamd_http.request({
-      url = 'http://127.0.0.1:18083' .. endpoint,
+      url = base_url .. endpoint,
       task = task,
       method = 'post',
       body = table.concat(body_parts),
@@ -365,7 +372,7 @@ local function test_immediate_close_large(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/immediate-close-413',
+    url = base_url .. '/immediate-close-413',
     task = task,
     method = 'post',
     body = large_body,
@@ -393,7 +400,7 @@ local function test_slow_response_large(task)
   local body = table.concat(body_parts)
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18083/slow-response-no-drain',
+    url = base_url .. '/slow-response-no-drain',
     task = task,
     method = 'post',
     body = body,
@@ -427,7 +434,7 @@ local function test_rapid_close_requests(task)
 
   for i = 1, 5 do
     local err, response = rspamd_http.request({
-      url = 'http://127.0.0.1:18083/immediate-close-413',
+      url = base_url .. '/immediate-close-413',
       task = task,
       method = 'post',
       body = body,
@@ -481,7 +488,7 @@ local function test_block_and_reply(task)
   end
 
   rspamd_http.request({
-    url = 'http://127.0.0.1:18083/block-and-reply',
+    url = base_url .. '/block-and-reply',
     task = task,
     method = 'post',
     body = huge_body,
@@ -506,7 +513,7 @@ local function test_block_and_reply_coro(task)
   local huge_body = string.rep("Y", 512 * 1024)
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18083/block-and-reply',
+    url = base_url .. '/block-and-reply',
     task = task,
     method = 'post',
     body = huge_body,
@@ -538,7 +545,7 @@ local function test_block_slow(task)
   local huge_body = string.rep("Z", 1024 * 1024)
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18083/block-and-reply-slow',
+    url = base_url .. '/block-and-reply-slow',
     task = task,
     method = 'post',
     body = huge_body,
@@ -571,7 +578,7 @@ local function test_instant_reply(task)
   local huge_body = string.rep("Z", 512 * 1024)
 
   local err, response = rspamd_http.request({
-    url = 'http://127.0.0.1:18083/instant-reply',
+    url = base_url .. '/instant-reply',
     task = task,
     method = 'post',
     body = huge_body,
index eb103db18feeb2db2a6b7156c64e1c07453c6f55..4dd2bb2a8f71cacf697bbb1bc65fba2fe3004ed9 100644 (file)
@@ -1,13 +1,20 @@
 local logger = require "rspamd_logger"
 local tcp_sync = require "lua_tcp_sync"
 
+-- dummy_http port comes from the test harness. This script runs under
+-- `rspamadm lua` (not the rspamd config loader), so prefer the exported
+-- RSPAMD_PORT_DUMMY_HTTP env var, then rspamd_env, then the historical
+-- literal for ad-hoc runs.
+local http_port = tonumber(os.getenv('RSPAMD_PORT_DUMMY_HTTP'))
+  or tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTP) or 18080
+
 local is_ok, connection = tcp_sync.connect {
   config = rspamd_config,
   ev_base = rspamadm_ev_base,
   session = rspamadm_session,
   host = '127.0.0.1',
   timeout = 20,
-  port = 18080,
+  port = http_port,
 }
 if not is_ok then
   logger.errx(rspamd_config, 'connect error: %1', connection)
index 92d55bb76fa113fc14d9261c934b5b16a3f30f56..a7358c7c454db7510fb64a0c75fe81feed78bde6 100644 (file)
@@ -6,6 +6,12 @@ local rspamd_tcp = require "rspamd_tcp"
 local logger = require "rspamd_logger"
 local tcp_sync = require "lua_tcp_sync"
 
+-- dummy_http / dummy_https ports come from the test harness; rspamd_env
+-- strips the RSPAMD_ prefix so PORT_DUMMY_HTTP/HTTPS carry the per-pabot
+-- worker slot value. Default to the historical literals for ad-hoc runs.
+local http_port = tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTP) or 18080
+local https_port = tonumber(rspamd_env and rspamd_env.PORT_DUMMY_HTTPS) or 18081
+
 -- [[ old fashioned callback api ]]
 local function http_simple_tcp_async_symbol(task)
   logger.errx(task, 'http_tcp_symbol: begin')
@@ -19,16 +25,16 @@ local function http_simple_tcp_async_symbol(task)
   end
   local function http_read_cb(err, data, conn)
     logger.errx(task, 'http_read_cb: got reply: %s, error: %s, conn: %s', data, err, conn)
-    conn:add_write(http_read_post_cb, "POST /request2 HTTP/1.1\r\nHost: 127.0.0.1:18080\r\n\r\n")
+    conn:add_write(http_read_post_cb, string.format("POST /request2 HTTP/1.1\r\nHost: 127.0.0.1:%d\r\n\r\n", http_port))
     task:insert_result('HTTP_ASYNC_RESPONSE', 1.0, data or err)
   end
   rspamd_tcp:request({
     task = task,
     callback = http_read_cb,
     host = '127.0.0.1',
-    data = {'GET /request HTTP/1.1\r\nHost: 127.0.0.1:18080\r\nConnection: keep-alive\r\n\r\n'},
+    data = {string.format('GET /request HTTP/1.1\r\nHost: 127.0.0.1:%d\r\nConnection: keep-alive\r\n\r\n', http_port)},
     read = true,
-    port = 18080,
+    port = http_port,
   })
 end
 
@@ -55,7 +61,7 @@ local function http_simple_tcp_ssl_symbol(task)
     read = true,
     ssl = true,
     ssl_noverify = true,
-    port = 18081,
+    port = https_port,
   })
 end
 
@@ -96,7 +102,7 @@ local function http_large_tcp_ssl_symbol(task)
       ssl = true,
       stop_pattern = '\n',
       ssl_noverify = true,
-      port = 18081,
+      port = https_port,
       timeout = 20,
     })
   else
@@ -112,7 +118,7 @@ local function http_simple_tcp_symbol(task)
     task = task,
     host = '127.0.0.1',
     timeout = 20,
-    port = 18080,
+    port = http_port,
   }
 
   if not is_ok then
@@ -122,7 +128,7 @@ local function http_simple_tcp_symbol(task)
 
   logger.errx(task, 'connect_sync %1, %2', is_ok, tostring(connection))
 
-  is_ok, err = connection:write('GET /request HTTP/1.1\r\nHost: 127.0.0.1:18080\r\nConnection: keep-alive\r\n\r\n')
+  is_ok, err = connection:write(string.format('GET /request HTTP/1.1\r\nHost: 127.0.0.1:%d\r\nConnection: keep-alive\r\n\r\n', http_port))
 
   logger.errx(task, 'write %1, %2', is_ok, err)
   if not is_ok then
@@ -149,7 +155,7 @@ local function http_simple_tcp_symbol(task)
 
   task:insert_result('HTTP_SYNC_RESPONSE', 1.0, got_content)
 
-  is_ok, err = connection:write("POST /request HTTP/1.1\r\nHost: 127.0.0.1:18080\r\n\r\n")
+  is_ok, err = connection:write(string.format("POST /request HTTP/1.1\r\nHost: 127.0.0.1:%d\r\n\r\n", http_port))
   logger.errx(task, 'write[2] %1, %2', is_ok, err)
 
   got_content = ''
@@ -185,7 +191,7 @@ local function http_tcp_symbol(task)
     task = task,
     host = '127.0.0.1',
     timeout = 20,
-    port = 18080,
+    port = http_port,
   }
 
   logger.errx(task, 'connect_sync %1, %2', is_ok, tostring(connection))
@@ -194,7 +200,7 @@ local function http_tcp_symbol(task)
     return
   end
 
-  is_ok, err = connection:write(string.format('%s %s HTTP/1.1\r\nHost: 127.0.0.1:18080\r\nConnection: close\r\n\r\n', method:upper(), url))
+  is_ok, err = connection:write(string.format('%s %s HTTP/1.1\r\nHost: 127.0.0.1:%d\r\nConnection: close\r\n\r\n', method:upper(), url, http_port))
 
   logger.errx(task, 'write %1, %2', is_ok, err)
   if not is_ok then
@@ -292,9 +298,9 @@ local function phased_timeout_symbol(task)
     task = task,
     callback = read_cb,
     host = '127.0.0.1',
-    data = {'GET /request HTTP/1.1\r\nHost: 127.0.0.1:18080\r\nConnection: close\r\n\r\n'},
+    data = {string.format('GET /request HTTP/1.1\r\nHost: 127.0.0.1:%d\r\nConnection: close\r\n\r\n', http_port)},
     read = true,
-    port = 18080,
+    port = http_port,
     connect_timeout = 2.0,
     read_timeout = 2.0,
     write_timeout = 2.0,
@@ -343,10 +349,10 @@ local function on_error_post_connect_symbol(task)
     callback = read_cb,
     on_error = err_cb,
     host = '127.0.0.1',
-    port = 18080,
+    port = http_port,
     -- /timeout sleeps 4s before responding. read_timeout=0.5 forces the read
     -- side to time out after the connect succeeds.
-    data = {'GET /timeout HTTP/1.1\r\nHost: 127.0.0.1:18080\r\nConnection: close\r\n\r\n'},
+    data = {string.format('GET /timeout HTTP/1.1\r\nHost: 127.0.0.1:%d\r\nConnection: close\r\n\r\n', http_port)},
     read = true,
     stop_pattern = '\r\n\r\n',
     connect_timeout = 2.0,
index e93285ec4b9de1b9baa7459edfa24c2760e9d2b8..82082ff026650c1130d2fb56e15c8b06cf09d2e8 100644 (file)
@@ -5,7 +5,7 @@ Content-Transfer-Encoding: quoted-printable
 <html>
 <body>
 <p>Test message with redirect chains</p>
-<a href="http://127.0.0.1:18080/chain1">Chain 1</a>
-<a href="http://127.0.0.1:18080/redirect2">Redirect 2</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/chain1">Chain 1</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/redirect2">Redirect 2</a>
 </body>
 </html>
index 2c30f0fb250dae4ed00cb90808a4674926a4b742..9884fbad1085a0b21147271735a35ae73ea98ff8 100644 (file)
@@ -4,6 +4,6 @@ Content-Transfer-Encoding: quoted-printable
 
 <html>
 <body>
-<a href="http://127.0.0.1:18080/chain1">chain link</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/chain1">chain link</a>
 </body>
 </html>
index c5218022fa05d3ad264379ed6d4740fbfd86eaf1..082701b54a6bdcf827239cce70517cba141cdc64 100644 (file)
@@ -1,6 +1,6 @@
 Content-type: text/plain
 
-bla http://127.0.0.1:18080/redirect2
+bla http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/redirect2
 
-lol http://127.0.0.1:18080/redirect3
+lol http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/redirect3
 
index 2c63e4563bfda30b8b5977652b309ce2638cd237..2bab1926d380ce6392923b04eec51a71214c2bd3 100644 (file)
@@ -1,7 +1,7 @@
-Content-type: text/html\r
-\r
-<html>\r
-<body>\r
-<a href="http://127.0.0.1:18080/chain_intermediate_1">Call us via chain</a>\r
-</body>\r
+Content-type: text/html
+
+<html>
+<body>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/chain_intermediate_1">Call us via chain</a>
+</body>
 </html>
\ No newline at end of file
index 6d82b9298e3e41dcc7c53df6528b8a79119bbefb..ec721db84e92c6949b43108f5069c31b9e4a5353 100644 (file)
@@ -2,7 +2,7 @@ Content-type: text/html
 
 <html>
 <body>
-<a href="http://127.0.0.1:18080/tel_redirect">Call us</a>
-<a href="http://127.0.0.1:18080/mailto_redirect">Email us</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/tel_redirect">Call us</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/mailto_redirect">Email us</a>
 </body>
 </html>
index 6c254d1ed4e20e8b5bf4e01900f19d5d2274419e..d4522df370c4c42e47741b8d56d9853193b915e5 100644 (file)
@@ -1,3 +1,3 @@
 Content-type: text/html
 
-<a href="http://redir.example.net:18080/redir_to_example">http://www.example.com/</a>
+<a href="http://redir.example.net:${RSPAMD_PORT_DUMMY_HTTP}/redir_to_example">http://www.example.com/</a>
index 77a179994554be4f67f9ea0b2a560daa3b8ad581..766e0ecc4f357f87ea936a3cd81d83de82903b67 100644 (file)
@@ -1,3 +1,3 @@
 Content-type: text/plain
 
-click http://127.0.0.1:18080/combo_entry
+click http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/combo_entry
index 13f08e64cb274a2a3d71433a9954e10a89157e4f..7463c95d8063cadc0e74d26bc6e53c939e041d22 100644 (file)
@@ -2,6 +2,6 @@ Content-type: text/html
 
 <html>
 <body>
-<a href="http://127.0.0.1:18080/tel_redirect">Call us</a>
+<a href="http://127.0.0.1:${RSPAMD_PORT_DUMMY_HTTP}/tel_redirect">Call us</a>
 </body>
 </html>