diff options
Diffstat (limited to 'test/functional/lua')
45 files changed, 2053 insertions, 0 deletions
diff --git a/test/functional/lua/composites.lua b/test/functional/lua/composites.lua new file mode 100644 index 0000000..648eda0 --- /dev/null +++ b/test/functional/lua/composites.lua @@ -0,0 +1,140 @@ +rspamd_config:register_symbol({ + name = 'EXPRESSIONS_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'POLICY_REMOVE_WEIGHT_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'POLICY_REMOVE_WEIGHT_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'POLICY_FORCE_REMOVE_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'POLICY_FORCE_REMOVE_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'POLICY_LEAVE_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'POLICY_LEAVE_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_REMOVE_WEIGHT_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_REMOVE_WEIGHT_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_REMOVE_SYMBOL_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_REMOVE_SYMBOL_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_LEAVE_A', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'DEFAULT_POLICY_LEAVE_B', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'POSITIVE_A', + score = -1.0, + group = "positive", + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'NEGATIVE_A', + score = -1.0, + group = "negative", + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'NEGATIVE_B', + score = 1.0, + group = "negative", + callback = function() + return true, 'Fires always' + end +}) +rspamd_config:register_symbol({ + name = 'ANY_A', + score = -1.0, + group = "any", + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'OPTS', + score = -1.0, + group = "any", + callback = function(task) + local lua_util = require "lua_util" + local woot = lua_util.str_split(tostring(task:get_request_header('opts') or ''), ',') + + if woot and #woot > 0 and #woot[1] > 0 then + return true, 1.0, woot + end + end +}) diff --git a/test/functional/lua/conditions.lua b/test/functional/lua/conditions.lua new file mode 100644 index 0000000..2baa04b --- /dev/null +++ b/test/functional/lua/conditions.lua @@ -0,0 +1,22 @@ +local logger = require 'rspamd_logger' + +rspamd_config:register_symbol({ + name = 'ANY_A', + score = -1.0, + group = "any", + callback = function() + return true, 'hello3' + end +}) + +rspamd_config:add_condition('ANY_A', function(task) + logger.infox(task, 'hello from condition1') + task:insert_result('ANY_A', 1.0, 'hello1') + return true +end) + +rspamd_config:add_condition('ANY_A', function(task) + logger.infox(task, 'hello from condition2') + task:insert_result('ANY_A', 1.0, 'hello2') + return true +end) diff --git a/test/functional/lua/deps.lua b/test/functional/lua/deps.lua new file mode 100644 index 0000000..6171db6 --- /dev/null +++ b/test/functional/lua/deps.lua @@ -0,0 +1,30 @@ +local cb = function(task) + task:insert_result('TOP', 1.0) +end + +local cb_dep1 = function(task) + if task:get_symbol('TOP') then + task:insert_result('DEP1', 1.0) + end +end + +local cb_gen = function(num) + local cb_dep = function(task) + if task:get_symbol('DEP' .. tostring(num)) then + task:insert_result('DEP' .. tostring(num + 1), 1.0) + end + end + + return cb_dep +end + +local id = rspamd_config:register_callback_symbol(1.0, cb) +rspamd_config:register_virtual_symbol('TOP', 1.0, id) + +rspamd_config:register_symbol('DEP1', 1.0, cb_dep1) +rspamd_config:register_dependency('DEP1', 'TOP') + +for i = 2,10 do + rspamd_config:register_symbol('DEP' .. tostring(i), 1.0, cb_gen(i - 1)) + rspamd_config:register_dependency('DEP' .. tostring(i), 'DEP' .. tostring(i - 1)) +end diff --git a/test/functional/lua/dns.lua b/test/functional/lua/dns.lua new file mode 100644 index 0000000..702b985 --- /dev/null +++ b/test/functional/lua/dns.lua @@ -0,0 +1,53 @@ +local rspamd_dns = require "rspamd_dns" +local logger = require "rspamd_logger" + +local function dns_sync_symbol(task) + local to_resolve = tostring(task:get_request_header('to-resolve')) + local is_ok, results = rspamd_dns.request({ + task = task, + type = 'a', + name = to_resolve , + }) + + logger.errx(task, "is_ok=%1, results=%2, results[1]=%3", is_ok, results, results[1]) + + if not is_ok then + task:insert_result('DNS_SYNC_ERROR', 1.0, results) + else + task:insert_result('DNS_SYNC', 1.0, tostring(results[1])) + end +end + +rspamd_config:register_symbol({ + name = 'SIMPLE_DNS_SYNC', + score = 1.0, + callback = dns_sync_symbol, + no_squeeze = true, + flags = 'coro', +}) + + +-- Async request +local function dns_symbol(task) + local function dns_cb(_, to_resolve, results, err) + logger.errx(task, "_=%1, to_resolve=%2, results=%3, err%4", _, to_resolve, results, err) + if err then + task:insert_result('DNS_ERROR', 1.0, err) + else + task:insert_result('DNS', 1.0, tostring(results[1])) + end + end + local to_resolve = tostring(task:get_request_header('to-resolve')) + + task:get_resolver():resolve_a({ + task = task, + name = to_resolve, + callback = dns_cb + }) +end + +rspamd_config:register_symbol({ + name = 'SIMPLE_DNS', + score = 1.0, + callback = dns_symbol, +})
\ No newline at end of file diff --git a/test/functional/lua/external_relay.lua b/test/functional/lua/external_relay.lua new file mode 100644 index 0000000..6aa3a29 --- /dev/null +++ b/test/functional/lua/external_relay.lua @@ -0,0 +1,10 @@ +rspamd_config:register_symbol({ + name = 'EXTERNAL_RELAY_TEST', + score = 0.0, + callback = function(task) + local from_ip = string.format('IP=%s', task:get_from_ip() or 'NIL') + local hostname = string.format('HOSTNAME=%s', task:get_hostname() or 'NIL') + local helo = string.format('HELO=%s', task:get_helo() or 'NIL') + return true, from_ip, hostname, helo + end +}) diff --git a/test/functional/lua/flags.lua b/test/functional/lua/flags.lua new file mode 100644 index 0000000..5d01ab1 --- /dev/null +++ b/test/functional/lua/flags.lua @@ -0,0 +1,35 @@ +--[[ +Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +]]-- + +rspamd_config:register_post_filter(function(task) + task:set_flag('no_stat') + task:set_flag('no_log', false) + task:set_flag('no_log', true) + task:set_flag('skip', true) + task:set_flag('extended_urls') + + task:insert_result('FLAGS_SYM', 1.0, table.concat(task:get_flags(), ',')) +end) diff --git a/test/functional/lua/get_from.lua b/test/functional/lua/get_from.lua new file mode 100644 index 0000000..9282866 --- /dev/null +++ b/test/functional/lua/get_from.lua @@ -0,0 +1,10 @@ +rspamd_config:register_symbol({ + name = 'GET_FROM', + score = 1.0, + callback = function(task) + local a = task:get_from('mime') + if not a then return end + a = a[1] + return true, (a.name or '') .. ',' .. (a.addr or '') .. ',' .. (a.user or '') .. ',' .. (a.domain or '') + end +}) diff --git a/test/functional/lua/hashes.lua b/test/functional/lua/hashes.lua new file mode 100644 index 0000000..7a1728b --- /dev/null +++ b/test/functional/lua/hashes.lua @@ -0,0 +1,74 @@ +rspamd_config:register_symbol({ + name = 'TEST_HASHES', + score = 1.0, + callback = function() + local hash = require 'rspamd_cryptobox_hash' + local logger = require 'rspamd_logger' + + local worry = {} + local test_data = { + { + ['str'] = 'asdf.qwerty.123', + ['hex'] = 'bf22dd95750034b9af93f0e4e5954aca3506bbcdbc051d91bd9af2d1a8fc294e848626b1c1751e58b44c4d3ea69dec5efa5a214dc59c77b1a9ca3bde3babac9d', + }, + { + ['specific'] = 'md5', + ['str'] = 'asdf.qwerty.123', + ['hex'] = 'cf25ddc406c50de0c13de2b79d127646', + }, + { + ['init'] = 'asdf.qwerty.123', + ['str'] = 'asdf.qwerty.123', + ['hex'] = 'bf22dd95750034b9af93f0e4e5954aca3506bbcdbc051d91bd9af2d1a8fc294e848626b1c1751e58b44c4d3ea69dec5efa5a214dc59c77b1a9ca3bde3babac9d', + ['reset'] = true, + }, + { + ['init'] = 'asdf.qwerty.123', + ['str'] = 'asdf.qwerty.123', + ['hex'] = 'e445046aa21a705dcce1343795630f88bc0196a0070011fdce789d5a2a349a8f85349834ade555ca21439f65fdc4dbcf82dcff7fcc559ef11c508507515c1532', + }, + { + ['init'] = 'asdf.qwerty.123', + ['specific'] = 'md5', + ['str'] = 'asdf.qwerty.123', + ['hex'] = '9ef941c4d050e43b1e665300f4fbe054', + }, + { + ['init'] = 'asdf.qwerty.123', + ['specific'] = 'md5', + ['str'] = 'asdf.qwerty.123', + ['hex'] = 'cf25ddc406c50de0c13de2b79d127646', + ['reset'] = true, + }, + { + ['init'] = 'hello', + ['specific'] = 'xxh3', + ['str'] = 'hello', + ['hex'] = 'c1156ae6cb7ff175', + } + } + + for _, t in ipairs(test_data) do + local h + if not t['specific'] then + h = hash.create(t['init']) + else + h = hash.create_specific(t['specific'], t['init']) + end + if t['reset'] then + h:reset() + end + h:update(t['str']) + if h:hex() ~= t['hex'] then + t['error'] = 'sum mismatch: ' .. h:hex() + table.insert(worry, logger.slog('%1', t)) + end + end + + if (#worry == 0) then + return true, "no worry" + else + return true, table.concat(worry, ",") + end + end +}) diff --git a/test/functional/lua/http.lua b/test/functional/lua/http.lua new file mode 100644 index 0000000..c5b91ff --- /dev/null +++ b/test/functional/lua/http.lua @@ -0,0 +1,169 @@ +local rspamd_http = require "rspamd_http" +local rspamd_logger = require "rspamd_logger" + +local function http_symbol(task) + + local url = tostring(task:get_request_header('url')) + local method = tostring(task:get_request_header('method')) + task:insert_result('method_' .. method, 1.0) + + local function http_callback(err, code, body) + if err then + rspamd_logger.errx('http_callback error: ' .. err) + task:insert_result('HTTP_ERROR', 1.0, err) + else + task:insert_result('HTTP_' .. code, 1.0, body) + end + end + + local function http_dns_callback(err, code, body) + if err then + rspamd_logger.errx('http_dns_callback error: ' .. err) + task:insert_result('HTTP_DNS_ERROR', 1.0, err) + else + task:insert_result('HTTP_DNS_' .. code, 1.0, body) + end + end + + rspamd_logger.errx(task, 'do http request with callback') + rspamd_http.request({ + url = 'http://127.0.0.1:18080' .. url, + task = task, + method = method, + callback = http_callback, + timeout = 1, + }) + + --[[ 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, + task = task, + method = method, + callback = http_dns_callback, + timeout = 1, + }) + + rspamd_logger.errx(task, 'rspamd_http.request[before]') + + local err, response = rspamd_http.request({ + url = 'http://127.0.0.1:18080' .. url, + task = task, + method = method, + timeout = 1, + }) + rspamd_logger.errx(task, 'rspamd_http.request[done] err: %1 response:%2', err, response) + + if not err then + task:insert_result('HTTP_CORO_' .. response.code, 1.0, response.content) + else + task:insert_result('HTTP_CORO_ERROR', 1.0, err) + end + + rspamd_logger.errx(task, 'do http request after coroutine finished') + err, response = rspamd_http.request({ + url = 'http://site.resolveme:18080' .. url, + task = task, + method = method, + timeout = 1, + }) + + if not err then + task:insert_result('HTTP_CORO_DNS_' .. response.code, 1.0, response.content) + else + task:insert_result('HTTP_CORO_DNS_ERROR', 1.0, err) + end +end + + +local function finish(task) + rspamd_logger.errx('function finish') + local err, response = rspamd_http.request({ + url = 'http://site.resolveme:18080/timeout', + task = task, + method = 'get', + timeout = 1, + }) + if err then + task:insert_result('HTTP_CORO_DNS_FINISH_ERROR', 1.0, err) + else + task:insert_result('HTTP_CORO_DNS_FINISH_' .. response.code, 1.0, response.content) + end +end + +local function periodic(cfg, ev_base) + local err, response = rspamd_http.request({ + url = 'http://site.resolveme:18080/request/periodic', + config = cfg, + }) + if err then + rspamd_logger.errx('periodic err ' .. err) + else + rspamd_logger.errx('periodic success ' .. response.content) + end + + return false +end + +rspamd_config:register_symbol({ + name = 'SIMPLE_HTTP_TEST', + score = 1.0, + callback = http_symbol, + no_squeeze = true, + flags = 'coro' +}) + +local function http_large_symbol(task) + if task:get_queue_id() == 'SSL Large HTTP request' then + local data = {} + for i = 1,2 do + local st = {} + for j=1,300000 do + st[j] = 't' + end + data[i] = table.concat(st) + end + data[#data + 1] = '\n' + + local function http_callback(err, code, body) + if err then + rspamd_logger.errx('http_callback error: ' .. err) + task:insert_result('HTTP_ERROR', 1.0, err) + else + task:insert_result('HTTP_SSL_LARGE', 1.0) + end + end + rspamd_http.request({ + url = 'https://127.0.0.1:18081/', + task = task, + method = 'post', + callback = http_callback, + timeout = 10, + body = data, + no_ssl_verify = true, + }) + end +end +rspamd_config:register_symbol({ + name = 'LARGE_HTTP_TEST', + score = 1.0, + callback = http_large_symbol, + no_squeeze = true, + flags = 'coro' +}) + +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', + config = cfg, + }) + if err then + rspamd_logger.errx('add_on_load err ' .. err) + else + rspamd_logger.errx('add_on_load success ' .. response.content) + end + + rspamd_config:add_periodic(ev_base, 0, periodic, false) +end) diff --git a/test/functional/lua/magic.lua b/test/functional/lua/magic.lua new file mode 100644 index 0000000..c0d5793 --- /dev/null +++ b/test/functional/lua/magic.lua @@ -0,0 +1,14 @@ +rspamd_config.MAGIC_SYM = { + callback = function(task) + local parts = task:get_parts() + + for i,p in ipairs(parts) do + local ext = p:get_detected_ext() + + if ext then + task:insert_result('MAGIC_SYM_' .. ext:upper() .. '_' .. tostring(i), 1.0) + end + end + end, + type = 'callback' +}
\ No newline at end of file diff --git a/test/functional/lua/mapreload.lua b/test/functional/lua/mapreload.lua new file mode 100644 index 0000000..ae20120 --- /dev/null +++ b/test/functional/lua/mapreload.lua @@ -0,0 +1,20 @@ +local test_map = rspamd_config:add_map ({ + url = '${MAP_FILE}', + type = 'set', +}) + +rspamd_config:register_symbol({ + name = 'MAP_SET_HIT_AND_MISS', + score = 1.0, + callback = function() + local has_example = test_map:get_key('example.com') + local has_rspamdtest = test_map:get_key('rspamd-test.com') + if has_example and not has_rspamdtest then + return true, 'example.com' + elseif has_rspamdtest and not has_example then + return true, 'rspamd.com' + else + return true, string.format('invalid: has_example=%s, has_rspamdtest=%s', has_example, has_rspamdtest) + end + end +}) diff --git a/test/functional/lua/maps_kv.lua b/test/functional/lua/maps_kv.lua new file mode 100644 index 0000000..b90f44d --- /dev/null +++ b/test/functional/lua/maps_kv.lua @@ -0,0 +1,94 @@ +local rspamd_ip = require 'rspamd_ip' +local rspamd_logger = require 'rspamd_logger' +local lua_maps = require "lua_maps" + +local radix_map = rspamd_config:add_map ({ + url = rspamd_env.RADIX_MAP, + type = 'radix', +}) + +local map_map = rspamd_config:add_map ({ + url = rspamd_env.MAP_MAP, + type = 'map', +}) + +local regexp_map = rspamd_config:add_map ({ + url = rspamd_env.REGEXP_MAP, + type = 'regexp', +}) + +rspamd_config:register_symbol({ + name = 'RADIX_KV', + score = 1.0, + callback = function() + local sip = {'8.8.8.8', '::1', '192.168.1.1', '10.0.1.1'} + local expected = {'test one', 'another', '1', false} + for i = 1, #sip do + if (radix_map:get_key(rspamd_ip.from_string(sip[i])) ~= expected[i]) then + local rip = rspamd_ip.from_string(sip[i]) + local val = radix_map:get_key(rip) + return true, rspamd_logger.slog('plain: get_key(%s) [%s] -> %s [%s] [expected %s]', rip, type(rip), val, type(val), expected[i]) + end + if (radix_map:get_key(sip[i]) ~= expected[i]) then + local val = radix_map:get_key(sip[i]) + return true, rspamd_logger.slog('string: get_key(%s) [%s] -> %s [%s] [expected %s]', sip[i], type(sip[i]), val, type(val), expected[i]) + end + end + return true, 'no worry' + end +}) + +rspamd_config:register_symbol({ + name = 'MAP_KV', + score = 1.0, + callback = function() + local str = {'foo', 'asdf.example.com', 'asdf', 'barf'} + local expected = {'bar', 'value', '', false} + for i = 1, #str do + if (map_map:get_key(str[i]) ~= expected[i]) then + local val = map_map:get_key(str[i]) + return true, rspamd_logger.slog('get_key(%s) [%s] -> %s [%s] [expected %s]', str[i], type(str[i]), val, type(val), expected[i]) + end + end + return true, 'no worry' + end, +}) + +rspamd_config:register_symbol({ + name = 'REGEXP_KV', + score = 1.0, + callback = function() + local str = {'foo', 'asdf.example.com', 'asdf', 'barf'} + local expected = {'bar', 'value', '1', false} + for i = 1, #str do + if (regexp_map:get_key(str[i]) ~= expected[i]) then + local val = regexp_map:get_key(str[i]) + return true, rspamd_logger.slog('get_key(%s) [%s] -> %s [%s] [expected %s]', str[i], type(str[i]), val, type(val), expected[i]) + end + end + return true, 'no worry' + end, +}) + +local simple_ext_map = lua_maps.map_add_from_ucl({ + external = true, + backend = "http://127.0.0.1:18080/map-simple", + method = "body", + encode = "json", +}, '', 'external map') +rspamd_config:register_symbol({ + name = 'EXTERNAL_MAP', + score = 1.0, + callback = function(task) + local function cb(res, data, code) + if res then + task:insert_result('EXTERNAL_MAP', 1.0, string.format('+%s', data)) + else + task:insert_result('EXTERNAL_MAP', 1.0, string.format('-%s:%s', code, data)) + end + end + simple_ext_map:get_key({ + key = "value", + }, cb, task) + end, +}) diff --git a/test/functional/lua/miltertest/combined.lua b/test/functional/lua/miltertest/combined.lua new file mode 100644 index 0000000..69fa2d6 --- /dev/null +++ b/test/functional/lua/miltertest/combined.lua @@ -0,0 +1,35 @@ +-- Combine tests + +dofile './lib.lua' +dofile './data.lua' + +setup() + +local old_setup = setup +local old_teardown = teardown + +local empty_function = function() end +setup = empty_function +teardown = empty_function + +local function shuffle(tbl) + local size = #tbl + for i = size, 1, -1 do + local rand = math.random(size) + tbl[i], tbl[rand] = tbl[rand], tbl[i] + end + return tbl +end + +local files = {'mt1.lua','mt2.lua','mt3.lua','mt4.lua'} +local num_files = #files +for i = 1, num_files do + table.insert(files, files[i]) +end +files = shuffle(files) + +for _, f in ipairs(files) do + dofile(f) +end + +old_teardown() diff --git a/test/functional/lua/miltertest/data.lua b/test/functional/lua/miltertest/data.lua new file mode 100644 index 0000000..84b953f --- /dev/null +++ b/test/functional/lua/miltertest/data.lua @@ -0,0 +1,26 @@ +innocuous_hdrs = { + ['Message-ID'] = '<20180202155326.Horde.GfEWpxCo_Dip2xJswIpQNgK@example.org>', + ['From'] = 'Andrew Lewis <nerf@example.org>', + ['To'] = 'nerf@example.org', + ['Subject'] = 'innocuous test message', + ['User-Agent'] = 'Horde Application Framework 5', + ['Content-Type'] = 'text/plain; charset=utf-8; format=flowed; DelSp=Yes', + ['MIME-Version'] = '1.0', + ['Content-Disposition'] = 'inline', + ['Date'] = 'Fri, 02 Feb 2018 15:53:26 +0200', +} + +default_hdrs = { + ['Subject'] = 'spam message', +} + +innocuous_msg = 'Hello Rupert' + +gtube = [[lo + +XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X + +thx]] + +gtube_add_header = string.gsub(gtube, "XJS", "YJS") +gtube_rw_subject = string.gsub(gtube, "XJS", "ZJS") diff --git a/test/functional/lua/miltertest/data_dkim.lua b/test/functional/lua/miltertest/data_dkim.lua new file mode 100644 index 0000000..15adf15 --- /dev/null +++ b/test/functional/lua/miltertest/data_dkim.lua @@ -0,0 +1,23 @@ +multi_hdrs = { + ['Message-ID'] = '<a44q4StVFY04V4_4gOMYXjTgMDvmlSFzZxnoyJPHFwM@cacophony.za.org>', + ['From'] = 'Rspamd <foo@cacophony.za.org>', + ['To'] = 'nerf@example.org', + ['Subject'] = 'dkim test message', + ['User-Agent'] = 'Vi IMproved 8.1', + ['Content-Type'] = 'text/plain; charset=utf-8;', + ['MIME-Version'] = '1.0', + ['Date'] = 'Sat, 02 Feb 2019 10:34:54 +0000', +} + +single_hdr = { + ['Message-ID'] = '<a44q4StVFY04V4_4gOMYXjTgMDvmlSFzZxnoyJPHFwM@cacophony.za.org>', + ['From'] = 'Rspamd <foo@invalid.za.org>', + ['To'] = 'nerf@example.org', + ['Subject'] = 'dkim test message', + ['User-Agent'] = 'Vi IMproved 8.1', + ['Content-Type'] = 'text/plain; charset=utf-8;', + ['MIME-Version'] = '1.0', + ['Date'] = 'Sat, 02 Feb 2019 10:34:54 +0000', +} + +innocuous_msg = 'hello' diff --git a/test/functional/lua/miltertest/dkim_many.lua b/test/functional/lua/miltertest/dkim_many.lua new file mode 100644 index 0000000..70a3a1b --- /dev/null +++ b/test/functional/lua/miltertest/dkim_many.lua @@ -0,0 +1,11 @@ +print('Check we get multiple dkim signatures') + +dofile './lib.lua' +dofile './data_dkim.lua' + +setup() + +send_message(innocuous_msg, multi_hdrs, 'test-id', 'foo@cacophony.za.org', {'nerf@example.org'}) +check_headers(2) + +teardown() diff --git a/test/functional/lua/miltertest/dkim_one.lua b/test/functional/lua/miltertest/dkim_one.lua new file mode 100644 index 0000000..0c7def8 --- /dev/null +++ b/test/functional/lua/miltertest/dkim_one.lua @@ -0,0 +1,11 @@ +print('Check we get single dkim signature') + +dofile './lib.lua' +dofile './data_dkim.lua' + +setup() + +send_message(innocuous_msg, single_hdr, 'test-id', 'foo@invalid.za.org', {'nerf@example.org'}) +check_headers(1) + +teardown() diff --git a/test/functional/lua/miltertest/lib.lua b/test/functional/lua/miltertest/lib.lua new file mode 100644 index 0000000..44dc76e --- /dev/null +++ b/test/functional/lua/miltertest/lib.lua @@ -0,0 +1,119 @@ +function setup(c_ip, helo, hn) + if not c_ip then c_ip = "127.0.0.1" end + if not helo then helo = "it.is.i" end + if not hn then hn = "localhost" end + conn = mt.connect("inet:" .. port .. "@" .. host) + if conn == nil then + error "mt.connect() failed" + end + if mt.conninfo(conn, hn, c_ip) then + error "mt.conninfo() failed" + end + if mt.getreply(conn) ~= SMFIR_CONTINUE then + error "mt.conninfo() unexpected reply" + end + if mt.helo(conn, helo) then + error "mt.helo() failed" + end + if mt.getreply(conn) ~= SMFIR_CONTINUE then + error "mt.helo() unexpected reply" + end +end + +function teardown() + if conn then + mt.disconnect(conn) + end + conn = nil +end + +function send_message(body, hdrs, id, sender, rcpts) + mt.macro(conn, SMFIC_MAIL, "i", id or "test-id") + if mt.mailfrom(conn, sender or "sender@example.com") then + error "mt.mailfrom() failed" + end + if mt.getreply(conn) ~= SMFIR_CONTINUE then + error "mt.mailfrom() unexpected reply" + end + if not rcpts then + rcpts = {"rcpt@example.com"} + end + for _, r in ipairs(rcpts) do + mt.rcptto(conn, r) + end + if not hdrs then + hdrs = default_hdrs + end + if not hdrs['From'] then + hdrs['From'] = sender or "sender@example.com" + end + for k, v in pairs(hdrs) do + if mt.header(conn, k, v) then + error (string.format("mt.header(%s) failed", k)) + end + end + if mt.eoh(conn) then + error "mt.eoh() failed" + end + if mt.getreply(conn) ~= SMFIR_CONTINUE then + error "mt.eoh() unexpected reply" + end + if mt.bodystring(conn, body .. "\r\n") then + error "mt.bodystring() failed" + end + if mt.getreply(conn) ~= SMFIR_CONTINUE then + error "mt.bodystring() unexpected reply" + end + if mt.eom(conn) then + error "mt.eom() failed" + end +end + +function check_accept() + local rc = mt.getreply(conn) + if rc ~= SMFIR_ACCEPT then + error (string.format("mt.eom() unexpected reply: %s", rc)) + end +end + +function check_gtube(code, ecode, msg) + if not mt.eom_check(conn, MT_SMTPREPLY, code or '554', ecode or '5.7.1', msg or 'Gtube pattern') then + error "mt.eom_check() failed" + end + local rc = mt.getreply(conn) + if rc ~= SMFIR_REPLYCODE then + error (string.format("mt.eom() unexpected reply: %s", rc)) + end +end + +function check_defer(code, ecode, msg) + if not mt.eom_check(conn, MT_SMTPREPLY, code or '451', ecode or '4.7.1', msg or 'Try much later') then + error "mt.eom_check() failed" + end + local rc = mt.getreply(conn) + if rc ~= SMFIR_REPLYCODE then + error (string.format("mt.eom() unexpected reply: %s", rc)) + end +end + +function check_subject_rw(subj, tmpl) + if not subj then + subj = default_hdrs['Subject'] + end + if not tmpl then + tmpl = "*** SPAM *** %s" + end + local new_subj = string.format(tmpl, subj) + if not mt.eom_check(conn, MT_HDRCHANGE, "Subject", new_subj) then + error "subject not rewritten" + end +end + +function check_headers(count) + for i=0, count-1 do + local hdr = mt.getheader(conn, "DKIM-Signature", i) + if not hdr then + error (string.format("Signature %s not added", i)) + end + end +end diff --git a/test/functional/lua/miltertest/mt1.lua b/test/functional/lua/miltertest/mt1.lua new file mode 100644 index 0000000..019a852 --- /dev/null +++ b/test/functional/lua/miltertest/mt1.lua @@ -0,0 +1,11 @@ +print('Check we will accept a message') + +dofile './lib.lua' +dofile './data.lua' + +setup() + +send_message(innocuous_msg, innocuous_hdrs, 'test-id', 'nerf@example.org', {'nerf@example.org'}) +check_accept() + +teardown() diff --git a/test/functional/lua/miltertest/mt2.lua b/test/functional/lua/miltertest/mt2.lua new file mode 100644 index 0000000..1c8fa83 --- /dev/null +++ b/test/functional/lua/miltertest/mt2.lua @@ -0,0 +1,11 @@ +print('Check we will reject a message') + +dofile './lib.lua' +dofile './data.lua' + +setup() + +send_message(gtube) +check_gtube() + +teardown() diff --git a/test/functional/lua/miltertest/mt3.lua b/test/functional/lua/miltertest/mt3.lua new file mode 100644 index 0000000..6b30126 --- /dev/null +++ b/test/functional/lua/miltertest/mt3.lua @@ -0,0 +1,12 @@ +print('Check we will rewrite subjects') + +dofile './lib.lua' +dofile './data.lua' + +setup() + +send_message(gtube_rw_subject) +check_accept() +check_subject_rw() + +teardown() diff --git a/test/functional/lua/miltertest/mt4.lua b/test/functional/lua/miltertest/mt4.lua new file mode 100644 index 0000000..300cf69 --- /dev/null +++ b/test/functional/lua/miltertest/mt4.lua @@ -0,0 +1,11 @@ +print('Check we will defer messages') + +dofile './lib.lua' +dofile './data.lua' + +setup() + +send_message(innocuous_msg, innocuous_hdrs, 'test-id', 'defer@example.org', {'nerf@example.org'}) +check_defer() + +teardown() diff --git a/test/functional/lua/neural.lua b/test/functional/lua/neural.lua new file mode 100644 index 0000000..5a09c50 --- /dev/null +++ b/test/functional/lua/neural.lua @@ -0,0 +1,64 @@ +local logger = require "rspamd_logger" + +for i = 1,14 do + rspamd_config:register_symbol({ + name = 'SPAM_SYMBOL'..tostring(i), + score = 5.0, + callback = function() + return true, 'Fires always' + end + }) + rspamd_config:register_symbol({ + name = 'HAM_SYMBOL'..tostring(i), + score = -3.0, + callback = function() + return true, 'Fires always' + end + }) +end + + + +rspamd_config:register_symbol({ + name = 'NEUTRAL_SYMBOL', + score = 1.0, + flags = 'explicit_disable', + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config.SAVE_NN_ROW = { + callback = function(task) + local fname = os.tmpname() + task:cache_set('nn_row_tmpfile', fname) + return true, 1.0, fname + end +} + +rspamd_config.SAVE_NN_ROW_IDEMPOTENT = { + callback = function(task) + local function tohex(str) + return (str:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) + end + local fname = task:cache_get('nn_row_tmpfile') + if not fname then + return + end + local f, err = io.open(fname, 'w') + if not f then + logger.errx(task, err) + return + end + f:write(tohex(task:cache_get('SHORT_neural_vec_mpack') or '')) + f:close() + return + end, + type = 'idempotent', + flags = 'explicit_disable', + priority = 100, +} + +dofile(rspamd_env.INSTALLROOT .. "/share/rspamd/rules/controller/init.lua") diff --git a/test/functional/lua/option_order.lua b/test/functional/lua/option_order.lua new file mode 100644 index 0000000..caff30f --- /dev/null +++ b/test/functional/lua/option_order.lua @@ -0,0 +1,15 @@ +rspamd_config:register_symbol({ + name = 'TBL_OPTION_ORDER', + score = 1.0, + callback = function() + return true, {'one', 'two', 'three', '4', '5', 'a'} + end +}) + +rspamd_config:register_symbol({ + name = 'OPTION_ORDER', + score = 1.0, + callback = function() + return true, 'one', 'two', 'three', '4', '5', 'a' + end +}) diff --git a/test/functional/lua/params.lua b/test/functional/lua/params.lua new file mode 100644 index 0000000..2846527 --- /dev/null +++ b/test/functional/lua/params.lua @@ -0,0 +1,80 @@ +rspamd_config.TEST_RCPT = { + callback = function(task) + local l = {} + local rcpts = task:get_recipients(1) + if not rcpts then return end + for _, r in ipairs(rcpts) do + table.insert(l, r['addr']) + end + table.sort(l) + local t = table.concat(l, ",") + return true, t + end +} + +rspamd_config.TEST_HELO = { + callback = function(task) + local helo = task:get_helo() + if not helo then return end + return true, helo + end +} + +rspamd_config.TEST_HOSTNAME = { + callback = function(task) + local h = task:get_hostname() + if not h then return end + return true, h + end +} + +rspamd_config.TEST_SMTP_FROM = { + callback = function(task) + local f = task:get_from('smtp') + if not (f and f[1] and f[1].addr) then return end + return true, f[1].addr + end +} + +rspamd_config.TEST_MTA_TAG = { + callback = function(task) + local h = task:get_request_header('MTA-Tag') + if not h then return end + return true, tostring(h) + end +} + +rspamd_config.TEST_USER = { + callback = function(task) + local u = task:get_user() + if not u then return end + return true, u + end +} + +rspamd_config.TEST_QUEUEID = { + callback = function(task) + local q = task:get_queue_id() + if not q then return end + return true, q + end +} + +rspamd_config.TEST_IPADDR = { + callback = function(task) + local i = task:get_from_ip() + if not (i and i:is_valid()) then return end + return true, tostring(i) + end +} + +rspamd_config.FORCE_DEFER = { + callback = function(task) + local f = task:get_from('smtp') + if not (f and f[1] and f[1].addr) then return end + if f[1].addr == "defer@example.org" then + task:set_pre_result('soft reject', 'Try much later') + return true + end + end +} diff --git a/test/functional/lua/prepostfilters.lua b/test/functional/lua/prepostfilters.lua new file mode 100644 index 0000000..c87c958 --- /dev/null +++ b/test/functional/lua/prepostfilters.lua @@ -0,0 +1,65 @@ +for i = 1,10 do + local name = string.format('DEP_TEST%d', i) + local dep_name = string.format('DEP_TEST%d', i - 1) + rspamd_config:register_symbol({ + type = 'normal', + name = name, + callback = function(task) + local function dns_cb() + if i ~= 1 then + if task:has_symbol(dep_name) then + task:insert_result(name, 1.0) + end + else + task:insert_result(name, 1.0) + end + end + if task:has_symbol('TEST_PRE') then + local r = task:get_resolver() + r:resolve_a({task = task, name = 'example.com', callback = dns_cb}) + end + end + }) + + if i ~= 1 then + rspamd_config:register_dependency(name, dep_name) + end + + rspamd_config:set_metric_symbol({ + name = name, + score = 1.0 + }) +end + + +rspamd_config:register_symbol({ + type = 'postfilter', + name = 'TEST_POST', + callback = function(task) + for i = 1,10 do + local name = string.format('DEP_TEST%d', i) + if not task:has_symbol(name) then + return + end + end + if task:has_symbol('TEST_PRE') then + task:insert_result('TEST_POST', 1.0) + end + end +}) +rspamd_config:set_metric_symbol({ + name = 'TEST_POST', + score = 1.0 +}) + +rspamd_config:register_symbol({ + type = 'prefilter', + name = 'TEST_PRE', + callback = function(task) + task:insert_result('TEST_PRE', 1.0) + end +}) +rspamd_config:set_metric_symbol({ + name = 'TEST_PRE', + score = 1.0 +}) diff --git a/test/functional/lua/preresult.lua b/test/functional/lua/preresult.lua new file mode 100644 index 0000000..72a73b1 --- /dev/null +++ b/test/functional/lua/preresult.lua @@ -0,0 +1,3 @@ +rspamd_config:register_post_filter(function(task) + task:set_pre_result('soft reject', 'Pre Result Set') +end) diff --git a/test/functional/lua/recipients.lua b/test/functional/lua/recipients.lua new file mode 100644 index 0000000..f11c1a8 --- /dev/null +++ b/test/functional/lua/recipients.lua @@ -0,0 +1,14 @@ +rspamd_config:register_symbol({ + name = 'TEST_RCPT', + score = 1.0, + callback = function(task) + local l = {} + local rcpts = task:get_recipients(1) + for _, r in ipairs(rcpts) do + table.insert(l, r['addr']) + end + table.sort(l) + local t = table.concat(l, ",") + return true, t + end +}) diff --git a/test/functional/lua/redis.lua b/test/functional/lua/redis.lua new file mode 100644 index 0000000..1a1eaf2 --- /dev/null +++ b/test/functional/lua/redis.lua @@ -0,0 +1,113 @@ +--[[[ +-- Just a test for Redis API +--]] + +local logger = require "rspamd_logger" +local redis_lua = require "lua_redis" + +local redis_params +local N = 'redis_test' + +local lua_script = [[ +local f = function() end +return "hello from lua on redis" +]] + +local function redis_simple_async_symbol(task) + local function redis_cb(err, data) + if err then + task:insert_result('REDIS_ASYNC_ERROR', 1.0, err) + else + task:insert_result('REDIS_ASYNC', 1.0, data) + end + end + + redis_lua.rspamd_redis_make_request( + task, + redis_params, + "test_key", + false, + redis_cb, + 'GET', + {'test_key'} + ) +end + +local function redis_simple_async_api201809(task) + local function redis_cb(err, data) + if err then + task:insert_result('REDIS_ASYNC201809_ERROR', 1.0, err) + else + task:insert_result('REDIS_ASYNC201809', 1.0, data) + end + end + + local attrs = { + task = task, + callback = redis_cb + } + local request = { + 'GET', + 'test_key' + } + redis_lua.request(redis_params, attrs, request) +end + +local function redis_symbol(task) + + local attrs = {task = task} + local is_ok, connection = redis_lua.connect(redis_params, attrs) + + logger.infox(task, "connect: %1, %2", is_ok, connection) + + if not is_ok then + task:insert_result('REDIS_ERROR', 1.0, connection) + return + end + + local err, data + + is_ok, err = connection:add_cmd('EVAL', {lua_script, 0}) + logger.infox(task, "add_cmd: %1, %2", is_ok, err) + + if not is_ok then + task:insert_result('REDIS_ERROR_2', 1.0, err) + return + end + + is_ok,data = connection:exec() + + logger.infox(task, "exec: %1, %2", is_ok, data) + + if not is_ok then + task:insert_result('REDIS_ERROR_3', 1.0, data) + return + end + + task:insert_result('REDIS', 1.0, data) + +end + +redis_params = rspamd_parse_redis_server(N) + +rspamd_config:register_symbol({ + name = 'SIMPLE_REDIS_ASYNC_TEST', + score = 1.0, + callback = redis_simple_async_symbol, + no_squeeze = true +}) + +rspamd_config:register_symbol({ + name = 'SIMPLE_REDIS_ASYNC201809_TEST', + score = 1.0, + callback = redis_simple_async_api201809, + no_squeeze = true +}) + +rspamd_config:register_symbol({ + name = 'REDIS_TEST', + score = 1.0, + callback = redis_symbol, + flags = 'coro', +}) +-- ]] diff --git a/test/functional/lua/regex_test.lua b/test/functional/lua/regex_test.lua new file mode 100644 index 0000000..01f0e22 --- /dev/null +++ b/test/functional/lua/regex_test.lua @@ -0,0 +1,12 @@ +local function get_urls(task) + local urls = task:get_urls() + for _, u in ipairs(urls) do + task:insert_result('FOUND_URL', 1.0, tostring(u)) + end +end + +rspamd_config:register_symbol({ + name = 'SIMPLE', + score = 1.0, + callback = get_urls +}) diff --git a/test/functional/lua/remove_result.lua b/test/functional/lua/remove_result.lua new file mode 100644 index 0000000..106d7f4 --- /dev/null +++ b/test/functional/lua/remove_result.lua @@ -0,0 +1,26 @@ +local id = rspamd_config:register_symbol({ + name = 'REMOVE_RESULT_CB', + callback = function(task) + task:insert_result('REMOVE_RESULT_UNEXPECTED', 1.0, 'ohno') + end, + type = 'callback', +}) + +rspamd_config:register_symbol({ + name = 'REMOVE_RESULT_UNEXPECTED', + type = 'virtual', + score = 0.1, + group = 'remove_result_test', + parent = id, +}) + +rspamd_config:register_symbol({ + name = 'REMOVE_RESULT_EXPECTED', + callback = function(task) + return task:remove_result('REMOVE_RESULT_UNEXPECTED') and true or false + end, + type = 'normal', + score = 0.1, +}) + +rspamd_config:register_dependency('REMOVE_RESULT_EXPECTED', 'REMOVE_RESULT_UNEXPECTED') diff --git a/test/functional/lua/rspamadm/test_batch.lua b/test/functional/lua/rspamadm/test_batch.lua new file mode 100644 index 0000000..dd50c9d --- /dev/null +++ b/test/functional/lua/rspamadm/test_batch.lua @@ -0,0 +1,4 @@ +local rspamd_logger = require "rspamd_logger" + +rspamd_logger.info(rspamd_config, "nope") +rspamd_logger.err(rspamd_config, "hello world") diff --git a/test/functional/lua/rspamadm/test_dns_client.lua b/test/functional/lua/rspamadm/test_dns_client.lua new file mode 100644 index 0000000..c54d594 --- /dev/null +++ b/test/functional/lua/rspamadm/test_dns_client.lua @@ -0,0 +1,30 @@ +local rspamd_dns = require "rspamd_dns" +local logger = require "rspamd_logger" + +local config_path = rspamd_paths['CONFDIR'] .. '/rspamd.conf' +local _r,err = rspamd_config:load_ucl(config_path) + +if not _r then + logger.errx('cannot parse %s: %s (r=%s)', config_path, err, _r) + os.exit(1) +end + +_r,err = rspamd_config:parse_rcl({'logging', 'worker'}) +if not _r then + logger.errx('cannot process %s: %s (r=%s)', config_path, err, _r) + os.exit(1) +end + +rspamd_config:init_subsystem('dns', rspamadm_ev_base) + + +local is_ok, results = rspamd_dns.request({ + config = rspamd_config, + session = rspamadm_session, + + type = 'txt', + name = 'test._domainkey.example.com', + -- name = '_dmarc.google.com', + }) + +print(is_ok, results[1]) diff --git a/test/functional/lua/rspamadm/test_message_callback.lua b/test/functional/lua/rspamadm/test_message_callback.lua new file mode 100644 index 0000000..6be512a --- /dev/null +++ b/test/functional/lua/rspamadm/test_message_callback.lua @@ -0,0 +1,5 @@ +function message_callback(task) + local parts = task:get_text_parts() + print("n parts = " .. tostring(#parts)) + return 1,2,4,6 +end diff --git a/test/functional/lua/rspamadm/test_redis_client.lua b/test/functional/lua/rspamadm/test_redis_client.lua new file mode 100644 index 0000000..a7428a8 --- /dev/null +++ b/test/functional/lua/rspamadm/test_redis_client.lua @@ -0,0 +1,40 @@ +local logger = require "rspamd_logger" +local redis = require "lua_redis" +local upstream_list = require "rspamd_upstream_list" + +local upstreams_write = upstream_list.create('127.0.0.1', 56379) +local upstreams_read = upstream_list.create('127.0.0.1', 56379) + +local is_ok, connection = redis.redis_connect_sync({ + write_servers = upstreams_write, + read_servers = upstreams_read, +-- config = rspamd_config, +-- ev_base = rspamadm_ev_base, +-- session = rspamadm_session, + timeout = 2 +}) + + +local lua_script = [[ +local f = function() end +--for k = 1,100000000 do +-- for i=1,100000000 do +-- f() +-- end +--end +return "hello from lua on redis" +]] + +local a,b = connection:add_cmd('EVAL', {lua_script, 0}) +local is_ok,ver = connection:exec() + +print(is_ok, ver) + +--[[ +a,b = connection:add_cmd('EVAL', {lua_script, 0}) +print(a,b) + +is_ok,ver = connection:exec() + +print(is_ok, ver) +]]
\ No newline at end of file diff --git a/test/functional/lua/rspamadm/test_tcp_client.lua b/test/functional/lua/rspamadm/test_tcp_client.lua new file mode 100644 index 0000000..eb103db --- /dev/null +++ b/test/functional/lua/rspamadm/test_tcp_client.lua @@ -0,0 +1,64 @@ +local logger = require "rspamd_logger" +local tcp_sync = require "lua_tcp_sync" + +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, +} +if not is_ok then + logger.errx(rspamd_config, 'connect error: %1', connection) + return +end +local err +is_ok, err = connection:write(string.format('POST /request HTTP/1.1\r\nConnection: close\r\n\r\n')) + +logger.info('write %1, %2', is_ok, err) +if not is_ok then + logger.errx(rspamd_config, 'write error: %1', err) + return +end + +local content_length, content + +while true do + local header_line + is_ok, header_line = connection:read_until("\r\n") + if not is_ok then + logger.errx(rspamd_config, 'failed to get header: %1', header_line) + return + end + + if header_line == "" then + logger.info('headers done') + break + end + + local value + local header = header_line:gsub("([%w-]+): (.*)", + function (h, v) value = v; return h:lower() end) + + logger.info('parsed header: %1 -> "%2"', header, value) + + if header == "content-length" then + content_length = tonumber(value) + end + +end + +if content_length then + is_ok, content = connection:read_bytes(content_length) + if is_ok then + end +else + is_ok, content = connection:read_until_eof() + if is_ok then + end +end +logger.info('(is_ok: %1) content [%2 bytes] %3', is_ok, content_length, content) + + +print(content) diff --git a/test/functional/lua/rspamadm/test_verbose.lua b/test/functional/lua/rspamadm/test_verbose.lua new file mode 100644 index 0000000..4470c63 --- /dev/null +++ b/test/functional/lua/rspamadm/test_verbose.lua @@ -0,0 +1,3 @@ +local rspamd_logger = require "rspamd_logger" + +rspamd_logger.info(rspamd_config, "hello world") diff --git a/test/functional/lua/selector_test.lua b/test/functional/lua/selector_test.lua new file mode 100644 index 0000000..dd52ee3 --- /dev/null +++ b/test/functional/lua/selector_test.lua @@ -0,0 +1,23 @@ +local lua_selectors = require 'lua_selectors' +local rspamd_text = require 'rspamd_text' + +rspamd_config:register_re_selector('test', 'user.lower;header(Subject).lower', ' ') + +config['regexp']['LUA_SELECTOR_RE'] = { + re = 'test=/^test@user\\.com some subject$/{selector}', + score = 100500, +} + +lua_selectors.register_extractor(rspamd_config, 'some_rspamd_text', { + get_value = function() + return {rspamd_text.fromstring('hello'), rspamd_text.fromstring('world')}, 'string_list' + end, + description = 'Return some rspamd_texts', +}) + +rspamd_config:register_re_selector('some_rspamd_text_re', 'some_rspamd_text', ' ') + +config['regexp']['RSPAMD_TEXT_SELECTOR'] = { + re = 'some_rspamd_text_re=/^hello$/{selector}', + score = 1, +} diff --git a/test/functional/lua/settings.lua b/test/functional/lua/settings.lua new file mode 100644 index 0000000..384c68e --- /dev/null +++ b/test/functional/lua/settings.lua @@ -0,0 +1,68 @@ +rspamd_config:register_symbol({ + name = 'SIMPLE_PRE', + score = 1.0, + priority = 9, -- after settings + group = 'a', + type = 'prefilter', + callback = function() + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'SIMPLE_POST', + score = 1.0, + type = 'postfilter', + group = 'c', + callback = function() + return true, 'Fires always' + end +}) + +local id = rspamd_config:register_symbol({ + name = 'SIMPLE_TEST', + score = 1.0, + group = 'b', + callback = function(task) + task:insert_result('SIMPLE_VIRTUAL', 1.0) + task:insert_result('SIMPLE_VIRTUAL1', 1.0) + return true, 'Fires always' + end +}) + +rspamd_config:register_symbol({ + name = 'SIMPLE_VIRTUAL', + type = 'virtual', + score = 1.0, + group = 'vg', + parent = id, +}) + +rspamd_config:register_symbol({ + name = 'SIMPLE_VIRTUAL1', + type = 'virtual', + forbidden_ids = 'id_virtual,id_virtual_group', + allowed_ids = 'id_virtual1', + score = 1.0, + group = 'vg', + parent = id, +}) + +id = rspamd_config:register_symbol({ + name = 'DEP_REAL', + callback = function(task) + task:insert_result('DEP_VIRTUAL', 1.0) + return true + end, + score = 1.0, +}) + +rspamd_config:register_symbol({ + name = 'DEP_VIRTUAL', + parent = id, + type = 'virtual', + allowed_ids = 'id_virtual1', + score = 1.0, +}) + +rspamd_config:register_dependency('DEP_VIRTUAL', 'EXPLICIT_VIRTUAL1')
\ No newline at end of file diff --git a/test/functional/lua/simple.lua b/test/functional/lua/simple.lua new file mode 100644 index 0000000..22ecde8 --- /dev/null +++ b/test/functional/lua/simple.lua @@ -0,0 +1,7 @@ +rspamd_config:register_symbol({ + name = 'SIMPLE_TEST', + score = 1.0, + callback = function() + return true, 'Fires always' + end +}) diff --git a/test/functional/lua/tcp.lua b/test/functional/lua/tcp.lua new file mode 100644 index 0000000..e5c765b --- /dev/null +++ b/test/functional/lua/tcp.lua @@ -0,0 +1,279 @@ +--[[[ +-- Just a test for TCP API +--]] + +local rspamd_tcp = require "rspamd_tcp" +local logger = require "rspamd_logger" +local tcp_sync = require "lua_tcp_sync" + +-- [[ old fashioned callback api ]] +local function http_simple_tcp_async_symbol(task) + logger.errx(task, 'http_tcp_symbol: begin') + local function http_get_cb(err, data, conn) + logger.errx(task, 'http_get_cb: got reply: %s, error: %s, conn: %s', data, err, conn) + task:insert_result('HTTP_ASYNC_RESPONSE_2', 1.0, data) + end + local function http_read_post_cb(err, conn) + logger.errx(task, 'http_read_post_cb: write done: error: %s, conn: %s', err, conn) + conn:add_read(http_get_cb) + 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\n\r\n") + 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\nConnection: keep-alive\r\n\r\n'}, + read = true, + port = 18080, + }) +end + +local function http_simple_tcp_ssl_symbol(task) + logger.errx(task, 'ssl_tcp_symbol: begin') + local function ssl_get_cb(err, data, conn) + logger.errx(task, 'ssl_get_cb: got reply: %s, error: %s, conn: %s', data, err, conn) + task:insert_result('TCP_SSL_RESPONSE_2', 1.0, tostring(data):gsub('%s', '')) + end + local function ssl_read_post_cb(err, conn) + logger.errx(task, 'ssl_read_post_cb: write done: error: %s, conn: %s', err, conn) + conn:add_read(ssl_get_cb) + end + local function ssl_read_cb(err, data, conn) + logger.errx(task, 'ssl_read_cb: got reply: %s, error: %s, conn: %s', data, err, conn) + conn:add_write(ssl_read_post_cb, "test2\n") + task:insert_result('TCP_SSL_RESPONSE', 1.0, tostring(data):gsub('%s', '')) + end + rspamd_tcp:request({ + task = task, + callback = ssl_read_cb, + host = '127.0.0.1', + data = {'test\n'}, + read = true, + ssl = true, + ssl_noverify = true, + port = 18081, + }) +end + +local function http_large_tcp_ssl_symbol(task) + local data = {} + + local function ssl_get_cb(err, rep, conn) + logger.errx(task, 'ssl_get_cb: got reply: %s, error: %s, conn: %s', rep, err, conn) + task:insert_result('TCP_SSL_LARGE_2', 1.0) + end + local function ssl_read_post_cb(err, conn) + logger.errx(task, 'ssl_large_read_post_cb: write done: error: %s, conn: %s', err, conn) + conn:add_read(ssl_get_cb) + end + local function ssl_read_cb(err, rep, conn) + logger.errx(task, 'ssl_large_read_cb: got reply: %s, error: %s, conn: %s', rep, err, conn) + conn:add_write(ssl_read_post_cb, 'foo\n') + task:insert_result('TCP_SSL_LARGE', 1.0) + end + + if task:get_queue_id() == 'SSL Large TCP request' then + logger.errx(task, 'ssl_large_tcp_symbol: begin') + for i = 1,2 do + local st = {} + for j=1,300000 do + st[j] = 't' + end + data[i] = table.concat(st) + end + data[#data + 1] = '\n' + + rspamd_tcp:request({ + task = task, + callback = ssl_read_cb, + host = '127.0.0.1', + data = data, + read = true, + ssl = true, + stop_pattern = '\n', + ssl_noverify = true, + port = 18081, + timeout = 20, + }) + else + logger.errx(task, 'ssl_large_tcp_symbol: skip') + end +end + +local function http_simple_tcp_symbol(task) + logger.errx(task, 'connect_sync, before') + + local err + local is_ok, connection = tcp_sync.connect { + task = task, + host = '127.0.0.1', + timeout = 20, + port = 18080, + } + + if not is_ok then + task:insert_result('HTTP_SYNC_WRITE_ERROR', 1.0, connection) + logger.errx(task, 'write error: %1', connection) + end + + logger.errx(task, 'connect_sync %1, %2', is_ok, tostring(connection)) + + is_ok, err = connection:write('GET /request HTTP/1.1\r\nConnection: keep-alive\r\n\r\n') + + logger.errx(task, 'write %1, %2', is_ok, err) + if not is_ok then + task:insert_result('HTTP_SYNC_WRITE_ERROR', 1.0, err) + logger.errx(task, 'write error: %1', err) + end + + local data + local got_content = '' + repeat + is_ok, data = connection:read_once(); + logger.errx(task, 'read_once: is_ok: %1, data: %2', is_ok, data) + if not is_ok then + task:insert_result('HTTP_SYNC_ERROR', 1.0, data) + return + else + got_content = got_content .. data + end + if got_content:find('hello') then + -- dummy_http.py responds with either hello world or hello post + break + end + until false + + task:insert_result('HTTP_SYNC_RESPONSE', 1.0, got_content) + + is_ok, err = connection:write("POST /request HTTP/1.1\r\n\r\n") + logger.errx(task, 'write[2] %1, %2', is_ok, err) + + got_content = '' + repeat + is_ok, data = connection:read_once(); + logger.errx(task, 'read_once[2]: is_ok %1, data: %2', is_ok, data) + if not is_ok then + task:insert_result('HTTP_SYNC_ERROR_2', 1.0, data) + return + else + got_content = got_content .. data + end + if got_content:find('hello') then + break + end + until false + + task:insert_result('HTTP_SYNC_RESPONSE_2', 1.0, data) + + connection:close() +end + +local function http_tcp_symbol(task) + local url = tostring(task:get_request_header('url')) + local method = tostring(task:get_request_header('method')) + + if url == 'nil' then + return + end + + local err + local is_ok, connection = tcp_sync.connect { + task = task, + host = '127.0.0.1', + timeout = 20, + port = 18080, + } + + logger.errx(task, 'connect_sync %1, %2', is_ok, tostring(connection)) + if not is_ok then + logger.errx(task, 'connect error: %1', connection) + return + end + + is_ok, err = connection:write(string.format('%s %s HTTP/1.1\r\nConnection: close\r\n\r\n', method:upper(), url)) + + logger.errx(task, 'write %1, %2', is_ok, err) + if not is_ok then + logger.errx(task, 'write error: %1', err) + return + end + + local content_length, content + + while true do + local header_line + is_ok, header_line = connection:read_until("\r\n") + if not is_ok then + logger.errx(task, 'failed to get header: %1', header_line) + return + end + + if header_line == "" then + logger.errx(task, 'headers done') + break + end + + local value + local header = header_line:gsub("([%w-]+): (.*)", + function (h, v) value = v; return h:lower() end) + + logger.errx(task, 'parsed header: %1 -> "%2"', header, value) + + if header == "content-length" then + content_length = tonumber(value) + end + + end + + if content_length then + is_ok, content = connection:read_bytes(content_length) + if is_ok then + task:insert_result('HTTP_SYNC_CONTENT_' .. method, 1.0, content) + end + else + is_ok, content = connection:read_until_eof() + if is_ok then + task:insert_result('HTTP_SYNC_EOF_' .. method, 1.0, content) + end + end + logger.errx(task, '(is_ok: %1) content [%2 bytes] %3', is_ok, content_length, content) +end + +rspamd_config:register_symbol({ + name = 'SIMPLE_TCP_ASYNC_TEST', + score = 1.0, + callback = http_simple_tcp_async_symbol, + no_squeeze = true +}) +rspamd_config:register_symbol({ + name = 'SIMPLE_TCP_ASYNC_SSL_TEST', + score = 1.0, + callback = http_simple_tcp_ssl_symbol, + no_squeeze = true +}) +rspamd_config:register_symbol({ + name = 'LARGE_TCP_ASYNC_SSL_TEST', + score = 1.0, + callback = http_large_tcp_ssl_symbol, + no_squeeze = true +}) +rspamd_config:register_symbol({ + name = 'SIMPLE_TCP_TEST', + score = 1.0, + callback = http_simple_tcp_symbol, + no_squeeze = true, + flags = 'coro', +}) + +rspamd_config:register_symbol({ + name = 'HTTP_TCP_TEST', + score = 1.0, + callback = http_tcp_symbol, + no_squeeze = true, + flags = 'coro', +}) +-- ]] diff --git a/test/functional/lua/test_coverage.lua b/test/functional/lua/test_coverage.lua new file mode 100644 index 0000000..68f2545 --- /dev/null +++ b/test/functional/lua/test_coverage.lua @@ -0,0 +1,46 @@ +--[[ +-- This should be the very first file executed during a test +-- otherwise coverage will be partly missed +--]] +local logger = require "rspamd_logger" +local mempool = require "rspamd_mempool" +local loaded, luacov = pcall(require, 'luacov.runner') +if not loaded then + logger.errx('luacov is not loaded, will not collect coverage') + return +end + +luacov.init() + +local pool = mempool.create() +-- we don't need the pool, we need userdata to put __gc() on it +-- __gc() is not called for tables, that't why there is such trick +-- so, we are free to clean memory, let's do this :) +pool:destroy() + +local woker_name + +rspamd_config:add_on_load(function(cfg, ev_base, worker) + woker_name = worker:get_name() + local stats_path = rspamd_paths["DBDIR"] .. '/' .. woker_name .. '.luacov.stats.out' + local config = luacov.load_config() + config.statsfile = stats_path +end) + +-- use global variable to prevent the object from being GC'ed too early +__GLOBAL_COVERAGE_WATCHDOG = {pool = pool} + +local mt = { + __gc = function() + --[[ + -- We could've used finish_script but in that case some coverage would be missed: + -- pool destructors are executed after finish_scripts (when Lua state is terminated and that's + -- how we can collect coverage of cove executed there + --]] + if woker_name then + luacov.shutdown() + end + end +} + +debug.setmetatable(__GLOBAL_COVERAGE_WATCHDOG.pool, mt) diff --git a/test/functional/lua/test_fname.lua b/test/functional/lua/test_fname.lua new file mode 100644 index 0000000..ffa7bb9 --- /dev/null +++ b/test/functional/lua/test_fname.lua @@ -0,0 +1,12 @@ +rspamd_config.TEST_FNAME = { + callback = function(task) + local r = task:get_parts() + local fnames = {} + for _,rh in ipairs(r) do + if rh:get_filename() then + table.insert(fnames, rh:get_filename()) + end + end + return true,1.0,fnames + end +}
\ No newline at end of file diff --git a/test/functional/lua/tlds.lua b/test/functional/lua/tlds.lua new file mode 100644 index 0000000..24836b3 --- /dev/null +++ b/test/functional/lua/tlds.lua @@ -0,0 +1,58 @@ +rspamd_config:register_symbol({ + name = 'TEST_TLD', + score = 1.0, + callback = function() + local prefixes = { + '', + 'example.' + } + local test_domains = { + 'example.ac', + 'example.b.br', + 'example.co', + 'example.com', + 'example.co.za', + 'example.in.net', + 'example.star.kawasaki.jp', + 'example.net', + 'example.net.in', + 'example.star.nom.br', + 'example.org', + 'example.org.ac', + 'example.ru.com', + 'example.za.net', + 'example.za.org', + 'org.org.za', + } + local worry = {} + local rspamd_mempool = require 'rspamd_mempool' + local rspamd_url = require 'rspamd_url' + local rspamd_util = require 'rspamd_util' + local pool = rspamd_mempool.create() + for _, d in ipairs(test_domains) do + (function() + for _, p in ipairs(prefixes) do + local test = rspamd_util.get_tld(p .. d) + if (test ~= d) then + local opt = string.format('util.get_tld:p=%s;d=%s;got=%s', p, d, test) + table.insert(worry, opt) + return + end + local u = rspamd_url.create(pool, p .. d) + assert(u, "cannot parse string: " .. p .. d) + test = u:get_tld() + if (test ~= d) then + local opt = string.format('url.create:p=%s;d=%s;got=%s', p, d, test) + table.insert(worry, opt) + return + end + end + end)() + end + if (#worry == 0) then + return true, 1.0, "no worry" + else + return true, 1.0, worry + end + end +}) diff --git a/test/functional/lua/udp.lua b/test/functional/lua/udp.lua new file mode 100644 index 0000000..0ed4b15 --- /dev/null +++ b/test/functional/lua/udp.lua @@ -0,0 +1,81 @@ +--[[[ +-- Just a test for UDP API +--]] + +local rspamd_udp = require "rspamd_udp" +local logger = require "rspamd_logger" + +-- [[ old fashioned callback api ]] +local function simple_udp_async_symbol(task) + logger.errx(task, 'udp_symbol: begin') + local function udp_cb(success, data) + logger.errx(task, 'udp_cb: got reply: %s', data) + + if success then + task:insert_result('UDP_SUCCESS', 1.0, data) + else + task:insert_result('UDP_FAIL', 1.0, data) + end + end + rspamd_udp:sendto({ + task = task, + callback = udp_cb, + host = '127.0.0.1', + data = {'hello', 'world'}, + port = 5005, + }) +end + +rspamd_config:register_symbol({ + name = 'UDP_SUCCESS', + score = 0.0, + callback = simple_udp_async_symbol, +}) + +local function send_only_udp(task) + logger.errx(task, 'udp_symbol_sendonly: begin') + if rspamd_udp:sendto({ + task = task, + host = '127.0.0.1', + data = {'hoho'}, + port = 5005, + }) then + + task:insert_result('UDP_SENDTO', 1.0) + end +end + +rspamd_config:register_symbol({ + name = 'UDP_SENDTO', + score = 0.0, + callback = send_only_udp, +}) + +local function udp_failed_cb(task) + logger.errx(task, 'udp_failed_cb: begin') + local function udp_cb(success, data) + logger.errx(task, 'udp_failed_cb: got reply: %s', data) + + if success then + task:insert_result('UDP_SUCCESS', 1.0, data) + else + task:insert_result('UDP_FAIL', 1.0, data) + end + end + rspamd_udp:sendto({ + task = task, + callback = udp_cb, + host = '127.0.0.1', + data = {'hello', 'world'}, + port = 5006, + retransmits = 2, + timeout = 0.1, + }) +end + +rspamd_config:register_symbol({ + name = 'UDP_FAIL', + score = 0.0, + callback = udp_failed_cb, +}) +-- ]] |