Skip to content

Commit

Permalink
server: refactor exec() sparse output support
Browse files Browse the repository at this point in the history
Simplify code from PR #351 based on @Totktonada advice.

Follows #350
  • Loading branch information
DifferentialOrange committed Jan 19, 2024
1 parent 0c06b68 commit 7b9aa5c
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 118 deletions.
21 changes: 6 additions & 15 deletions luatest/server.lua
Original file line number Diff line number Diff line change
Expand Up @@ -686,33 +686,24 @@ function Server:exec(fn, args, options)
:format(utils.get_fn_location(fn)))
end

local utils_dumps = {
unpack_sparse_array = string.dump(utils.unpack_sparse_array),
}

-- The function `fn` can return multiple values and we cannot use the
-- classical approach to work with the `pcall`:
--
-- local status, result = pcall(function() return 1, 2, 3 end)
--
-- `result` variable will contain only `1` value, not `1, 2, 3`.
-- To solve this, we put everything from `pcall` in a table.
-- Table must be unpacked with `unpack(result, i, table.maxn(result))`,
-- otherwise nil return values won't be supported.
return exec_tail(pcall(self.net_box.eval, self.net_box, [[
local fn_dump, args, passthrough_ups, utils_dumps = ...
local fn = loadstring(fn_dump)
local dump, args, passthrough_ups = ...
local fn = loadstring(dump)
for i = 1, debug.getinfo(fn, 'u').nups do
local name, _ = debug.getupvalue(fn, i)
if passthrough_ups[name] then
debug.setupvalue(fn, i, require(passthrough_ups[name]))
end
end
local utils = {}
for k, v in pairs(utils_dumps) do
utils[k] = loadstring(v)
end
local result
if args == nil then
result = {pcall(fn)}
Expand All @@ -725,8 +716,8 @@ function Server:exec(fn, args, options)
end
error(result[2], 0)
end
return utils.unpack_sparse_array(result, 2)
]], {string.dump(fn), args, passthrough_ups, utils_dumps}, options))
return unpack(result, 2, table.maxn(result))
]], {string.dump(fn), args, passthrough_ups}, options))
end

function Server:coverage(action)
Expand Down
22 changes: 0 additions & 22 deletions luatest/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -191,26 +191,4 @@ function utils.is_tarantool_binary(path)
return path:find('^.*/tarantool[^/]*$') ~= nil
end

function utils.unpack_sparse_array(array, index)
-- Embed everything so no upvalues required on server.
index = index or 1

local len = 0
for k, _ in pairs(array) do
if type(k) == 'number' then
len = math.max(len, k)
end
end

local function unpack_sparse_array_tail(array, index, len) -- luacheck: ignore
if index > len then
return
end

return array[index], unpack_sparse_array_tail(array, index + 1, len)
end

return unpack_sparse_array_tail(array, index, len)
end

return utils
81 changes: 0 additions & 81 deletions test/utils_test.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
local json = require('json')

local t = require('luatest')
local g = t.group()

Expand All @@ -24,82 +22,3 @@ g.test_is_tarantool_binary = function()
("Unexpected result for %q"):format(path))
end
end

g.test_unpack_sparse_array_with_values = function()
local non_sparse_input = {
{{1, 2, 3, 4}, nil},
{{1, 2, 3, 4}, 3},
}

-- Test unpack_sparse_array() is unpack() if non-sparse input.
local non_sparse_cases = {}
for _, v in ipairs(non_sparse_input) do
table.insert(non_sparse_cases, {v[1], v[2], {unpack(v[1], v[2])}})
end

local sparse_cases = {
{{1, nil, 3}, nil, {1, nil, 3}},
{{1, nil, 3}, 2, {nil, 3}},
{{nil, 2, nil}, nil, {nil, 2}},
{{nil, 2, nil}, 2, {2}},
{{nil, 2, box.NULL}, nil, {nil, 2, box.NULL}},
{{nil, 2, box.NULL}, 3 ,{box.NULL}},
{{nil, nil, nil, nil, 5}, 4, {nil, 5}},
{{nil, nil, nil, nil, 5}, 5, {5}},
}

local cases = {unpack(non_sparse_cases), unpack(sparse_cases)}

for _, case in ipairs(cases) do
local array, index, result_packed = unpack(case)

local assert_msg
if index ~= nil then
assert_msg = ("Unexpected result for unpack_sparse_array(%q, %d)"):format(
json.encode(array), index)
else
assert_msg = ("Unexpected result for unpack_sparse_array(%q)"):format(
json.encode(array))
end

t.assert_equals(
{utils.unpack_sparse_array(array, index)},
result_packed,
assert_msg
)
end
end

local function assert_return_no_values(func, ...)
-- http://lua-users.org/lists/lua-l/2011-09/msg00312.html
t.assert_error_msg_contains(
"bad argument #1 to 'assert' (value expected)",
function(...)
assert(func(...))
end,
...
)
end

g.test_unpack_sparse_array_no_values = function()
local non_sparse_cases = {
{{1, 2, 3, 4}, 5},
{{}, 1},
}

local sparse_cases = {
{{1, nil, 3}, 6},
}

-- Assert built-in unpack() symmetric behavior.
for _, case in ipairs(sparse_cases) do
local array, index = unpack(case)
assert_return_no_values(unpack, array, index)
end

local cases = {unpack(non_sparse_cases), unpack(sparse_cases)}
for _, case in ipairs(cases) do
local array, index = unpack(case)
assert_return_no_values(utils.unpack_sparse_array, array, index)
end
end

0 comments on commit 7b9aa5c

Please sign in to comment.