diff --git a/debian/tarantool-common.logrotate b/debian/tarantool-common.logrotate index 4fc10a52c0ddaa3f83751666ea5d07e32010e237..7d08ce3cf59ea1e7a7a255be0f3b802e2cef550d 100644 --- a/debian/tarantool-common.logrotate +++ b/debian/tarantool-common.logrotate @@ -7,7 +7,7 @@ delaycompress create 0640 tarantool adm postrotate - /usr/bin/tarantool /usr/lib/tarantool/dist.lua logrotate `basename $1 .log` + /usr/bin/tarantool /usr/bin/tarantoolctl logrotate `basename $1 .log` endscript } diff --git a/extra/dist/default/tarantool b/extra/dist/default/tarantool index 81faf68920a1a7d6b61794b59c2ed71c736a532c..a861bdf5f135e95405a28eab718517f5992537d6 100644 --- a/extra/dist/default/tarantool +++ b/extra/dist/default/tarantool @@ -1,10 +1,11 @@ -- Options for Tarantool default_cfg = { - pid_file = "/var/run/tarantool", -- will become pid_file .. instance .. '.pid' - wal_dir = "/var/lib/tarantool", -- will become wal_dir/instance/ - snap_dir = "/var/lib/tarantool", -- snap_dir/instance/ - logger = "/var/log/tarantool", -- logger/instance .. '.log' - username = "tarantool", + pid_file = "/var/run/tarantool", -- will become pid_file .. instance .. '.pid' + wal_dir = "/var/lib/tarantool", -- will become wal_dir/instance/ + snap_dir = "/var/lib/tarantool", -- snap_dir/instance/ + sophia_dir = "/var/lib/tarantool", -- will become sophia_dir/sophia/instance/ + logger = "/var/log/tarantool", -- logger/instance .. '.log' + username = "tarantool", } instance_dir = "/etc/tarantool/instances.enabled" diff --git a/extra/dist/dist.lua b/extra/dist/dist.lua index e103a2de90d153a73094e5e2eefbe2565c68b343..8a27a76e8cfd50aa0a39eb7451be975519699e7f 100755 --- a/extra/dist/dist.lua +++ b/extra/dist/dist.lua @@ -31,6 +31,9 @@ The file contains common default instances options: -- snap_dir/instance/ snap_dir = "/var/lib/tarantool", + + -- sophia_dir/instance/ + sophia_dir = "/var/lib/tarantool/sophia", -- logger/instance .. '.log' logger = "/var/log/tarantool", @@ -111,19 +114,21 @@ if instance_dir == nil then instance_dir = '/etc/tarantool/instances.enabled' end -default_cfg.pid_file = default_cfg.pid_file and default_cfg.pid_file or "/var/run/tarantool" -default_cfg.wal_dir = default_cfg.wal_dir and default_cfg.wal_dir or "/var/lib/tarantool" -default_cfg.snap_dir = default_cfg.snap_dir and default_cfg.snap_dir or "/var/lib/tarantool" -default_cfg.logger = default_cfg.logger and default_cfg.logger or "/var/log/tarantool" -default_cfg.username = default_cfg.username and default_cfg.username or "tarantool" +default_cfg.pid_file = default_cfg.pid_file and default_cfg.pid_file or "/var/run/tarantool" +default_cfg.wal_dir = default_cfg.wal_dir and default_cfg.wal_dir or "/var/lib/tarantool" +default_cfg.snap_dir = default_cfg.snap_dir and default_cfg.snap_dir or "/var/lib/tarantool" +default_cfg.sophia_dir = default_cfg.sophia_dir and default_cfg.sophia_dir or "/var/lib/tarantool" +default_cfg.logger = default_cfg.logger and default_cfg.logger or "/var/log/tarantool" +default_cfg.username = default_cfg.username and default_cfg.username or "tarantool" -- create a path to the control socket (admin console) local console_sock = fio.pathjoin(default_cfg.pid_file, instance .. '.control') -default_cfg.pid_file = fio.pathjoin(default_cfg.pid_file, instance .. '.pid') -default_cfg.wal_dir = fio.pathjoin(default_cfg.wal_dir, instance) -default_cfg.snap_dir = fio.pathjoin(default_cfg.snap_dir, instance) -default_cfg.logger = fio.pathjoin(default_cfg.logger, instance .. '.log') +default_cfg.pid_file = fio.pathjoin(default_cfg.pid_file, instance .. '.pid') +default_cfg.wal_dir = fio.pathjoin(default_cfg.wal_dir, instance) +default_cfg.snap_dir = fio.pathjoin(default_cfg.snap_dir, instance) +default_cfg.sophia_dir = fio.pathjoin(default_cfg.sophia_dir, instance, 'sophia') +default_cfg.logger = fio.pathjoin(default_cfg.logger, instance .. '.log') local instance_lua = fio.pathjoin(instance_dir, instance .. '.lua') @@ -146,16 +151,18 @@ function mk_default_dirs(cfg) if fio.stat(pid_dir) == nil then mkdir(pid_dir) end - -- create wal_dir if fio.stat(cfg.wal_dir) == nil then mkdir(cfg.wal_dir) end - -- create snap_dir if fio.stat(cfg.snap_dir) == nil then mkdir(cfg.snap_dir) end + -- create sophia_dir + if fio.stat(cfg.sophia_dir) == nil then + mkdir(cfg.sophia_dir) + end -- create log_dir log_dir = fio.dirname(cfg.logger) if log_dir:find('|') == nil and fio.stat(log_dir) == nil then diff --git a/src/box/box.cc b/src/box/box.cc index e1bc1271665f37780be61539d87a4c409a576eff..a4af9caa02bd1d899767e99a25a3db0a49dca52c 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -125,6 +125,7 @@ box_check_replication_source(const char *source) static void box_check_wal_mode(const char *mode_name) { + assert(mode_name != NULL); /* checked in Lua */ int mode = strindex(wal_mode_STRS, mode_name, WAL_MODE_MAX); if (mode == WAL_MODE_MAX) { tnt_raise(ClientError, ER_CFG, diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 3b073880ea5dffe4eff97924ddbaf742256c45f2..47496a3e64d8c2c0834214b20cddab28acf7b028 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -59,7 +59,7 @@ local default_cfg = { -- types of available options -- could be comma separated lua types or 'any' if any type is allowed -local template_cfg = { +local template = { listen = 'string, number', slab_alloc_arena = 'number', slab_alloc_minimal = 'number', @@ -104,45 +104,9 @@ local dynamic_cfg = { snapshot_count = box.internal.snap_daemon.set_snapshot_count, } -local function reload_cfg(oldcfg, newcfg) - if newcfg == nil then - newcfg = {} - end - for key, val in pairs(newcfg) do - if dynamic_cfg[key] == nil then - box.error(box.error.RELOAD_CFG, key); - end - if val == "" then - val = nil - end - if wrapper_cfg[key] ~= nil then - val = wrapper_cfg[key](val) - end - dynamic_cfg[key](val) - rawset(oldcfg, key, val) - end - if type(box.on_reload_configuration) == 'function' then - box.on_reload_configuration() - end -end - -local box = require('box') --- Move all box members to box_saved -local box_configured = {} -for k, v in pairs(box) do - box_configured[k] = v - box[k] = nil -end - -setmetatable(box, { - __index = function(table, index) - error("Please call box.cfg{} first") - end -}) - -local function check_param_table(table, template) +local function prepare_cfg(table) if table == nil then - return + return {} end if type(table) ~= 'table' then error("Error: cfg should be a table") @@ -151,9 +115,13 @@ local function check_param_table(table, template) if table.dont_check then return end + local newtable = {} for k,v in pairs(table) do if template[k] == nil then error("Error: cfg parameter '" .. k .. "' is unexpected") + elseif v == "" or v == nil then + -- "" and NULL = ffi.cast('void *', 0) set option to default value + v = default_cfg[k] elseif template[k] == 'any' then -- any type is ok elseif (string.find(template[k], ',') == nil) then @@ -168,29 +136,48 @@ local function check_param_table(table, template) error("Error: cfg parameter '" .. k .. "' should be one of types: " .. template[k]) end end + if wrapper_cfg[k] ~= nil then + v = wrapper_cfg[k](v) + end + newtable[k] = v end + return newtable end - -local function update_param_table(table, defaults) - if table == nil then - table = {} - end - for k,v in pairs(defaults) do - if table[k] == nil then - table[k] = v +local function reload_cfg(oldcfg, newcfg) + newcfg = prepare_cfg(newcfg) + for key, val in pairs(newcfg) do + if dynamic_cfg[key] == nil then + box.error(box.error.RELOAD_CFG, key); end + dynamic_cfg[key](val) + rawset(oldcfg, key, val) + end + if type(box.on_reload_configuration) == 'function' then + box.on_reload_configuration() end - return table end -function box.cfg(cfg) - check_param_table(cfg, template_cfg) - cfg = update_param_table(cfg, default_cfg) +local box = require('box') +-- Move all box members to box_saved +local box_configured = {} +for k, v in pairs(box) do + box_configured[k] = v + box[k] = nil +end - for k,v in pairs(wrapper_cfg) do - -- options that can be number or string - cfg[k] = wrapper_cfg[k](cfg[k]) +setmetatable(box, { + __index = function(table, index) + error("Please call box.cfg{} first") + end +}) + +function box.cfg(cfg) + cfg = prepare_cfg(cfg) + for k,v in pairs(default_cfg) do + if cfg[k] == nil then + cfg[k] = v + end end -- Restore box members from box_saved after initial configuration for k, v in pairs(box_configured) do diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index bb1e9a46f2f4a0d167c9a0b39baad5a224a7494b..e925bd17bb58505f887ae0bf0c64e2374083138e 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -188,7 +188,7 @@ box.schema.space.create = function(name, options) engine = 'string', id = 'number', field_count = 'number', - user = 'user', + user = 'string, number', } local options_defaults = { engine = 'memtx', diff --git a/src/box/sophia_index.cc b/src/box/sophia_index.cc index c82c9a717f548747970285de45d4ec1a69ee36df..b50bf1c2c128acfe6a54323428d6387a01ac8bc0 100644 --- a/src/box/sophia_index.cc +++ b/src/box/sophia_index.cc @@ -176,6 +176,31 @@ SophiaIndex::~SophiaIndex() } } +struct tuple * +SophiaIndex::random(uint32_t rnd) const +{ + void *o = sp_object(db); + if (o == NULL) + tnt_raise(ClientError, ER_SOPHIA, sp_error(db)); + sp_set(o, "key", &rnd, sizeof(rnd)); + void *c = sp_cursor(db, "random", o); + if (c == NULL) + tnt_raise(ClientError, ER_SOPHIA, sp_error(db)); + auto scoped_guard = + make_scoped_guard([=] { sp_destroy(c); }); + o = sp_get(c); + if (o == NULL) + return NULL; + struct space *space = space_cache_find(key_def->space_id); + int valuesize; + void *value = sp_get(o, "value", &valuesize); + struct tuple *ret = + tuple_new(space->format, (char*)value, + (char*)value + valuesize); + tuple_ref(ret, 1); + return ret; +} + void SophiaIndex::endBuild() { @@ -184,9 +209,9 @@ SophiaIndex::endBuild() size_t SophiaIndex::size() const { - tnt_raise(ClientError, ER_UNSUPPORTED, - "SophiaIndex", "size operation"); - return 0; + void *profiler = sp_ctl(db, "profiler"); + uint64_t count = *(uint64_t*)sp_get(profiler, "count", NULL); + return count; } size_t diff --git a/src/box/sophia_index.h b/src/box/sophia_index.h index 063961d790843fd5f5c17a6977327f5b0ffc14c6..322db9d97b17a5f763f12b9b9fbbfeab746c8878 100644 --- a/src/box/sophia_index.h +++ b/src/box/sophia_index.h @@ -38,12 +38,11 @@ class SophiaIndex: public Index { virtual size_t size() const; virtual void endBuild(); - + virtual struct tuple *random(uint32_t rnd) const; virtual struct tuple *findByKey(const char *key, uint32_t part_count) const; virtual struct tuple *replace(struct tuple *old_tuple, struct tuple *new_tuple, enum dup_replace_mode mode); - virtual struct iterator *allocIterator() const; virtual void initIterator(struct iterator *iterator, enum iterator_type type, diff --git a/src/lua/bsdsocket.cc b/src/lua/bsdsocket.cc index 9e1e1693ad30c545036faeb8955df280d6bf9fe0..422571af9aef4323fe2188c44657682353a013c4 100644 --- a/src/lua/bsdsocket.cc +++ b/src/lua/bsdsocket.cc @@ -336,8 +336,8 @@ bsdsocket_local_resolve(const char *host, const char *port, } /* IPv6 */ - char ipv6[16]; - if (inet_pton(AF_INET6, host, ipv6) == 1) { + struct in6_addr ipv6; + if (inet_pton(AF_INET6, host, &ipv6) == 1) { struct sockaddr_in6 *inaddr6 = (struct sockaddr_in6 *) addr; if (*socklen < sizeof(*inaddr6)) { errno = ENOBUFS; @@ -345,8 +345,8 @@ bsdsocket_local_resolve(const char *host, const char *port, } memset(inaddr6, 0, sizeof(*inaddr6)); inaddr6->sin6_family = AF_INET6; - inaddr6->sin6_port = htonl(atol(port)); - memcpy(inaddr6->sin6_addr.s6_addr, ipv6, 16); + inaddr6->sin6_port = htons(atoi(port)); + memcpy(inaddr6->sin6_addr.s6_addr, &ipv6, sizeof(ipv6)); *socklen = sizeof(*inaddr6); return 0; } @@ -804,6 +804,24 @@ lbox_bsdsocket_peername(struct lua_State *L) return 1; } +static int +lbox_bsdsocket_accept(struct lua_State *L) +{ + int fh = lua_tointeger(L, 1); + + struct sockaddr_storage fa; + socklen_t len = sizeof(fa); + + int sc = accept(fh, (struct sockaddr*)&fa, &len); + if (sc < 0) { + lua_pushnil(L); + return 1; + } + lua_pushnumber(L, sc); + lbox_bsdsocket_push_addr(L, (struct sockaddr *)&fa, len); + return 2; +} + static int lbox_bsdsocket_recvfrom(struct lua_State *L) { @@ -860,6 +878,7 @@ tarantool_lua_bsdsocket_init(struct lua_State *L) { "peer", lbox_bsdsocket_peername }, { "recvfrom", lbox_bsdsocket_recvfrom }, { "abort", lbox_bsdsocket_abort }, + { "accept", lbox_bsdsocket_accept }, { NULL, NULL } }; diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua index 871bdbd356a6fdf65f1d67199b3681c9b0a3dffc..e7aa926cda7ada49175a24c5132020c859babdab 100644 --- a/src/lua/bsdsocket.lua +++ b/src/lua/bsdsocket.lua @@ -504,12 +504,12 @@ socket_methods.accept = function(self) local fd = check_socket(self) self._errno = nil - local cfd = ffi.C.accept(fd, nil, nil) - if cfd < 1 then + local cfd, from = internal.accept(fd) + if cfd == nil then self._errno = box.errno() return nil end - return bless_socket(cfd) + return bless_socket(cfd), from end local function readchunk(self, size, timeout) @@ -964,96 +964,80 @@ local function tcp_connect(host, port, timeout) return nil end -local function tcp_server_remote(list, prepare, handler) - local slist = {} - - -- bind/create sockets - for _, addr in pairs(list) do - local s = create_socket(addr.family, addr.type, addr.protocol) - - local ok = false - if s ~= nil then - local backlog = prepare(s) - if s:bind(addr.host, addr.port) then - if s:listen(backlog) then - ok = true - end - end - end - - -- errors - if not ok then - if s ~= nil then - s:close() - end - local save_errno = boxerrno() - for _, s in pairs(slist) do - s:close() - end - boxerrno(save_errno) - return nil - end - - table.insert(slist, s) - end - - local server = { s = slist } +local function tcp_server_handler(server, sc, from) + fiber.name(sprintf("%s/client/%s:%s", server.name, from.host, from.port)) + server.handler(sc, from) + sc:close() +end - server.stop = function() - if #server.s == 0 then - return false +local function tcp_server_loop(server, s, addr) + fiber.name(sprintf("%s/listen/%s:%s", server.name, addr.host, addr.port)) + while s:readable() do + local sc, from = s:accept() + if sc == nil then + break end - for _, s in pairs(server.s) do - s:close() - end - server.s = {} - return true + fiber.create(tcp_server_handler, server, sc, from) end - - for _, s in pairs(server.s) do - fiber.create(function(s) - fiber.name(sprintf("listen_fd=%d",s:fd())) - - while s:readable() do - - local sc = s:accept() - - if sc == nil then - break - end - - fiber.create(function(sc) - pcall(handler, sc) - sc:close() - end, sc) - end - end, s) + if addr.family == 'AF_UNIX' and addr.port then + os.remove(addr.port) -- remove unix socket end - - return server end -local function tcp_server(host, port, prepare, handler, timeout) - if handler == nil then - handler = prepare - prepare = function() end - end +local function tcp_server_usage() + error('Usage: socket.tcp_server(host, port, handler | opts)') +end - if type(prepare) ~= 'function' or type(handler) ~= 'function' then - error("Usage: socket.tcp_server(host, port[, prepare], handler)") +local function tcp_server(host, port, opts, timeout) + local server = {} + if type(opts) == 'function' then + server.handler = opts + elseif type(opts) == 'table' then + if type(opts.handler) ~='function' or (opts.prepare ~= nil and + type(opts.prepare) ~= 'function') then + tcp_server_usage() + end + for k, v in pairs(opts) do + server[k] = v + end + else + tcp_server_usage() end - + server.name = server.name or 'server' + timeout = timeout and tonumber(timeout) or TIMEOUT_INFINITY + local dns if host == 'unix/' then - return tcp_server_remote({{host = host, port = port, protocol = 0, - family = 'PF_UNIX', type = 'SOCK_STREAM' }}, prepare, handler) + dns = {{host = host, port = port, family = 'AF_UNIX', protocol = 0, + type = 'SOCK_STREAM' }} + else + dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM' }) + if dns == nil then + return nil + end end - local dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM', - protocol = 'tcp' }) - if dns == nil then - return nil + for _, addr in ipairs(dns) do + local s = create_socket(addr.family, addr.type, addr.protocol) + if s ~= nil then + local backlog + if server.prepare then + backlog = server.prepare(s) + else + s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', 1) -- ignore error + end + if not s:bind(addr.host, addr.port) or not s:listen(backlog) then + local save_errno = boxerrno() + s:close() + boxerrno(save_errno) + return nil + end + fiber.create(tcp_server_loop, server, s, addr) + return s, addr + end end - return tcp_server_remote(dns, prepare, handler) + -- DNS resolved successfully, but addresss family is not supported + boxerrno(boxerrno.EAFNOSUPPORT) + return nil end socket_mt = { diff --git a/src/lua/console.lua b/src/lua/console.lua index 57d78d9f9093978fca5febda82ebba828ddd5405..fe04952f5b75c7ef940bb576a42e298be02df506 100644 --- a/src/lua/console.lua +++ b/src/lua/console.lua @@ -5,6 +5,7 @@ local fiber = require('fiber') local socket = require('socket') local log = require('log') local errno = require('errno') +local urilib = require('uri') -- admin formatter must be able to encode any Lua variable local formatter = require('yaml').new() @@ -221,13 +222,23 @@ end -- -- Connect to remove server -- -local function connect(...) +local function connect(uri) local self = fiber.self().storage.console if self == nil then error("console.connect() need existing console") end + + local u + if uri then + u = urilib.parse(tostring(uri)) + end + if u == nil or u.service == nil then + error('Usage: console.connect("[login:password@][host:]port")') + end + -- connect to remote host - local remote = require('net.box'):new(...) + local remote = require('net.box'):new(u.host, u.service, + { user = u.login, password = u.password }) -- check permissions remote:call('dostring', 'return true') -- override methods @@ -237,22 +248,16 @@ local function connect(...) log.info("connected to %s:%s", self.remote.host, self.remote.port) end -local function server_loop(server) - while server:readable() do - local client = server:accept() - if client then - local peer = client:peer() - log.info("console: client %s:%s connected", peer.host, peer.port) - local state = setmetatable({ - running = true; - read = client_read; - print = client_print; - client = client; - }, repl_mt) - fiber.create(repl, state) - end - end - log.info("console: stopped") +local function client_handler(client, peer) + log.info("console: client %s:%s connected", peer.host, peer.port) + local state = setmetatable({ + running = true; + read = client_read; + print = client_print; + client = client; + }, repl_mt) + repl(state) + log.info("console: client %s:%s disconnected", peer.host, peer.port) end -- @@ -262,46 +267,23 @@ local function listen(uri) local host, port if uri == nil then host = 'unix/' - elseif type(uri) == 'number' or uri:match("^%d+$") then - port = tonumber(uri) - elseif uri:match("^/") then - host = 'unix/' - port = uri + port = '/tmp/tarantool-console.sock' else - host, port = uri:match("^(.*):(.*)$") - if not host then - port = uri + local u = urilib.parse(tostring(uri)) + if u == nil or u.service == nil then + error('Usage: console.listen("[host:]port")') end + host = u.host + port = u.service or 3313 end - local server - if host == 'unix/' then - port = port or '/tmp/tarantool-console.sock' - os.remove(port) - server = socket('AF_UNIX', 'SOCK_STREAM', 0) - else - host = host or '127.0.0.1' - port = port or 3313 - server = socket('AF_INET', 'SOCK_STREAM', 'tcp') - end - if not server then - error(string.format('failed to create socket %s%s : %s', - host, port, errno.strerror())) - end - server:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', true) - - if not server:bind(host, port) then - local msg = string.format('failed to bind: %s', server:error()) - server:close() - error(msg) - end - if not server:listen() then - local msg = string.format('failed to listen: %s', server:error()) - server:close() - error(msg) + local s, addr = socket.tcp_server(host, port, { handler = client_handler, + name = 'console'}) + if not s then + error(string.format('failed to create server %s:%s: %s', + host, port, errno.strerror())) end - log.info("console: started on %s:%s", host, port) - fiber.create(server_loop, server) - return server + log.info("console: started on %s:%s", addr.host, addr.port) + return s end return { diff --git a/test/app/cfg.result b/test/app/cfg.result index 60f07692ade6cf0b4b14e0acd40124a0a2176809..38f4a9c0db8c3de4ad176a7e8d11d5b527ce1b80 100644 --- a/test/app/cfg.result +++ b/test/app/cfg.result @@ -1,2 +1,10 @@ -false [string "-- load_cfg.lua - internal file..."]:139: Please call box.cfg{} first -true table +TAP version 13 +1..8 +ok - exception on unconfigured box +ok - configured box +ok - cfg.wal_mode default value +ok - cfg.wal_mode default value +ok - cfg.wal_mode change +ok - cfg.wal_mode default value +ok - cfg.wal_mode change +ok - cfg.wal_mode default value diff --git a/test/app/cfg.test.lua b/test/app/cfg.test.lua index bce98a2db290b603bec2a20e71572090c8a3ea2a..d768107c2cae79144649420f3a1ae68ca9b86e91 100755 --- a/test/app/cfg.test.lua +++ b/test/app/cfg.test.lua @@ -1,19 +1,48 @@ #!/usr/bin/env tarantool +local tap = require('tap') +local test = tap.test('cfg') +test:plan(8) + -------------------------------------------------------------------------------- -- All box members must raise an exception on access if box.cfg{} wasn't called -------------------------------------------------------------------------------- local box = require('box') -local function test() +local function testfun() return type(box.space) end -print(pcall(test)) +local status, result = pcall(testfun) + +test:ok(not status and result:match('Please call box.cfg{}'), + 'exception on unconfigured box') + box.cfg{ logger="tarantool.log", slab_alloc_arena=0.1, + wal_mode = "", -- "" means default value } -print(pcall(test)) +status, result = pcall(testfun) +test:ok(status and result == 'table', 'configured box') + +-------------------------------------------------------------------------------- +-- gh-534: Segmentation fault after two bad wal_mode settings +-------------------------------------------------------------------------------- + +test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value") +box.cfg{wal_mode = ""} +test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value") +box.cfg{wal_mode = "none"} +test:is(box.cfg.wal_mode, "none", "cfg.wal_mode change") +-- "" or NULL resets option to default value +box.cfg{wal_mode = ""} +test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value") +box.cfg{wal_mode = "none"} +test:is(box.cfg.wal_mode, "none", "cfg.wal_mode change") +box.cfg{wal_mode = require('msgpack').NULL} +test:is(box.cfg.wal_mode, "write", "cfg.wal_mode default value") + +test:check() os.exit(0) diff --git a/test/app/console.result b/test/app/console.result index e7f5b5ca465f82e795277c588e439b323a4cc9e4..c36eef7c724fd19eb6ed3b1f3a20fd4f865a97a3 100644 --- a/test/app/console.result +++ b/test/app/console.result @@ -1,5 +1,5 @@ TAP version 13 -1..18 +1..25 ok - console.listen started ok - connect to console ok - eval @@ -11,6 +11,7 @@ ok - get delimiter is ';' ok - clear delimiter ok - remote network error ok - remote access denied +ok - remote access denied ok - remote connect ok - remote eval ok - remote state.remote.host @@ -18,3 +19,9 @@ ok - remote state.remote.port ok - remote state.prompt ok - remote disconnect ok - console.listen stopped +ok - console.listen uri support +ok - console.listen uri support +ok - console.listen uri support +ok - console.listen uri support +ok - console.listen uri support +ok - console.listen uri support diff --git a/test/app/console.test.lua b/test/app/console.test.lua index b569dce375b2fce8deca8ece69504ce2f68beee7..8ee97cbaf1dfe4bb67951b516a7ff692c324f803 100755 --- a/test/app/console.test.lua +++ b/test/app/console.test.lua @@ -22,7 +22,7 @@ local EOL = "\n%.%.%.\n" test = tap.test("console") -test:plan(18) +test:plan(25) -- Start console and connect to it local server = console.listen(CONSOLE_SOCKET) @@ -55,22 +55,30 @@ client:write("require('console').delimiter('');\n") test:is(yaml.decode(client:read(EOL)), '', "clear delimiter") -- Connect to iproto console (CALL) -client:write(string.format("require('console').connect('unix/', '/')\n")) +client:write(string.format("require('console').connect('/')\n")) -- error: Connection is not established test:ok(yaml.decode(client:read(EOL))[1].error:find('not established'), 'remote network error') -client:write(string.format("require('console').connect('unix/', '%s')\n", +client:write(string.format("require('console').connect('%s')\n", IPROTO_SOCKET)) -- error: Execute access denied for user 'guest' to function 'dostring test:ok(yaml.decode(client:read(EOL))[1].error:find('access denied'), 'remote access denied') +-- create user +box.schema.user.create('test', { password = 'pass' }) +client:write(string.format("require('console').connect('test:pass@%s')\n", + IPROTO_SOCKET)) +-- error: Execute access denied for user 'tester' to function 'dostring +test:ok(yaml.decode(client:read(EOL))[1].error:find('access denied'), + 'remote access denied') + -- Add permissions to execute `dostring` for `guest` box.schema.func.create('dostring') -box.schema.user.grant('guest', 'execute', 'function', 'dostring') +box.schema.user.grant('test', 'execute', 'function', 'dostring') -client:write(string.format("require('console').connect('unix/', '%s')\n", +client:write(string.format("require('console').connect('test:pass@%s')\n", IPROTO_SOCKET)) test:is(yaml.decode(client:read(EOL)), '', "remote connect") @@ -102,11 +110,24 @@ server:close() -- Check that admon console has been stopped test:isnil(socket.tcp_connect("unix/", CONSOLE_SOCKET), "console.listen stopped") -test:check() - -- Stop iproto (not implemented yet) -- box.cfg{listen = nil} - -os.remove(CONSOLE_SOCKET) os.remove(IPROTO_SOCKET) + +local s = console.listen('127.0.0.1:0') +addr = s:name() +test:is(addr.family, 'AF_INET', 'console.listen uri support') +test:is(addr.host, '127.0.0.1', 'console.listen uri support') +test:isnt(addr.port, 0, 'console.listen uri support') +s:close() + +local s = console.listen('console://unix/:'..CONSOLE_SOCKET) +addr = s:name() +test:is(addr.family, 'AF_UNIX', 'console.listen uri support') +test:is(addr.host, 'unix/', 'console.listen uri support') +test:is(addr.port, CONSOLE_SOCKET, 'console.listen uri support') +s:close() + +test:check() + os.exit(0) diff --git a/test/box/access.result b/test/box/access.result index eaf920e8f612ae728e6f467e72eba74730d87ed7..7ad11d39e9fed0a5ee2de6ac5226c74d2e5d3dc8 100644 --- a/test/box/access.result +++ b/test/box/access.result @@ -156,7 +156,14 @@ box.schema.user.drop('ПетÑ_Иванов') --- ... -- gh-300: misleading error message if a function does not exist -c = (require 'net.box'):new("127.0.0.1", box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +--- +... +LISTEN ~= nil +--- +- true +... +c = (require 'net.box'):new(LISTEN.host, LISTEN.service) --- ... c:call('nosuchfunction') diff --git a/test/box/access.test.lua b/test/box/access.test.lua index cc7ff3a2b4c6202749f1cf5157c2fa783bcf3cb2..8569e0ec32e5093cffe4a40b75c1dc6541e17ccf 100644 --- a/test/box/access.test.lua +++ b/test/box/access.test.lua @@ -74,7 +74,9 @@ box.schema.user.create('ПетÑ_Иванов') box.schema.user.drop('ПетÑ_Иванов') -- gh-300: misleading error message if a function does not exist -c = (require 'net.box'):new("127.0.0.1", box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +LISTEN ~= nil +c = (require 'net.box'):new(LISTEN.host, LISTEN.service) c:call('nosuchfunction') function nosuchfunction() end diff --git a/test/box/access_bin.result b/test/box/access_bin.result index 23aa5b2d6f54fc0b81d192f24bec291cd079f5c2..796a085ac0370c0f898497aeb16e9c2a94c35cc7 100644 --- a/test/box/access_bin.result +++ b/test/box/access_bin.result @@ -11,7 +11,14 @@ session = box.session net = { box = require('net.box') } --- ... -c = net.box:new(0, box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +--- +... +LISTEN ~= nil +--- +- true +... +c = net.box:new(LISTEN.host, LISTEN.service) --- ... c:call("dostring", "session.su('admin')") @@ -45,7 +52,7 @@ box.schema.func.create('setuid_func') box.schema.user.grant('guest', 'execute', 'function', 'setuid_func') --- ... -c = net.box:new(0, box.cfg.listen) +c = net.box:new(LISTEN.host, LISTEN.service) --- ... c:call("setuid_func") diff --git a/test/box/access_bin.test.lua b/test/box/access_bin.test.lua index f9841d7ea50220baa1ddb83ccf11d29607c37b0c..18f3d167f28dac7446dbec4e7af1bd913a415274 100644 --- a/test/box/access_bin.test.lua +++ b/test/box/access_bin.test.lua @@ -5,7 +5,9 @@ box.schema.user.grant('guest','read,write,execute','universe') session = box.session net = { box = require('net.box') } -c = net.box:new(0, box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +LISTEN ~= nil +c = net.box:new(LISTEN.host, LISTEN.service) c:call("dostring", "session.su('admin')") c:call("dostring", "return session.user()") c:close() @@ -18,7 +20,7 @@ setuid_space:create_index('primary') setuid_func = function() return box.space.setuid_space:auto_increment{} end box.schema.func.create('setuid_func') box.schema.user.grant('guest', 'execute', 'function', 'setuid_func') -c = net.box:new(0, box.cfg.listen) +c = net.box:new(LISTEN.host, LISTEN.service) c:call("setuid_func") session.su('guest') setuid_func() diff --git a/test/box/bad_trigger.result b/test/box/bad_trigger.result index f44644d9f8c100cd2fbf57b4bb3d56fcb4847eb2..5740f76833df897d234d482b85063b3b325d19f3 100644 --- a/test/box/bad_trigger.result +++ b/test/box/bad_trigger.result @@ -1,7 +1,7 @@ - + # # if on_connect() trigger raises an exception, the connection is dropped - # + # function f1() nosuchfunction() end --- diff --git a/test/box/bad_trigger.test.py b/test/box/bad_trigger.test.py index ebbed28bf956dc93ef8450aa8bb093c36b635036..b7337cdf61c6dade851eb05a9af917b45d9275e6 100644 --- a/test/box/bad_trigger.test.py +++ b/test/box/bad_trigger.test.py @@ -1,14 +1,15 @@ from lib.box_connection import BoxConnection +from lib.tarantool_connection import TarantoolConnection from tarantool import NetworkError from tarantool.const import IPROTO_GREETING_SIZE, IPROTO_CODE, IPROTO_ERROR, \ REQUEST_TYPE_ERROR import socket import msgpack -print """ +print """ # # if on_connect() trigger raises an exception, the connection is dropped - # + # """ server.admin("function f1() nosuchfunction() end") @@ -16,8 +17,9 @@ server.admin("box.session.on_connect(f1)") unpacker = msgpack.Unpacker(use_list = False) -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.connect(('localhost', server.sql.port)) +conn = TarantoolConnection(server.sql.host, server.sql.port) +conn.connect() +s = conn.socket # Read greeting print 'greeting: ', len(s.recv(IPROTO_GREETING_SIZE)) == IPROTO_GREETING_SIZE diff --git a/test/box/box.net.box.result b/test/box/box.net.box.result index 9cb0f175bd202b0206a2d8ecd5a19285bf49b5e7..eff5cf47758c133d3d2552d1acfcc9a76cf90369 100644 --- a/test/box/box.net.box.result +++ b/test/box/box.net.box.result @@ -13,7 +13,7 @@ msgpack = require 'msgpack' box.schema.user.grant('guest', 'read,write,execute', 'universe') --- ... -port = box.cfg.listen +LISTEN = require('uri').parse(box.cfg.listen) --- ... space = box.schema.create_space('net_box_test_space') @@ -26,7 +26,7 @@ space:create_index('primary', { type = 'tree' }) log.info("create connection") --- ... -cn = remote:new('127.0.0.1', port) +cn = remote:new(LISTEN.host, LISTEN.service) --- ... cn:_wait_state({'active', 'error'}, 1) @@ -301,7 +301,7 @@ cn:call('test_foo') - error: Connection is not established ... -- -- 2 reconnect -cn = remote:new('127.0.0.1', port, { reconnect_after = .1 }) +cn = remote:new(LISTEN.host, LISTEN.service, { reconnect_after = .1 }) --- ... cn:_wait_state({'active'}, 1) @@ -362,7 +362,7 @@ cn:ping() - true ... -- -- dot-new-method -cn1 = remote.new('127.0.0.1', port) +cn1 = remote.new(LISTEN.host, LISTEN.service) --- ... cn1:_select(space.id, 0, {}, { iterator = 'ALL' }) @@ -439,7 +439,7 @@ cn.proto.b64decode('gJLoc!!!!!!!') --- - !!binary gJLo ... -cn = remote:new('127.0.0.1', port, { user = 'netbox', password = '123', wait_connected = true }) +cn = remote:new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true }) --- ... cn:is_connected() @@ -460,7 +460,7 @@ box.schema.user.create('netbox', { password = 'test' }) box.schema.user.grant('netbox', 'read, write, execute', 'universe'); --- ... -cn = remote:new('127.0.0.1', port, { user = 'netbox', password = 'test' }) +cn = remote:new(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' }) --- ... cn.state @@ -495,11 +495,11 @@ cn:timeout(.01):call('ret_after', 1) --- - error: Timeout exceeded ... -cn = remote:timeout(0.0000000001):new('127.0.0.1', port, { user = 'netbox', password = '123' }) +cn = remote:timeout(0.0000000001):new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' }) --- - error: Timeout exceeded ... -cn = remote:timeout(1):new('127.0.0.1', port, { user = 'netbox', password = '123' }) +cn = remote:timeout(1):new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' }) --- ... remote.self:ping() diff --git a/test/box/box.net.box.test.lua b/test/box/box.net.box.test.lua index dfb82eb0460ecd264e2e2019490b13683b48de6e..6dc3448aaf4362294bdf8be04f5bb286e707ce05 100644 --- a/test/box/box.net.box.test.lua +++ b/test/box/box.net.box.test.lua @@ -4,13 +4,13 @@ log = require 'log' msgpack = require 'msgpack' box.schema.user.grant('guest', 'read,write,execute', 'universe') -port = box.cfg.listen +LISTEN = require('uri').parse(box.cfg.listen) space = box.schema.create_space('net_box_test_space') space:create_index('primary', { type = 'tree' }) -- low level connection log.info("create connection") -cn = remote:new('127.0.0.1', port) +cn = remote:new(LISTEN.host, LISTEN.service) cn:_wait_state({'active', 'error'}, 1) log.info("state is %s", cn.state) @@ -106,7 +106,7 @@ cn:ping() cn:call('test_foo') -- -- 2 reconnect -cn = remote:new('127.0.0.1', port, { reconnect_after = .1 }) +cn = remote:new(LISTEN.host, LISTEN.service, { reconnect_after = .1 }) cn:_wait_state({'active'}, 1) cn.space ~= nil @@ -129,7 +129,7 @@ cn:ping() -- -- dot-new-method -cn1 = remote.new('127.0.0.1', port) +cn1 = remote.new(LISTEN.host, LISTEN.service) cn1:_select(space.id, 0, {}, { iterator = 'ALL' }) -- -- error while waiting for response @@ -159,7 +159,7 @@ res[1][2] == string.rep('a', 50000) cn.proto.b64decode('gJLocxbO32VmfO8x04xRVxKfgwzmNVM2t6a1ME8XsD0=') cn.proto.b64decode('gJLoc!!!!!!!') -cn = remote:new('127.0.0.1', port, { user = 'netbox', password = '123', wait_connected = true }) +cn = remote:new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123', wait_connected = true }) cn:is_connected() cn.error cn.state @@ -167,7 +167,7 @@ cn.state box.schema.user.create('netbox', { password = 'test' }) box.schema.user.grant('netbox', 'read, write, execute', 'universe'); -cn = remote:new('127.0.0.1', port, { user = 'netbox', password = 'test' }) +cn = remote:new(LISTEN.host, LISTEN.service, { user = 'netbox', password = 'test' }) cn.state cn.error cn:ping() @@ -180,8 +180,8 @@ cn:call('ret_after', .01) cn:timeout(1):call('ret_after', .01) cn:timeout(.01):call('ret_after', 1) -cn = remote:timeout(0.0000000001):new('127.0.0.1', port, { user = 'netbox', password = '123' }) -cn = remote:timeout(1):new('127.0.0.1', port, { user = 'netbox', password = '123' }) +cn = remote:timeout(0.0000000001):new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' }) +cn = remote:timeout(1):new(LISTEN.host, LISTEN.service, { user = 'netbox', password = '123' }) diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result index ccc0973dea38030d9b48b65242cb2c55859ef2ea..043ac1e95ce91274c569ca22e00fb7a3f63a7a39 100644 --- a/test/box/bsdsocket.result +++ b/test/box/bsdsocket.result @@ -22,6 +22,9 @@ log = require 'log' errno = require 'errno' --- ... +fio = require 'fio' +--- +... type(socket) --- - table @@ -59,18 +62,26 @@ for k in pairs(getmetatable(s).__index) do end; --- ... ---# setopt delimiter '' -port = string.gsub(box.cfg.listen, '^.*:', '') +s:close() --- +- true ... -s:nonblock(false) +--# setopt delimiter '' +s:close() + --- - false ... -s:sysconnect('127.0.0.1', port) +LISTEN = require('uri').parse(box.cfg.listen) +--- +... +LISTEN ~= nil --- - true ... +s = socket.tcp_connect(LISTEN.host, LISTEN.service) +--- +... s:nonblock(true) --- - true @@ -349,9 +360,20 @@ sc:write('Hello, world') --- - true ... -sa = s:accept() +sa, addr = s:accept() +--- +... +addr2 = sa:name() --- ... +addr2.host == addr.host +--- +- true +... +addr2.family == addr.family +--- +- true +... sa:nonblock(1) --- - true @@ -1209,9 +1231,13 @@ os.remove(path) --- - true ... -server = socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end) +server, addr = socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end) --- ... +type(addr) +--- +- table +... server ~= nil --- - true @@ -1230,11 +1256,83 @@ client:read(123) --- - Hello, world ... -server:stop() +server:close() --- - true ... -os.remove(path) +-- unix socket automatically removed +fio.stat(path) == nil +--- +- true +... +--# setopt delimiter ';' +server, addr = socket.tcp_server('localhost', 0, { handler = function(s) + s:read(2) + s:write('Hello, world') +end, name = 'testserv'}); +--- +... +--# setopt delimiter '' +type(addr) +--- +- table +... +server ~= nil +--- +- true +... +addr2 = server:name() +--- +... +addr.host == addr2.host +--- +- true +... +addr.family == addr2.family +--- +- true +... +fiber.sleep(.5) +--- +... +client = socket.tcp_connect(addr2.host, addr2.port) +--- +... +client ~= nil +--- +- true +... +-- Check that listen and client fibers have appropriate names +cnt = 0 +--- +... +--# setopt delimiter ';' +for i=100,200 do + local f = fiber.find(i) + if f and f:name():match('^testserv/') then + cnt = cnt + 1 + end +end; +--- +... +--# setopt delimiter '' +cnt +--- +- 2 +... +client:write('hi') +--- +- true +... +client:read(123) +--- +- Hello, world +... +client:close() +--- +- true +... +server:close() --- - true ... @@ -1275,11 +1373,7 @@ client:read{ line = { "\n\n", "\r\n\r\n" } } --- - "Hello\r\n\r\n" ... -server:stop() ---- -- true -... -os.remove(path) +server:close() --- - true ... diff --git a/test/box/bsdsocket.test.lua b/test/box/bsdsocket.test.lua index 7ead95599262bb1498d51354ba5cd88928b7ed1b..faf0346c4099676777570ff8f70f3c88caa69d16 100644 --- a/test/box/bsdsocket.test.lua +++ b/test/box/bsdsocket.test.lua @@ -6,6 +6,7 @@ fiber = require 'fiber' msgpack = require 'msgpack' log = require 'log' errno = require 'errno' +fio = require 'fio' type(socket) socket('PF_INET', 'SOCK_STREAM', 'tcp121222'); @@ -23,12 +24,12 @@ for k in pairs(getmetatable(s).__index) do error("Arguments is not checked for "..k) end end; +s:close() --# setopt delimiter '' -port = string.gsub(box.cfg.listen, '^.*:', '') - -s:nonblock(false) -s:sysconnect('127.0.0.1', port) +LISTEN = require('uri').parse(box.cfg.listen) +LISTEN ~= nil +s = socket.tcp_connect(LISTEN.host, LISTEN.service) s:nonblock(true) s:nonblock() s:nonblock(false) @@ -114,7 +115,10 @@ sc:writable(10) sc:write('Hello, world') -sa = s:accept() +sa, addr = s:accept() +addr2 = sa:name() +addr2.host == addr.host +addr2.family == addr.family sa:nonblock(1) sa:read(8) sa:read(3) @@ -404,37 +408,59 @@ s:close() os.remove(path) -server = socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end) +server, addr = socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end) +type(addr) server ~= nil fiber.sleep(.5) client = socket.tcp_connect('unix/', path) client ~= nil client:read(123) -server:stop() -os.remove(path) +server:close() +-- unix socket automatically removed +fio.stat(path) == nil +--# setopt delimiter ';' +server, addr = socket.tcp_server('localhost', 0, { handler = function(s) + s:read(2) + s:write('Hello, world') +end, name = 'testserv'}); +--# setopt delimiter '' +type(addr) +server ~= nil +addr2 = server:name() +addr.host == addr2.host +addr.family == addr2.family +fiber.sleep(.5) +client = socket.tcp_connect(addr2.host, addr2.port) +client ~= nil +-- Check that listen and client fibers have appropriate names +cnt = 0 +--# setopt delimiter ';' +for i=100,200 do + local f = fiber.find(i) + if f and f:name():match('^testserv/') then + cnt = cnt + 1 + end +end; +--# setopt delimiter '' +cnt +client:write('hi') +client:read(123) +client:close() +server:close() longstring = string.rep("abc", 65535) server = socket.tcp_server('unix/', path, function(s) s:write(longstring) end) - client = socket.tcp_connect('unix/', path) client:read(#longstring) == longstring - client = socket.tcp_connect('unix/', path) client:read(#longstring + 1) == longstring - client = socket.tcp_connect('unix/', path) client:read(#longstring - 1) == string.sub(longstring, 1, #longstring - 1) - - longstring = "Hello\r\n\r\nworld\n\n" - client = socket.tcp_connect('unix/', path) client:read{ line = { "\n\n", "\r\n\r\n" } } - - -server:stop() -os.remove(path) +server:close() -- Test that socket is closed on GC diff --git a/test/box/cfg.result b/test/box/cfg.result index 86c19dbde9033cefeba93ac7d8585460cd4838cc..60f359c31f8e870efd19e77d2601ffbeea567c33 100644 --- a/test/box/cfg.result +++ b/test/box/cfg.result @@ -2,7 +2,7 @@ --# push filter 'admin: .*' to 'admin: <uri>' box.cfg.nosuchoption = 1 --- -- error: '[string "-- load_cfg.lua - internal file..."]:204: Attempt to modify a read-only +- error: '[string "-- load_cfg.lua - internal file..."]:191: Attempt to modify a read-only table' ... t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'function' then table.insert(t, k..': '..tostring(v)) end end @@ -63,4 +63,26 @@ t - 'snapshot_period: 0' - 'wal_dir_rescan_delay: 0.1' ... +-- check that cfg with unexpected parameter fails. +box.cfg{sherlock = 'holmes'} +--- +- error: '[string "-- load_cfg.lua - internal file..."]:121: Error: cfg parameter + ''sherlock'' is unexpected' +... +-- check that cfg with unexpected type of parameter failes +box.cfg{listen = {}} +--- +- error: '[string "-- load_cfg.lua - internal file..."]:136: Error: cfg parameter + ''listen'' should be one of types: string, number' +... +box.cfg{wal_dir = 0} +--- +- error: '[string "-- load_cfg.lua - internal file..."]:130: Error: cfg parameter + ''wal_dir'' should be of type string' +... +box.cfg{coredump = 'true'} +--- +- error: '[string "-- load_cfg.lua - internal file..."]:130: Error: cfg parameter + ''coredump'' should be of type boolean' +... --# clear filter diff --git a/test/box/cfg.test.lua b/test/box/cfg.test.lua index ee99deae794a6f606d6711abe6d65f4d19adb0d6..9d4e87075df1a961723c3e1a9badf8d65257f974 100644 --- a/test/box/cfg.test.lua +++ b/test/box/cfg.test.lua @@ -7,4 +7,13 @@ t box.cfg() t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'function' then table.insert(t, k..': '..tostring(v)) end end t + +-- check that cfg with unexpected parameter fails. +box.cfg{sherlock = 'holmes'} + +-- check that cfg with unexpected type of parameter failes +box.cfg{listen = {}} +box.cfg{wal_dir = 0} +box.cfg{coredump = 'true'} + --# clear filter diff --git a/test/box/iproto.test.py b/test/box/iproto.test.py index 031ae92ee3731de4a7ebceda1342dae17a07495a..d95af37e1e7f156fb18dfe925d637f7e29bb1c86 100644 --- a/test/box/iproto.test.py +++ b/test/box/iproto.test.py @@ -8,6 +8,7 @@ from tarantool import Connection from tarantool.request import RequestInsert from tarantool.request import RequestSelect from tarantool.response import Response +from lib.tarantool_connection import TarantoolConnection print """ # @@ -16,8 +17,9 @@ print """ """ # opeing new connection to tarantool/box -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) -s.connect(('localhost', server.sql.port)) +conn = TarantoolConnection(server.sql.host, server.sql.port) +conn.connect() +s = conn.socket print """ # Test bug #899343 (server assertion failure on incorrect packet) diff --git a/test/box/protocol.result b/test/box/protocol.result index fbbe9a349d1bfb0d36868ed35a4e8568f23f3d3a..f1e99fccb70c88b6891e9fa4be66a9540d47fd2b 100644 --- a/test/box/protocol.result +++ b/test/box/protocol.result @@ -13,10 +13,14 @@ space:create_index('primary', { type = 'tree'}) for i=1,5 do space:insert{i} end --- ... -port = string.gsub(box.cfg.listen, '^.*:', '') +LISTEN = require('uri').parse(box.cfg.listen) --- ... -conn = (require 'net.box'):new('127.0.0.1', tonumber(port)) +LISTEN ~= nil +--- +- true +... +conn = (require 'net.box'):new(LISTEN.host, LISTEN.service) --- ... conn.space[space.id]:select(3, { iterator = 'GE' }) diff --git a/test/box/protocol.test.lua b/test/box/protocol.test.lua index 975fb20ffa50199fbf1bf2e2e16568e5ff6e01ad..fa75d8d8cd854e8020ccfb2ae59dc567fcd1f6f1 100644 --- a/test/box/protocol.test.lua +++ b/test/box/protocol.test.lua @@ -8,8 +8,9 @@ space = box.schema.create_space('tweedledum') space:create_index('primary', { type = 'tree'}) for i=1,5 do space:insert{i} end -port = string.gsub(box.cfg.listen, '^.*:', '') -conn = (require 'net.box'):new('127.0.0.1', tonumber(port)) +LISTEN = require('uri').parse(box.cfg.listen) +LISTEN ~= nil +conn = (require 'net.box'):new(LISTEN.host, LISTEN.service) conn.space[space.id]:select(3, { iterator = 'GE' }) conn.space[space.id]:select(3, { iterator = 'LE' }) conn.space[space.id]:select(3, { iterator = 'GT' }) diff --git a/test/box/session.result b/test/box/session.result index b0610ea741b85f00382872938bfcf11f28861874..96469ca9389aae39fe99580b2ec388a3bc57bc05 100644 --- a/test/box/session.result +++ b/test/box/session.result @@ -128,7 +128,10 @@ session.on_disconnect(dec) active_connections = 0 --- ... -c = net.box:new(0, box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +--- +... +c = net.box:new(LISTEN.host, LISTEN.service) --- ... while active_connections < 1 do fiber.sleep(0.001) end @@ -138,7 +141,7 @@ active_connections --- - 1 ... -c1 = net.box:new(0, box.cfg.listen) +c1 = net.box:new(LISTEN.host, LISTEN.service) --- ... while active_connections < 2 do fiber.sleep(0.001) end @@ -183,7 +186,7 @@ session.on_disconnect(audit_disconnect) box.schema.user.grant('guest', 'read,write,execute', 'universe') --- ... -a = net.box:new('127.0.0.1', box.cfg.listen) +a = net.box:new(LISTEN.host, LISTEN.service) --- ... a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1] diff --git a/test/box/session.test.lua b/test/box/session.test.lua index 9be90f703391a53abcb661a3562237698bfbd292..95152624feb1015433c4c135a6500a97510228ed 100644 --- a/test/box/session.test.lua +++ b/test/box/session.test.lua @@ -51,10 +51,11 @@ net = { box = require('net.box') } session.on_connect(inc) session.on_disconnect(dec) active_connections = 0 -c = net.box:new(0, box.cfg.listen) +LISTEN = require('uri').parse(box.cfg.listen) +c = net.box:new(LISTEN.host, LISTEN.service) while active_connections < 1 do fiber.sleep(0.001) end active_connections -c1 = net.box:new(0, box.cfg.listen) +c1 = net.box:new(LISTEN.host, LISTEN.service) while active_connections < 2 do fiber.sleep(0.001) end active_connections c:close() @@ -72,7 +73,7 @@ session.on_connect(audit_connect) session.on_disconnect(audit_disconnect) box.schema.user.grant('guest', 'read,write,execute', 'universe') -a = net.box:new('127.0.0.1', box.cfg.listen) +a = net.box:new(LISTEN.host, LISTEN.service) a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1] a:close() diff --git a/test/lib/preprocessor.py b/test/lib/preprocessor.py index 8f536568d0ea86a77069ac872f2a369539dbf712..f5f63678679fd15f8f0aaf3d9d257cce2b2960ff 100644 --- a/test/lib/preprocessor.py +++ b/test/lib/preprocessor.py @@ -30,8 +30,8 @@ class TestState(object): # curcon is an array since we may have many connections self.curcon = [self.connections['default']] nmsp = Namespace() - setattr(nmsp, 'admin', default_server.admin.port) - setattr(nmsp, 'listen', default_server.sql.port) + setattr(nmsp, 'admin', default_server.admin.uri) + setattr(nmsp, 'listen', default_server.sql.uri) setattr(self.environ, 'default', nmsp) def parse_preprocessor(self, string): diff --git a/test/lib/server.py b/test/lib/server.py index d7f8420abf5cce5f8a899a0e30abcb1086a64467..5aed7f27a4f043480c1dacd8d5794908b699efb7 100644 --- a/test/lib/server.py +++ b/test/lib/server.py @@ -15,8 +15,7 @@ import ConfigParser def check_port(port): """Check if the port we're connecting to is available""" try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(("localhost", port)) + sock = socket.create_connection(("localhost", port)) except socket.error as e: return raise RuntimeError("The server is already running on port {0}".format(port)) diff --git a/test/lib/tarantool-python b/test/lib/tarantool-python index df94b88d87c249e41cdf45dd74b13a2949be24f0..b2bcd37691d3f4664bd34646078b02709fa102cd 160000 --- a/test/lib/tarantool-python +++ b/test/lib/tarantool-python @@ -1 +1 @@ -Subproject commit df94b88d87c249e41cdf45dd74b13a2949be24f0 +Subproject commit b2bcd37691d3f4664bd34646078b02709fa102cd diff --git a/test/lib/tarantool_connection.py b/test/lib/tarantool_connection.py index 873c1db09d874eb602abd2b82a73dbbc6e906b0e..5278809c10e72512cfb41ea95eb753da4633bbe6 100644 --- a/test/lib/tarantool_connection.py +++ b/test/lib/tarantool_connection.py @@ -27,6 +27,14 @@ import errno import re class TarantoolConnection(object): + + @property + def uri(self): + if self.host == 'unix/' or re.search(r'^/', str(self.port)): + return self.port + else: + return self.host+':'+str(self.port) + def __init__(self, host, port): self.host = host self.port = port @@ -37,9 +45,8 @@ class TarantoolConnection(object): self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self.socket.connect(self.port) else: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket = socket.create_connection((self.host, self.port)) self.socket.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) - self.socket.connect((self.host, self.port)) self.is_connected = True def disconnect(self): diff --git a/test/lib/tarantool_server.py b/test/lib/tarantool_server.py index 332d37cbfd996000cb9c4c950c361d366d5ffe17..114f505fbaff71e0aa8b38c274c9c803fa4e4b26 100644 --- a/test/lib/tarantool_server.py +++ b/test/lib/tarantool_server.py @@ -36,8 +36,7 @@ color_stdout = Colorer() def check_port(port, rais=True): try: if isinstance(port, (int, long)): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect(("localhost", port)) + sock = socket.create_connection(("localhost", port)) else: sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(port) @@ -464,10 +463,10 @@ class TarantoolServer(Server): check_port(self.admin.port) - os.putenv("LISTEN", str(self.sql.port)) - os.putenv("ADMIN", str(self.admin.port)) + os.putenv("LISTEN", self.sql.uri) + os.putenv("ADMIN", self.admin.uri) if self.rpl_master: - os.putenv("MASTER", "127.0.0.1:"+str(self.rpl_master.sql.port)) + os.putenv("MASTER", self.rpl_master.sql.uri) args = self.prepare_args() self.logfile_pos = self.logfile self.process = subprocess.Popen(args, diff --git a/test/replication/hot_standby.result b/test/replication/hot_standby.result index 65676c970e8ca4bc47d827bf854fb6ac33a1e5fb..0f939412486f09b1b533d1173cc859b3281fafcb 100644 --- a/test/replication/hot_standby.result +++ b/test/replication/hot_standby.result @@ -64,7 +64,14 @@ end; --# set connection default -- set begin lsn on master, replica and hot_standby. --# set variable replica_port to 'replica.listen' -a = (require 'net.box'):new('127.0.0.1', replica_port) +REPLICA = require('uri').parse(tostring(replica_port)) +--- +... +REPLICA ~= nil +--- +- true +... +a = (require 'net.box'):new(REPLICA.host, REPLICA.service) --- ... a:call('_set_pri_lsn', box.info.server.id, box.info.server.lsn) @@ -132,7 +139,14 @@ while box.info.status ~= 'running' do fiber.sleep(0.001) end -- hot_standby.listen is garbage, since hot_standby.lua -- uses MASTER environment variable for its listen --# set variable hot_standby_port to 'hot_standby.master' -a = (require 'net.box'):new('127.0.0.1', hot_standby_port) +HOT_STANDBY = require('uri').parse(tostring(hot_standby_port)) +--- +... +HOT_STANDBY ~= nil +--- +- true +... +a = (require 'net.box'):new(HOT_STANDBY.host, HOT_STANDBY.service) --- ... a:call('_set_pri_lsn', box.info.server.id, box.info.server.lsn) diff --git a/test/replication/hot_standby.test.lua b/test/replication/hot_standby.test.lua index e52f915b86fa06c02bfd5b890db023638db34a42..82c5165dfdd6a7e70fe23595a3e160e58cf77671 100644 --- a/test/replication/hot_standby.test.lua +++ b/test/replication/hot_standby.test.lua @@ -56,7 +56,9 @@ end; -- set begin lsn on master, replica and hot_standby. --# set variable replica_port to 'replica.listen' -a = (require 'net.box'):new('127.0.0.1', replica_port) +REPLICA = require('uri').parse(tostring(replica_port)) +REPLICA ~= nil +a = (require 'net.box'):new(REPLICA.host, REPLICA.service) a:call('_set_pri_lsn', box.info.server.id, box.info.server.lsn) a:close() @@ -78,7 +80,9 @@ while box.info.status ~= 'running' do fiber.sleep(0.001) end -- hot_standby.listen is garbage, since hot_standby.lua -- uses MASTER environment variable for its listen --# set variable hot_standby_port to 'hot_standby.master' -a = (require 'net.box'):new('127.0.0.1', hot_standby_port) +HOT_STANDBY = require('uri').parse(tostring(hot_standby_port)) +HOT_STANDBY ~= nil +a = (require 'net.box'):new(HOT_STANDBY.host, HOT_STANDBY.service) a:call('_set_pri_lsn', box.info.server.id, box.info.server.lsn) a:close() diff --git a/test/replication/swap.test.py b/test/replication/swap.test.py index 49088df3f94ba61fb7a623c70903340463802149..eb3021ebdad958602e7d0454f9309e03a5765cbc 100644 --- a/test/replication/swap.test.py +++ b/test/replication/swap.test.py @@ -7,7 +7,6 @@ import yaml REPEAT = 20 ID_BEGIN = 0 ID_STEP = 5 -HOST = '127.0.0.1' LOGIN = 'test' PASSWORD = 'pass123456' @@ -24,7 +23,7 @@ master = server master.admin("box.schema.user.create('%s', { password = '%s'})" % (LOGIN, PASSWORD)) master.admin("box.schema.user.grant('%s', 'read,write,execute', 'universe')" % LOGIN) master.sql.py_con.authenticate(LOGIN, PASSWORD) -master.uri = '%s:%s@%s:%s' % (LOGIN, PASSWORD, HOST, master.sql.port) +master.uri = '%s:%s@%s' % (LOGIN, PASSWORD, master.sql.uri) os.putenv('MASTER', master.uri) # replica server @@ -33,7 +32,7 @@ replica.script = "replication/replica.lua" replica.vardir = os.path.join(server.vardir, 'replica') replica.deploy() replica.admin("while box.info.server == nil do require('fiber').sleep(0.01) end") -replica.uri = '%s:%s@%s:%s' % (LOGIN, PASSWORD, HOST, replica.sql.port) +replica.uri = '%s:%s@%s' % (LOGIN, PASSWORD, replica.sql.uri) replica.admin("while box.space['_priv']:len() < 1 do require('fiber').sleep(0.01) end") replica.sql.py_con.authenticate(LOGIN, PASSWORD) @@ -42,7 +41,7 @@ master.admin("s:create_index('primary', {type = 'hash'})") ### gh-343: replica.cc must not add login and password to proc title #status = replica.get_param("status") -#host_port = "%s:%s" % (HOST, master.sql.port) +#host_port = "%s:%s" % master.sql.uri #m = re.search(r'replica/(.*)/.*', status) #if not m or m.group(1) != host_port: # print 'invalid box.info.status', status, 'expected host:port', host_port diff --git a/test/sophia/crud.result b/test/sophia/crud.result index 236262ca5bb91327cb6e2bb204c2fe03a5897cfc..52822918ea54bc3c82205c05c31912985589da3d 100644 --- a/test/sophia/crud.result +++ b/test/sophia/crud.result @@ -1161,9 +1161,18 @@ index:select(7, {iterator = box.index.LT}) - [2] - [1] ... +-- random +dofile('index_random_test.lua') +--- +... +index_random_test(space, 'primary') +--- +- true +... space:drop() --- ... +-- sophia_rmdir() --- ... diff --git a/test/sophia/crud.test.lua b/test/sophia/crud.test.lua index 204853e301b6fdf7f5d15bc3bd69842c2a32745b..191a58057830fb0de8478d8a21cbcf01e88b9e29 100644 --- a/test/sophia/crud.test.lua +++ b/test/sophia/crud.test.lua @@ -43,6 +43,13 @@ index:select(7, {iterator = box.index.LE}) index:select({}, {iterator = box.index.LT}) index:select(7, {iterator = box.index.LT}) +-- random + +dofile('index_random_test.lua') +index_random_test(space, 'primary') + space:drop() +-- + sophia_rmdir() diff --git a/test/sophia/dml.result b/test/sophia/dml.result index 8276e134d01b32ee38e60b1cb41bbee6b9efe6b0..69b0f8746bf5b7d9d09d73126652466522b10167 100644 --- a/test/sophia/dml.result +++ b/test/sophia/dml.result @@ -20,7 +20,7 @@ sophia_printdir() space = box.schema.create_space('test', { id = 101, engine = 'sophia' }) --- ... -primary = space:create_index('primary') +space:create_index('primary') --- ... sophia_printdir() @@ -40,7 +40,7 @@ sophia_printdir() space = box.schema.create_space('test', { id = 102, engine = 'sophia' }) --- ... -primary = space:create_index('primary') +space:create_index('primary') --- ... sophia_printdir() @@ -67,7 +67,7 @@ space:drop() space = box.schema.create_space('test', { id = 103, engine = 'sophia' }) --- ... -primary = space:create_index('primary', {type = 'tree', parts = {1, 'STR'}}) +space:create_index('primary', {type = 'tree', parts = {1, 'STR'}}) --- ... space:insert({'test'}) @@ -87,7 +87,7 @@ space:drop() space = box.schema.create_space('test', { id = 104, engine = 'sophia' }) --- ... -primary = space:create_index('primary', {type = 'tree', parts = {1, 'num'}}) +space:create_index('primary', {type = 'tree', parts = {1, 'num'}}) --- ... space:insert({13}) @@ -107,7 +107,7 @@ space:drop() space = box.schema.create_space('test', { id = 105, engine = 'sophia' }) --- ... -primary = space:create_index('primary', {type = 'hash'}) +space:create_index('primary', {type = 'hash'}) --- - error: Unsupported index type supplied for index 0 in space 105 ... @@ -133,6 +133,39 @@ sophia_printdir() --- - ... +-- index size +space = box.schema.create_space('test', { id = 107, engine = 'sophia' }) +--- +... +space:create_index('primary') +--- +... +primary = space.index[0] +--- +... +primary:len() +--- +- 0 +... +space:insert({13}) +--- +- [13] +... +space:insert({14}) +--- +- [14] +... +space:insert({15}) +--- +- [15] +... +primary:len() +--- +- 3 +... +space:drop() +--- +... sophia_rmdir() --- ... diff --git a/test/sophia/dml.test.lua b/test/sophia/dml.test.lua index b26ba247b795eff9d047a9c4ca9bb9555603347f..56ca115287d3c6edca13fda99bc4e70c403e45c4 100644 --- a/test/sophia/dml.test.lua +++ b/test/sophia/dml.test.lua @@ -11,7 +11,7 @@ sophia_printdir() -- index create/drop space = box.schema.create_space('test', { id = 101, engine = 'sophia' }) -primary = space:create_index('primary') +space:create_index('primary') sophia_printdir() space:drop() sophia_printdir() @@ -19,7 +19,7 @@ sophia_printdir() -- index create/drop alter space = box.schema.create_space('test', { id = 102, engine = 'sophia' }) -primary = space:create_index('primary') +space:create_index('primary') sophia_printdir() _index = box.space[box.schema.INDEX_ID] _index:delete{102, 0} @@ -29,7 +29,7 @@ space:drop() -- index create/drop tree string space = box.schema.create_space('test', { id = 103, engine = 'sophia' }) -primary = space:create_index('primary', {type = 'tree', parts = {1, 'STR'}}) +space:create_index('primary', {type = 'tree', parts = {1, 'STR'}}) space:insert({'test'}) sophia_printdir() space:drop() @@ -37,7 +37,7 @@ space:drop() -- index create/drop tree num space = box.schema.create_space('test', { id = 104, engine = 'sophia' }) -primary = space:create_index('primary', {type = 'tree', parts = {1, 'num'}}) +space:create_index('primary', {type = 'tree', parts = {1, 'num'}}) space:insert({13}) sophia_printdir() space:drop() @@ -45,7 +45,7 @@ space:drop() -- index create hash space = box.schema.create_space('test', { id = 105, engine = 'sophia' }) -primary = space:create_index('primary', {type = 'hash'}) +space:create_index('primary', {type = 'hash'}) space:drop() -- secondary index create @@ -56,4 +56,16 @@ space:create_index('secondary') space:drop() sophia_printdir() +-- index size + +space = box.schema.create_space('test', { id = 107, engine = 'sophia' }) +space:create_index('primary') +primary = space.index[0] +primary:len() +space:insert({13}) +space:insert({14}) +space:insert({15}) +primary:len() +space:drop() + sophia_rmdir() diff --git a/test/sophia/gh.result b/test/sophia/gh.result index 9b0340de6b4e16b98f109f45f9ff66abf9a2e336..7debe9511955e359d13fe24eb09354eca7aebd68 100644 --- a/test/sophia/gh.result +++ b/test/sophia/gh.result @@ -94,24 +94,6 @@ s:select{10000} s:drop() --- ... --- gh-456: Sophia: index size() is unsupported -s = box.schema.create_space('tester',{engine='sophia'}) ---- -... -s:create_index('sophia_index', {}) ---- -... -s.index[0]:len() -- exception ---- -- error: SophiaIndex does not support size operation -... -box.error() ---- -- error: SophiaIndex does not support size operation -... -s:drop() ---- -... -- gh-436: No error when creating temporary sophia space s = box.schema.create_space('tester',{engine='sophia', temporary=true}) --- diff --git a/test/sophia/gh.test.lua b/test/sophia/gh.test.lua index 1cfc5e8101132fb959903d6e36eb896413532c08..790863b4d17aee01ae13a365d1f4ff4f0924de0f 100644 --- a/test/sophia/gh.test.lua +++ b/test/sophia/gh.test.lua @@ -39,14 +39,6 @@ box.rollback() s:select{10000} s:drop() --- gh-456: Sophia: index size() is unsupported - -s = box.schema.create_space('tester',{engine='sophia'}) -s:create_index('sophia_index', {}) -s.index[0]:len() -- exception -box.error() -s:drop() - -- gh-436: No error when creating temporary sophia space s = box.schema.create_space('tester',{engine='sophia', temporary=true}) diff --git a/test/sophia/index_random_test.lua b/test/sophia/index_random_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..5fb09f03c2b4c48723d45c62fd7181b1a5e0da73 --- /dev/null +++ b/test/sophia/index_random_test.lua @@ -0,0 +1,36 @@ + +function index_random_test(space, index_no) + local COUNT = 1028 + -- clear the space + space:truncate() + -- randomize + math.randomseed(os.time()) + -- insert values into the index + for k=1,COUNT,1 do space:insert{k} end + local rnd_start = math.random(4294967296) + -- try to get all values from the index using index.random + local tuples = {} + local found = 0 + while found < COUNT do + local rnd = math.random(4294967296) + if rnd == rnd_start then + error('too many iterations') + return nil + end + + local tuple = space.index[index_no]:random(rnd) + if tuple == nil then + error('nil returned') + return nil + end + print(tuple) + + local k = tuple[1] + if tuples[k] == nil then + found = found + 1 + end + tuples[k] = 1 + end + + return true +end diff --git a/test/sophia/suite.ini b/test/sophia/suite.ini index 5139d0b87a1637c650a005a530dc72e9ef6f6986..ddf62d5dadc3cadb5233e84cb7d7eed7348221ba 100644 --- a/test/sophia/suite.ini +++ b/test/sophia/suite.ini @@ -5,5 +5,5 @@ script = box.lua disabled = valgrind_disabled = release_disabled = -lua_libs = +lua_libs = index_random_test.lua use_unix_sockets = True diff --git a/test/unit/fiob.skipcond b/test/unit/fiob.skipcond new file mode 100644 index 0000000000000000000000000000000000000000..d246d3b7c4bf083f7654bd631877fc1579adaedf --- /dev/null +++ b/test/unit/fiob.skipcond @@ -0,0 +1,17 @@ +# vim: set ft=python : +import re +import os +import os.path +import tempfile + +dir = tempfile.mkdtemp() +file = os.path.join(dir, 'test-o-direct') + +try: + fh = os.open(file, os.O_CREAT | os.O_DIRECT | os.O_TRUNC | os.O_RDWR) + os.unlink(file) + os.rmdir(dir) +except: + self.skip = 1 + + diff --git a/third_party/sophia b/third_party/sophia index 95a187853ad34e858897871e6b4047df82febf89..6c6c69d376d8452a7dfefd2086c4934065ab89cc 160000 --- a/third_party/sophia +++ b/third_party/sophia @@ -1 +1 @@ -Subproject commit 95a187853ad34e858897871e6b4047df82febf89 +Subproject commit 6c6c69d376d8452a7dfefd2086c4934065ab89cc