1

我正在尝试使用 busted 测试我们的 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找到关于如何使用 busted 的最佳/唯一好的示例,但它似乎使用相同用于构建被破坏的文档所做的模拟对象的简单语法。

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:尝试索引函数值

在下面的 if 语句中,这个异常是被破坏的库的依赖项 luassert 抛出的

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 很陌生,所以我似乎只是错过了该语言的一些明显部分,但任何帮助或指针将不胜感激。

4

3 回答 3

2

所以我在又一天的调试后发现的答案是,是的,你确实需要使用一个表作为你调用模拟的对象。但是,由于 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

一个重要的警告,因为你必须将 self 传递给将使用 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)
于 2014-04-30T22:06:32.190 回答
1

FreeSWITCH 中的 mod_lua 使用了稍微定制的 Lua 解释器,而您似乎使用了安装在主机上的不同 Lua 解释器。我想他们不会轻易合作。

于 2014-04-30T10:59:05.337 回答
0

我对bustedbin 脚本进行了一些逆向工程,得到了以下脚本(我们称之为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东西,但仍然可用。您可以使用此脚本执行的操作是从 Freeswitch 控制台runner.lua运行它:luarun

fs_cli
luarun /path/to/runner.lua

你会在那里得到输出。

于 2014-07-23T13:55:14.947 回答