Sat, 12 Mar 2016 19:52:31 +0100
Add test for instant MUC rooms
#!/usr/bin/env luajit local json = require "cjson"; local time = require "socket".gettime; local sleep = require "socket".sleep; local result_log_filename = nil; local server_log_reader = nil; local test_metadata = {}; local server_log_wait_time = 0.2; local skip_server_startup_log = false; local action_timeout = 5; local property_rules = {}; local function apply_object_properties(class, name, object) for _, rule in ipairs(property_rules) do if (not(rule.class) or tostring(rule.class):lower() == tostring(class):lower()) and (not(rule.name) or tostring(rule.name):lower() == tostring(name):lower()) then for prop_key, prop_value in pairs(rule.properties) do object[prop_key] = prop_value; end end end end function process_options() local function get_value() return (assert(table.remove(arg, 1), "unexpected end of command-line options")); end while arg[1] and arg[1]:sub(1,1) == "-" do local opt = arg[1]; if opt == "--" then table.remove(arg, 1); break; end table.remove(arg, 1); if opt == "--port" or opt == "-p" then local port = assert(tonumber(get_value()), "port number must be a number"); table.insert(property_rules, { class = "client", properties = { connect_port = port } }); elseif opt == "--host" or opt == "-h" then local host = get_value(); table.insert(property_rules, { class = "client", properties = { connect_host = host } }); elseif opt == "--out" or opt == "-o" then result_log_filename = get_value(); elseif opt == "--server-log" or opt == "-s" then local server_log = assert(io.open(get_value(), "r")); function server_log_reader() local new_lines = {}; local last_line_time = time(); while time() - last_line_time < server_log_wait_time do sleep(0.05); for line in server_log:lines() do table.insert(new_lines, line); last_line_time = time(); end end return new_lines; end elseif opt == "--skip-server-startup-log" then skip_server_startup_log = true; elseif opt == "--step-timeout" then action_timeout = assert(tonumber(get_value()), "number expected for --step-timeout"); elseif opt == "--tag" then local tag = get_value(); local key, value = tag:match("^([^=]+):(.+)$"); if key and value then test_metadata[key] = value; else error("Unable to parse tag: "..tag); end else error("Unhandled command-line option: "..opt); end end assert(#arg > 0, "No test script provided"); assert(#arg < 2, "Too many parameters"); if not test_metadata["Name"] then test_metadata["Name"] = arg[1]; end end function read_script() io.input(arg[1]); return io.read("*a"); end function parse_script(data) local parser = require "scansion.parser"; return assert(parser.parse(data)); end function initialize_script(script) local c = 0; for name, object in pairs(script.objects) do local o = require("scansion.objects."..object.type); object.handler = o; object.script = script; apply_object_properties(object.type, object.name, object); if object.type == "client" and not object.stanza_timeout then object.stanza_timeout = action_timeout - 1; end o._validate(object); c = c + 1; end --print("Script defines "..c.." objects, and "..#script.actions.." actions"); return script; end function initialize_verse(errcb) local verse = require "verse"; verse.set_log_handler(verse._default_log_handler, { "debug", "info", "warn", "error" }); local function error_handler(err) verse.log("error", "Error: %s", err); verse.log("error", "Traceback: %s", debug.traceback()); errcb(err); end verse.set_error_handler(error_handler); return verse; end function main(log_data) local ok, err = true; local script = initialize_script(parse_script(read_script())); log_data("script", { title = script.title, summary = script.summary, tags = script.tags }); if server_log_reader then if skip_server_startup_log then server_log_reader(); else log_data("server", { lines = server_log_reader() }); end end local verse = initialize_verse(function (_err) ok, err = false, _err end); local async = require "scansion.async"; local runner = async.runner(function (d) for i, action in ipairs(script.actions) do local object = script.objects[action.object_name]; local handler = object.handler; assert(handler[action.action], "Objects of type '"..object.type.."' do not support action '"..action.action.."'"); print(""); if server_log_reader then log_data("server", { lines = server_log_reader() }); end log_data("action", { action = action.action; object = object.name; object_type = object.type; extra = action.extra; annotation = action.annotation; }); if action.annotation then print(action.annotation); end print(object.name, action.action.."..."); if action_timeout and action_timeout > 0 then local action_number = i; verse.add_task(action_timeout, function () if i == action_number then error("Timeout waiting for response from server"); end end); end local ok, err = pcall(handler[action.action], object, action.extra); if server_log_reader then log_data("server", { lines = server_log_reader() }); end if not ok then log_data("error", { message = err }); error(err); end end verse.log("info", "Completed script!"); verse.quit(); end, { error = function (runner, _err) verse.log("error", "Runner caught error: %s", _err); ok, err = false, _err; verse.quit(); end; }); runner:run(true); verse.log("debug", "runner paused") verse.loop(); if server_log_reader then log_data("server", { lines = server_log_reader() }); end return ok, err; end -- Process command-line options process_options(); -- Dummy logging function, used if no log file set local log_data = function () end; local result_log; if result_log_filename then result_log = assert(io.open(result_log_filename, "w+")); result_log:write("[\n"); function log_data(type, data) local entry = { type = type, data = data, time = time() }; result_log:write(" ", json.encode(entry), ",\n"); result_log:flush(); end end log_data("start", { metadata = test_metadata }); local ok, result, err = pcall(main, log_data); local exit_code = 0; if not ok then print("TEST ERROR:", result); exit_code = 2; log_data("test-error", { error = result }); elseif not result then print("TEST FAILED", err); exit_code = 1; log_data("test-failed", { error = err }); else print("TEST PASSED"); log_data("test-passed"); end if result_log then result_log:write([[ {"type": "end", "time": ]]..time().."}\n]\n"); result_log:close(); end os.exit(exit_code);