* [Tarantool-patches] [PATCH v2 0/3] box/console: Fix multireturn and empty output @ 2020-01-15 8:56 Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 1/3] box/console: handle multireturn in lua mode Cyrill Gorcunov ` (2 more replies) 0 siblings, 3 replies; 6+ messages in thread From: Cyrill Gorcunov @ 2020-01-15 8:56 UTC (permalink / raw) To: tml In v2 Sasha provided more suitable tests which I've updated a bit. The issues are https://github.com/tarantool/tarantool/issues/4604 https://github.com/tarantool/tarantool/issues/4638 Branch gorcunov/console-fixes-2 Cyrill Gorcunov (3): box/console: handle multireturn in lua mode box/console: handle empty output format test/app-tap: add console_lua test src/box/lua/console.lua | 41 +++++--- test/app-tap/console_lua.test.lua | 154 ++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+), 13 deletions(-) create mode 100755 test/app-tap/console_lua.test.lua -- 2.20.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Tarantool-patches] [PATCH 1/3] box/console: handle multireturn in lua mode 2020-01-15 8:56 [Tarantool-patches] [PATCH v2 0/3] box/console: Fix multireturn and empty output Cyrill Gorcunov @ 2020-01-15 8:56 ` Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 2/3] box/console: handle empty output format Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test Cyrill Gorcunov 2 siblings, 0 replies; 6+ messages in thread From: Cyrill Gorcunov @ 2020-01-15 8:56 UTC (permalink / raw) To: tml Currently we handle only first member of multireturn statement. Fix it processing each element separately. n.b.: While at this file add vim settings. | tarantool> \set output lua | true; | tarantool> 1,2,3,4 | 1, 2, 3, 4; Fixes #4604 Reported-by: Alexander Turenko <alexander.turenko@tarantool.org> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- src/box/lua/console.lua | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/box/lua/console.lua b/src/box/lua/console.lua index d4d8ec984..a4a36c625 100644 --- a/src/box/lua/console.lua +++ b/src/box/lua/console.lua @@ -1,4 +1,6 @@ -- console.lua -- internal file +-- +-- vim: ts=4 sw=4 et local serpent = require('serpent') local internal = require('console') @@ -75,28 +77,38 @@ local serpent_map_symbols = function(tag, head, body, tail, level) return tag..head..body..tail end -output_handlers["lua"] = function(status, opts, ...) - -- - -- If no data present at least EOS should be put, - -- otherwise wire readers won't be able to find - -- where the end of string is. - if not ... then - return output_eos["lua"] - end +-- +-- Format a Lua value. +local function format_lua_value(value, opts) for k,v in pairs(lua_map_direct_symbols) do - if k == ... then - return v .. output_eos["lua"] + if k == value then + return v end end local serpent_opts = { custom = serpent_map_symbols, comment = false, - nocode = true, + nocode = true, } if opts == "block" then - return serpent.block(..., serpent_opts) .. output_eos["lua"] + return serpent.block(value, serpent_opts) + end + return serpent.line(value, serpent_opts) +end + +output_handlers["lua"] = function(status, opts, ...) + local collect = {} + -- + -- If no data present at least EOS should be put, + -- otherwise wire readers won't be able to find + -- where the end of string is. + if not ... then + return output_eos["lua"] + end + for i = 1, select('#', ...) do + collect[i] = format_lua_value(select(i, ...), opts) end - return serpent.line(..., serpent_opts) .. output_eos["lua"] + return table.concat(collect, ', ') .. output_eos["lua"] end local function output_verify_opts(fmt, opts) -- 2.20.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Tarantool-patches] [PATCH 2/3] box/console: handle empty output format 2020-01-15 8:56 [Tarantool-patches] [PATCH v2 0/3] box/console: Fix multireturn and empty output Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 1/3] box/console: handle multireturn in lua mode Cyrill Gorcunov @ 2020-01-15 8:56 ` Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test Cyrill Gorcunov 2 siblings, 0 replies; 6+ messages in thread From: Cyrill Gorcunov @ 2020-01-15 8:56 UTC (permalink / raw) To: tml In case if output format is not specified we should exit with more readable error message. Fixes #4638 Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- src/box/lua/console.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/box/lua/console.lua b/src/box/lua/console.lua index a4a36c625..17e2c91b2 100644 --- a/src/box/lua/console.lua +++ b/src/box/lua/console.lua @@ -126,6 +126,9 @@ end local function parse_output(value) local fmt, opts + if not value then + return 'Specify output format: lua or yaml.' + end if value:match("([^,]+),([^,]+)") ~= nil then fmt, opts = value:match("([^,]+),([^,]+)") else -- 2.20.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test 2020-01-15 8:56 [Tarantool-patches] [PATCH v2 0/3] box/console: Fix multireturn and empty output Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 1/3] box/console: handle multireturn in lua mode Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 2/3] box/console: handle empty output format Cyrill Gorcunov @ 2020-01-15 8:56 ` Cyrill Gorcunov 2020-01-17 18:59 ` Alexander Turenko 2 siblings, 1 reply; 6+ messages in thread From: Cyrill Gorcunov @ 2020-01-15 8:56 UTC (permalink / raw) To: tml Test multireturn and empty output in lua mode. Co-developed-by: Alexander Turenko <alexander.turenko@tarantool.org> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> --- test/app-tap/console_lua.test.lua | 154 ++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100755 test/app-tap/console_lua.test.lua diff --git a/test/app-tap/console_lua.test.lua b/test/app-tap/console_lua.test.lua new file mode 100755 index 000000000..76b67f6f4 --- /dev/null +++ b/test/app-tap/console_lua.test.lua @@ -0,0 +1,154 @@ +#!/usr/bin/env tarantool +-- +-- vim: ts=4 sw=4 et + +local console = require('console') +local socket = require('socket') +local tap = require('tap') +local fio = require('fio') + +local EOL = ';' +local CONSOLE_SOCKET = 'console-lua.sock' + +-- +-- Set Lua output mode. +local function set_lua_output(client, opts) + if opts ~= nil then + local mode = opts.block and 'lua,block' or 'lua' + client:write(('\\set output %s\n'):format(mode)) + assert(client:read(EOL), 'true' .. EOL, 'set lua output mode') + end +end + +-- +-- Start console and setup a client. +local function start_console() + -- Make sure not stale sockets are + -- left from previous runs. + fio.unlink(CONSOLE_SOCKET) + + local server = console.listen('unix/:./' .. CONSOLE_SOCKET) + assert(server ~= nil, 'console.listen started') + + local client = socket.tcp_connect('unix/', CONSOLE_SOCKET) + assert(client ~= nil, 'connect to console') + local handshake = client:read({chunk = 128}) + assert(string.match(handshake, '^Tarantool .*console') ~= nil, 'handshake') + + -- Switch to Lua output mode. + set_lua_output(client, {block=false}) + return server, client +end + +-- +-- Disconnect from console and stop it. +local function stop_console(server, client) + client:close() + server:close() + + local new_client = socket.tcp_connect('unix/', CONSOLE_SOCKET) + assert(new_client == nil, 'console.listen stopped') +end + +-- +-- Give `{x}` for a scalar `x`, just `x` otherwise. +local function totable(x) + return type(x) == 'table' and x or {x} +end + +-- +-- Execute a list of statements, show requests and responses. +local function execute_statements(test, client, statements, name) + test:test(name, function(test) + test:plan(2 * #statements) + + for _, stmt in ipairs(statements) do + local request = stmt .. '\n' + local res = client:write(request) + test:ok(res ~= nil, ('-> [[%s]]'):format(request:gsub('\n', '\\n'))) + + local response = client:read(EOL) + test:ok(response ~= nil and response:endswith(EOL), + ('<- [[%s]]'):format(response)) + end + end) +end + +-- +-- Execute a statement and verify its response. +local function execute_and_verify(test, client, input, exp_output, name) + test:test(name, function(test) + test:plan(2) + + local res = client:write(input .. '\n') + test:ok(res ~= nil, ('-> [[%s]]'):format(input)) + + local exp = exp_output .. EOL + local res = client:read(EOL) + test:is(res, exp, ('<- [[%s]]'):format(exp:gsub('\n', '\\n'))) + end) +end + +-- +-- Test cases table: +-- @name: Name of the test, mandatory +-- @prepare: Preparation script, optional +-- @opts: Console options, optional +-- @input: Input statement to execute, mandatory +-- @expected: Expected results to compare with, mandatory +-- @cleanup: Cleanup script to run after the test, optional +local cases = { + { + name = 'multireturn line mode', + prepare = 'a = {1, 2, 3}', + opts = {block = false}, + input = '1, 2, nil, a', + expected = '1, 2, box.NULL, {1, 2, 3}', + cleanup = 'a = nil', + }, { + name = 'multireturn block mode', + prepare = 'a = {1, 2, 3}', + opts = {block = true}, + input = '1, 2, nil, a', + expected = '1, 2, box.NULL, {\n 1,\n 2,\n 3\n}', + cleanup = 'a = nil', + }, { + name = 'empty output', + input = '\\set output', + expected = '"Specify output format: lua or yaml."', + } +} + +local test = tap.test('console-lua') +test:plan(#cases) + +local server, client = start_console() + +for _, case in ipairs(cases) do + test:test(case.name, function(test) + local plan = 1 + + for k, _ in pairs(case) do + if k == 'prepare' or k == 'cleanup' then + plan = plan + 1 + end + end + + test:plan(plan) + + if case.prepare ~= nil then + execute_statements(test, client, totable(case.prepare), case.name .. ': prepare script') + end + + set_lua_output(client, case.opts) + execute_and_verify(test, client, case.input, case.expected, case.name) + + if case.cleanup ~= nil then + execute_statements(test, client, totable(case.cleanup), case.name .. ': cleanup script') + end + end) +end + +stop_console(server, client) + +os.exit(test:check() and 0 or 1) -- 2.20.1 ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test Cyrill Gorcunov @ 2020-01-17 18:59 ` Alexander Turenko 2020-01-19 14:09 ` Cyrill Gorcunov 0 siblings, 1 reply; 6+ messages in thread From: Alexander Turenko @ 2020-01-17 18:59 UTC (permalink / raw) To: Cyrill Gorcunov; +Cc: tml Sorry for nitpicking, but I still have several comments. All comments are not blocking, so if there will be some urgency, the patchset is okay to push. But it would be better to address them if time permits. WBR, Alexander Turenko. > test/app-tap: add console_lua test Nit: we often use 'test:' prefix and it is useful for searching / excluding of such commits. I would use it here too. > > Test multireturn and empty output in lua mode. Nit: I would say "lack of a parameter of '\set output' command" or at least "empty output format", because 'empty output' is hard to understand w/o looking into previous commits. > > Co-developed-by: Alexander Turenko <alexander.turenko@tarantool.org> > Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com> > --- > test/app-tap/console_lua.test.lua | 154 ++++++++++++++++++++++++++++++ > 1 file changed, 154 insertions(+) > create mode 100755 test/app-tap/console_lua.test.lua > > diff --git a/test/app-tap/console_lua.test.lua b/test/app-tap/console_lua.test.lua > new file mode 100755 > index 000000000..76b67f6f4 > --- /dev/null > +++ b/test/app-tap/console_lua.test.lua > @@ -0,0 +1,154 @@ > +#!/usr/bin/env tarantool > +-- > +-- vim: ts=4 sw=4 et > + > +local console = require('console') > +local socket = require('socket') > +local tap = require('tap') > +local fio = require('fio') > + > +local EOL = ';' > +local CONSOLE_SOCKET = 'console-lua.sock' > + > +-- > +-- Set Lua output mode. > +local function set_lua_output(client, opts) > + if opts ~= nil then > + local mode = opts.block and 'lua,block' or 'lua' > + client:write(('\\set output %s\n'):format(mode)) > + assert(client:read(EOL), 'true' .. EOL, 'set lua output mode') > + end If opts are not set, then, it worth to set some default rather then leave an existing mode: it would be strange if set_lua_output() function will not set some lua output mode with default opts. I propose to set lua line mode by default. Like so: | local opts = opts or {} | local mode = opts.block and 'lua,block' or 'lua' > +end > + > +-- > +-- Start console and setup a client. > +local function start_console() > + -- Make sure not stale sockets are > + -- left from previous runs. > + fio.unlink(CONSOLE_SOCKET) > + > + local server = console.listen('unix/:./' .. CONSOLE_SOCKET) > + assert(server ~= nil, 'console.listen started') > + > + local client = socket.tcp_connect('unix/', CONSOLE_SOCKET) > + assert(client ~= nil, 'connect to console') > + local handshake = client:read({chunk = 128}) > + assert(string.match(handshake, '^Tarantool .*console') ~= nil, 'handshake') > + > + -- Switch to Lua output mode. > + set_lua_output(client, {block=false}) Nit: We surround '=' with spaces in a table. See https://www.tarantool.io/en/doc/1.10/dev_guide/lua_style_guide/ , around 'use space in map definitions around equality sign and commas'. > + return server, client > +end > + > +-- > +-- Disconnect from console and stop it. > +local function stop_console(server, client) > + client:close() > + server:close() > + > + local new_client = socket.tcp_connect('unix/', CONSOLE_SOCKET) > + assert(new_client == nil, 'console.listen stopped') > +end > + > +-- > +-- Give `{x}` for a scalar `x`, just `x` otherwise. > +local function totable(x) > + return type(x) == 'table' and x or {x} > +end > + > +-- > +-- Execute a list of statements, show requests and responses. > +local function execute_statements(test, client, statements, name) Ref 1 (see below): | if #statements == 0 then | test:skip(name) | return | end Just in case: I don't propose to add this hunk. > + test:test(name, function(test) > + test:plan(2 * #statements) > + > + for _, stmt in ipairs(statements) do > + local request = stmt .. '\n' > + local res = client:write(request) > + test:ok(res ~= nil, ('-> [[%s]]'):format(request:gsub('\n', '\\n'))) > + > + local response = client:read(EOL) > + test:ok(response ~= nil and response:endswith(EOL), > + ('<- [[%s]]'):format(response)) > + end > + end) > +end > + > +-- > +-- Execute a statement and verify its response. > +local function execute_and_verify(test, client, input, exp_output, name) > + test:test(name, function(test) > + test:plan(2) > + > + local res = client:write(input .. '\n') > + test:ok(res ~= nil, ('-> [[%s]]'):format(input)) > + > + local exp = exp_output .. EOL > + local res = client:read(EOL) > + test:is(res, exp, ('<- [[%s]]'):format(exp:gsub('\n', '\\n'))) > + end) > +end > + > +-- > +-- Test cases table: > +-- @name: Name of the test, mandatory > +-- @prepare: Preparation script, optional > +-- @opts: Console options, optional > +-- @input: Input statement to execute, mandatory > +-- @expected: Expected results to compare with, mandatory > +-- @cleanup: Cleanup script to run after the test, optional That's neat :) > +local cases = { > + { > + name = 'multireturn line mode', > + prepare = 'a = {1, 2, 3}', > + opts = {block = false}, > + input = '1, 2, nil, a', > + expected = '1, 2, box.NULL, {1, 2, 3}', > + cleanup = 'a = nil', > + }, { > + name = 'multireturn block mode', > + prepare = 'a = {1, 2, 3}', > + opts = {block = true}, > + input = '1, 2, nil, a', > + expected = '1, 2, box.NULL, {\n 1,\n 2,\n 3\n}', > + cleanup = 'a = nil', > + }, { > + name = 'empty output', > + input = '\\set output', > + expected = '"Specify output format: lua or yaml."', > + } > +} > + > +local test = tap.test('console-lua') > +test:plan(#cases) > + > +local server, client = start_console() > + > +for _, case in ipairs(cases) do > + test:test(case.name, function(test) > + local plan = 1 > + > + for k, _ in pairs(case) do > + if k == 'prepare' or k == 'cleanup' then > + plan = plan + 1 > + end > + end > + > + test:plan(plan) We can simplify this: just plan 3 tests. See: diff --git a/test/app-tap/console_lua.test.lua b/test/app-tap/console_lua.test.lua index 76b67f6f4..cf9e091f7 100755 --- a/test/app-tap/console_lua.test.lua +++ b/test/app-tap/console_lua.test.lua @@ -126,26 +126,14 @@ local server, client = start_console() for _, case in ipairs(cases) do test:test(case.name, function(test) - local plan = 1 + test:plan(3) - for k, _ in pairs(case) do - if k == 'prepare' or k == 'cleanup' then - plan = plan + 1 - end - end - - test:plan(plan) - - if case.prepare ~= nil then - execute_statements(test, client, totable(case.prepare), case.name .. ': prepare script') - end + execute_statements(test, client, totable(case.prepare), case.name .. ': prepare script') set_lua_output(client, case.opts) execute_and_verify(test, client, case.input, case.expected, case.name) - if case.cleanup ~= nil then - execute_statements(test, client, totable(case.cleanup), case.name .. ': cleanup script') - end + execute_statements(test, client, totable(case.cleanup), case.name .. ': cleanup script') end) end It is completely okay to emit '1..0' plan: this is mentioned in the TAP spec (see [1]), used in other implementations (see [2]), works good with our 'tap' module and test-run (at least for nested tests). We however can add explicit skip of prepare/cleanup in execute_statements(), see ref 1 above. But I don't think it is necessary. [1]: https://testanything.org/tap-version-13-specification.html#skipping-tests [2]: https://node-tap.org/tap-protocol/#plan > + > + if case.prepare ~= nil then > + execute_statements(test, client, totable(case.prepare), case.name .. ': prepare script') > + end Too long line. We usually fit lines within 80 symbols. case.name is not necessary here, because it is printed within case.name section in TAP13 output. Compare: Current: TAP version 13 1..3 # multireturn line mode 1..3 # multireturn line mode: prepare script 1..2 ok - -> [[a = {1, 2, 3}\n]] ok - <- [[;]] # multireturn line mode: prepare script: end ok - multireturn line mode: prepare script # multireturn line mode 1..2 ok - -> [[1, 2, nil, a]] ok - <- [[1, 2, box.NULL, {1, 2, 3};]] # multireturn line mode: end ok - multireturn line mode # multireturn line mode: cleanup script 1..2 ok - -> [[a = nil\n]] ok - <- [[;]] # multireturn line mode: cleanup script: end ok - multireturn line mode: cleanup script # multireturn line mode: end ok - multireturn line mode <...> W/o case.name: TAP version 13 1..3 # multireturn line mode 1..3 # prepare script 1..2 ok - -> [[a = {1, 2, 3}\n]] ok - <- [[;]] # prepare script: end ok - prepare script # script 1..2 ok - -> [[1, 2, nil, a]] ok - <- [[1, 2, box.NULL, {1, 2, 3};]] # script: end ok - script # cleanup script 1..2 ok - -> [[a = nil\n]] ok - <- [[;]] # cleanup script: end ok - cleanup script # multireturn line mode: end ok - multireturn line mode <...> I got this output using the following code: | execute_statements(test, client, totable(case.prepare), 'prepare script') | | set_lua_output(client, case.opts) | execute_and_verify(test, client, case.input, case.expected, 'script') | | execute_statements(test, client, totable(case.cleanup), 'cleanup script') I think that the latter output is cleaner, but I don't mind to include a case name again if you'll find this useful. Just is case: you can get this output using one of the following commands: $ ./src/tarantool test/app-tap/console_lua.test.lua $ (cd test && ./test-run.py console_lua --verbose) > + > + set_lua_output(client, case.opts) > + execute_and_verify(test, client, case.input, case.expected, case.name) Same as above: case.name is not necessary. > + > + if case.cleanup ~= nil then > + execute_statements(test, client, totable(case.cleanup), case.name .. ': cleanup script') > + end Same as above: too long line. Same as above: case.name is not necessary. > + end) > +end > + > +stop_console(server, client) > + > +os.exit(test:check() and 0 or 1) > -- > 2.20.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test 2020-01-17 18:59 ` Alexander Turenko @ 2020-01-19 14:09 ` Cyrill Gorcunov 0 siblings, 0 replies; 6+ messages in thread From: Cyrill Gorcunov @ 2020-01-19 14:09 UTC (permalink / raw) To: Alexander Turenko; +Cc: tml On Fri, Jan 17, 2020 at 09:59:11PM +0300, Alexander Turenko wrote: > Sorry for nitpicking, but I still have several comments. > Thanks a huge, Sasha! I'll address them. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-01-19 14:09 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-01-15 8:56 [Tarantool-patches] [PATCH v2 0/3] box/console: Fix multireturn and empty output Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 1/3] box/console: handle multireturn in lua mode Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 2/3] box/console: handle empty output format Cyrill Gorcunov 2020-01-15 8:56 ` [Tarantool-patches] [PATCH 3/3] test/app-tap: add console_lua test Cyrill Gorcunov 2020-01-17 18:59 ` Alexander Turenko 2020-01-19 14:09 ` Cyrill Gorcunov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox