我试图用破坏的方式测试我们的Freeswitch lua脚本,并且遇到了麻烦。它的要点是我需要能够监视代码,如下所示
local req_host = session:getVariable('sip_req_host')
session:setVariable('curl_timeout', 0)
但我似乎无法弄清楚如何构建我应该设置_G.session的对象。我可以找到的最好/唯一的好例子是https://github.com/chris-allnutt/unit-tested-corona/blob/master/mocks/button.lua,但似乎使用相同的简单语法来构建被破坏的文档所做的模拟对象。
local button = {
x = 0,
y = 0,
addEventListener = function() end
}
我可以看到这对于不需要返回任何东西的简单函数是如何工作的,但我需要能够使用getVariable和setVariable函数在会话对象中获取和设置变量。我的简单模拟对象如下:
Session = {}
Session.__index = Session
function Session.create(params)
local session = {}
setmetatable(session, Session)
session.params = params
return session
end
function Session:getVariable(key)
return self.params[key]
end
function Session:setVariable(key, val)
self.params[key] = val
end
function Session:execute(cmd, code)
end
,测试如下
require "busted"
require("test_utils")
describe("Test voip lua script", function()
it('Test webrtc bad domain', function()
domain = 'rtc.baddomain.com';
session_params = {['sip_req_host'] = domain,
['sip_req_user'] = 'TEST-WebRTC-Client',
["sip_from_user"] = 'testwebrtc_p_12345',
['sip_call_id'] = 'test@call_id',
['sip_authorized'] = 'false'}
exec_str = 'sofia_contact TEST-WebRTC-Client@'..domain;
api_params = {[exec_str] = 'error/user_not_registered'}
_G.session = mock(Session.create(session_params), 'execute')
_G.api = API.create(api_params)
_G.freeswitch = Freeswitch.create()
dofile("tested_script.lua")
assert.spy(_G.session.execute).called_with("respond", "407")
end)
end)
我最终遇到以下异常。 /usr/local/share/lua/5.2/luassert/spy.lua:78:尝试索引函数值
luassert抛出了这个异常,这是一个被破坏的库的依赖,在下面的if语句中
77:local function called_with(state, arguments)
78: if rawget(state, "payload") and rawget(state, "payload").called_with then
79: return state.payload:called_with(arguments)
80: else
81: error("'called_with' must be chained after 'spy(aspy)'")
82: end
83:end
我对lua很陌生,所以我似乎只是错过了一些明显的语言部分,但是我们将非常感谢任何帮助或指示。
答案 0 :(得分:1)
mod_lua使用稍微定制的Lua解释器,您似乎使用安装在主机上的不同Lua解释器。我猜他们不会轻易合作。
答案 1 :(得分:1)
所以我在调试的另一天之后找到的答案是肯定的,你确实需要使用一个表作为你调用mock的对象。但是,因为在构建具有可调参数的对象时,lua是一种非常宽容的语言,所以这仍然最终起作用。由于与此问题无关的原因,我在对象周围构建了一个包装器,但您可以看到我最终在下面工作的内容。
function SessionConstructor.create(params)
local session_constructor = {}
setmetatable(session_constructor, SessionConstructor)
session_constructor.session = {}
session_constructor.session.params = params
session_constructor.session.getVariable = function(self,key)
return self.params[key]
end
session_constructor.session.setVariable = function(self, key, val)
self.params[key] = val
end
session_constructor.session.execute = function(self, cmd, code)
end
return session_constructor
end
function SessionConstructor:construct()
return self.session
end
一个重要的警告,因为你必须将自己传递给将被lua""调用的函数:"语法中监视调用的函数的方法确实发生了变化,如下面的测试文件中所示。
require "busted"
require "test_utils"
describe("Test voip lua script", function()
it('Test webrtc bad domain', function()
domain = 'rtc.baddomain.com';
session_params = {['sip_req_host'] = domain,
['sip_req_user'] = 'TEST-WebRTC-Client',
["sip_from_user"] = 'testwebrtc_p_12345',
['sip_call_id'] = 'test@call_id',
['sip_authorized'] = 'false'}
local sess_con = SessionConstructor.create(session_params)
exec_str = 'sofia_contact TEST-WebRTC-Client@'..domain;
local api_con = APIConstructor.create()
api_con:expect_exec(exec_str, 'error/user_not_registered')
_G.session = mock(sess_con:construct())
_G.api = mock(api_con:construct())
_G.freeswitch = create_freeswitch()
dofile("tested_script.lua")
assert.spy(session.execute).was.called_with(session, "respond", "407")
assert.spy(session.execute).was_not.called_with("respond", "407") --This is unfortunate
end)
end)
答案 2 :(得分:0)
我对busted
bin脚本进行了一些逆向工程,并得到了以下脚本(我们称之为runner.lua
):
busted = require 'busted.core'()
local environment = require 'busted.environment'(busted.context)
function unpack(t, i)
i = i or 1
if t[i] ~= nil then
return t[i], unpack(t, i + 1)
end
end
busted.getTrace = function(element, level, msg)
level = level or 3
local info = debug.getinfo(level, 'Sl')
info.traceback = debug.traceback('', level)
info.message = msg
if msg ~= nil then
freeswitch.consoleLog("NOTICE", msg)
end
local file = busted.getFile(element)
return file.getTrace(file.name, info)
end
busted.safe = function(descriptor, run, element, setenv)
if setenv and (type(run) == 'function' or getmetatable(run).__call) then
-- prioritize __call if it exists, like in files
environment.wrap(getmetatable(run).__call or run)
end
busted.context.push(element)
local trace, message
local ret = { xpcall(run, function(msg)
message = busted.rewriteMessage(element, msg)
freeswitch.consoleLog("ERR", message)
trace = busted.getTrace(element, 3, msg)
end) }
if not ret[1] then
busted.publish({ 'error', descriptor }, element, busted.context.parent(element), message, trace)
end
busted.context.pop()
return unpack(ret)
end
require 'busted.init'(busted)
local checkTag = function(name, tag, modifier)
local found = name:find('#' .. tag)
return (modifier == (found ~= nil))
end
local checkTags = function(name)
for i, tag in pairs(tags) do
if not checkTag(name, tag, true) then
return nil, false
end
end
for i, tag in pairs(excludeTags) do
if not checkTag(name, tag, false) then
return nil, false
end
end
return nil, true
end
local getTrace = function(filename, info)
local index = info.traceback:find('\n%s*%[C]')
info.traceback = info.traceback:sub(1, index)
return info, false
end
local file = setmetatable({
getTrace = getTrace
}, {
__call = loadfile("/path/scripts/main_spec.lua")
})
busted.executors.file("main_spec.lua", file)
local failures = 0
local errors = 0
busted.subscribe({ 'error' }, function()
errors = errors + 1
end)
busted.subscribe({ 'test', 'end' }, function(element, parent, status)
if status == 'failure' then
failures = failures + 1
end
end)
busted.publish({ 'suite', 'start' })
busted.execute()
busted.publish({ 'suite', 'end' })
freeswitch.consoleLog("NOTICE", "Failures: " .. failures)
freeswitch.consoleLog("NOTICE", "Errors: " .. errors)
该脚本仅针对一个文件/path/scripts/main_spec.lua
,但仍可使用。
您可以使用此runner.lua
脚本执行的操作是使用来自Freeswitch控制台的luarun
运行它:
fs_cli
luarun /path/to/runner.lua
你会在那里得到输出。