Skip to content

Commit e6a2093

Browse files
Oleg Chaplashkinylobankov
andcommitted
Add error handling at the server instance
When executing the following code on the remote server instance using `server:exec()`, we could get an unobvious error: s = Server:new() s:start() -- we expected a custom error with the "My error" message, but -- got "Transaction is active at return from function" s:exec(function() box.begin() error("My error") end) This is due to the specific evaluation and capture of the return values of `net_box:eval` (for more details see here: tarantool/tarantool#7288). The error will be raised on the server instance side. In the process of development we found that our approach does not work in the specific case: -- an error message has been expected but got an error table: -- { -- class = LuatestError, -- status = fail, -- message = "a value evaluating to true, actual: false" -- } s:exec(function() require('luatest').assert(false) end) To fix this error we decided to add the encoding an error to JSON format on the server and decode it on the client side. Close #242 Co-authored-by: Yaroslav Lobankov <[email protected]>
1 parent 78220f8 commit e6a2093

File tree

2 files changed

+67
-4
lines changed

2 files changed

+67
-4
lines changed

luatest/server.lua

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,8 @@ end
522522

523523
local function exec_tail(ok, ...)
524524
if not ok then
525-
error(..., 0)
525+
local _ok, res = pcall(json.decode, tostring(...))
526+
error(_ok and res or ..., 0)
526527
else
527528
return ...
528529
end
@@ -604,7 +605,14 @@ function Server:exec(fn, args, options)
604605
:format(utils.get_fn_location(fn)))
605606
end
606607

607-
return exec_tail(self.net_box:eval([[
608+
-- The function `fn` can return multiple values and we cannot use the
609+
-- classical approach to work with the `pcall`:
610+
--
611+
-- local status, result = pcall(function() return 1, 2, 3 end)
612+
--
613+
-- `result` variable will contain only `1` value, not `1, 2, 3`.
614+
-- To solve this, we put everything from `pcall` in a table.
615+
return exec_tail(pcall(self.net_box.eval, self.net_box, [[
608616
local dump, args, passthrough_ups = ...
609617
local fn = loadstring(dump)
610618
for i = 1, debug.getinfo(fn, 'u').nups do
@@ -613,11 +621,19 @@ function Server:exec(fn, args, options)
613621
debug.setupvalue(fn, i, require(passthrough_ups[name]))
614622
end
615623
end
624+
local result
616625
if args == nil then
617-
return pcall(fn)
626+
result = {pcall(fn)}
618627
else
619-
return pcall(fn, unpack(args))
628+
result = {pcall(fn, unpack(args))}
620629
end
630+
if not result[1] then
631+
if type(result[2]) == 'table' then
632+
result[2] = require('json').encode(result[2])
633+
end
634+
error(result[2], 0)
635+
end
636+
return unpack(result, 2)
621637
]], {string.dump(fn), args, passthrough_ups}, options))
622638
end
623639

test/server_test.lua

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,50 @@ end
429429
g.after_test('test_netbox_uri_is_not_overridden', function()
430430
g.s1:drop()
431431
end)
432+
433+
g.before_test('test_error_level_is_correct', function()
434+
g.s = Server:new()
435+
g.s:start()
436+
end)
437+
438+
g.test_error_level_is_correct = function()
439+
local c = require('net.box').connect(g.s.net_box_uri)
440+
441+
t.assert_error_msg_contains( -- error in exec
442+
"My error", g.s.exec, g.s,
443+
function() error("My error") end)
444+
445+
t.assert_error_msg_contains( -- error in eval
446+
"eval", g.s.eval, g.s,
447+
[[error("My error")]])
448+
449+
t.assert_error_msg_contains( -- error in closures
450+
"My error", g.s.exec, g.s,
451+
function()
452+
local function internal() error("My error") end
453+
internal()
454+
end)
455+
456+
t.assert_error_msg_contains( -- error in tx netbox connection
457+
"My error", c.eval, c,
458+
[[box.begin() error("My error")]])
459+
460+
t.assert_error_msg_contains( -- error in tx eval
461+
"My error", g.s.eval, g.s,
462+
[[box.begin() error("My error")]])
463+
464+
t.assert_error_msg_contains( -- error in tx exec
465+
"My error", g.s.exec, g.s,
466+
function() box.begin() error("My error") end)
467+
468+
t.assert_error_msg_contains( -- error in tx closures
469+
"My error", g.s.exec, g.s,
470+
function()
471+
local function internal() box.begin() error("My error") end
472+
internal()
473+
end)
474+
end
475+
476+
g.after_test('test_error_level_is_correct', function()
477+
g.s:drop()
478+
end)

0 commit comments

Comments
 (0)